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; 020import org.apache.camel.CamelContext; 021import org.apache.camel.Exchange; 022import org.apache.camel.Message; 023import org.apache.camel.converter.stream.OutputStreamBuilder; 024import org.apache.camel.model.DataFormatDefinition; 025import org.apache.camel.spi.DataFormat; 026import org.apache.camel.spi.DataType; 027import org.apache.camel.spi.Transformer; 028import org.apache.camel.util.ServiceHelper; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032/** 033 * A {@link Transformer} implementation which leverages {@link DataFormat} to perform transformation. 034 * 035 * {@see Transformer} 036 */ 037public class DataFormatTransformer extends Transformer { 038 private static final Logger LOG = LoggerFactory.getLogger(DataFormatTransformer.class); 039 040 private String dataFormatRef; 041 private DataFormatDefinition dataFormatType; 042 private DataFormat dataFormat; 043 private String transformerString; 044 045 public DataFormatTransformer(CamelContext context) { 046 setCamelContext(context); 047 } 048 049 /** 050 * Perform data transformation with specified from/to type using DataFormat. 051 * @param message message to apply transformation 052 * @param from 'from' data type 053 * @param to 'to' data type 054 */ 055 @Override 056 public void transform(Message message, DataType from, DataType to) throws Exception { 057 Exchange exchange = message.getExchange(); 058 CamelContext context = exchange.getContext(); 059 060 // Unmarshaling into Java Object 061 if ((to == null || to.isJavaType()) && (from.equals(getFrom()) || from.getModel().equals(getModel()))) { 062 DataFormat dataFormat = getDataFormat(exchange); 063 LOG.debug("Unmarshaling with '{}'", dataFormat); 064 Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class)); 065 if (to != null && to.getName() != null) { 066 Class<?> toClass = context.getClassResolver().resolveClass(to.getName()); 067 if (!toClass.isAssignableFrom(answer.getClass())) { 068 LOG.debug("Converting to '{}'", toClass.getName()); 069 answer = context.getTypeConverter().mandatoryConvertTo(toClass, answer); 070 } 071 } 072 message.setBody(answer); 073 074 // Marshaling from Java Object 075 } else if ((from == null || from.isJavaType()) && (to.equals(getTo()) || to.getModel().equals(getModel()))) { 076 Object input = message.getBody(); 077 if (from != null && from.getName() != null) { 078 Class<?> fromClass = context.getClassResolver().resolveClass(from.getName()); 079 if (!fromClass.isAssignableFrom(input.getClass())) { 080 LOG.debug("Converting to '{}'", fromClass.getName()); 081 input = context.getTypeConverter().mandatoryConvertTo(fromClass, input); 082 } 083 } 084 OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange); 085 DataFormat dataFormat = getDataFormat(exchange); 086 LOG.debug("Marshaling with '{}'", dataFormat); 087 dataFormat.marshal(exchange, message.getBody(), osb); 088 message.setBody(osb.build()); 089 090 } else { 091 throw new IllegalArgumentException("Unsupported transformation: from='" + from + ", to='" + to + "'"); 092 } 093 } 094 095 /** 096 * A bit dirty hack to create DataFormat instance, as it requires a RouteContext anyway. 097 */ 098 private DataFormat getDataFormat(Exchange exchange) throws Exception { 099 if (this.dataFormat == null) { 100 this.dataFormat = DataFormatDefinition.getDataFormat( 101 exchange.getUnitOfWork().getRouteContext(), this.dataFormatType, this.dataFormatRef); 102 if (this.dataFormat != null && !getCamelContext().hasService(this.dataFormat)) { 103 getCamelContext().addService(this.dataFormat, false); 104 } 105 } 106 return this.dataFormat; 107 } 108 109 /** 110 * Set DataFormat ref. 111 * @param ref DataFormat ref 112 * @return this DataFormatTransformer instance 113 */ 114 public DataFormatTransformer setDataFormatRef(String ref) { 115 this.dataFormatRef = ref; 116 this.transformerString = null; 117 return this; 118 } 119 120 /** 121 * Set DataFormatDefinition. 122 * @param dataFormatType DataFormatDefinition 123 * @return this DataFormatTransformer instance 124 */ 125 public DataFormatTransformer setDataFormatType(DataFormatDefinition dataFormatType) { 126 this.dataFormatType = dataFormatType; 127 this.transformerString = null; 128 return this; 129 } 130 131 @Override 132 public String toString() { 133 if (transformerString == null) { 134 transformerString = 135 String.format("DataFormatTransformer[scheme='%s', from='%s', to='%s', ref='%s', type='%s']", 136 getModel(), getFrom(), getTo(), dataFormatRef, dataFormatType); 137 } 138 return transformerString; 139 } 140 141 @Override 142 public void doStart() throws Exception { 143 // no-op 144 } 145 146 @Override 147 public void doStop() throws Exception { 148 ServiceHelper.stopService(this.dataFormat); 149 getCamelContext().removeService(this.dataFormat); 150 } 151}