001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.impl.transformer; 018 019import java.io.InputStream; 020 021import org.apache.camel.CamelContext; 022import org.apache.camel.Exchange; 023import org.apache.camel.Message; 024import org.apache.camel.converter.stream.OutputStreamBuilder; 025import org.apache.camel.model.DataFormatDefinition; 026import org.apache.camel.spi.DataFormat; 027import org.apache.camel.spi.DataType; 028import org.apache.camel.spi.Transformer; 029import org.apache.camel.util.ServiceHelper; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * A {@link Transformer} implementation which leverages {@link DataFormat} to perform transformation. 035 * 036 * {@see Transformer} 037 */ 038public class DataFormatTransformer extends Transformer { 039 private static final Logger LOG = LoggerFactory.getLogger(DataFormatTransformer.class); 040 041 private String dataFormatRef; 042 private DataFormatDefinition dataFormatType; 043 private DataFormat dataFormat; 044 private String transformerString; 045 046 public DataFormatTransformer(CamelContext context) { 047 setCamelContext(context); 048 } 049 050 /** 051 * Perform data transformation with specified from/to type using DataFormat. 052 * @param message message to apply transformation 053 * @param from 'from' data type 054 * @param to 'to' data type 055 */ 056 @Override 057 public void transform(Message message, DataType from, DataType to) throws Exception { 058 Exchange exchange = message.getExchange(); 059 CamelContext context = exchange.getContext(); 060 061 // Unmarshaling into Java Object 062 if ((to == null || to.isJavaType()) && (from.equals(getFrom()) || from.getModel().equals(getModel()))) { 063 DataFormat dataFormat = getDataFormat(exchange); 064 LOG.debug("Unmarshaling with '{}'", dataFormat); 065 Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class)); 066 if (to != null && to.getName() != null) { 067 Class<?> toClass = context.getClassResolver().resolveClass(to.getName()); 068 if (!toClass.isAssignableFrom(answer.getClass())) { 069 LOG.debug("Converting to '{}'", toClass.getName()); 070 answer = context.getTypeConverter().mandatoryConvertTo(toClass, answer); 071 } 072 } 073 message.setBody(answer); 074 075 // Marshaling from Java Object 076 } else if ((from == null || from.isJavaType()) && (to.equals(getTo()) || to.getModel().equals(getModel()))) { 077 Object input = message.getBody(); 078 if (from != null && from.getName() != null) { 079 Class<?> fromClass = context.getClassResolver().resolveClass(from.getName()); 080 if (!fromClass.isAssignableFrom(input.getClass())) { 081 LOG.debug("Converting to '{}'", fromClass.getName()); 082 input = context.getTypeConverter().mandatoryConvertTo(fromClass, input); 083 } 084 } 085 OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange); 086 DataFormat dataFormat = getDataFormat(exchange); 087 LOG.debug("Marshaling with '{}'", dataFormat); 088 dataFormat.marshal(exchange, message.getBody(), osb); 089 message.setBody(osb.build()); 090 091 } else { 092 throw new IllegalArgumentException("Unsupported transformation: from='" + from + ", to='" + to + "'"); 093 } 094 } 095 096 /** 097 * A bit dirty hack to create DataFormat instance, as it requires a RouteContext anyway. 098 */ 099 private DataFormat getDataFormat(Exchange exchange) throws Exception { 100 if (this.dataFormat == null) { 101 this.dataFormat = DataFormatDefinition.getDataFormat( 102 exchange.getUnitOfWork().getRouteContext(), this.dataFormatType, this.dataFormatRef); 103 if (this.dataFormat != null && !getCamelContext().hasService(this.dataFormat)) { 104 getCamelContext().addService(this.dataFormat, false); 105 } 106 } 107 return this.dataFormat; 108 } 109 110 /** 111 * Set DataFormat ref. 112 * @param ref DataFormat ref 113 * @return this DataFormatTransformer instance 114 */ 115 public DataFormatTransformer setDataFormatRef(String ref) { 116 this.dataFormatRef = ref; 117 this.transformerString = null; 118 return this; 119 } 120 121 /** 122 * Set DataFormatDefinition. 123 * @param dataFormatType DataFormatDefinition 124 * @return this DataFormatTransformer instance 125 */ 126 public DataFormatTransformer setDataFormatType(DataFormatDefinition dataFormatType) { 127 this.dataFormatType = dataFormatType; 128 this.transformerString = null; 129 return this; 130 } 131 132 @Override 133 public String toString() { 134 if (transformerString == null) { 135 transformerString = 136 String.format("DataFormatTransformer[scheme='%s', from='%s', to='%s', ref='%s', type='%s']", 137 getModel(), getFrom(), getTo(), dataFormatRef, dataFormatType); 138 } 139 return transformerString; 140 } 141 142 @Override 143 public void doStart() throws Exception { 144 // no-op 145 } 146 147 @Override 148 public void doStop() throws Exception { 149 ServiceHelper.stopService(this.dataFormat); 150 getCamelContext().removeService(this.dataFormat); 151 } 152}