/*
* 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;
}
}