/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.soa.esb.actions.converters;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.actions.AbstractActionPipelineProcessor;
import org.jboss.soa.esb.actions.ActionProcessingException;
import org.jboss.soa.esb.actions.ActionUtils;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.helpers.KeyValuePair;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.MessagePayloadProxy;
import org.jboss.soa.esb.message.body.content.BytesBody;
/**
* Object to CSV String processor.
* <p/>
* Returns a CSV string based on the supplied message object and a comma-separated "bean-properties"
* action property that specifies a list of bean property names.
* <p/>
* Sample Action Configuration:
* <pre>
* <Action name="Customer-To-CSV" processor="ObjectToCSVString">
* <property name="bean-properties" value="name,address1,address2,phone" />
* <property name="fail-on-missing-property" value="true" /> <!-- (Optional) Default of false. -->
* </Action>
* </pre>
* <p/>
* TODO: Add support for arrays ala producing the contents of a CSV file.
* @author <a href="mailto:tom.fennelly@jboss.com">tom.fennelly@jboss.com</a>
* @since Version 4.0
*/
public class ObjectToCSVString extends AbstractActionPipelineProcessor {
public static final String BEAN_PROPERTIES_PROP = "bean-properties";
public static final String FAIL_ON_MISSING_PROPERTY = "fail-on-missing-property";
private static Logger logger = Logger.getLogger(ObjectToCSVString.class);
private List<String> propertyMethodNames = new ArrayList<String>();
private boolean failOnMissingProperty;
private MessagePayloadProxy payloadProxy;
/**
* Public constructor.
* @param properties Action Properties.
* @throws ConfigurationException Action not properly configured.
*/
public ObjectToCSVString(ConfigTree properties) throws ConfigurationException {
this("ObjectToCSVString", properties.attributesAsList());
payloadProxy = new MessagePayloadProxy(properties,
new String[] {BytesBody.BYTES_LOCATION, ActionUtils.POST_ACTION_DATA},
new String[] {ActionUtils.POST_ACTION_DATA});
}
/**
* Public constructor.
* @param actionName Action name.
* @param properties Action Properties.
* @throws ConfigurationException Action not properly configured.
*/
private ObjectToCSVString(String actionName, List<KeyValuePair> properties) throws ConfigurationException {
String objectProps = KeyValuePair.getValue(BEAN_PROPERTIES_PROP, properties);
if(objectProps == null || objectProps.trim().equals("")) {
throw new ConfigurationException("Action [" + actionName + "] must specify a comma seperated object bean property list via a '" + BEAN_PROPERTIES_PROP + "' property setting.");
}
// Construct a bean method name list from the configured property name list...
String[] propertyNames = objectProps.split(",");
StringBuffer methodNameConstructionBuffer = new StringBuffer();
for(String propertyName : propertyNames) {
propertyName = propertyName.trim();
if(propertyName.equals("")) {
continue;
}
methodNameConstructionBuffer.setLength(0);
methodNameConstructionBuffer.append("get");
methodNameConstructionBuffer.append(propertyName);
// Capitalise the 4th char to make it a proper bean method....
methodNameConstructionBuffer.setCharAt(3, Character.toUpperCase(methodNameConstructionBuffer.charAt(3)));
// Add to the set...
propertyMethodNames.add(methodNameConstructionBuffer.toString());
}
failOnMissingProperty = KeyValuePair.getBooleanValue(FAIL_ON_MISSING_PROPERTY, properties, false);
}
/* (non-Javadoc)
* @see org.jboss.soa.esb.actions.ActionProcessor#process(java.lang.Object)
*/
public Message process(Message message) throws ActionProcessingException {
Object oCurr = null;
try {
oCurr = payloadProxy.getPayload(message);
} catch (MessageDeliverException e) {
throw new ActionProcessingException(e);
}
Class oCurrClass = (null==oCurr) ? null : oCurr.getClass();
StringBuffer csv = new StringBuffer();
boolean hasAppendStarted = false; // Have we appended a value yet?
for(String methodName : propertyMethodNames) {
Method method;
if(hasAppendStarted) {
csv.append(",");
}
hasAppendStarted = true;
// Get the bean method....
try {
method = oCurrClass.getMethod(methodName, new Class[] {});
} catch (Exception e) {
String exceptionMessage = "Bean method: " + methodName + " not found/accessible on message object " + oCurr.getClass().getName();
logger.error(exceptionMessage, e);
if(failOnMissingProperty) {
throw new ActionProcessingException(exceptionMessage, e);
}
csv.append("<no-such-property>");
continue;
}
// Call the bean method and add the toString of the return to the CSV string....
try {
Object value = method.invoke(oCurr, new Object[] {});
// TODO: Some sort of encoding is required here to make a proper CSV string...
csv.append(value != null?value.toString():"");
} catch (Exception e) {
logger.error("Exception calling bean method: " + methodName, e);
}
}
try {
payloadProxy.setPayload(message, csv.toString());
} catch (MessageDeliverException e) {
throw new ActionProcessingException(e);
}
return message;
}
}