/* * Copyright 2011-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package biz.c24.io.spring.integration.transformer; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.messaging.Message; import org.springframework.integration.transformer.AbstractTransformer; import org.springframework.util.Assert; import biz.c24.io.api.data.ComplexDataObject; import biz.c24.io.api.presentation.JavaClassSink; import biz.c24.io.api.transform.Transform; /** * TODO Consider adding a subclass that uses a pool of transform objects. * * @author askogman * @author Andrew Elmore * */ public class C24Transformer extends AbstractTransformer implements InitializingBean { private final Log logger = LogFactory.getLog(this.getClass()); private Class<? extends Transform> transformClass; private JavaClassSink javaSink = null; private boolean alwaysReturnArray = false; public Class<? extends Transform> getTransformClass() { return transformClass; } // Cache Transforms per-thread for performance private ThreadLocal<Transform> transform = new ThreadLocal<Transform>(); public void setTransformClass(Class<? extends Transform> transformClass) { Assert.notNull(transformClass, "The transform class cannot be set to null"); this.transformClass = transformClass; } /* * Controls whether this transformer returns its default ComplexDataObject-based destination type, or instances of the supplied bean-compliant type. * * @param targetClass Either null (to use the default CDO-based type) or a Java Bean compliant class whose fields match those of the target model. */ public void setTargetClass(Class<?> targetClass) { if(targetClass != null) { javaSink = new JavaClassSink(); javaSink.setRootClass(targetClass); } else { javaSink = null; } } /** * */ public C24Transformer() { } /** * * @return The transformed payload * * @see org.springframework.integration.transformer.AbstractTransformer#doTransform * (org.springframework.messaging.Message) */ @Override protected Object doTransform(Message<?> message) throws Exception { Transform transform = buildTransform(message); // TODO Support list or array as input Object payload = message.getPayload(); Object[][] results = transform .transform(new Object[][] { new Object[] { payload } }); Object output = extractOutputPayload(results); return output; } protected Object extractOutputPayload(Object[][] results) throws IOException { if (results.length == 0) { // Empty matrix return alwaysReturnArray ? new Object[0] : null; } // Get the first vector from matrix List resultVector = new ArrayList(); for(int i = 0; i < results.length; i++) { if (results[i].length > 0) {//Some outputs may be null for (int j = 0; j < results[i].length; j++) { resultVector.add(results[i][j]); } } } if (resultVector.size() == 0) { // Empty matrix return alwaysReturnArray ? new Object[0] : null; } // Single result, unwrap and use as new payload. Fairly common. if (resultVector.size() == 1 && !alwaysReturnArray) { return sink(resultVector.get(0)); } // Return a full array of output return sink(resultVector.toArray()); } private Object sink(Object obj) throws IOException { if(javaSink != null) { obj = javaSink.convertObject((ComplexDataObject)obj); } return obj; } private Object[] sink(Object[] objs) throws IOException { if(javaSink != null) { for(int i = 0; i < objs.length; i++) { objs[i] = javaSink.convertObject((ComplexDataObject)objs[i]); } } return objs; } /** * * @param message * @return * @throws Exception */ protected Transform buildTransform(Message<?> message) throws Exception { Transform xform = this.transform.get(); if(xform == null) { xform = createTransform(); this.transform.set(xform); } return xform; } protected Transform createTransform() throws Exception { try { return transformClass.newInstance(); } catch (Exception e) { logger.error("Could not instantiate Transformer of class [" + transformClass.getName() + "]", e); throw e; } } @Override protected void onInit() throws Exception { super.onInit(); Assert.state(transformClass != null, "The transformClass property must not be null"); try { createTransform(); } catch (Exception e) { throw new IllegalArgumentException( "The provided transform class threw an exception from its default constructor.", e); } } public boolean isAlwaysReturnArray() { return alwaysReturnArray; } public void setAlwaysReturnArray(boolean alwaysReturnArray) { this.alwaysReturnArray = alwaysReturnArray; } }