/*
* 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.listeners.gateway;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.util.StreamUtils;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.addressing.EPR;
import org.jboss.soa.esb.addressing.eprs.JDBCEpr;
import org.jboss.soa.esb.client.ServiceInvoker;
import org.jboss.soa.esb.common.Environment;
import org.jboss.soa.esb.common.TransactionStrategy;
import org.jboss.soa.esb.common.TransactionStrategyException;
import org.jboss.soa.esb.couriers.CourierException;
import org.jboss.soa.esb.filter.FilterManager;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.helpers.persist.JdbcCleanConn;
import org.jboss.soa.esb.helpers.persist.SimpleDataSource;
import org.jboss.soa.esb.listeners.ListenerTagNames;
import org.jboss.soa.esb.listeners.ListenerUtil;
import org.jboss.soa.esb.listeners.RegistryUtil;
import org.jboss.soa.esb.listeners.lifecycle.AbstractThreadedManagedLifecycle;
import org.jboss.soa.esb.listeners.lifecycle.ManagedLifecycleException;
import org.jboss.soa.esb.listeners.lifecycle.ManagedLifecycleThreadState;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.MessagePayloadProxy;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.services.registry.RegistryException;
import org.jboss.soa.esb.services.registry.ServiceNotFoundException;
import org.jboss.soa.esb.util.ClassUtil;
import org.jboss.soa.esb.util.Util;
/**
* Polls an SQL table for rows that satisfy conditions defined in the xml
* runtime configuration
* <p/>
* <p/>When a row that matches conditions is retrieved, it's contents are packed
* into an ESB Message and
* <p/>
* <p/> The following fields are mandatory (see checkMyParms()): <br/> <br/>SQL
* table name <br/>list of fields to retrieve <br/>list of key fields to use in
* the update statement <br/>a field that will be used to mark a row as
* 'P' (pending), 'W' (in process), 'D' (done) or 'E' (error). When adding
* a pending row, make sure that the status_col value if an upper-cased 'P', as
* upper-cased characters are used as a convention.
*
* @author <a
* href="mailto:schifest@heuristica.com.ar">schifest@heuristica.com.ar</a>
* @author <a href="mailto:tcunning@redhat.com">tcunning@redhat.com</a>
* @since Version 4.0
*/
public class SqlTableGatewayListener extends AbstractThreadedManagedLifecycle {
/**
* The current transaction strategy
*/
private TransactionStrategy transactionStrategy ;
private boolean transacted;
public SqlTableGatewayListener(ConfigTree config)
throws ConfigurationException {
super(config);
_config = config;
_sleepBetweenPolls = 10000;
checkMyParms();
} // __________________________________
/**
* Handle the initialisation of the managed instance.
*
* @throws ManagedLifecycleException for errors while initialisation.
*/
protected void doInitialise() throws ManagedLifecycleException {
// Needed to retain prior semantics of fail-on-initialise if service lookup fails
try {
Collection<EPR> _targetEprs = RegistryUtil.getEprs(_targetServiceCategory,
_targetServiceName);
if (null == _targetEprs || _targetEprs.size() < 1)
throw new ManagedLifecycleException("EPR <"
+ _targetServiceName + "> not found in registry");
} catch (ServiceNotFoundException snfe) {
throw new ManagedLifecycleException("EPR <" + _targetServiceName + " "
+ _targetServiceName + "> not found in registry");
}
catch (final RegistryException re) {
throw new ManagedLifecycleException("Unexpected registry exception", re);
}
try {
_serviceInvoker = new ServiceInvoker(_targetServiceCategory, _targetServiceName);
_serviceInvoker.loadServiceClusterInfo();
} catch (MessageDeliverException mde) {
throw new ManagedLifecycleException(mde);
}
boolean failure = true;
try {
_dbConn = getDbConn();
failure = false;
}
finally {
if (failure) {
releaseDBConnection();
}
}
}
/**
* Execute on the thread.
*/
protected void doRun() {
if (_logger.isDebugEnabled()) {
_logger.debug("doRun() method of "
+ this.getClass().getSimpleName() + " started on thread "
+ Thread.currentThread().getName());
}
try {
do {
transactionStrategy.begin() ;
boolean rollbackOnly = true ;
try {
for (Map<String, Object> row : pollForCandidates()) {
_currentRow = row;
// Try to mark as 'in process' - if unsuccessful, somebody else
// got it first
if (!changeStatusToWorking())
continue;
Throwable thrown = null;
String text = null;
try {
Object obj = _processMethod.invoke(_composer, new Object[]
{_currentRow});
if (null == obj) {
_logger.warn("Action class method <"
+ _processMethod.getName()
+ "> returned a null object");
continue;
}
Message message = (Message) obj;
Map<String, Object> params = new HashMap<String, Object>();
params.put(Environment.GATEWAY_CONFIG, _config);
message = FilterManager.getInstance().doOutputWork(message, params);
_serviceInvoker.deliverAsync(message);
} catch (MessageDeliverException e) {
thrown = e;
text = "Target service <" + _targetServiceCategory
+ "," + _targetServiceName
+ "> is not registered";
} catch (InvocationTargetException e) {
thrown = e;
text = "Problems invoking method <"
+ _processMethod.getName() + ">";
}
catch (IllegalAccessException e) {
thrown = e;
text = "Problems invoking method <"
+ _processMethod.getName() + ">";
}
catch (ClassCastException e) {
thrown = e;
text = "Action class method <" + _processMethod.getName()
+ "> returned a non Message object";
}
catch (CourierException e) {
thrown = e;
text = "Message filter FAILED";
}
if (null == thrown) {
if (_deleteAfterOK)
deleteCurrentRow();
else
changeStatusToDone();
} else {
_logger.error(text);
_logger.debug(text, thrown);
changeStatusToError();
}
}
rollbackOnly = false ;
} finally {
if (rollbackOnly) {
transactionStrategy.rollbackOnly() ;
}
transactionStrategy.terminate() ;
}
}
while (!waitForRunningStateChange(ManagedLifecycleThreadState.STOPPING,
_sleepBetweenPolls));
} catch (final TransactionStrategyException tse) {
_logger.warn("Unexpected transaction strategy exception", tse) ;
}
if (_logger.isDebugEnabled()) {
_logger
.debug("run() method of " + this.getClass().getSimpleName()
+ " finished on thread "
+ Thread.currentThread().getName());
}
} // ________________________________
/**
* Handle the threaded destroy of the managed instance.
*
* @throws ManagedLifecycleException for errors while destroying.
*/
protected void doThreadedDestroy() throws ManagedLifecycleException {
if (_dbConn != null) {
_dbConn.release();
}
}
/**
* Check for mandatory and optional attributes in parameter tree
*
* @throws ConfigurationException -
* if mandatory atts are not right or actionClass not in
* classpath
*/
private void checkMyParms() throws ConfigurationException {
_targetServiceCategory = ListenerUtil.getValue(_config,
ListenerTagNames.TARGET_SERVICE_CATEGORY_TAG, null);
_targetServiceName = ListenerUtil.getValue(_config,
ListenerTagNames.TARGET_SERVICE_NAME_TAG, null);
if (_targetServiceCategory == null)
throw new ConfigurationException("No service category defined!");
if (_targetServiceName == null)
throw new ConfigurationException("No service name defined!");
// Polling interval
String sAux = _config
.getAttribute(ListenerTagNames.POLL_LATENCY_SECS_TAG);
if (!Util.isNullString(sAux)) {
try {
_sleepBetweenPolls = 1000 * Long.parseLong(sAux);
}
catch (NumberFormatException e) {
_logger.warn("Invalid poll latency - keeping default of "
+ (_sleepBetweenPolls / 1000));
}
} else {
_logger.warn("No value specified for: "
+ ListenerTagNames.POLL_LATENCY_SECS_TAG
+ " - Using default of " + (_sleepBetweenPolls / 1000));
}
resolveComposerClass();
_driver = ListenerUtil.getValue(_config, JDBCEpr.DRIVER_TAG, null);
_url = ListenerUtil.getValue(_config, JDBCEpr.URL_TAG, null);
_user = ListenerUtil.getValue(_config, JDBCEpr.USERNAME_TAG, null);
_password = ListenerUtil.getValue(_config, JDBCEpr.PASSWORD_TAG, "");
_datasource = ListenerUtil.getValue(_config, JDBCEpr.DATASOURCE_TAG, null);
_tableName = _config.getAttribute(ListenerTagNames.SQL_TABLE_NAME_TAG);
if (null == _tableName)
_tableName = _config.getRequiredAttribute(JDBCEpr.TABLE_NAME_TAG);
if (Util.isNullString(_tableName))
throw new ConfigurationException("Empty or invalid table name");
_selectFields = ListenerUtil.getValue(_config,
ListenerTagNames.SQL_SELECT_FIELDS_TAG, "*");
if (Util.isNullString(_selectFields))
throw new ConfigurationException(
"Empty or invalid list of select fields");
_keyFields = _config.getAttribute(ListenerTagNames.SQL_KEY_FIELDS_TAG);
if (null == _keyFields)
_keyFields = _config
.getRequiredAttribute(JDBCEpr.MESSAGE_ID_COLUMN_TAG);
if (Util.isNullString(_keyFields))
throw new ConfigurationException(
"Empty or invalid list of key fields");
_inProcessField = _config
.getAttribute(ListenerTagNames.SQL_IN_PROCESS_FIELD_TAG);
if (null == _inProcessField)
_inProcessField = _config.getAttribute(JDBCEpr.STATUS_COLUMN_TAG);
if (Util.isNullString(_inProcessField))
throw new ConfigurationException(
"A valid inProcessField attribute must be specified");
_timestamp = ListenerUtil.getValue(_config,
JDBCEpr.TIMESTAMP_COLUMN_TAG);
if ((_timestamp == null) || (_timestamp.trim().length() == 0))
{
_logger.debug("No value specified for: "
+ ListenerTagNames.SQL_TIMESTAMP_TAG);
_timestamp = null ;
}
_where = ListenerUtil.getValue(_config,
ListenerTagNames.SQL_WHERE_CONDITION_TAG, "");
if (_where.trim().length() < 1)
_logger.debug("No value specified for: "
+ ListenerTagNames.SQL_WHERE_CONDITION_TAG);
_orderBy = ListenerUtil.getValue(_config,
ListenerTagNames.SQL_ORDER_BY_TAG, "");
if (_orderBy.trim().length() < 1)
_logger.debug("No value specified for: "
+ ListenerTagNames.SQL_ORDER_BY_TAG);
_inProcessVals = ListenerUtil.getValue(_config,
ListenerTagNames.SQL_IN_PROCESS_VALUES_TAG,
DEFAULT_IN_PROCESS_STATES);
_deleteAfterOK = Boolean.parseBoolean(ListenerUtil.getValue(_config,
ListenerTagNames.SQL_POST_DEL_TAG, "false"));
if (null == _config.getAttribute(ListenerTagNames.SQL_POST_DEL_TAG))
_logger
.debug("No value specified for: "
+ ListenerTagNames.SQL_POST_DEL_TAG
+ " - trigger row will not be deleted - 'in process field' will be used to show processing status");
if (_inProcessVals.length() < 4)
throw new ConfigurationException("Parameter <"
+ ListenerTagNames.SQL_IN_PROCESS_VALUES_TAG
+ "> must be at least 4 characters long (PWED)");
_columns = _selectFields.split(",");
if (_columns.length < 1)
throw new ConfigurationException("Empty list of select fields");
_keys = _keyFields.split(",");
if (!"*".equals(_selectFields)) {
Set<String> colSet = new HashSet<String>(Arrays.asList(_columns));
if (_keys.length < 1)
throw new ConfigurationException("Empty list of keyFields");
for (String currKey : _keys) {
if (colSet.contains(currKey))
continue;
else {
StringBuilder sb = new StringBuilder().append(
"All key field names in the <").append(
ListenerTagNames.SQL_KEY_FIELDS_TAG).append(
"> attribute must be in the ").append(
ListenerTagNames.SQL_SELECT_FIELDS_TAG).append(
"list - '").append(currKey)
.append("' is not there");
throw new ConfigurationException(sb.toString());
}
}
}
transacted = _config.getBooleanAttribute(ListenerTagNames.TRANSACTED_TAG, false);
transactionStrategy = TransactionStrategy.getTransactionStrategy(transacted) ;
} // ________________________________
protected void prepareStatements() throws SQLException {
_PSscan = _dbConn.prepareStatement(scanStatement());
_PSupdate = _dbConn.prepareStatement(updateStatement());
_PSdeleteRow = _dbConn.prepareStatement(deleteStatement());
} // ________________________________
/*
* Throw ConfigurationException for anything to do with setup.
* Ultimately could do with finer grained error handling. Probably need
* different types of setup exceptions.
*/
protected void resolveComposerClass() throws ConfigurationException {
try {
String sProcessMethod = null;
_composerName = _config
.getAttribute(ListenerTagNames.GATEWAY_COMPOSER_CLASS_TAG);
if (null != _composerName) { // class attribute
_composerClass = ClassUtil.forName(_composerName, getClass());
Constructor oConst = _composerClass.getConstructor(new Class[]
{ConfigTree.class});
_composer = oConst.newInstance(_config);
sProcessMethod = _config
.getAttribute(
ListenerTagNames.GATEWAY_COMPOSER_METHOD_TAG,
"process");
} else {
_composerName = PackageRowContents.class.getName();
_composerClass = PackageRowContents.class;
_composer = new PackageRowContents(PackageRowContents.createPayloadProxy(_config));
sProcessMethod = "process";
_logger
.debug("No <" + ListenerTagNames.ACTION_ELEMENT_TAG
+ "> element found in configuration"
+ " - Using default composer class : "
+ _composerName);
}
_processMethod = _composerClass.getMethod(sProcessMethod,
new Class[]
{Object.class});
}
catch (InvocationTargetException ex) {
_logger.debug(ex);
throw new ConfigurationException(ex);
}
catch (IllegalAccessException ex) {
_logger.debug(ex);
throw new ConfigurationException(ex);
}
catch (InstantiationException ex) {
_logger.debug(ex);
throw new ConfigurationException(ex);
}
catch (ClassNotFoundException ex) {
_logger.debug(ex);
throw new ConfigurationException(ex);
}
catch (NoSuchMethodException ex) {
_logger.debug(ex);
throw new ConfigurationException(ex);
}
} // ________________________________
protected List<Map<String, Object>> pollForCandidates() {
List<Map<String, Object>> oResults = new ArrayList<Map<String, Object>>();
final JdbcCleanConn oConn = getDbConn();
ResultSet RS = null;
try {
RS = oConn.execQueryWait(_PSscan, 1);
ResultSetMetaData meta = RS.getMetaData();
while (RS.next()) {
Map<String, Object> row = new HashMap<String, Object>();
for (int iCurr = 1; iCurr <= meta.getColumnCount(); iCurr++) {
String sCol = meta.getColumnName(iCurr);
if (!_inProcessField.equalsIgnoreCase(sCol)) {
final int type = meta.getColumnType(iCurr) ;
if (type == Types.BLOB) {
final Blob blob = RS.getBlob(iCurr) ;
row.put(sCol, ((blob != null) ? StreamUtils.readStreamString(blob.getBinaryStream(), "UTF-8") : null));
} else if (type == Types.CLOB) {
final Clob clob = RS.getClob(iCurr) ;
row.put(sCol, ((clob != null) ? StreamUtils.readReader(clob.getCharacterStream()) : null));
} else {
row.put(sCol, RS.getObject(iCurr));
}
}
}
oResults.add(row);
}
}
catch (Exception e) {
_logger.debug("Some triggers might not have been returned", e);
}
finally {
try {
if (RS != null)
RS.close();
oConn.rollback();
} catch (final SQLException sqle) {
refreshDatasource();
}
}
if (_logger.isDebugEnabled()) {
_logger.debug("Returning " + oResults.size() + " rows.\n");
}
return oResults;
} // ________________________________
public void refreshDatasource() {
releaseDBConnection();
if (_datasource != null) {
getDbConn();
}
}
private void releaseDBConnection() {
if(_dbConn != null) {
try {
_dbConn.release();
} finally {
_dbConn = null;
}
}
}
/**
* Obtain a new database connection with parameter info
*
* @return A new connection
* @throws ConfigurationException -
* if problems are encountered
*/
protected JdbcCleanConn getDbConn() {
DataSource oDS = null;
if (null == _dbConn) {
if (_datasource == null) {
oDS = new SimpleDataSource(_driver, _url, _user,
_password);
} else {
InitialContext initContext;
try {
initContext = new InitialContext();
oDS = (DataSource) initContext.lookup(_datasource);
} catch (NamingException e) {
_logger.error("SqlTableGatewayListener.getDbConn failed to lookup datasource.", e);
}
}
/*
* Create JdbcCleanConn even if oDS is null because that will
* manage the error handling for us by throwing SQLExceptions
* at the appropriate time.
*/
_dbConn = new JdbcCleanConn(oDS, transacted);
}
if ((null != _dbConn) && (_dbConn.getStatements().size() == 0)) {
try {
prepareStatements();
} catch (SQLException e) {
releaseDBConnection();
_logger.warn("Exception preparing statements", e);
}
}
return _dbConn;
} // ________________________________
/**
* Assemble the SQL statement to scan (poll) the table
*
* @return - The resulting SQL statement
*/
protected String scanStatement() {
StringBuilder sb = new StringBuilder().append("select ").append(
_selectFields).append(" from ").append(_tableName);
boolean bWhere = !Util.isNullString(_where);
if (bWhere)
sb.append(" where ").append(_where);
sb.append((bWhere) ? " and " : " where ");
String sLike = _inProcessVals.substring(0, 1).toUpperCase();
sb.append(" upper(").append(_inProcessField).append(") like '").append(
sLike).append("%'");
if (!Util.isNullString(_orderBy))
sb.append(" order by ").append(_orderBy);
return sb.toString();
} // ________________________________
/**
* Assemble the SQL statement to update the field in the
* "inProcessField" parameter
* <p/>
* in the table row uniquely identified by the list of fields in the
* "keyFields" parameter
*
* @return - The resulting SQL statement
*/
protected String updateStatement() {
StringBuilder sb = new StringBuilder().append("update ").append(
_tableName).append(" set ").append(_inProcessField).append(" = ? ");
if (_timestamp != null) {
sb.append(", " + _timestamp + " = ? ");
}
sb.append("where ").append(_inProcessField).append(" = ?");
for (String sCurr : _keys) {
sb.append(" and ").append(sCurr).append(" = ?");
}
return sb.toString();
} // ________________________________
/**
* Assemble the SQL statement to delete the current row in the table row
* uniquely identified by the list of fields in the "keyFields"
* parameter
*
* @return - The resulting SQL statement
*/
protected String deleteStatement() {
StringBuilder sb = new StringBuilder().append("delete from ").append(
_tableName).append(" where ");
int iCurr = 0;
for (String sCurr : _keys) {
if (iCurr++ > 0)
sb.append(" and ");
sb.append(sCurr).append(" = ?");
}
return sb.toString();
} // ________________________________
/**
* Try to delete 'current row' from polled table
*
* @return true if row deletion was successful - false otherwise
*/
protected boolean deleteCurrentRow() {
try {
int iParm = 1;
for (String sColName : _keys) {
final Object val ;
if (_currentRow.containsKey(sColName)) {
val = _currentRow.get(sColName);
} else {
val = _upperCurrentRow.get(sColName.toUpperCase());
}
_PSdeleteRow.setObject(iParm++, val);
}
try {
getDbConn().execUpdWait(_PSdeleteRow, 5);
getDbConn().commit();
return true;
}
catch (Exception e) {
_logger.debug("Delete row has failed. Rolling back!!", e);
}
try {
getDbConn().rollback();
}
catch (Exception e) {
_logger.debug("Unable to rollback delete row", e);
}
}
catch (Exception e) {
_logger.debug("Unexpected exception.", e);
}
return false;
} // ________________________________
protected String getStatus(ROW_STATE p_oState) {
int iPos = p_oState.ordinal();
return _inProcessVals.substring(iPos, ++iPos);
} // ________________________________
protected boolean changeStatusToWorking() {
return changeStatus(ROW_STATE.Pending, ROW_STATE.Working);
} // ________________________________
protected boolean changeStatusToDone() {
return changeStatus(ROW_STATE.Working, ROW_STATE.Done);
} // ________________________________
protected boolean changeStatusToError() {
return changeStatus(ROW_STATE.Working, ROW_STATE.Error);
} // ________________________________
protected boolean changeStatus(ROW_STATE fromState, ROW_STATE toState) {
try {
getDbConn();
}
catch (Exception e) {
_logger.debug("Unable to get DB connection.", e);
throw new IllegalStateException("Unable to get DB connection.", e);
}
try {
int iParm = 3;
if (_timestamp != null) {
iParm++;
}
List<String> tempKeys = new ArrayList<String>();
for (String key : _currentRow.keySet()) {
tempKeys.add(key);
}
if (_upperCurrentRow != null) {
_upperCurrentRow.clear();
} else {
_upperCurrentRow = new HashMap<String, Object>();
}
for (String key : tempKeys) {
Object value = _currentRow.get(key);
_upperCurrentRow.put(key.toUpperCase(), value);
}
for (String sColName : _keys) {
Object oVal = null;
if (_currentRow.containsKey(sColName)) {
oVal = _currentRow.get(sColName);
} else {
oVal = _upperCurrentRow.get(sColName.toUpperCase());
}
_PSupdate.setObject(iParm++, oVal);
}
try {
int counter = 1;
_PSupdate.setString(counter++, getStatus(toState));
if (_timestamp != null) {
Date now = new Date();
_PSupdate.setString(counter++, now.toString());
}
_PSupdate.setString(counter++, getStatus(fromState));
final int count = getDbConn().execUpdWait(_PSupdate, 5);
if (count == 1) {
getDbConn().commit();
if (_logger.isDebugEnabled())
_logger.debug("Successfully changed row state from "
+ fromState + " to " + toState + ".");
return true;
} else {
_logger.warn("Cannot change row state from " + fromState
+ " to " + toState + ". Number of rows in state "
+ fromState + " = " + count);
if (count == 0) // the execute affected zero rows!
{
// https://jira.jboss.org/jira/browse/SOA-642
_logger.warn("No rows affected by update statement. Check listener/gateway/notifier table definitions are correct.");
}
else
_logger.warn("Curent implementation expected only one row to be applicable to update request.");
return false;
}
}
catch (Exception e) {
final String message = "Row status change to " + toState
+ " has failed. Rolling back!!";
_logger.error(message);
_logger.debug(message, e);
}
try {
getDbConn().rollback();
}
catch (Exception e) {
final String message = "Unable to rollback row status change to "
+ fromState;
_logger.error(message);
_logger.debug(message, e);
}
}
catch (Exception e) {
final String message = "Unexpected exception.";
_logger.error(message);
_logger.debug(message, e);
}
return false;
} // ________________________________
/**
* Default gateway action for SQL table rows <p/>It will just drop the
* result set contents into a Message
*
* @author <a
* href="mailto:schifest@heuristica.com.ar">schifest@heuristica.com.ar</a>
* @since Version 4.0
*/
public static class PackageRowContents {
private MessagePayloadProxy payloadProxy;
public PackageRowContents(MessagePayloadProxy payloadProxy) {
this.payloadProxy = payloadProxy;
}
public Message process(Object obj) throws MessageDeliverException {
if (!(obj instanceof Serializable))
throw new IllegalArgumentException(
"Object must be instance of Map");
Message message = MessageFactory.getInstance().getMessage();
org.jboss.soa.esb.message.Properties props = message
.getProperties();
if(MessagePayloadProxy.isUsingLegacyPatterns()) {
props.setProperty(ListenerTagNames.SQL_ROW_DATA_TAG, obj);
} else {
payloadProxy.setPayload(message, obj);
}
return message;
}
public static MessagePayloadProxy createPayloadProxy(ConfigTree config) {
return new MessagePayloadProxy(config);
}
} // ____________________________________________________
protected final static Logger _logger = Logger
.getLogger(SqlTableGatewayListener.class);
protected ConfigTree _config;
protected long _sleepBetweenPolls; // milliseconds
protected String _targetServiceCategory, _targetServiceName;
protected String _composerName;
protected ServiceInvoker _serviceInvoker;
protected Class _composerClass;
protected Object _composer;
protected Method _processMethod;
protected String _driver, _url, _user, _password, _datasource;
protected String _tableName, _selectFields, _keyFields, _timestamp;
protected String _where, _orderBy;
protected String _inProcessField, _inProcessVals;
protected boolean _deleteAfterOK;
protected String[] _columns, _keys;
protected PreparedStatement _PSscan, _PSupdate, _PSdeleteRow;
protected JdbcCleanConn _dbConn;
protected Map<String, Object> _currentRow, _upperCurrentRow;
public static enum ROW_STATE {
Pending, Working, Error, Done
}
public static final String DEFAULT_IN_PROCESS_STATES = "PWED";
} // ____________________________________________________________________________