[jboss-svn-commits] JBL Code SVN: r7083 - in labs/jbossesb/trunk/product/core/listeners: src/org/jboss/soa/esb/actions src/org/jboss/soa/esb/actions/routing src/org/jboss/soa/esb/listeners src/org/jboss/soa/esb/listeners/old tests/src/org/jboss/soa/esb/listeners tests/src/org/jboss/soa/esb/util
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Tue Oct 24 09:54:32 EDT 2006
Author: daniel.brum at jboss.com
Date: 2006-10-24 09:54:17 -0400 (Tue, 24 Oct 2006)
New Revision: 7083
Added:
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/ListenerTagNames.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/AbstractListener.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/AbstractPoller.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/DirectoryPoller.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/GpListener.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/JmsQueueListener.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/RemoteDirectoryPoller.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/SqlTablePoller.java
Removed:
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractListener.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractPoller.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/DirectoryPoller.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/GpListener.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/JmsQueueListener.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/RemoteDirectoryPoller.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/SqlTablePoller.java
Modified:
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/AbstractSqlRowAction.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpDownloader.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpUploader.java
labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/routing/FileCopier.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/AbstractListenerUnitTest.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/DirectoryPollerUnitTest.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/GpListenerUnitTest.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/SqlTablePollerUnitTest.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/AbstractMockListner.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/ListenersManagerExecThread.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockNonblockingListener.java
labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockPoller.java
Log:
Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/AbstractSqlRowAction.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/AbstractSqlRowAction.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/AbstractSqlRowAction.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -10,7 +10,7 @@
/**
* Abstract SQL Row action.
* <p/>
- * Convienience class for processing messages from the {@link org.jboss.soa.esb.listeners.SqlTablePoller} listener.
+ * Convienience class for processing messages from the {@link org.jboss.soa.esb.listeners.old.SqlTablePoller} listener.
* Implementing classes receive a single row resultset through their implementation of the {@link #process(Map)}
* method.
*
Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpDownloader.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpDownloader.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpDownloader.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -30,8 +30,8 @@
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.helpers.DomElement;
import org.jboss.soa.esb.helpers.KeyValuePair;
-import org.jboss.soa.esb.listeners.GpListener;
-import org.jboss.soa.esb.listeners.RemoteDirectoryPoller;
+import org.jboss.soa.esb.listeners.old.GpListener;
+import org.jboss.soa.esb.listeners.old.RemoteDirectoryPoller;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.util.FtpClientUtil;
Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpUploader.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpUploader.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/FtpUploader.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -30,8 +30,8 @@
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.helpers.DomElement;
import org.jboss.soa.esb.helpers.KeyValuePair;
-import org.jboss.soa.esb.listeners.DirectoryPoller;
-import org.jboss.soa.esb.listeners.GpListener;
+import org.jboss.soa.esb.listeners.old.DirectoryPoller;
+import org.jboss.soa.esb.listeners.old.GpListener;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.util.FtpClientUtil;
Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/routing/FileCopier.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/routing/FileCopier.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/routing/FileCopier.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -37,7 +37,7 @@
import org.jboss.soa.esb.actions.ActionProcessingException;
import org.jboss.soa.esb.actions.ActionUtils;
import org.jboss.soa.esb.helpers.KeyValuePair;
-import org.jboss.soa.esb.listeners.DirectoryPoller.WorkingFile;
+import org.jboss.soa.esb.listeners.old.DirectoryPoller.WorkingFile;
import org.jboss.soa.esb.message.Message;
/**
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractListener.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractListener.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,293 +0,0 @@
-/*
- * 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;
-
-import java.util.Arrays;
-
-import org.apache.log4j.Logger;
-import org.jboss.soa.esb.actions.ActionDefinition;
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.actions.ActionProcessingException;
-import org.jboss.soa.esb.actions.ActionProcessor;
-import org.jboss.soa.esb.actions.ActionUtils;
-import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.message.Message;
-import org.jboss.soa.esb.message.format.MessageFactory;
-
-/**
- * Base abstract listener implementation.
- * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
- * @since Version 4.0
- */
-public abstract class AbstractListener implements Runnable {
-
- /**
- * Name constant def for the Message attachemnt carrying the list of actions to be applied to the
- * incomming message. This allows the configured processing pipeline to be overridden by the Message
- * producer.
- */
- public static final String MESSAGE_PROCESSING_ACTIONS_LIST = "MESSAGE_PROCESSING_ACTIONS_LIST";
-
- // You can override these values at constructor time of your
- // derived class after calling super(GpListener,DomElement)
- protected int m_iSleepForThreads = 3000; // default sleep if no threads available
- protected int m_iUpperThreadLimit = 10; // just in case - override if you wish
-
- protected int m_iQthr = 0, m_iMaxThr;
-
- protected ThreadGroup m_oThrGrp = null;
- protected Logger logger;
- protected GpListener m_oDad;
- protected DomElement listenerConfig;
- protected String[] m_oActions;
- protected ActionDefinitionFactory m_oActionDefinitionFactory;
- protected MessageFactory m_oMsgFactory;
-
- protected AbstractListener(GpListener p_oDad, DomElement p_oParms, ActionDefinitionFactory actionDefinitionFactory) throws Exception {
-
- logger = Logger.getLogger(this.getClass());
- m_oDad = p_oDad;
- listenerConfig = p_oParms.cloneObj();
- m_oActionDefinitionFactory = actionDefinitionFactory;
- m_oMsgFactory = MessageFactory.getInstance();
- m_oThrGrp = new ThreadGroup(listenerConfig.getName());
-
- String sAtt = GpListener.obtainAtt(listenerConfig, GpListener.PARM_ACTIONS, "");
- if(!sAtt.trim().equals("")) {
- m_oActions = sAtt.split(",");
- }
-
- sAtt = GpListener.obtainAtt(listenerConfig, GpListener.PARM_MAX_THREADS, "1");
- int iMax = Integer.parseInt(sAtt);
- m_iMaxThr = Math.min(iMax, m_iUpperThreadLimit);
- } // __________________________________
-
- /**
- * Implement run method for this Runnable <p/> Will continue to run until
- * controlling class (ref in m_oDad) indicates no more looping allowed for
- * all child classes <p/> This condition will not prevent child processes to
- * finish normally
- */
- public void run() {
- while (m_oDad.continueLooping()) {
- Object[] processList = receive();
- if (null==processList) {
- try { Thread.sleep(500); }
- catch(InterruptedException e) {/* ok do nothing */}
- } else {
- for (Object currentObj : processList) {
- if (m_iQthr >= m_iMaxThr) {
- logger.info("Waiting for available threads...(max=" + m_iMaxThr + ")");
- try {
- Thread.sleep(m_iSleepForThreads);
- } catch (InterruptedException e) {
- return;
- }
- break;
- }
-
- // Spawn a thread and push the message message through the pipeline...
- ActionProcessingPipeline runner = new ActionProcessingPipeline(currentObj);
- new Thread(runner).start();
- incThreads();
- }
- }
- }
-
- // Wait for all the processing pipelines to complete before closing the listener and existing...
- while(m_iQthr > 0) {
- logger.info("Waiting for all processing pipelines to complete.");
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- logger.warn("Thread interrupted while waiting for all processing pipelines to complete.", e);
- }
- }
-
- logger.info("All processing pipelines complete. Closing listener now.");
-
- close();
- }
-
- /**
- * Receive message from underlying channel implementation.
- * <p/>
- * Implementations must perform a blocking receive.
- * @return An array of Objects received on the channel.
- */
- protected abstract Object[] receive();
-
- /**
- * Called on the listener implementation when pipeline processing error has occured.
- * @param initialMsg The message that was initialy supplied to the pipeline.
- * @param processor The processor that raised the error. Can be null where the error was raised before
- * pipeline processing of the message.
- * @param error The error. Can be null.
- */
- protected abstract void processingError(Object initialMsg, ActionProcessor processor, Throwable error);
-
- /**
- * Called on the listener implementation when pipeline processing of a message is complete.
- * @param initialMsg The message that was initialy supplied to the pipeline.
- */
- protected abstract void processingComplete(Object initialMsg);
-
- /**
- * Close the listener implemenation.
- * <p/>
- * Allows the listener to perform relevant close/cleanup tasks.
- */
- protected abstract void close();
-
- /**
- * Increment the active thread count.
- */
- private void incThreads() {
- m_iQthr++;
- }
-
- /**
- * Decrement the active thread count.
- */
- private void decThreads() {
- m_iQthr--;
- }
-
- /**
- * Action Processing Pipeline.
- * <p/>
- * Runs the actions in a listeners "actions" config on a message payload message received
- * by the listener implementation.
- *
- * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
- * @since Version 4.0
- */
- private class ActionProcessingPipeline implements Runnable {
-
- private Object initialObject;
-
- /**
- * Private constructor.
- * @param pMessage The inital processing target message.
- */
- private ActionProcessingPipeline(Object obj) {
- initialObject = obj;
- }
-
- /* (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- public void run() {
- String currentAction = null;
- ActionProcessor currentProcessor = null;
-
- try {
- Message message;
- String[] actions;
-
- if(initialObject instanceof Message) {
- message = (Message)initialObject;
- } else {
- message = m_oMsgFactory.getMessage();
- ActionUtils.setTaskObject(message,initialObject);
- }
-
- actions = getActions(message);
-
- // Run the message through each ActionProcessor...
- for(String action : actions) {
- ActionDefinition actionDefinition;
-
- currentAction = action.trim();
- actionDefinition = m_oActionDefinitionFactory.getInstance(currentAction);
- if(actionDefinition == null) {
- throw new java.lang.IllegalStateException("Bad Listener Configuration. No 'Actions/Action' definition for action [" + currentAction + "].");
- }
-
- // The processing result of each action feeds into the processing of the next action...
- currentProcessor = actionDefinition.getProcessor();
- try {
- ActionUtils.copyCurrentToPrevious(message);
- message = currentProcessor.process(message);
- } catch (Exception e) {
- GpListener.notifyError(listenerConfig, e, currentProcessor.getErrorNotification(message));
- throw e;
- }
-
- if(message == null && action != m_oActions[m_oActions.length - 1]) {
- String exceptionMessage = "Premature termination of action processing pipeline [" + Arrays.asList(m_oActions) + "]. ActionProcessor [" + currentProcessor.getClass().getName() + "] returned a null message result on processing of action [" + currentAction + "].";
- processingError(initialObject, currentProcessor, new ActionProcessingException(exceptionMessage));
- logger.warn(exceptionMessage);
- return;
- }
- // Notify on all processors. May want to do this differently in the future i.e. more selectively ...
- GpListener.notifyOK(listenerConfig, currentProcessor.getOkNotification(message));
-
- // Setup the message for processing by the next processor...
- if(message != null) {
- message.getBody().remove(ActionUtils.BEFORE_ACTION);
- }
- }
-
- processingComplete(initialObject);
- } catch(Throwable thrown) {
- processingError(initialObject, currentProcessor, thrown);
- logger.error("Premature termination of action processing pipeline [" + (m_oActions != null?Arrays.asList(m_oActions):"") + "]. Action [" + currentAction + "] threw an exception.", thrown);
- } finally {
- // Decrement the active thread count for the listener on completion...
- decThreads();
- }
- }
-
- /**
- * Get the list of actions to be applied to the supplied message.
- * @param message The message to be processed.
- * @return The set of processing actions to be performed on the message.
- * @throws ActionProcessingException Invalid actions list attachment setting.
- */
- private String[] getActions(Message message) throws ActionProcessingException {
- // Check is there an attachment specifying an override pipeline config...
- Object overrideActionsAttachment = message.getAttachment().get(MESSAGE_PROCESSING_ACTIONS_LIST);
- if(overrideActionsAttachment != null) {
- if(overrideActionsAttachment instanceof String) {
- String overrideActions = (String)overrideActionsAttachment;
-
- if(overrideActions.trim().equals("")) {
- throw new ActionProcessingException("Message attachement [" + MESSAGE_PROCESSING_ACTIONS_LIST + "] was specified but with an empty value. Aborting message processing.");
- }
-
- return overrideActions.split(",");
- } else {
- throw new ActionProcessingException("Message attachement [" + MESSAGE_PROCESSING_ACTIONS_LIST + "] must be of type java.lang.String. Received [" + overrideActionsAttachment.getClass().getName() + "]. Aborting message processing.");
- }
- } else {
- // Otherwise use the actions configured on the listener...
- if(m_oActions == null || m_oActions.length == 0) {
- throw new ActionProcessingException("No actions configuration specified either on the listener or as a Message attachement [" + MESSAGE_PROCESSING_ACTIONS_LIST + "]. Aborting message processing.");
- }
- return m_oActions;
- }
- }
- }
-
-} // ____________________________________________________________________________
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractPoller.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractPoller.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,111 +0,0 @@
-/*
- * 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;
-
-import java.util.List;
-
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.helpers.DomElement;
-
-/**
- * Abstract Polling Listener.
- * <p/>
- * Polling listeners are listener implementations that periodically poll for message objects
- * that require processing. This type of listener implementation is required where the underlying
- * message channel doesn't support a blocking receive operation.
- *
- * @author Esteban
- */
-public abstract class AbstractPoller extends AbstractListener {
-
- // You can override these values at constructor time of your
- // derived class after calling super(GpListener,DomElement)
- protected int m_iMinPollMillis = 3000 // minimum polling interval
- , m_iDfltPollMillis = 20000 // default polling interval
- ;
-
- public static final String PARM_POLL_LTCY = "pollLatencySecs";
-
- protected int m_iPollMillis;
-
- /**
- * Construct an abstract polling listener.
- * @param commandListener The command listener.
- * @param listenerConfig The configuration for this polling listener.
- * @param actionDefinitionFactory The action definition factory for the bus.
- * @throws Exception
- */
- protected AbstractPoller(GpListener commandListener, DomElement listenerConfig, ActionDefinitionFactory actionDefinitionFactory) throws Exception {
- super(commandListener, listenerConfig, actionDefinitionFactory);
-
- String sAtt = listenerConfig.getAttr(PARM_POLL_LTCY);
- m_iPollMillis = (null == sAtt) ? m_iDfltPollMillis : 1000 * Integer.parseInt(sAtt);
- if (m_iPollMillis < m_iMinPollMillis) {
- m_iPollMillis = m_iMinPollMillis;
- }
- }
-
- /**
- * Polling listener receive implementation.
- * @return An array of objects polled from the concrete Poller implementation.
- */
- protected Object[] receive() {
- while (m_oDad.continueLooping()) {
- List<Object> olPending = pollForCandidates();
-
- if (olPending == null || olPending.isEmpty()) {
- try {
- Thread.sleep(m_iPollMillis);
- } catch (InterruptedException e) {
- logger.error("Unexpected thread interupt exception. Not terminating blocking receive!!", e);
- }
- continue;
- } else {
- Object[] objForProcessing = new Object[olPending.size()];
-
- // Preprocess all the message objects.
- // TODO: I really think this is no longer required or a good idea!!
- for(int i = 0; i < olPending.size(); i++) {
- objForProcessing[i] = preProcess(olPending.get(i));
- }
- return objForProcessing;
- }
- }
-
- return null;
- }
-
- /**
- * Poll for message objects.
- * @return A list of message objects, or an empty list if there are no message objects.
- */
- protected abstract List<Object> pollForCandidates();
-
- /**
- * Preprocess the message object before returning for pipeline processing.
- * @param message Message object for preprocessing.
- * @return The preprocessed message object, or the supplied message unmodified.
- */
- protected abstract Object preProcess(Object message);
- // TODO: Is this "preprocessing" step needed now that we have processing pipelines on listeners???
-}
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/DirectoryPoller.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/DirectoryPoller.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/DirectoryPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,263 +0,0 @@
-/*
-* 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;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.List;
-
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.actions.ActionProcessor;
-import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.util.Util;
-
-public class DirectoryPoller extends AbstractPoller
-{
- public static final String FILE_INPUT_DIR = "inputDirURI";
- public static final String FILE_INPUT_SFX = "inputSuffix";
- public static final String FILE_WORK_SFX = "workSuffix";
- public static final String FILE_ERROR_DIR = "errorDirURI";
- public static final String FILE_ERROR_SFX = "errorSuffix";
- public static final String FILE_POST_DIR = "postDirURI";
- public static final String FILE_POST_SFX = "postSuffix";
- public static final String FILE_POST_DEL = "postDelete";
-
- public DirectoryPoller(GpListener p_oDad, DomElement p_oParms, ActionDefinitionFactory actionDefinitionFactory) throws Exception
- {
- super(p_oDad, p_oParms, actionDefinitionFactory);
- checkMyParms();
- } //__________________________________
-
-
- protected File m_oInpDir ,m_oErrorDir ,m_oPostDir;
- protected FileFilter m_oFFilt;
- protected String m_sInpSfx ,m_sWrkSfx ,m_sErrSfx ,m_sPostSfx;
- protected boolean m_bPostDel;
-
- /**
- *
- * @param inputObject Object - Must be a File representing the file that has to be processed
- * @return Object - an array of 3 Files containing:
- * <p/>[0] renamed file (workSuffix appended to input file name)
- * <p/>[1] target file name in case actionClass is unable to complete successfuly
- * <p/>[2] target file name in case actionClass finishes successfuly
- */
- @Override
- public Object preProcess(Object inputObject)
- {
- if (!(inputObject instanceof File)) {
- return null;
- }
-
- File inputFile = (File)inputObject;
- WorkingFile workingFile = new WorkingFile(inputFile.getParentFile(), inputFile.getName() + m_sWrkSfx);
-
- if (!inputFile.renameTo(workingFile)) {
- return null;
- }
-
- workingFile.postDelete = m_bPostDel;
- workingFile.inputFile = inputFile;
- workingFile.errorFile = new File (m_oErrorDir ,inputFile.getName()+m_sErrSfx);
- workingFile.outputFile = new File (m_oPostDir ,inputFile.getName()+m_sPostSfx);
-
- return workingFile;
- } //________________________________
-
- @Override
- protected List<Object> pollForCandidates()
- {
- File[] oaF = m_oInpDir.listFiles(m_oFFilt);
- return Arrays.asList((Object[])oaF);
- } //________________________________
-
- private void checkMyParms() throws Exception
- {
- // INPUT directory and suffix (used for FileFilter)
- String sInpDir = GpListener.obtainAtt(listenerConfig,FILE_INPUT_DIR,null);
- m_oInpDir = getFile(sInpDir);
- seeIfOkToWorkOnDir(m_oInpDir);
-
- m_sInpSfx = GpListener.obtainAtt(listenerConfig,FILE_INPUT_SFX,null);
- m_sInpSfx = m_sInpSfx.trim();
- if (m_sInpSfx.length()<1)
- throw new Exception ("Invalid "+FILE_INPUT_SFX+" attribute");
- m_oFFilt = new FileEndsWith(m_sInpSfx);
-
- // WORK suffix (will rename in input directory)
- m_sWrkSfx = GpListener.obtainAtt(listenerConfig,FILE_WORK_SFX,".esbWork").trim();
- if (m_sWrkSfx.length()<1)
- throw new Exception ("Invalid "+FILE_WORK_SFX+" attribute");
- if (m_sInpSfx.equals(m_sWrkSfx))
- throw new Exception("Work suffix must differ from input suffix <"+m_sWrkSfx+">");
-
- // ERROR directory and suffix (defaults to input dir and ".esbError" suffix)
- String sErrDir = GpListener.obtainAtt(listenerConfig,FILE_ERROR_DIR,sInpDir);
- m_oErrorDir = getFile(sErrDir);
- seeIfOkToWorkOnDir(m_oErrorDir);
-
- m_sErrSfx = GpListener.obtainAtt(listenerConfig,FILE_ERROR_SFX,".esbError").trim();
- if (m_sErrSfx.length()<1)
- throw new Exception ("Invalid "+FILE_ERROR_SFX+" attribute");
- if (m_oErrorDir.equals(m_oInpDir) && m_sInpSfx.equals(m_sErrSfx))
- throw new Exception("Error suffix must differ from input suffix <"+m_sErrSfx+">");
-
-
- // Do users wish to delete files that were processed OK ?
- String sPostDel = GpListener.obtainAtt(listenerConfig,FILE_POST_DEL,"false").trim();
- m_bPostDel = Boolean.parseBoolean(sPostDel);
- if (m_bPostDel)
- return;
-
- // POST (done) directory and suffix (defaults to input dir and ".esbDone" suffix)
- String sPostDir = GpListener.obtainAtt(listenerConfig,FILE_POST_DIR,sInpDir);
- m_oPostDir = getFile(sPostDir);
- seeIfOkToWorkOnDir(m_oPostDir);
- m_sPostSfx = GpListener.obtainAtt(listenerConfig,FILE_POST_SFX,".esbDone").trim();
- if (m_oPostDir.equals(m_oInpDir))
- { if (m_sPostSfx.length()<1)
- throw new Exception ("Invalid "+FILE_POST_SFX+" attribute");
- if (m_sPostSfx.equals(m_sInpSfx))
- throw new Exception("Post process suffix must differ from input suffix <"+m_sPostSfx+">");
- }
-
- } //________________________________
-
- private File getFile(String file) {
- try {
- return new File(new URI(file));
- } catch(Exception e) {
- return new File(file);
- }
- }
-
- protected void seeIfOkToWorkOnDir (File p_oDir) throws Exception
- {
- if (! p_oDir.exists())
- throw new Exception ("Directory "+p_oDir.toString()+" not found");
- if (!p_oDir.isDirectory())
- throw new Exception(p_oDir.toString()+" is not a directory");
- if (!p_oDir.canRead())
- throw new Exception("Can't read directory "+p_oDir.toString());
- if (! p_oDir.canWrite())
- throw new Exception ("Can't write/rename in directory "+p_oDir.toString());
- } //________________________________
-
-
- private class FileEndsWith implements FileFilter
- {
- String m_sSuffix;
- FileEndsWith(String p_sEnd) throws Exception
- {
- m_sSuffix = p_sEnd;
- if (Util.isNullString(m_sSuffix))
- throw new Exception("Must specify file extension");
- } //______________________________
-
- public boolean accept(File p_f)
- { return (p_f.isFile())
- ? p_f.toString().endsWith(m_sSuffix)
- : false;
- } //______________________________
- } //____________________________________________________
-
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#close()
- */
- @Override
- protected void close() {
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
- */
- @Override
- protected void processingError(Object currentObject, ActionProcessor processor, Throwable error) {
-
- if (null!=currentObject)
- { WorkingFile workingFile = (WorkingFile) currentObject;
- workingFile.renameToError();
- }
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
- */
- @Override
- protected void processingComplete(Object currentObject) {
- WorkingFile workingFile = (WorkingFile) currentObject;
-
- // Delete or rename the file...
- if (workingFile.postDelete) {
- workingFile.delete();
- } else {
- workingFile.renameToOutputFile();
- }
- }
-
- /**
- * Working file.
- * <p/>
- * Once the directory poller picks up on an input file, it immediately renames it to a working file
- * in order to avoid a situation where the file gets processed again.
- *
- * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
- * @since Version 4.0
- */
- public static class WorkingFile extends File {
- private static final long serialVersionUID = 1L;
-
- private boolean postDelete;
- public boolean isPostDelete() { return postDelete; }
-
- private File inputFile, errorFile, outputFile;
-
- public WorkingFile(String filename) {
- super(filename);
- }
-
- public WorkingFile(File parentFile, String filename) {
- super(parentFile, filename);
- }
-
- public boolean renameToError() {
- return renameTo(errorFile);
- }
-
- public boolean renameToOutputFile() {
- return renameTo(outputFile);
- }
-
- /**
- * Get the File instance representing the original input file.
- * @return Original input file.
- */
- public File getInputFile() {
- return inputFile;
- }
- }
-}
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/GpListener.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/GpListener.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/GpListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,660 +0,0 @@
-/*
- * 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;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-import org.jboss.internal.soa.esb.command.CommandQueue;
-import org.jboss.internal.soa.esb.command.CommandQueueException;
-import org.jboss.soa.esb.ConfigurationException;
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.common.Configuration;
-import org.jboss.soa.esb.common.Environment;
-import org.jboss.soa.esb.common.ModulePropertyManager;
-import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.notification.NotificationList;
-import org.jboss.soa.esb.parameters.ParamRepositoryException;
-import org.jboss.soa.esb.parameters.ParamRepositoryFactory;
-import org.jboss.soa.esb.services.NotificationHandlerFactory;
-import org.jboss.soa.esb.services.NotificationManager;
-import org.jboss.soa.esb.util.Util;
-import org.xml.sax.SAXException;
-
-/**
- * Controlling class that will launch listener child threads for supported
- * transport listener classes, as indicated in the configuration XML tree
- * pointed by arg[0]
- *
- * <p />
- * Can be launched as uppermost controller (it has a main(args) method)
- * <p />
- * Also implements Runnable, and can thus be launched in a child thread from an
- * upper controlling process
- * <p />
- * Listens on a JMS queue (with an optional message selector) for commands (e.g.
- * Quiesce, Reload Parameters, Set End Time, etc.)
- * <p />
- * Parameter reloading can also be set using the PARM_RELOAD_SECS attribute
- * <p />
- * End time for this instance can also be set using the PARM_END_TIME attribute
- * <p />
- *
- * @author Esteban
- *
- */
-public class GpListener implements Runnable {
-
- private static Logger m_oLogger = Logger.getLogger(GpListener.class);
-
- public static void main(String[] args) throws Exception {
- GpListener oProc = new GpListener(args[0]);
- oProc.run();
- GpListener.State oS = oProc.getState();
-
- if (null != oS.getException()) {
- m_oLogger.error("GpListener <" + args[0] + "> FAILED\n", oS
- .getException());
- }
- System.exit(oS.getCompletionCode());
- } // ________________________________
-
- protected int m_iDfltReloadMillis = 180000 // default interval between
- // parameter reloads
- ;
-
- public static final String PARM_RELOAD_SECS = "parameterReloadSecs";
- public static final String PARM_END_TIME = "endTime";
-
- // Attribute name that denotes listener class to be instantiated in a child
- // thread
- // This attribute is not in the root node but in first level child
- // DomElements
- public static final String PARM_LISTENER_CLASS = "listenerClass";
- public static final String PARM_ACTIONS = "actions";
- public static final String PARM_MAX_THREADS = "maxThreads";
- public static final String CHLD_EMAIL_PARMS = "EmailProperties";
-
- private String m_sParmsName;
- private DomElement m_oParms;
-
- private HashMap<String, Object> m_oAtts;
-
- /**
- * Obtain a shallow copy of needed atributes in this object's last loaded
- * parameter tree <p/>The local bject is cloned so child threads can use it
- * as they choose to without interfering with the environment
- * <p />
- * Listener processes controlled by this object should keep a reference to
- * this object at construction time, and not call this method again unless
- * they specifically need updated values. Parameter reload could have
- * happened since last call
- *
- * @return Map - a shallow copy of the attributes Map
- */
- @SuppressWarnings("unchecked")
- public Map<String, Object> getControllerAttributes() {
- return (Map<String, Object>) m_oAtts.clone();
- }
-
- private boolean m_bReloadRequested, m_bEndRequested;
-
- private long m_lNextReload = Long.MAX_VALUE;
-
- private long m_lEndTime = Long.MAX_VALUE;
-
- public static final SimpleDateFormat s_oDateParse = new SimpleDateFormat(
- "yyyyMMdd hh:mm:ss");
-
- private State m_oState = null;
-
- public State getState() {
- return m_oState;
- }
-
- public static enum State {
- Loading_parameters, Running, Shutting_down, Done_OK, Exception_thrown;
- int m_iCompletionCode = 0;
-
- Exception m_oException = null;
-
- public int getCompletionCode() {
- return m_iCompletionCode;
- };
-
- public Exception getException() {
- return m_oException;
- }
- };
-
- private CommandQueue commandQueue;
-
- private ActionDefinitionFactory actionDefinitionFactory;
-
- private static CommandQueue defaultCommandQueue = null;
-
- /**
- * Package pivate default constructor.
- */
- protected GpListener() {
- }
-
- /**
- * Construct a Listener Manager from the named repository based
- * configuration.
- *
- * @param p_sParameterName
- * Name of the Repository entry containing the configuration.
- * @throws Exception
- * Unable to load/use the named configuration.
- */
- public GpListener(String p_sParameterName) throws Exception {
- this(GpListener.getListenerConfig(p_sParameterName));
- m_sParmsName = p_sParameterName;
- }
-
- /**
- * Construct a Listener Manager using the specified listener configuration.
- *
- * @param config
- * The configuration.
- * @throws Exception
- * Unable to load/use the supplied configuration.
- */
- public GpListener(DomElement config) throws Exception {
- m_oParms = config;
- m_oState = State.Loading_parameters;
-
- try {
- checkParms(m_oParms);
- setEmailSystemProperties();
- } catch (Exception e) {
- String configSource = config.getAttr("configSource");
-
- m_oState = State.Exception_thrown;
- m_oState.m_oException = e;
- m_oLogger.fatal("Listener configuration and startup error. Config Source: "
- + (configSource != null ? configSource
- : "unknown"), e);
-
- throw e;
- }
- }
-
- /**
- * Load the named listener configuration from the configured parameter
- * repository.
- *
- * @param reposParam
- * The name of the repository entry containing the Listener
- * configuration.
- * @return Listener Configuration as {@link DomElement}.
- * @throws IOException
- * Unable to access the repository.
- * @throws ParamRepositoryException
- * Unable to access the configuration in the repository.
- * @throws SAXException
- * Unable to parse the configuration.
- */
- private static DomElement getListenerConfig(String reposParam)
- throws IOException, ParamRepositoryException, SAXException {
- String sXml = ParamRepositoryFactory.getInstance().get(reposParam);
- DomElement config = DomElement.fromXml(sXml);
-
- config.setAttr("configSource", "param-repository:" + reposParam);
-
- return config;
- }
-
- /**
- * Check to see if all needed parameters are there, and assign default
- * values to some of them
- *
- * @param p_oP
- * DomElement - Where to look for the mandatory/optional
- * configuration attributes
- * @throws Exception -
- * If attributes are wrong or not enough for a proper runtime
- * configuration
- */
- public void checkParms(DomElement p_oP) throws Exception {
- // We've just loaded - set to false until next reload requested
- m_bReloadRequested = false;
- commandQueue = createCommandQueue(p_oP);
-
- // Open the command queue...
- if (null!=commandQueue)
- commandQueue.open(p_oP);
-
- // if PARM_RELOAD_SECS not set, and no command queue
- // then reload every 10 minutes
- // If there is a command queue, run until command is received
- String sRldSecs = p_oP.getAttr(PARM_RELOAD_SECS);
- m_lNextReload = (null != sRldSecs)
- ? System.currentTimeMillis() + 1000 * Long.parseLong(sRldSecs)
- : (null == commandQueue)
- ? Long.MAX_VALUE
- : System.currentTimeMillis() + m_iDfltReloadMillis;
-
- // if PARM_END_TIME not set try to run forever
- // not a good practice if command queue is not set
- // Expected date format is "yyyyMMdd hh:mm:ss"
- String sEndT = p_oP.getAttr(PARM_END_TIME);
- m_lEndTime = (null == sEndT) ? Long.MAX_VALUE : s_oDateParse.parse(
- sEndT).getTime();
-
- // Read and initialise the action definitions...
- DomElement actionConfig = p_oP.getFirstElementChild("Actions");
- if(actionConfig == null) {
- throw new ConfigurationException("No 'Actions' configuration.");
- }
- actionDefinitionFactory = new ActionDefinitionFactory(actionConfig);
-
- } // ________________________________
-
- /**
- * Factory method for creating the command queue.
- * @param config GpListener config.
- * @return GpListener CommandQueue instance.
- */
- private CommandQueue createCommandQueue(DomElement config) {
- String commandQueueClass = config.getAttr("command-queue-class");
-
- if(commandQueueClass != null) {
- try {
- return (CommandQueue) Class.forName(commandQueueClass).newInstance();
- } catch (Exception e) {
- m_oLogger.error("Failed to instantiate CommandQueue ["+ commandQueueClass + "]. Defaulting to no Command Queue", e);
- }
- }
-
- return defaultCommandQueue;
- }
-
- /**
- * Allows a default command queue to be set statically for all GpListener instances.
- * @param defaultCommandQueue The defaultCommandQueue to set.
- */
- public static void setDefaultCommandQueue(CommandQueue defaultCommandQueue) {
- GpListener.defaultCommandQueue = defaultCommandQueue;
- }
-
- /**
- * Main execution loop <p/> Will continue to run until either <p/>a) run
- * time is expired <p/>b) quiesce command is received in command queue
- * <p/>For every child element that contains a PARM_LISTENER_CLASS
- * attribute, this method will try to launch a child thread instantiating an
- * object of that class, and will call it's run() method <p/>Once all child
- * processes are trigered, the main thread will either <p/>1) wait for a
- * message in the command queue (if one was configured) until next reload or
- * end of run period expired <p/>or 2) Just sleep if there's no command
- * queue to listen on
- */
- public void run() {
- while (endNotRequested()) {
- m_oState = State.Running;
- for (DomElement oCurr : m_oParms.getAllElemChildren()) {
- String sClass = oCurr.getAttr(PARM_LISTENER_CLASS);
- if (Util.isNullString(sClass))
- continue;
- tryToLaunchChildListener(oCurr, sClass);
- }
-
- waitForCmdOrSleep();
-
- if (endRequested()) {
- break;
- }
- if (m_sParmsName != null && timeToReload()) {
- try {
- m_oState = State.Loading_parameters;
- m_oLogger
- .info("Reloading parameters _____________________________________________________");
- DomElement oNew = GpListener.getListenerConfig(m_sParmsName);
- checkParms(oNew);
- m_oParms = oNew;
- setEmailSystemProperties();
- } catch (Exception e) {
- m_oLogger.error("Failed to reload parameters"
- + " - Continuing with cached version", e);
- }
- }
- }
- // m_oState = State.Shutting_down;
-
- m_oState = State.Done_OK;
- m_oState.m_iCompletionCode = 0;
- m_oLogger
- .info("Finishing_____________________________________________________");
-
- // Close the command queue...
- try {
- commandQueue.close();
- } catch (CommandQueueException e) {
- m_oLogger.error("Error closing Command Queue.", e);
- }
- } // ________________________________
-
- private void tryToLaunchChildListener(DomElement p_oP, String p_sClassName) {
- try {
- Class oListener = Class.forName(p_sClassName);
- Constructor oConst = oListener.getConstructor(new Class[] {
- this.getClass(), DomElement.class, ActionDefinitionFactory.class });
- Runnable oRun = (Runnable) oConst.newInstance(new Object[] { this,
- p_oP, actionDefinitionFactory });
- new Thread(oRun).start();
- } catch (Exception e) {
- m_oLogger.error("Cannot launch <" + p_sClassName + ">\n", e);
- }
- } // ________________________________
-
- long millisToWait() {
- return Math.min(m_lNextReload, m_lEndTime) - System.currentTimeMillis();
- } // ________________________________
-
- private void waitForCmdOrSleep() {
- long lToGo = millisToWait();
-
- if (null == commandQueue) {
- m_oLogger.debug("About to sleep " + lToGo);
- // No command queue nor topic - Just sleep until time
- // exhausted, or thread interrupted
- try {
- if (lToGo > 0)
- Thread.sleep(lToGo);
- } catch (InterruptedException e) {
- m_lEndTime = 0; // mark as end requested and return
- }
- return;
- }
-
- // Wait for commands until time exhausted or command received
- // Note that received commands might change time variables (reload/end)
- // that's why time to go is recalculated on each cycle
- while ((lToGo = millisToWait()) > 0) {
- try {
- m_oLogger.info("Waiting for command ... timeout=" + lToGo + " millis");
-
- String oM = commandQueue.receiveCommand(lToGo);
- if (null == oM) {
- return;
- }
- processCommand(oM);
- if (endRequested() || timeToReload()) {
- break;
- }
- } catch (CommandQueueException eJ) {
- m_oLogger.info("receive on command queue failed", eJ);
- }
- }
- } // ________________________________
-
- /**
- * Processes the command that has been received in the command queue (or
- * topic) <p/>m_bEndRequested, m_bReloadRequested, and m_lEndTime could be
- * changed
- *
- * <p/> <p/><TABLE border="1"> <COLGROUP> <COL width="200"/> <COL
- * width="400"/> </COLGROUP>
- * <TR>
- * <TD align="center">message text</TD>
- * <TD align="center">effect</TD>
- * </TR>
- * <TR>
- * <TD>shutdown*</TD>
- * <TD>End time will be immediately set to 'now' - quiesce process will
- * start - Child threads will be allowed to finish normally</TD>
- * </TR>
- * <TR>
- * <TD>reload param*</TD>
- * <TD>Parameters will be immediately reloaded, and listener reconfigured
- * with new values</TD>
- * </TR>
- * <TR>
- * <TD>endTime yyyyMMdd hh:mm:ss</TD>
- * <TD>End time will be set to new value. If hh:mm:ss is not supplied =>
- * end of day assumed (23:59:59)</TD>
- * </TR>
- * </TABLE> * startsWith() <p/>
- *
- * @param p_oMsg
- * Message received from the command queue.
- *
- */
- private void processCommand(String sTxt) {
- if (null == sTxt)
- return;
-
- String sLow = sTxt.trim().toLowerCase();
- if (sLow.startsWith("shutdown")) {
- m_bEndRequested = true;
- m_oLogger.info("Shutdown has been requested");
- return;
- }
- if (sLow.startsWith("reload param")) {
- m_bReloadRequested = true;
- m_oLogger
- .info("Request for parameter reload has been received");
- return;
- }
- String[] sa = sLow.split("\\s+");
- if (sa.length > 1 && "endtime".equals(sa[0])) {
- try {
- String sDate = sa[1];
- String sTime = (sa.length < 3 || null == sa[2]) ? "23:59:59"
- : sa[2];
- Date oEnd = s_oDateParse.parse(sDate + " " + sTime);
- m_oLogger.info("New end date set to : " + oEnd);
- m_lEndTime = oEnd.getTime();
- } catch (Exception eDat) {
- m_oLogger.info("Problems with endTime command", eDat);
- }
- }
- } // ________________________________
-
- /**
- * Accessor to determine if execution time is expired or shutdown requested
- *
- * @return boolean if processing has to stop (all child threads will be
- * allowed to finish)
- */
- public boolean endRequested() {
- return m_bEndRequested || System.currentTimeMillis() >= m_lEndTime;
- }
-
- /**
- * Accessor to determine if execution time is not expired, and no shutdown
- * request received
- *
- * @return boolean - true if run time has not expired and quiesce has not
- * been requested
- */
- public boolean endNotRequested() {
- return !endRequested();
- }
-
- /**
- * Provide a common accessor to determine if parameters have to be reloaded
- * <p/> For child threads this means thread execution has to end
- * </p>
- * Child processes should only call this method when they are idle (as
- * opposed to in the middle of executing a unit of work)
- *
- * @return boolean - true if it's time to reload parameters
- */
- public boolean timeToReload() {
- return m_bReloadRequested
- || System.currentTimeMillis() >= m_lNextReload;
- }
-
- /**
- * Helper accessor for child processes that provides info to determine if
- * they can continue with yet another execution cycle
- *
- * @return boolean - true if runtime is not expired and not time yet to
- * reload parameters
- */
- public boolean continueLooping() {
- return (endNotRequested() && !timeToReload());
- } // ________________________________
-
- private static final String[] s_saMailProps = { Environment.SMTP_HOST,
- Environment.SMTP_USERNAME, Environment.SMTP_PASSWORD,
- Environment.SMTP_PORT, Environment.SMTP_FROM,
- Environment.SMTP_AUTH };
-
- private void setEmailSystemProperties() {
- DomElement oEmail = m_oParms.getFirstElementChild(CHLD_EMAIL_PARMS);
- if (null != oEmail)
- for (String sCurr : s_saMailProps) {
- String sProp = oEmail.getAttr(sCurr);
- if (null != sProp)
- ModulePropertyManager.getPropertyManager(ModulePropertyManager.TRANSPORTS_MODULE).setProperty(sCurr, sProp);
- }
- } // ________________________________
-
- /**
- * Find an attribute in the tree (arg 0) or assign default value (arg 2)
- *
- * @param p_oP
- * DomElement - look for attributes in this Element only
- * @param p_sAtt
- * String - Name of attribute to find
- * @param p_sDefault
- * String -default value if requested attribute is not there
- * @return String - value of attribute, or default value (if null)
- * @throws Exception -
- * If requested attribute not found and no default value
- * supplied by invoker
- */
- public static String obtainAtt(DomElement p_oP, String p_sAtt, String p_sDefault)
- throws ConfigurationException {
- String sVal = p_oP.getAttr(p_sAtt);
- if ((null == sVal) && (null == p_sDefault))
- throw new ConfigurationException("Missing or invalid <" + p_sAtt + "> attribute");
-
- return (null != sVal) ? sVal : p_sDefault;
- } // ________________________________
-
- /**
- * Find child nodes named "NotificationList" that contain an attribute
- * 'type' that starts with "ok" (case insensitive)
- *
- * @param p_oP -
- * DomElement to search for "NotificationList" child Elements
- * @param p_oSer
- * Serializable - Will constitute the body of the notification
- */
- public static void notifyOK(DomElement p_oP, Serializable p_oSer) {
- if(p_oSer == null) {
- return;
- }
-
- try {
- Serializable oNotif = p_oSer;
- for (DomElement oCurr : p_oP
- .getElementChildren(NotificationList.ELEMENT)) {
- NotificationList oNL = new NotificationList(oCurr);
- if (!oNL.isOK())
- continue;
- getNotifHandler().sendNotifications(oCurr, oNotif);
- }
- } catch (Exception e) {
- }
- } // __________________________________
-
- /**
- * Find child nodes named "NotificationList" that contain an attribute
- * 'type' that starts with "err" (case insensitive) or no 'type' attribute
- * set
- *
- * @param p_oP -
- * DomElement to search for "NotificationList" child Elements
- * @param p_e -
- * Exception if not null, will be appended to the body
- * @param p_oSer
- * Serializable - Will be included at the beginning of the body
- * of the notification
- */
- public static void notifyError(DomElement p_oP, Exception p_e, Serializable p_oSer) {
- if(p_oSer == null) {
- return;
- }
-
- Serializable oNotif = p_oSer;
- ByteArrayOutputStream oBO = new ByteArrayOutputStream();
- PrintStream oPS = new PrintStream(oBO);
- try {
- oPS.println(oNotif.toString());
- if (null != p_e)
- p_e.printStackTrace(oPS);
- oPS.close();
-
- String sMsg = oBO.toString();
- for (DomElement oCurr : p_oP
- .getElementChildren(NotificationList.ELEMENT)) {
- NotificationList oNL = new NotificationList(oCurr);
- if (!oNL.isErr())
- continue;
- getNotifHandler().sendNotifications(oNL, sMsg);
- }
- } catch (Exception e) {
- }
- } // ________________________________
-
- private static NotificationManager s_oNH;
-
- private static final Object s_oSync = new Integer(0);
-
- /**
- * Lazy instantiator of a InotificationHandler
- *
- * @return - a reference to an implementation of the interface or null if it
- * can't be instantiated
- */
- protected static NotificationManager getNotifHandler() {
- if (null != s_oNH)
- return s_oNH;
- synchronized (s_oSync) {
- if (null == s_oNH)
- try {
- s_oNH = NotificationHandlerFactory.getNotifHandler(
- "remote", Configuration.getJndiServerType(),
- Configuration.getJndiServerURL());
- } catch (Exception e) {
- Logger.getLogger(GpListener.class).error(
- "Notification FAILED", e);
- }
- }
- return s_oNH;
- } // ______________________________
-
-} // ____________________________________________________________________________
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/JmsQueueListener.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/JmsQueueListener.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/JmsQueueListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,187 +0,0 @@
-/*
- * 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;
-
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageConsumer;
-import javax.jms.ObjectMessage;
-import javax.jms.Queue;
-import javax.jms.QueueConnection;
-import javax.jms.QueueConnectionFactory;
-import javax.jms.QueueSession;
-import javax.jms.TextMessage;
-import javax.jms.TopicSession;
-import javax.naming.Context;
-
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.actions.ActionProcessor;
-import org.jboss.soa.esb.helpers.AppServerContext;
-import org.jboss.soa.esb.helpers.DomElement;
-
-public class JmsQueueListener extends AbstractListener {
-
- public static final String LISTEN_QUEUE_CONN_FACT = "queueConnFactoryClass";
- public static final String LISTEN_JNDI_TYPE = "listenJndiType";
- public static final String LISTEN_JNDI_URL = "listenJndiURL";
- public static final String LISTEN_QUEUE = "listenQueue";
- public static final String LISTEN_MSG_SELECTOR = "listenMsgSelector";
-
- protected boolean m_bError = false;
- protected QueueConnection m_oQconn;
- protected QueueSession m_oQsess;
- protected Queue m_oQueue;
- protected String m_sSelector;
-
- protected MessageConsumer jmsMessageReceiver;
-
-
- public JmsQueueListener(GpListener commandListener, DomElement listenerConfig, ActionDefinitionFactory actionDefinitionFactory) throws Exception {
- super(commandListener, listenerConfig, actionDefinitionFactory);
- checkMyParms();
- } // __________________________________
-
- /**
- * Check for mandatory and optional attributes in parameter tree
- *
- * @throws Exception -
- * if mandatory atts are not right or actionClass not in
- * classpath
- */
- protected void checkMyParms() throws Exception {
- // Third arg is null - Exception will br thrown if listenQueue is not
- // found
- String sQueue = GpListener.obtainAtt(listenerConfig, LISTEN_QUEUE, null);
-
- // No problem if selector is null - everything in queue will be returned
- m_sSelector = listenerConfig.getAttr(LISTEN_MSG_SELECTOR);
-
- m_oQconn = null;
- m_oQsess = null;
- m_oQueue = null;
-
- String sJndiType = GpListener.obtainAtt(listenerConfig, LISTEN_JNDI_TYPE,
- "jboss");
- String sJndiURL = GpListener.obtainAtt(listenerConfig, LISTEN_JNDI_URL,
- "localhost");
- Context oJndiCtx = AppServerContext.getServerContext(sJndiType,
- sJndiURL);
-
- String sFactClass = GpListener.obtainAtt(listenerConfig,
- LISTEN_QUEUE_CONN_FACT, "ConnectionFactory");
- Object tmp = oJndiCtx.lookup(sFactClass);
- QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
-
- m_oQconn = qcf.createQueueConnection();
- m_oQueue = (Queue) oJndiCtx.lookup(sQueue);
- m_oQsess = m_oQconn.createQueueSession(false,
- TopicSession.AUTO_ACKNOWLEDGE);
- m_oQconn.start();
- jmsMessageReceiver = m_oQsess.createReceiver(m_oQueue, m_sSelector);
-
- } // ________________________________
-
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#receive()
- */
- @Override
- protected Object[] receive() {
- while (m_oDad.continueLooping()) {
- Message jmsMessage = null;
- try {
- jmsMessage = jmsMessageReceiver.receive(m_oDad.millisToWait());
- } catch (JMSException oJ) {
- logger.error("JMS error on receive. Attempting JMS Destination reconnect.", oJ);
- for (int i1 = 0; i1 < 3; i1++)
- try {
- checkMyParms();
- } // try to reconnect to the queue
- catch (Exception e) {
- logger.error("Reconnecting to Queue", e);
- try {
- Thread.sleep(m_iSleepForThreads);
- } catch (InterruptedException e1) { // Just return
- logger.error("Unexpected thread interupt exception.", e);
- return null;
- }
- }
- }
- if (null == jmsMessage) {
- // REVIEW: Can this really happen i.e. the JMS
- continue;
- }
-
- if (jmsMessage instanceof ObjectMessage) {
- try {
- return new Object[] {((ObjectMessage)jmsMessage).getObject()};
- } catch (JMSException e) {
- logger.error("Failed to read Serialized Object from JMS message.", e);
- }
- } else if (jmsMessage instanceof TextMessage) {
- try {
- return new Object[] {((TextMessage)jmsMessage).getText()};
- } catch (JMSException e) {
- logger.error("Failed to read Serialized Object from JMS message.", e);
- }
- } else {
- logger.error("Unsupported JMS message type: " + jmsMessage.getClass().getName());
- }
- }
-
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#close()
- */
- @Override
- protected void close() {
- if (null != m_oQsess) {
- try {
- m_oQsess.close();
- } catch (Exception e1) {/* Tried my best - Just continue */
- }
- }
- if (null != m_oQconn) {
- try {
- m_oQconn.close();
- } catch (Exception e2) {/* Tried my best - Just continue */
- }
- }
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
- */
- @Override
- protected void processingError(Object initialMessage, ActionProcessor processor, Throwable error) {
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
- */
- @Override
- protected void processingComplete(Object initialMessage) {
- }
-}
Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/ListenerTagNames.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/ListenerTagNames.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/ListenerTagNames.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,13 @@
+package org.jboss.soa.esb.listeners;
+
+public class ListenerTagNames
+{
+ public static final String SERVICE_NAME_TAG = "service-name";
+ public static final String TARGET_SERVICE_NAME_TAG = "target-service-name";
+
+ public static final String ACTION_ELEMENT_TAG = "action";
+ public static final String ACTION_CLASS_TAG = "class";
+ public static final String PROCESS_METHOD_TAG = "process";
+ public static final String NORMAL_COMPLETION_METHOD_TAG = "okMethod";
+ public static final String EXCEPTION_METHOD_TAG = "exceptionMethod";
+}
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/RemoteDirectoryPoller.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/RemoteDirectoryPoller.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/RemoteDirectoryPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,284 +0,0 @@
-/*
-* 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;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.actions.ActionProcessor;
-import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.helpers.KeyValuePair;
-import org.jboss.soa.esb.util.FtpClientUtil;
-import org.jboss.soa.esb.util.Util;
-
-public class RemoteDirectoryPoller extends AbstractPoller
-{
- public static final String FILE_INPUT_DIR = "inputDir";
- public static final String FILE_INPUT_SFX = "inputSuffix";
- public static final String FILE_WORK_SFX = "workSuffix";
- public static final String FILE_ERROR_DIR = "errorDir";
- public static final String FILE_ERROR_SFX = "errorSuffix";
- public static final String FILE_POST_DIR = "postDir";
- public static final String FILE_POST_SFX = "postSuffix";
- public static final String FILE_POST_DEL = "postDelete";
-
- private DomElement _params;
- private Logger _logger = Logger.getLogger(this.getClass());
- FtpClientUtil _ftpClient;
-
- public RemoteDirectoryPoller(GpListener p_oDad, DomElement p_oParms,ActionDefinitionFactory actionDF)
- throws Exception
- {
- super(p_oDad,p_oParms,actionDF);
- _params = p_oParms;
- checkMyParms();
- } //__________________________________
-
-
- protected File m_oInpDir ,m_oErrorDir ,m_oPostDir;
- protected String m_sInpSfx ,m_sWrkSfx ,m_sErrSfx ,m_sPostSfx;
- protected boolean m_bPostDel;
- private List <KeyValuePair> m_ftpProps = new ArrayList<KeyValuePair>();
-
- /**
- *
- * @param p_o Object - Must be a File representing the file that has to be processed
- * @return Object - an instance of the internal WorkingFile class
- */
- @Override
- public Object preProcess(Object p_o)
- {
- if (!(p_o instanceof File))
- return null;
- File oF = (File)p_o;
- WorkingFile oCurr = new WorkingFile(oF,m_sWrkSfx,m_bPostDel);
- oCurr.errorFile = new File (m_oErrorDir ,oF.getName()+m_sErrSfx);
- oCurr.outputFile = new File (m_oPostDir ,oF.getName()+m_sPostSfx);
- oCurr.setFtpProps(m_ftpProps);
-
- try
- {
- _ftpClient = new FtpClientUtil(_params,true);
- _ftpClient.remoteRename(oF,oCurr);
- }
- catch (Exception e)
- {
- _logger.error("Can't FTP rename",e);
- return null;
- }
- finally
- {
- if (null!=_ftpClient)
- _ftpClient.quit();
- _ftpClient = null;
- }
-
- return oCurr;
- } //________________________________
-
- @Override
- protected List<Object> pollForCandidates()
- {
- List<Object> oRet = new ArrayList<Object>();
- FtpClientUtil _ftpClient = null;
- try
- {
- _ftpClient = new FtpClientUtil(_params,true);
- _ftpClient.setRemoteDir(FtpClientUtil.fileToFtpString(m_oInpDir));
- String[] sa = _ftpClient.getFileListFromRemoteDir(m_sInpSfx);
- if (null!=sa)
- for (String sCurr : sa)
- oRet.add(new File(m_oInpDir,sCurr));
- }
- catch (Exception e)
- {
- _logger.error("Problems with FTP",e);
- }
- finally
- {
- if (null!=_ftpClient)
- _ftpClient.quit();
- _ftpClient = null;
- }
- return oRet;
-
- } //________________________________
-
- protected void checkMyParms() throws Exception
- {
- // INPUT directory and suffix (used for FileFilter)
- String sInpDir = GpListener.obtainAtt(_params,FILE_INPUT_DIR,null);
- m_oInpDir = new File(sInpDir);
-
- m_sInpSfx = GpListener.obtainAtt(_params,FILE_INPUT_SFX,null);
- m_sInpSfx = m_sInpSfx.trim();
- if (m_sInpSfx.length()<1)
- throw new Exception ("Invalid "+FILE_INPUT_SFX+" attribute");
-
- // WORK suffix (will rename in input directory)
- m_sWrkSfx = GpListener.obtainAtt(_params,FILE_WORK_SFX,".esbWork").trim();
- if (m_sWrkSfx.length()<1)
- throw new Exception ("Invalid "+FILE_WORK_SFX+" attribute");
- if (m_sInpSfx.equals(m_sWrkSfx))
- throw new Exception("Work suffix must differ from input suffix <"+m_sWrkSfx+">");
-
- // ERROR directory and suffix (defaults to input dir and ".esbError" suffix)
- String sErrDir = GpListener.obtainAtt(_params,FILE_ERROR_DIR,sInpDir);
- m_oErrorDir = new File(sErrDir);
-
- m_sErrSfx = GpListener.obtainAtt(_params,FILE_ERROR_SFX,".esbError").trim();
- if (m_sErrSfx.length()<1)
- throw new Exception ("Invalid "+FILE_ERROR_SFX+" attribute");
- if (m_oErrorDir.equals(m_oInpDir) && m_sInpSfx.equals(m_sErrSfx))
- throw new Exception("Error suffix must differ from input suffix <"+m_sErrSfx+">");
-
-
- // Do users wish to delete files that were processed OK ?
- String sPostDel = GpListener.obtainAtt(_params,FILE_POST_DEL,"false").trim();
- m_bPostDel = Boolean.parseBoolean(sPostDel);
- if (m_bPostDel)
- return;
-
- // POST (done) directory and suffix (defaults to input dir and ".esbDone" suffix)
- String sPostDir = GpListener.obtainAtt(_params,FILE_POST_DIR,sInpDir);
- m_oPostDir = new File(sPostDir);
- m_sPostSfx = GpListener.obtainAtt(_params,FILE_POST_SFX,".esbDone").trim();
- if (m_oPostDir.equals(m_oInpDir))
- { if (m_sPostSfx.length()<1)
- throw new Exception ("Invalid "+FILE_POST_SFX+" attribute");
- if (m_sPostSfx.equals(m_sInpSfx))
- throw new Exception("Post process suffix must differ from input suffix <"+m_sPostSfx+">");
- }
-
-
- FtpClientUtil _ftpClient = new FtpClientUtil(_params,false);
- _ftpClient.quit();
-
- // Copy FTP parameters to be passed to the action class (inside the WorkingFile class)
- // This is a kludge - we have to get back to this (ES)
- String[] sa = new String[]
- {FtpClientUtil.PARMS_FTP_SERVER
- ,FtpClientUtil.PARMS_USER
- ,FtpClientUtil.PARMS_PASSWD
- ,FtpClientUtil.PARMS_PASSIVE
- ,FtpClientUtil.PARMS_PORT
- };
- for (String sProp : sa)
- {
- String sVal = _params.getAttr(sProp);
- if (!Util.isNullString(sVal))
- m_ftpProps.add(new KeyValuePair(sProp,sVal));
- }
-
- } //________________________________
-
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#close()
- */
- @Override
- protected void close() { }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
- */
- @Override
- protected void processingError(Object initialMessage, ActionProcessor processor, Throwable error)
- {
- @SuppressWarnings("unused")
- WorkingFile workingFile = (WorkingFile) initialMessage;
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
- */
- @Override
- protected void processingComplete(Object initialMessage)
- {
- @SuppressWarnings("unused")
- WorkingFile workingFile = (WorkingFile) initialMessage;
- }
-
- /**
- * Working file.
- * <p/>
- * Once the remote directory poller picks up on an input file, it immediately tries to rename
- * it to a working file in order to avoid a situation where the file gets processed again.
- *
- * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
- * @since Version 4.0
- */
- public static class WorkingFile extends File
- {
- private static final long serialVersionUID = 1L;
-
- private boolean postDelete;
- private File inputFile, errorFile, outputFile;
- private List <KeyValuePair> ftpProps;
- public void setFtpProps(List <KeyValuePair>props) {ftpProps = props; }
- public List <KeyValuePair >getFtpProps() {return ftpProps; }
-
- private WorkingFile(File pFile,String pWrkSfx, boolean pPostDelete)
- {
- super(pFile.getParentFile(), pFile.getName() + pWrkSfx);
- inputFile = pFile;
- }
- /**
- * Get the File instance representing the original input file.
- * @return Original input file.
- */
- public File getInputFile() { return inputFile; }
- /**
- * is this working file to be deleted after successful processing ?
- * @return boolean - true if this file can be deleted
- */
- public boolean isPostDelete() { return postDelete; }
-
- public boolean localRenameToInput() { return super.renameTo(inputFile); }
- public void remoteRenameToInput(FtpClientUtil util) throws Exception
- {
- util.remoteRename(this,inputFile);
- }
-
- public boolean localRenameToError() { return super.renameTo(errorFile); }
- public void remoteRenameToError(FtpClientUtil util) throws Exception
- {
- util.remoteRename(this,errorFile);
- }
-
- public boolean localRenameToOutput() { return renameTo(outputFile); }
- public void remoteRenameToOutput(FtpClientUtil util) throws Exception
- {
- util.remoteRename(this,outputFile);
- }
-
- public boolean localDelete() {return delete(); }
- public void remoteDelete(FtpClientUtil util) throws Exception
- {util.deleteRemoteFile(this.toString()); }
-
- }
-} //____________________________________________________________________________
Deleted: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/SqlTablePoller.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/SqlTablePoller.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/SqlTablePoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -1,505 +0,0 @@
-/*
-* 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;
-
-import java.io.Serializable;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-import javax.sql.DataSource;
-
-import org.jboss.soa.esb.actions.ActionDefinitionFactory;
-import org.jboss.soa.esb.actions.ActionProcessor;
-import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.helpers.persist.JdbcCleanConn;
-import org.jboss.soa.esb.helpers.persist.SimpleDataSource;
-import org.jboss.soa.esb.util.Util;
-
-/**
- * SqlTablePoller class
- *
- * The SQL table that is polled should have
- * 1) a unique key (see "keyFields" parameter) that will be used to update status
- * 2) a column to indicate the "processing status" of this trigger row (see ROW_STATE enum)
- *
- * Each retrieved row (see OPTIONAL_ATT.whereCondition) should be considered as a trigger
- * that is intended to instantiate an object of "actionClass". The new instance will
- * receive the full DomElement (level 1 for each child group)
- *
- * @author Esteban Schifman
- */
-public class SqlTablePoller extends AbstractPoller
-{
-/* ___________________ Example XML configuration file for a SqlTablePoller_______________
- *
-<DocumentElementName>
- <ExampleListenChapter
- maxThreads="2"
- listenerClass="org.jboss.soa.esb.listeners.SqlTablePoller"
- actionClass="org.jboss.soa.esb.actions.templates.MockSqlRowAction"
-
- driver-class="org.postgresql.Driver"
- connection-url="jdbc:postgresql://myhost:5432/myDB"
- user-name="postgres"
- password=""
-
- tableName="test_notif_table"
- selectFields="oid,ref,msg"
- keyFields="oid,ref"
- inProcessField="statusCol"
- whereCondition="src='pepe'"
- orderBy="oid desc"
- >
- <NotificationList type="OK">
- <target class="NotifyFiles">
- <file URI="file:///tmp/jbossEsb/notifyDir/ListenOnNotifTable.notifOK"
- append="true"
- />
- </target>
- </NotificationList>
-
- <NotificationList type="err">
- <target class="NotifyFiles">
- <file URI="file:///tmp/jbossEsb/notifyDir/ListenOnNotifTable.notifErr"
- append="true"
- />
- </target>
- </NotificationList>
- </ExampleListenChapter>
-</DocumentElementName>
- *
- */
-
- /**
- * Mandatory attributes needed for SqlTablePoller
- * 1) Table name
- * 2) Comma separated list of fields needed in the ResultSet
- * 3) Comma separated list of fields that constitute a unique ID of the working row
- * all fields in this list MUST also be in the "selectFields" list
- * these fields will be used in the "where" clause of update statements
- * 4) Name of table field used as indicator/semaphore to avoid concurrent update
- *
- */
- public static enum TABLE_ATT
- {
- tableName
- ,selectFields
- ,keyFields
- ,inProcessField
- };
-
- /**
- * Optional fields that can be included in your parameter tree as attributes in the
- * upper Element
- * 1) 4 character long String that indicate status of each row for this poller
- * 1st: Character that indicates "Pending" state = available for processing
- * 2nd: "Working" : some poller is working on the row (or ab-ended while working)
- * 3rd: "Error" : some poller tried to process, and found an error during processing
- * 4th: "Done" : this row has already been processed successfully
- * 2) if you wish to further filter your ResultSet, you can add an optional list of
- * conditions that will be included in the "scan" SQL statement (without "where")
- * 3) Comma separated list of fields to order ResultSet (without "order by")
- *
- */
- public static enum OPTIONAL_ATT
- {
- inProcessVals
- ,whereCondition
- ,orderBy
- };
-
- /**
- * First character of these values are the default states of a table row trigger
- * the "inProcessVals" parameter can override these (if that were ever necessary)
- * this is why the default value for that parameter is "PWED" (see below)
- * The poller will only process rows that have the "inProcessField" first character
- * equal to the first character of whatever the "Pending" state is (typically "P")
- *
- */
- public static enum ROW_STATE
- {Pending
- ,Working
- ,Error
- ,Done
- };
- public static final String DEFAULT_STATES = "PWED";
-
- protected Map<String,String> m_oVals = new HashMap<String,String>();
- protected String[] m_saCols ,m_saKeys;
- protected String m_sUpdStates;
-
- /**
- * In this constructor you can override default values for the following protected base class values:
- * <br/>
- * <p/>m_iMinPollMillis : minimum polling interval (default 3000)
- * <br/>m_iDfltPollMillis : default polling interval (default 20000)
- * <br/>m_iSleepForThreads : how long to sleep if all configured threads are in use (default 3000)
- * <br/>m_iUpperThreadLimit : max number of threads allowed (default 10)
- * @param p_oDad GpListener - The controlling process
- * @param p_oParms DomElement - Sub tree that corresponds to this instance
- * @throws Exception
- */
- public SqlTablePoller(GpListener p_oDad, DomElement p_oParms, ActionDefinitionFactory actionDefinitionFactory) throws Exception
- {
- super(p_oDad, p_oParms, actionDefinitionFactory);
- try { checkMyParms(); }
- catch (Exception e)
- {
- logger.error("checkMyParms() FAILED",e);
- throw e;
- }
- } //__________________________________
-
- private void checkAndStoreAtt(DomElement p_oP, String p_sName, String p_sDflt)
- throws Exception
- {
- m_oVals.put(p_sName,GpListener.obtainAtt(p_oP,p_sName,p_sDflt));
- } //________________________________
-
- protected void checkMyParms() throws Exception
- {
- checkAndStoreAtt(listenerConfig,SimpleDataSource.DRIVER ,null);
- checkAndStoreAtt(listenerConfig,SimpleDataSource.URL ,null);
- checkAndStoreAtt(listenerConfig,SimpleDataSource.USER ,"");
- checkAndStoreAtt(listenerConfig,SimpleDataSource.PASSWORD ,"");
-
- for (TABLE_ATT oCurr : TABLE_ATT.values())
- checkAndStoreAtt(listenerConfig,oCurr.toString(),null);
-
- checkAndStoreAtt(listenerConfig,OPTIONAL_ATT.whereCondition.toString(),"");
- checkAndStoreAtt(listenerConfig,OPTIONAL_ATT.orderBy.toString(),"");
-
- String sAtt = OPTIONAL_ATT.inProcessVals.toString();
- checkAndStoreAtt(listenerConfig,sAtt,DEFAULT_STATES);
- m_sUpdStates = m_oVals.get(sAtt);
- if (m_sUpdStates.length()<4)
- throw new Exception("Parameter <"+sAtt+"> must be at least 4 characters long (PWED)");
-
- StringTokenizer ST = new StringTokenizer
- (m_oVals.get(TABLE_ATT.selectFields.toString()),",");
- m_saCols = new String[ST.countTokens()];
- Set<String> oSelFlds = new HashSet<String>();
- int iCurr = 0;
- while (ST.hasMoreElements())
- {
- String sColName = ST.nextToken().trim();
- m_saCols[iCurr++] = sColName;
- oSelFlds.add(sColName);
- }
-
- ST = new StringTokenizer
- (m_oVals.get(TABLE_ATT.keyFields.toString()),",");
- m_saKeys = new String[ST.countTokens()];
- if (m_saKeys.length < 1)
- throw new Exception("Empty list of keyFields");
-
- for (iCurr = 0; ST.hasMoreTokens(); iCurr++)
- { String sKeyCol = ST.nextToken().trim();
- if (! oSelFlds.contains(sKeyCol))
- throw new Exception("Key field <"+ sKeyCol + "> must also be in select list");
- m_saKeys[iCurr] = sKeyCol;
- }
-
- } //________________________________
-
- @Override
- protected Object preProcess(Object p_o)
- {
- return p_o;
- } //________________________________
-
- @SuppressWarnings("unchecked")
- @Override
- protected List<Object> pollForCandidates()
- {
- String sSel4U = selectForUpdStatement();
- String sUpdStmt = updateStatement();
- JdbcCleanConn oConn = null;
- List<Object> oResults = new ArrayList<Object>();
- try
- {
- oConn = newDbConn();
- String sScan = scanStatement();
-
- PreparedStatement PS = oConn.prepareStatement(sScan);
- ResultSet RS = oConn.execQueryWait(PS,1);
- while (RS.next()) {
- SQLPollResult rowParams = new SQLPollResult(sSel4U, sUpdStmt);
- int iCurr = 0;
-
- for (String sColName : m_saCols) {
- rowParams.put(sColName,RS.getObject(++iCurr));
- }
-
- // Set up the parameter object for the SqlRowAction
- rowParams.sUpdStates = m_sUpdStates;
- rowParams.saKeys = m_saKeys;
- rowParams.sSel4Upd = sSel4U;
- rowParams.sUpdate = sUpdStmt;
-
- // Mark the row as "working"...
- rowParams.changeStatusToWorking();
-
- oResults.add(rowParams);
- }
- }
- catch (Exception e)
- {
- logger.warn("Some triggers might not have been returned",e);
- }
- finally
- {
- if (null!=oConn)
- oConn.release();
- }
-
- logger.info("Returning " + oResults.size() + " rows.");
- return oResults;
- } //________________________________
-
- /**
- * Obtain a new database connection with parameter info
- * @return A new connection
- * @throws Exception - if problems are encountered
- */
- protected JdbcCleanConn newDbConn() throws Exception
- { DataSource oDS = new SimpleDataSource
- (m_oVals.get(SimpleDataSource.DRIVER)
- ,m_oVals.get(SimpleDataSource.URL)
- ,m_oVals.get(SimpleDataSource.USER)
- ,m_oVals.get(SimpleDataSource.PASSWORD)
- );
- return new JdbcCleanConn(oDS);
- } //________________________________
-
- /**
- * Assemble the SQL statement to scan (poll) the table
- * @return - The resulting SQL statement
- */
- protected String scanStatement()
- {
- StringBuilder sb = new StringBuilder ()
- .append("select ").append(m_oVals.get(TABLE_ATT.selectFields.toString()))
- .append(" from ") .append(m_oVals.get(TABLE_ATT.tableName.toString()));
-
- String sAux = m_oVals.get(OPTIONAL_ATT.whereCondition.toString());
- boolean bWhere = ! Util.isNullString(sAux);
- if (bWhere)
- sb.append(" where ").append(sAux);
- sb.append((bWhere) ? " and " : " where ");
-
- String sLike = m_oVals.get(OPTIONAL_ATT.inProcessVals.toString())
- .substring(0,1).toUpperCase();
- sb.append(" upper(").append(m_oVals.get(TABLE_ATT.inProcessField.toString()))
- .append(") like '").append(sLike).append("%'");
-
-
- sAux = m_oVals.get(OPTIONAL_ATT.orderBy);
- if (! Util.isNullString(sAux))
- sb.append(" order by ").append(sAux);
- return sb.toString();
- } //________________________________
-
- /**
- * Assemble the SQL statement to update the field
- * in the "inProcessField" parameter
- *
- * 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(m_oVals.get(TABLE_ATT.tableName.toString()))
- .append(" set ") .append(m_oVals.get(TABLE_ATT.inProcessField.toString()))
- .append(" = ? where ")
- ;
- int iCurr = 0;
- for(String sCurr : m_saKeys)
- { if (iCurr++ > 0)
- sb.append(" and ");
- sb.append(sCurr).append(" = ?");
- }
- return sb.toString();
- } //________________________________
-
- /**
- * Assemble the SQL "select for update" statement
- * for the "inProcessField" parameter
- *
- * in the table row uniquely identified by the list of fields
- * in the "keyFields" parameter
- *
- * @return - The resulting SQL statement
- */
- protected String selectForUpdStatement()
- {
- StringBuilder sb = new StringBuilder ()
- .append("select ").append(m_oVals.get(TABLE_ATT.inProcessField.toString()))
- .append(" from ") .append(m_oVals.get(TABLE_ATT.tableName.toString()))
- .append(" where ")
- ;
- int iCurr = 0;
- for(String sCurr : m_saKeys)
- { if (iCurr++ > 0)
- sb.append(" and ");
- sb.append(sCurr).append(" = ?");
- }
- return sb.append(" for update").toString();
- } //________________________________
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#close()
- */
- @Override
- protected void close() {
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
- */
- @Override
- protected void processingError(Object initialMessage, ActionProcessor processor, Throwable error) {
- // Mark the row as "error"...
- ((SQLPollResult)initialMessage).changeStatusToError();
- }
-
- /* (non-Javadoc)
- * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
- */
- @Override
- protected void processingComplete(Object initialMessage) {
- // Mark the row as "working"...
- ((SQLPollResult)initialMessage).changeStatusToDone();
- }
-
- private class SQLPollResult extends LinkedHashMap implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private String sUpdStates;
-
- private String[] saKeys;
-
- private String sSel4Upd, sUpdate;
-
- private SQLPollResult(String sSel4Upd, String sUpdate) throws Exception {
- this.sSel4Upd = sSel4Upd;
- this.sUpdate = sUpdate;
- }
-
- private String getStatus(ROW_STATE p_oState) {
- int iPos = p_oState.ordinal();
- return sUpdStates.substring(iPos, ++iPos);
- }
-
- private boolean changeStatusToWorking() {
- return changeStatus(ROW_STATE.Pending, ROW_STATE.Working);
- }
-
- private boolean changeStatusToDone() {
- return changeStatus(ROW_STATE.Working, ROW_STATE.Done);
- }
-
- private boolean changeStatusToError() {
- return changeStatus(ROW_STATE.Working, ROW_STATE.Error);
- }
-
- private boolean changeStatus(ROW_STATE fromState, ROW_STATE toState) {
- JdbcCleanConn dbConnection = null;
-
- try {
- // This is expensive at the moment but will be OK once we get proper connection pooling enabled!
- dbConnection = newDbConn();
- } catch (Exception e) {
- logger.error("Unable to get DB connection.", e);
- throw new IllegalStateException("Unable to get DB connection.", e);
- }
-
- try {
- PreparedStatement m_PSsel4U;
- PreparedStatement m_PSupd;
-
- m_PSsel4U = dbConnection.prepareStatement(sSel4Upd);
- m_PSupd = dbConnection.prepareStatement(sUpdate);
-
- int iParm=1;
- for (String sColName : saKeys) {
- Object oVal = get(sColName);
- m_PSsel4U.setObject (iParm ,oVal);
- // parameters are +1 in update statement
- // autoincrement leaves things ready for next SQL parameter
- m_PSupd.setObject (++iParm,oVal);
- }
-
- try {
- ResultSet resultSet = dbConnection.execQueryWait(m_PSsel4U, 5);
-
- if (resultSet.next()) {
- String sOldStatus = resultSet.getString(1).substring(0, 1);
-
- if (sOldStatus.equalsIgnoreCase(getStatus(fromState))) {
- m_PSupd.setString(1, getStatus(toState));
- dbConnection.execUpdWait(m_PSupd, 5);
- dbConnection.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 + ". Row not in state " + fromState);
- return false;
- }
- }
- logger.error("Row status change to " + toState + " has failed. Rolling back!!");
- } catch(Exception e) {
- logger.error("Row status change to " + toState + " has failed. Rolling back!!", e);
- }
-
- try {
- dbConnection.rollback();
- } catch (Exception e) {
- logger.error("Unable to rollback row status change to " + fromState.name(), e);
- }
- } catch (Exception e) {
- logger.error("Unexpected exception.", e);
- } finally {
- dbConnection.release();
- }
-
- return false;
- }
- }
-}
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/AbstractListener.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractListener.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractListener.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/AbstractListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,293 @@
+/*
+ * 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.old;
+
+import java.util.Arrays;
+
+import org.apache.log4j.Logger;
+import org.jboss.soa.esb.actions.ActionDefinition;
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.actions.ActionProcessor;
+import org.jboss.soa.esb.actions.ActionUtils;
+import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.message.Message;
+import org.jboss.soa.esb.message.format.MessageFactory;
+
+/**
+ * Base abstract listener implementation.
+ * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
+ * @since Version 4.0
+ */
+public abstract class AbstractListener implements Runnable {
+
+ /**
+ * Name constant def for the Message attachemnt carrying the list of actions to be applied to the
+ * incomming message. This allows the configured processing pipeline to be overridden by the Message
+ * producer.
+ */
+ public static final String MESSAGE_PROCESSING_ACTIONS_LIST = "MESSAGE_PROCESSING_ACTIONS_LIST";
+
+ // You can override these values at constructor time of your
+ // derived class after calling super(GpListener,DomElement)
+ protected int m_iSleepForThreads = 3000; // default sleep if no threads available
+ protected int m_iUpperThreadLimit = 10; // just in case - override if you wish
+
+ protected int m_iQthr = 0, m_iMaxThr;
+
+ protected ThreadGroup m_oThrGrp = null;
+ protected Logger logger;
+ protected GpListener m_oDad;
+ protected DomElement listenerConfig;
+ protected String[] m_oActions;
+ protected ActionDefinitionFactory m_oActionDefinitionFactory;
+ protected MessageFactory m_oMsgFactory;
+
+ protected AbstractListener(GpListener p_oDad, DomElement p_oParms, ActionDefinitionFactory actionDefinitionFactory) throws Exception {
+
+ logger = Logger.getLogger(this.getClass());
+ m_oDad = p_oDad;
+ listenerConfig = p_oParms.cloneObj();
+ m_oActionDefinitionFactory = actionDefinitionFactory;
+ m_oMsgFactory = MessageFactory.getInstance();
+ m_oThrGrp = new ThreadGroup(listenerConfig.getName());
+
+ String sAtt = GpListener.obtainAtt(listenerConfig, GpListener.PARM_ACTIONS, "");
+ if(!sAtt.trim().equals("")) {
+ m_oActions = sAtt.split(",");
+ }
+
+ sAtt = GpListener.obtainAtt(listenerConfig, GpListener.PARM_MAX_THREADS, "1");
+ int iMax = Integer.parseInt(sAtt);
+ m_iMaxThr = Math.min(iMax, m_iUpperThreadLimit);
+ } // __________________________________
+
+ /**
+ * Implement run method for this Runnable <p/> Will continue to run until
+ * controlling class (ref in m_oDad) indicates no more looping allowed for
+ * all child classes <p/> This condition will not prevent child processes to
+ * finish normally
+ */
+ public void run() {
+ while (m_oDad.continueLooping()) {
+ Object[] processList = receive();
+ if (null==processList) {
+ try { Thread.sleep(500); }
+ catch(InterruptedException e) {/* ok do nothing */}
+ } else {
+ for (Object currentObj : processList) {
+ if (m_iQthr >= m_iMaxThr) {
+ logger.info("Waiting for available threads...(max=" + m_iMaxThr + ")");
+ try {
+ Thread.sleep(m_iSleepForThreads);
+ } catch (InterruptedException e) {
+ return;
+ }
+ break;
+ }
+
+ // Spawn a thread and push the message message through the pipeline...
+ ActionProcessingPipeline runner = new ActionProcessingPipeline(currentObj);
+ new Thread(runner).start();
+ incThreads();
+ }
+ }
+ }
+
+ // Wait for all the processing pipelines to complete before closing the listener and existing...
+ while(m_iQthr > 0) {
+ logger.info("Waiting for all processing pipelines to complete.");
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ logger.warn("Thread interrupted while waiting for all processing pipelines to complete.", e);
+ }
+ }
+
+ logger.info("All processing pipelines complete. Closing listener now.");
+
+ close();
+ }
+
+ /**
+ * Receive message from underlying channel implementation.
+ * <p/>
+ * Implementations must perform a blocking receive.
+ * @return An array of Objects received on the channel.
+ */
+ protected abstract Object[] receive();
+
+ /**
+ * Called on the listener implementation when pipeline processing error has occured.
+ * @param initialMsg The message that was initialy supplied to the pipeline.
+ * @param processor The processor that raised the error. Can be null where the error was raised before
+ * pipeline processing of the message.
+ * @param error The error. Can be null.
+ */
+ protected abstract void processingError(Object initialMsg, ActionProcessor processor, Throwable error);
+
+ /**
+ * Called on the listener implementation when pipeline processing of a message is complete.
+ * @param initialMsg The message that was initialy supplied to the pipeline.
+ */
+ protected abstract void processingComplete(Object initialMsg);
+
+ /**
+ * Close the listener implemenation.
+ * <p/>
+ * Allows the listener to perform relevant close/cleanup tasks.
+ */
+ protected abstract void close();
+
+ /**
+ * Increment the active thread count.
+ */
+ private void incThreads() {
+ m_iQthr++;
+ }
+
+ /**
+ * Decrement the active thread count.
+ */
+ private void decThreads() {
+ m_iQthr--;
+ }
+
+ /**
+ * Action Processing Pipeline.
+ * <p/>
+ * Runs the actions in a listeners "actions" config on a message payload message received
+ * by the listener implementation.
+ *
+ * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
+ * @since Version 4.0
+ */
+ private class ActionProcessingPipeline implements Runnable {
+
+ private Object initialObject;
+
+ /**
+ * Private constructor.
+ * @param pMessage The inital processing target message.
+ */
+ private ActionProcessingPipeline(Object obj) {
+ initialObject = obj;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ String currentAction = null;
+ ActionProcessor currentProcessor = null;
+
+ try {
+ Message message;
+ String[] actions;
+
+ if(initialObject instanceof Message) {
+ message = (Message)initialObject;
+ } else {
+ message = m_oMsgFactory.getMessage();
+ ActionUtils.setTaskObject(message,initialObject);
+ }
+
+ actions = getActions(message);
+
+ // Run the message through each ActionProcessor...
+ for(String action : actions) {
+ ActionDefinition actionDefinition;
+
+ currentAction = action.trim();
+ actionDefinition = m_oActionDefinitionFactory.getInstance(currentAction);
+ if(actionDefinition == null) {
+ throw new java.lang.IllegalStateException("Bad Listener Configuration. No 'Actions/Action' definition for action [" + currentAction + "].");
+ }
+
+ // The processing result of each action feeds into the processing of the next action...
+ currentProcessor = actionDefinition.getProcessor();
+ try {
+ ActionUtils.copyCurrentToPrevious(message);
+ message = currentProcessor.process(message);
+ } catch (Exception e) {
+ GpListener.notifyError(listenerConfig, e, currentProcessor.getErrorNotification(message));
+ throw e;
+ }
+
+ if(message == null && action != m_oActions[m_oActions.length - 1]) {
+ String exceptionMessage = "Premature termination of action processing pipeline [" + Arrays.asList(m_oActions) + "]. ActionProcessor [" + currentProcessor.getClass().getName() + "] returned a null message result on processing of action [" + currentAction + "].";
+ processingError(initialObject, currentProcessor, new ActionProcessingException(exceptionMessage));
+ logger.warn(exceptionMessage);
+ return;
+ }
+ // Notify on all processors. May want to do this differently in the future i.e. more selectively ...
+ GpListener.notifyOK(listenerConfig, currentProcessor.getOkNotification(message));
+
+ // Setup the message for processing by the next processor...
+ if(message != null) {
+ message.getBody().remove(ActionUtils.BEFORE_ACTION);
+ }
+ }
+
+ processingComplete(initialObject);
+ } catch(Throwable thrown) {
+ processingError(initialObject, currentProcessor, thrown);
+ logger.error("Premature termination of action processing pipeline [" + (m_oActions != null?Arrays.asList(m_oActions):"") + "]. Action [" + currentAction + "] threw an exception.", thrown);
+ } finally {
+ // Decrement the active thread count for the listener on completion...
+ decThreads();
+ }
+ }
+
+ /**
+ * Get the list of actions to be applied to the supplied message.
+ * @param message The message to be processed.
+ * @return The set of processing actions to be performed on the message.
+ * @throws ActionProcessingException Invalid actions list attachment setting.
+ */
+ private String[] getActions(Message message) throws ActionProcessingException {
+ // Check is there an attachment specifying an override pipeline config...
+ Object overrideActionsAttachment = message.getAttachment().get(MESSAGE_PROCESSING_ACTIONS_LIST);
+ if(overrideActionsAttachment != null) {
+ if(overrideActionsAttachment instanceof String) {
+ String overrideActions = (String)overrideActionsAttachment;
+
+ if(overrideActions.trim().equals("")) {
+ throw new ActionProcessingException("Message attachement [" + MESSAGE_PROCESSING_ACTIONS_LIST + "] was specified but with an empty value. Aborting message processing.");
+ }
+
+ return overrideActions.split(",");
+ } else {
+ throw new ActionProcessingException("Message attachement [" + MESSAGE_PROCESSING_ACTIONS_LIST + "] must be of type java.lang.String. Received [" + overrideActionsAttachment.getClass().getName() + "]. Aborting message processing.");
+ }
+ } else {
+ // Otherwise use the actions configured on the listener...
+ if(m_oActions == null || m_oActions.length == 0) {
+ throw new ActionProcessingException("No actions configuration specified either on the listener or as a Message attachement [" + MESSAGE_PROCESSING_ACTIONS_LIST + "]. Aborting message processing.");
+ }
+ return m_oActions;
+ }
+ }
+ }
+
+} // ____________________________________________________________________________
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/AbstractPoller.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractPoller.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/AbstractPoller.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/AbstractPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,111 @@
+/*
+ * 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.old;
+
+import java.util.List;
+
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.helpers.DomElement;
+
+/**
+ * Abstract Polling Listener.
+ * <p/>
+ * Polling listeners are listener implementations that periodically poll for message objects
+ * that require processing. This type of listener implementation is required where the underlying
+ * message channel doesn't support a blocking receive operation.
+ *
+ * @author Esteban
+ */
+public abstract class AbstractPoller extends AbstractListener {
+
+ // You can override these values at constructor time of your
+ // derived class after calling super(GpListener,DomElement)
+ protected int m_iMinPollMillis = 3000 // minimum polling interval
+ , m_iDfltPollMillis = 20000 // default polling interval
+ ;
+
+ public static final String PARM_POLL_LTCY = "pollLatencySecs";
+
+ protected int m_iPollMillis;
+
+ /**
+ * Construct an abstract polling listener.
+ * @param commandListener The command listener.
+ * @param listenerConfig The configuration for this polling listener.
+ * @param actionDefinitionFactory The action definition factory for the bus.
+ * @throws Exception
+ */
+ protected AbstractPoller(GpListener commandListener, DomElement listenerConfig, ActionDefinitionFactory actionDefinitionFactory) throws Exception {
+ super(commandListener, listenerConfig, actionDefinitionFactory);
+
+ String sAtt = listenerConfig.getAttr(PARM_POLL_LTCY);
+ m_iPollMillis = (null == sAtt) ? m_iDfltPollMillis : 1000 * Integer.parseInt(sAtt);
+ if (m_iPollMillis < m_iMinPollMillis) {
+ m_iPollMillis = m_iMinPollMillis;
+ }
+ }
+
+ /**
+ * Polling listener receive implementation.
+ * @return An array of objects polled from the concrete Poller implementation.
+ */
+ protected Object[] receive() {
+ while (m_oDad.continueLooping()) {
+ List<Object> olPending = pollForCandidates();
+
+ if (olPending == null || olPending.isEmpty()) {
+ try {
+ Thread.sleep(m_iPollMillis);
+ } catch (InterruptedException e) {
+ logger.error("Unexpected thread interupt exception. Not terminating blocking receive!!", e);
+ }
+ continue;
+ } else {
+ Object[] objForProcessing = new Object[olPending.size()];
+
+ // Preprocess all the message objects.
+ // TODO: I really think this is no longer required or a good idea!!
+ for(int i = 0; i < olPending.size(); i++) {
+ objForProcessing[i] = preProcess(olPending.get(i));
+ }
+ return objForProcessing;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Poll for message objects.
+ * @return A list of message objects, or an empty list if there are no message objects.
+ */
+ protected abstract List<Object> pollForCandidates();
+
+ /**
+ * Preprocess the message object before returning for pipeline processing.
+ * @param message Message object for preprocessing.
+ * @return The preprocessed message object, or the supplied message unmodified.
+ */
+ protected abstract Object preProcess(Object message);
+ // TODO: Is this "preprocessing" step needed now that we have processing pipelines on listeners???
+}
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/DirectoryPoller.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/DirectoryPoller.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/DirectoryPoller.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/DirectoryPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,263 @@
+/*
+* 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.old;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.actions.ActionProcessor;
+import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.util.Util;
+
+public class DirectoryPoller extends AbstractPoller
+{
+ public static final String FILE_INPUT_DIR = "inputDirURI";
+ public static final String FILE_INPUT_SFX = "inputSuffix";
+ public static final String FILE_WORK_SFX = "workSuffix";
+ public static final String FILE_ERROR_DIR = "errorDirURI";
+ public static final String FILE_ERROR_SFX = "errorSuffix";
+ public static final String FILE_POST_DIR = "postDirURI";
+ public static final String FILE_POST_SFX = "postSuffix";
+ public static final String FILE_POST_DEL = "postDelete";
+
+ public DirectoryPoller(GpListener p_oDad, DomElement p_oParms, ActionDefinitionFactory actionDefinitionFactory) throws Exception
+ {
+ super(p_oDad, p_oParms, actionDefinitionFactory);
+ checkMyParms();
+ } //__________________________________
+
+
+ protected File m_oInpDir ,m_oErrorDir ,m_oPostDir;
+ protected FileFilter m_oFFilt;
+ protected String m_sInpSfx ,m_sWrkSfx ,m_sErrSfx ,m_sPostSfx;
+ protected boolean m_bPostDel;
+
+ /**
+ *
+ * @param inputObject Object - Must be a File representing the file that has to be processed
+ * @return Object - an array of 3 Files containing:
+ * <p/>[0] renamed file (workSuffix appended to input file name)
+ * <p/>[1] target file name in case actionClass is unable to complete successfuly
+ * <p/>[2] target file name in case actionClass finishes successfuly
+ */
+ @Override
+ public Object preProcess(Object inputObject)
+ {
+ if (!(inputObject instanceof File)) {
+ return null;
+ }
+
+ File inputFile = (File)inputObject;
+ WorkingFile workingFile = new WorkingFile(inputFile.getParentFile(), inputFile.getName() + m_sWrkSfx);
+
+ if (!inputFile.renameTo(workingFile)) {
+ return null;
+ }
+
+ workingFile.postDelete = m_bPostDel;
+ workingFile.inputFile = inputFile;
+ workingFile.errorFile = new File (m_oErrorDir ,inputFile.getName()+m_sErrSfx);
+ workingFile.outputFile = new File (m_oPostDir ,inputFile.getName()+m_sPostSfx);
+
+ return workingFile;
+ } //________________________________
+
+ @Override
+ protected List<Object> pollForCandidates()
+ {
+ File[] oaF = m_oInpDir.listFiles(m_oFFilt);
+ return Arrays.asList((Object[])oaF);
+ } //________________________________
+
+ private void checkMyParms() throws Exception
+ {
+ // INPUT directory and suffix (used for FileFilter)
+ String sInpDir = GpListener.obtainAtt(listenerConfig,FILE_INPUT_DIR,null);
+ m_oInpDir = getFile(sInpDir);
+ seeIfOkToWorkOnDir(m_oInpDir);
+
+ m_sInpSfx = GpListener.obtainAtt(listenerConfig,FILE_INPUT_SFX,null);
+ m_sInpSfx = m_sInpSfx.trim();
+ if (m_sInpSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_INPUT_SFX+" attribute");
+ m_oFFilt = new FileEndsWith(m_sInpSfx);
+
+ // WORK suffix (will rename in input directory)
+ m_sWrkSfx = GpListener.obtainAtt(listenerConfig,FILE_WORK_SFX,".esbWork").trim();
+ if (m_sWrkSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_WORK_SFX+" attribute");
+ if (m_sInpSfx.equals(m_sWrkSfx))
+ throw new Exception("Work suffix must differ from input suffix <"+m_sWrkSfx+">");
+
+ // ERROR directory and suffix (defaults to input dir and ".esbError" suffix)
+ String sErrDir = GpListener.obtainAtt(listenerConfig,FILE_ERROR_DIR,sInpDir);
+ m_oErrorDir = getFile(sErrDir);
+ seeIfOkToWorkOnDir(m_oErrorDir);
+
+ m_sErrSfx = GpListener.obtainAtt(listenerConfig,FILE_ERROR_SFX,".esbError").trim();
+ if (m_sErrSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_ERROR_SFX+" attribute");
+ if (m_oErrorDir.equals(m_oInpDir) && m_sInpSfx.equals(m_sErrSfx))
+ throw new Exception("Error suffix must differ from input suffix <"+m_sErrSfx+">");
+
+
+ // Do users wish to delete files that were processed OK ?
+ String sPostDel = GpListener.obtainAtt(listenerConfig,FILE_POST_DEL,"false").trim();
+ m_bPostDel = Boolean.parseBoolean(sPostDel);
+ if (m_bPostDel)
+ return;
+
+ // POST (done) directory and suffix (defaults to input dir and ".esbDone" suffix)
+ String sPostDir = GpListener.obtainAtt(listenerConfig,FILE_POST_DIR,sInpDir);
+ m_oPostDir = getFile(sPostDir);
+ seeIfOkToWorkOnDir(m_oPostDir);
+ m_sPostSfx = GpListener.obtainAtt(listenerConfig,FILE_POST_SFX,".esbDone").trim();
+ if (m_oPostDir.equals(m_oInpDir))
+ { if (m_sPostSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_POST_SFX+" attribute");
+ if (m_sPostSfx.equals(m_sInpSfx))
+ throw new Exception("Post process suffix must differ from input suffix <"+m_sPostSfx+">");
+ }
+
+ } //________________________________
+
+ private File getFile(String file) {
+ try {
+ return new File(new URI(file));
+ } catch(Exception e) {
+ return new File(file);
+ }
+ }
+
+ protected void seeIfOkToWorkOnDir (File p_oDir) throws Exception
+ {
+ if (! p_oDir.exists())
+ throw new Exception ("Directory "+p_oDir.toString()+" not found");
+ if (!p_oDir.isDirectory())
+ throw new Exception(p_oDir.toString()+" is not a directory");
+ if (!p_oDir.canRead())
+ throw new Exception("Can't read directory "+p_oDir.toString());
+ if (! p_oDir.canWrite())
+ throw new Exception ("Can't write/rename in directory "+p_oDir.toString());
+ } //________________________________
+
+
+ private class FileEndsWith implements FileFilter
+ {
+ String m_sSuffix;
+ FileEndsWith(String p_sEnd) throws Exception
+ {
+ m_sSuffix = p_sEnd;
+ if (Util.isNullString(m_sSuffix))
+ throw new Exception("Must specify file extension");
+ } //______________________________
+
+ public boolean accept(File p_f)
+ { return (p_f.isFile())
+ ? p_f.toString().endsWith(m_sSuffix)
+ : false;
+ } //______________________________
+ } //____________________________________________________
+
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#close()
+ */
+ @Override
+ protected void close() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
+ */
+ @Override
+ protected void processingError(Object currentObject, ActionProcessor processor, Throwable error) {
+
+ if (null!=currentObject)
+ { WorkingFile workingFile = (WorkingFile) currentObject;
+ workingFile.renameToError();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
+ */
+ @Override
+ protected void processingComplete(Object currentObject) {
+ WorkingFile workingFile = (WorkingFile) currentObject;
+
+ // Delete or rename the file...
+ if (workingFile.postDelete) {
+ workingFile.delete();
+ } else {
+ workingFile.renameToOutputFile();
+ }
+ }
+
+ /**
+ * Working file.
+ * <p/>
+ * Once the directory poller picks up on an input file, it immediately renames it to a working file
+ * in order to avoid a situation where the file gets processed again.
+ *
+ * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
+ * @since Version 4.0
+ */
+ public static class WorkingFile extends File {
+ private static final long serialVersionUID = 1L;
+
+ private boolean postDelete;
+ public boolean isPostDelete() { return postDelete; }
+
+ private File inputFile, errorFile, outputFile;
+
+ public WorkingFile(String filename) {
+ super(filename);
+ }
+
+ public WorkingFile(File parentFile, String filename) {
+ super(parentFile, filename);
+ }
+
+ public boolean renameToError() {
+ return renameTo(errorFile);
+ }
+
+ public boolean renameToOutputFile() {
+ return renameTo(outputFile);
+ }
+
+ /**
+ * Get the File instance representing the original input file.
+ * @return Original input file.
+ */
+ public File getInputFile() {
+ return inputFile;
+ }
+ }
+}
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/GpListener.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/GpListener.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/GpListener.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/GpListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,660 @@
+/*
+ * 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.old;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.jboss.internal.soa.esb.command.CommandQueue;
+import org.jboss.internal.soa.esb.command.CommandQueueException;
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.common.Configuration;
+import org.jboss.soa.esb.common.Environment;
+import org.jboss.soa.esb.common.ModulePropertyManager;
+import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.notification.NotificationList;
+import org.jboss.soa.esb.parameters.ParamRepositoryException;
+import org.jboss.soa.esb.parameters.ParamRepositoryFactory;
+import org.jboss.soa.esb.services.NotificationHandlerFactory;
+import org.jboss.soa.esb.services.NotificationManager;
+import org.jboss.soa.esb.util.Util;
+import org.xml.sax.SAXException;
+
+/**
+ * Controlling class that will launch listener child threads for supported
+ * transport listener classes, as indicated in the configuration XML tree
+ * pointed by arg[0]
+ *
+ * <p />
+ * Can be launched as uppermost controller (it has a main(args) method)
+ * <p />
+ * Also implements Runnable, and can thus be launched in a child thread from an
+ * upper controlling process
+ * <p />
+ * Listens on a JMS queue (with an optional message selector) for commands (e.g.
+ * Quiesce, Reload Parameters, Set End Time, etc.)
+ * <p />
+ * Parameter reloading can also be set using the PARM_RELOAD_SECS attribute
+ * <p />
+ * End time for this instance can also be set using the PARM_END_TIME attribute
+ * <p />
+ *
+ * @author Esteban
+ *
+ */
+public class GpListener implements Runnable {
+
+ private static Logger m_oLogger = Logger.getLogger(GpListener.class);
+
+ public static void main(String[] args) throws Exception {
+ GpListener oProc = new GpListener(args[0]);
+ oProc.run();
+ GpListener.State oS = oProc.getState();
+
+ if (null != oS.getException()) {
+ m_oLogger.error("GpListener <" + args[0] + "> FAILED\n", oS
+ .getException());
+ }
+ System.exit(oS.getCompletionCode());
+ } // ________________________________
+
+ protected int m_iDfltReloadMillis = 180000 // default interval between
+ // parameter reloads
+ ;
+
+ public static final String PARM_RELOAD_SECS = "parameterReloadSecs";
+ public static final String PARM_END_TIME = "endTime";
+
+ // Attribute name that denotes listener class to be instantiated in a child
+ // thread
+ // This attribute is not in the root node but in first level child
+ // DomElements
+ public static final String PARM_LISTENER_CLASS = "listenerClass";
+ public static final String PARM_ACTIONS = "actions";
+ public static final String PARM_MAX_THREADS = "maxThreads";
+ public static final String CHLD_EMAIL_PARMS = "EmailProperties";
+
+ private String m_sParmsName;
+ private DomElement m_oParms;
+
+ private HashMap<String, Object> m_oAtts;
+
+ /**
+ * Obtain a shallow copy of needed atributes in this object's last loaded
+ * parameter tree <p/>The local bject is cloned so child threads can use it
+ * as they choose to without interfering with the environment
+ * <p />
+ * Listener processes controlled by this object should keep a reference to
+ * this object at construction time, and not call this method again unless
+ * they specifically need updated values. Parameter reload could have
+ * happened since last call
+ *
+ * @return Map - a shallow copy of the attributes Map
+ */
+ @SuppressWarnings("unchecked")
+ public Map<String, Object> getControllerAttributes() {
+ return (Map<String, Object>) m_oAtts.clone();
+ }
+
+ private boolean m_bReloadRequested, m_bEndRequested;
+
+ private long m_lNextReload = Long.MAX_VALUE;
+
+ private long m_lEndTime = Long.MAX_VALUE;
+
+ public static final SimpleDateFormat s_oDateParse = new SimpleDateFormat(
+ "yyyyMMdd hh:mm:ss");
+
+ private State m_oState = null;
+
+ public State getState() {
+ return m_oState;
+ }
+
+ public static enum State {
+ Loading_parameters, Running, Shutting_down, Done_OK, Exception_thrown;
+ int m_iCompletionCode = 0;
+
+ Exception m_oException = null;
+
+ public int getCompletionCode() {
+ return m_iCompletionCode;
+ };
+
+ public Exception getException() {
+ return m_oException;
+ }
+ };
+
+ private CommandQueue commandQueue;
+
+ private ActionDefinitionFactory actionDefinitionFactory;
+
+ private static CommandQueue defaultCommandQueue = null;
+
+ /**
+ * Package pivate default constructor.
+ */
+ protected GpListener() {
+ }
+
+ /**
+ * Construct a Listener Manager from the named repository based
+ * configuration.
+ *
+ * @param p_sParameterName
+ * Name of the Repository entry containing the configuration.
+ * @throws Exception
+ * Unable to load/use the named configuration.
+ */
+ public GpListener(String p_sParameterName) throws Exception {
+ this(GpListener.getListenerConfig(p_sParameterName));
+ m_sParmsName = p_sParameterName;
+ }
+
+ /**
+ * Construct a Listener Manager using the specified listener configuration.
+ *
+ * @param config
+ * The configuration.
+ * @throws Exception
+ * Unable to load/use the supplied configuration.
+ */
+ public GpListener(DomElement config) throws Exception {
+ m_oParms = config;
+ m_oState = State.Loading_parameters;
+
+ try {
+ checkParms(m_oParms);
+ setEmailSystemProperties();
+ } catch (Exception e) {
+ String configSource = config.getAttr("configSource");
+
+ m_oState = State.Exception_thrown;
+ m_oState.m_oException = e;
+ m_oLogger.fatal("Listener configuration and startup error. Config Source: "
+ + (configSource != null ? configSource
+ : "unknown"), e);
+
+ throw e;
+ }
+ }
+
+ /**
+ * Load the named listener configuration from the configured parameter
+ * repository.
+ *
+ * @param reposParam
+ * The name of the repository entry containing the Listener
+ * configuration.
+ * @return Listener Configuration as {@link DomElement}.
+ * @throws IOException
+ * Unable to access the repository.
+ * @throws ParamRepositoryException
+ * Unable to access the configuration in the repository.
+ * @throws SAXException
+ * Unable to parse the configuration.
+ */
+ private static DomElement getListenerConfig(String reposParam)
+ throws IOException, ParamRepositoryException, SAXException {
+ String sXml = ParamRepositoryFactory.getInstance().get(reposParam);
+ DomElement config = DomElement.fromXml(sXml);
+
+ config.setAttr("configSource", "param-repository:" + reposParam);
+
+ return config;
+ }
+
+ /**
+ * Check to see if all needed parameters are there, and assign default
+ * values to some of them
+ *
+ * @param p_oP
+ * DomElement - Where to look for the mandatory/optional
+ * configuration attributes
+ * @throws Exception -
+ * If attributes are wrong or not enough for a proper runtime
+ * configuration
+ */
+ public void checkParms(DomElement p_oP) throws Exception {
+ // We've just loaded - set to false until next reload requested
+ m_bReloadRequested = false;
+ commandQueue = createCommandQueue(p_oP);
+
+ // Open the command queue...
+ if (null!=commandQueue)
+ commandQueue.open(p_oP);
+
+ // if PARM_RELOAD_SECS not set, and no command queue
+ // then reload every 10 minutes
+ // If there is a command queue, run until command is received
+ String sRldSecs = p_oP.getAttr(PARM_RELOAD_SECS);
+ m_lNextReload = (null != sRldSecs)
+ ? System.currentTimeMillis() + 1000 * Long.parseLong(sRldSecs)
+ : (null == commandQueue)
+ ? Long.MAX_VALUE
+ : System.currentTimeMillis() + m_iDfltReloadMillis;
+
+ // if PARM_END_TIME not set try to run forever
+ // not a good practice if command queue is not set
+ // Expected date format is "yyyyMMdd hh:mm:ss"
+ String sEndT = p_oP.getAttr(PARM_END_TIME);
+ m_lEndTime = (null == sEndT) ? Long.MAX_VALUE : s_oDateParse.parse(
+ sEndT).getTime();
+
+ // Read and initialise the action definitions...
+ DomElement actionConfig = p_oP.getFirstElementChild("Actions");
+ if(actionConfig == null) {
+ throw new ConfigurationException("No 'Actions' configuration.");
+ }
+ actionDefinitionFactory = new ActionDefinitionFactory(actionConfig);
+
+ } // ________________________________
+
+ /**
+ * Factory method for creating the command queue.
+ * @param config GpListener config.
+ * @return GpListener CommandQueue instance.
+ */
+ private CommandQueue createCommandQueue(DomElement config) {
+ String commandQueueClass = config.getAttr("command-queue-class");
+
+ if(commandQueueClass != null) {
+ try {
+ return (CommandQueue) Class.forName(commandQueueClass).newInstance();
+ } catch (Exception e) {
+ m_oLogger.error("Failed to instantiate CommandQueue ["+ commandQueueClass + "]. Defaulting to no Command Queue", e);
+ }
+ }
+
+ return defaultCommandQueue;
+ }
+
+ /**
+ * Allows a default command queue to be set statically for all GpListener instances.
+ * @param defaultCommandQueue The defaultCommandQueue to set.
+ */
+ public static void setDefaultCommandQueue(CommandQueue defaultCommandQueue) {
+ GpListener.defaultCommandQueue = defaultCommandQueue;
+ }
+
+ /**
+ * Main execution loop <p/> Will continue to run until either <p/>a) run
+ * time is expired <p/>b) quiesce command is received in command queue
+ * <p/>For every child element that contains a PARM_LISTENER_CLASS
+ * attribute, this method will try to launch a child thread instantiating an
+ * object of that class, and will call it's run() method <p/>Once all child
+ * processes are trigered, the main thread will either <p/>1) wait for a
+ * message in the command queue (if one was configured) until next reload or
+ * end of run period expired <p/>or 2) Just sleep if there's no command
+ * queue to listen on
+ */
+ public void run() {
+ while (endNotRequested()) {
+ m_oState = State.Running;
+ for (DomElement oCurr : m_oParms.getAllElemChildren()) {
+ String sClass = oCurr.getAttr(PARM_LISTENER_CLASS);
+ if (Util.isNullString(sClass))
+ continue;
+ tryToLaunchChildListener(oCurr, sClass);
+ }
+
+ waitForCmdOrSleep();
+
+ if (endRequested()) {
+ break;
+ }
+ if (m_sParmsName != null && timeToReload()) {
+ try {
+ m_oState = State.Loading_parameters;
+ m_oLogger
+ .info("Reloading parameters _____________________________________________________");
+ DomElement oNew = GpListener.getListenerConfig(m_sParmsName);
+ checkParms(oNew);
+ m_oParms = oNew;
+ setEmailSystemProperties();
+ } catch (Exception e) {
+ m_oLogger.error("Failed to reload parameters"
+ + " - Continuing with cached version", e);
+ }
+ }
+ }
+ // m_oState = State.Shutting_down;
+
+ m_oState = State.Done_OK;
+ m_oState.m_iCompletionCode = 0;
+ m_oLogger
+ .info("Finishing_____________________________________________________");
+
+ // Close the command queue...
+ try {
+ commandQueue.close();
+ } catch (CommandQueueException e) {
+ m_oLogger.error("Error closing Command Queue.", e);
+ }
+ } // ________________________________
+
+ private void tryToLaunchChildListener(DomElement p_oP, String p_sClassName) {
+ try {
+ Class oListener = Class.forName(p_sClassName);
+ Constructor oConst = oListener.getConstructor(new Class[] {
+ this.getClass(), DomElement.class, ActionDefinitionFactory.class });
+ Runnable oRun = (Runnable) oConst.newInstance(new Object[] { this,
+ p_oP, actionDefinitionFactory });
+ new Thread(oRun).start();
+ } catch (Exception e) {
+ m_oLogger.error("Cannot launch <" + p_sClassName + ">\n", e);
+ }
+ } // ________________________________
+
+ long millisToWait() {
+ return Math.min(m_lNextReload, m_lEndTime) - System.currentTimeMillis();
+ } // ________________________________
+
+ private void waitForCmdOrSleep() {
+ long lToGo = millisToWait();
+
+ if (null == commandQueue) {
+ m_oLogger.debug("About to sleep " + lToGo);
+ // No command queue nor topic - Just sleep until time
+ // exhausted, or thread interrupted
+ try {
+ if (lToGo > 0)
+ Thread.sleep(lToGo);
+ } catch (InterruptedException e) {
+ m_lEndTime = 0; // mark as end requested and return
+ }
+ return;
+ }
+
+ // Wait for commands until time exhausted or command received
+ // Note that received commands might change time variables (reload/end)
+ // that's why time to go is recalculated on each cycle
+ while ((lToGo = millisToWait()) > 0) {
+ try {
+ m_oLogger.info("Waiting for command ... timeout=" + lToGo + " millis");
+
+ String oM = commandQueue.receiveCommand(lToGo);
+ if (null == oM) {
+ return;
+ }
+ processCommand(oM);
+ if (endRequested() || timeToReload()) {
+ break;
+ }
+ } catch (CommandQueueException eJ) {
+ m_oLogger.info("receive on command queue failed", eJ);
+ }
+ }
+ } // ________________________________
+
+ /**
+ * Processes the command that has been received in the command queue (or
+ * topic) <p/>m_bEndRequested, m_bReloadRequested, and m_lEndTime could be
+ * changed
+ *
+ * <p/> <p/><TABLE border="1"> <COLGROUP> <COL width="200"/> <COL
+ * width="400"/> </COLGROUP>
+ * <TR>
+ * <TD align="center">message text</TD>
+ * <TD align="center">effect</TD>
+ * </TR>
+ * <TR>
+ * <TD>shutdown*</TD>
+ * <TD>End time will be immediately set to 'now' - quiesce process will
+ * start - Child threads will be allowed to finish normally</TD>
+ * </TR>
+ * <TR>
+ * <TD>reload param*</TD>
+ * <TD>Parameters will be immediately reloaded, and listener reconfigured
+ * with new values</TD>
+ * </TR>
+ * <TR>
+ * <TD>endTime yyyyMMdd hh:mm:ss</TD>
+ * <TD>End time will be set to new value. If hh:mm:ss is not supplied =>
+ * end of day assumed (23:59:59)</TD>
+ * </TR>
+ * </TABLE> * startsWith() <p/>
+ *
+ * @param p_oMsg
+ * Message received from the command queue.
+ *
+ */
+ private void processCommand(String sTxt) {
+ if (null == sTxt)
+ return;
+
+ String sLow = sTxt.trim().toLowerCase();
+ if (sLow.startsWith("shutdown")) {
+ m_bEndRequested = true;
+ m_oLogger.info("Shutdown has been requested");
+ return;
+ }
+ if (sLow.startsWith("reload param")) {
+ m_bReloadRequested = true;
+ m_oLogger
+ .info("Request for parameter reload has been received");
+ return;
+ }
+ String[] sa = sLow.split("\\s+");
+ if (sa.length > 1 && "endtime".equals(sa[0])) {
+ try {
+ String sDate = sa[1];
+ String sTime = (sa.length < 3 || null == sa[2]) ? "23:59:59"
+ : sa[2];
+ Date oEnd = s_oDateParse.parse(sDate + " " + sTime);
+ m_oLogger.info("New end date set to : " + oEnd);
+ m_lEndTime = oEnd.getTime();
+ } catch (Exception eDat) {
+ m_oLogger.info("Problems with endTime command", eDat);
+ }
+ }
+ } // ________________________________
+
+ /**
+ * Accessor to determine if execution time is expired or shutdown requested
+ *
+ * @return boolean if processing has to stop (all child threads will be
+ * allowed to finish)
+ */
+ public boolean endRequested() {
+ return m_bEndRequested || System.currentTimeMillis() >= m_lEndTime;
+ }
+
+ /**
+ * Accessor to determine if execution time is not expired, and no shutdown
+ * request received
+ *
+ * @return boolean - true if run time has not expired and quiesce has not
+ * been requested
+ */
+ public boolean endNotRequested() {
+ return !endRequested();
+ }
+
+ /**
+ * Provide a common accessor to determine if parameters have to be reloaded
+ * <p/> For child threads this means thread execution has to end
+ * </p>
+ * Child processes should only call this method when they are idle (as
+ * opposed to in the middle of executing a unit of work)
+ *
+ * @return boolean - true if it's time to reload parameters
+ */
+ public boolean timeToReload() {
+ return m_bReloadRequested
+ || System.currentTimeMillis() >= m_lNextReload;
+ }
+
+ /**
+ * Helper accessor for child processes that provides info to determine if
+ * they can continue with yet another execution cycle
+ *
+ * @return boolean - true if runtime is not expired and not time yet to
+ * reload parameters
+ */
+ public boolean continueLooping() {
+ return (endNotRequested() && !timeToReload());
+ } // ________________________________
+
+ private static final String[] s_saMailProps = { Environment.SMTP_HOST,
+ Environment.SMTP_USERNAME, Environment.SMTP_PASSWORD,
+ Environment.SMTP_PORT, Environment.SMTP_FROM,
+ Environment.SMTP_AUTH };
+
+ private void setEmailSystemProperties() {
+ DomElement oEmail = m_oParms.getFirstElementChild(CHLD_EMAIL_PARMS);
+ if (null != oEmail)
+ for (String sCurr : s_saMailProps) {
+ String sProp = oEmail.getAttr(sCurr);
+ if (null != sProp)
+ ModulePropertyManager.getPropertyManager(ModulePropertyManager.TRANSPORTS_MODULE).setProperty(sCurr, sProp);
+ }
+ } // ________________________________
+
+ /**
+ * Find an attribute in the tree (arg 0) or assign default value (arg 2)
+ *
+ * @param p_oP
+ * DomElement - look for attributes in this Element only
+ * @param p_sAtt
+ * String - Name of attribute to find
+ * @param p_sDefault
+ * String -default value if requested attribute is not there
+ * @return String - value of attribute, or default value (if null)
+ * @throws Exception -
+ * If requested attribute not found and no default value
+ * supplied by invoker
+ */
+ public static String obtainAtt(DomElement p_oP, String p_sAtt, String p_sDefault)
+ throws ConfigurationException {
+ String sVal = p_oP.getAttr(p_sAtt);
+ if ((null == sVal) && (null == p_sDefault))
+ throw new ConfigurationException("Missing or invalid <" + p_sAtt + "> attribute");
+
+ return (null != sVal) ? sVal : p_sDefault;
+ } // ________________________________
+
+ /**
+ * Find child nodes named "NotificationList" that contain an attribute
+ * 'type' that starts with "ok" (case insensitive)
+ *
+ * @param p_oP -
+ * DomElement to search for "NotificationList" child Elements
+ * @param p_oSer
+ * Serializable - Will constitute the body of the notification
+ */
+ public static void notifyOK(DomElement p_oP, Serializable p_oSer) {
+ if(p_oSer == null) {
+ return;
+ }
+
+ try {
+ Serializable oNotif = p_oSer;
+ for (DomElement oCurr : p_oP
+ .getElementChildren(NotificationList.ELEMENT)) {
+ NotificationList oNL = new NotificationList(oCurr);
+ if (!oNL.isOK())
+ continue;
+ getNotifHandler().sendNotifications(oCurr, oNotif);
+ }
+ } catch (Exception e) {
+ }
+ } // __________________________________
+
+ /**
+ * Find child nodes named "NotificationList" that contain an attribute
+ * 'type' that starts with "err" (case insensitive) or no 'type' attribute
+ * set
+ *
+ * @param p_oP -
+ * DomElement to search for "NotificationList" child Elements
+ * @param p_e -
+ * Exception if not null, will be appended to the body
+ * @param p_oSer
+ * Serializable - Will be included at the beginning of the body
+ * of the notification
+ */
+ public static void notifyError(DomElement p_oP, Exception p_e, Serializable p_oSer) {
+ if(p_oSer == null) {
+ return;
+ }
+
+ Serializable oNotif = p_oSer;
+ ByteArrayOutputStream oBO = new ByteArrayOutputStream();
+ PrintStream oPS = new PrintStream(oBO);
+ try {
+ oPS.println(oNotif.toString());
+ if (null != p_e)
+ p_e.printStackTrace(oPS);
+ oPS.close();
+
+ String sMsg = oBO.toString();
+ for (DomElement oCurr : p_oP
+ .getElementChildren(NotificationList.ELEMENT)) {
+ NotificationList oNL = new NotificationList(oCurr);
+ if (!oNL.isErr())
+ continue;
+ getNotifHandler().sendNotifications(oNL, sMsg);
+ }
+ } catch (Exception e) {
+ }
+ } // ________________________________
+
+ private static NotificationManager s_oNH;
+
+ private static final Object s_oSync = new Integer(0);
+
+ /**
+ * Lazy instantiator of a InotificationHandler
+ *
+ * @return - a reference to an implementation of the interface or null if it
+ * can't be instantiated
+ */
+ protected static NotificationManager getNotifHandler() {
+ if (null != s_oNH)
+ return s_oNH;
+ synchronized (s_oSync) {
+ if (null == s_oNH)
+ try {
+ s_oNH = NotificationHandlerFactory.getNotifHandler(
+ "remote", Configuration.getJndiServerType(),
+ Configuration.getJndiServerURL());
+ } catch (Exception e) {
+ Logger.getLogger(GpListener.class).error(
+ "Notification FAILED", e);
+ }
+ }
+ return s_oNH;
+ } // ______________________________
+
+} // ____________________________________________________________________________
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/JmsQueueListener.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/JmsQueueListener.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/JmsQueueListener.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/JmsQueueListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,187 @@
+/*
+ * 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.old;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSession;
+import javax.jms.TextMessage;
+import javax.jms.TopicSession;
+import javax.naming.Context;
+
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.actions.ActionProcessor;
+import org.jboss.soa.esb.helpers.AppServerContext;
+import org.jboss.soa.esb.helpers.DomElement;
+
+public class JmsQueueListener extends AbstractListener {
+
+ public static final String LISTEN_QUEUE_CONN_FACT = "queueConnFactoryClass";
+ public static final String LISTEN_JNDI_TYPE = "listenJndiType";
+ public static final String LISTEN_JNDI_URL = "listenJndiURL";
+ public static final String LISTEN_QUEUE = "listenQueue";
+ public static final String LISTEN_MSG_SELECTOR = "listenMsgSelector";
+
+ protected boolean m_bError = false;
+ protected QueueConnection m_oQconn;
+ protected QueueSession m_oQsess;
+ protected Queue m_oQueue;
+ protected String m_sSelector;
+
+ protected MessageConsumer jmsMessageReceiver;
+
+
+ public JmsQueueListener(GpListener commandListener, DomElement listenerConfig, ActionDefinitionFactory actionDefinitionFactory) throws Exception {
+ super(commandListener, listenerConfig, actionDefinitionFactory);
+ checkMyParms();
+ } // __________________________________
+
+ /**
+ * Check for mandatory and optional attributes in parameter tree
+ *
+ * @throws Exception -
+ * if mandatory atts are not right or actionClass not in
+ * classpath
+ */
+ protected void checkMyParms() throws Exception {
+ // Third arg is null - Exception will br thrown if listenQueue is not
+ // found
+ String sQueue = GpListener.obtainAtt(listenerConfig, LISTEN_QUEUE, null);
+
+ // No problem if selector is null - everything in queue will be returned
+ m_sSelector = listenerConfig.getAttr(LISTEN_MSG_SELECTOR);
+
+ m_oQconn = null;
+ m_oQsess = null;
+ m_oQueue = null;
+
+ String sJndiType = GpListener.obtainAtt(listenerConfig, LISTEN_JNDI_TYPE,
+ "jboss");
+ String sJndiURL = GpListener.obtainAtt(listenerConfig, LISTEN_JNDI_URL,
+ "localhost");
+ Context oJndiCtx = AppServerContext.getServerContext(sJndiType,
+ sJndiURL);
+
+ String sFactClass = GpListener.obtainAtt(listenerConfig,
+ LISTEN_QUEUE_CONN_FACT, "ConnectionFactory");
+ Object tmp = oJndiCtx.lookup(sFactClass);
+ QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
+
+ m_oQconn = qcf.createQueueConnection();
+ m_oQueue = (Queue) oJndiCtx.lookup(sQueue);
+ m_oQsess = m_oQconn.createQueueSession(false,
+ TopicSession.AUTO_ACKNOWLEDGE);
+ m_oQconn.start();
+ jmsMessageReceiver = m_oQsess.createReceiver(m_oQueue, m_sSelector);
+
+ } // ________________________________
+
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#receive()
+ */
+ @Override
+ protected Object[] receive() {
+ while (m_oDad.continueLooping()) {
+ Message jmsMessage = null;
+ try {
+ jmsMessage = jmsMessageReceiver.receive(m_oDad.millisToWait());
+ } catch (JMSException oJ) {
+ logger.error("JMS error on receive. Attempting JMS Destination reconnect.", oJ);
+ for (int i1 = 0; i1 < 3; i1++)
+ try {
+ checkMyParms();
+ } // try to reconnect to the queue
+ catch (Exception e) {
+ logger.error("Reconnecting to Queue", e);
+ try {
+ Thread.sleep(m_iSleepForThreads);
+ } catch (InterruptedException e1) { // Just return
+ logger.error("Unexpected thread interupt exception.", e);
+ return null;
+ }
+ }
+ }
+ if (null == jmsMessage) {
+ // REVIEW: Can this really happen i.e. the JMS
+ continue;
+ }
+
+ if (jmsMessage instanceof ObjectMessage) {
+ try {
+ return new Object[] {((ObjectMessage)jmsMessage).getObject()};
+ } catch (JMSException e) {
+ logger.error("Failed to read Serialized Object from JMS message.", e);
+ }
+ } else if (jmsMessage instanceof TextMessage) {
+ try {
+ return new Object[] {((TextMessage)jmsMessage).getText()};
+ } catch (JMSException e) {
+ logger.error("Failed to read Serialized Object from JMS message.", e);
+ }
+ } else {
+ logger.error("Unsupported JMS message type: " + jmsMessage.getClass().getName());
+ }
+ }
+
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#close()
+ */
+ @Override
+ protected void close() {
+ if (null != m_oQsess) {
+ try {
+ m_oQsess.close();
+ } catch (Exception e1) {/* Tried my best - Just continue */
+ }
+ }
+ if (null != m_oQconn) {
+ try {
+ m_oQconn.close();
+ } catch (Exception e2) {/* Tried my best - Just continue */
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
+ */
+ @Override
+ protected void processingError(Object initialMessage, ActionProcessor processor, Throwable error) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
+ */
+ @Override
+ protected void processingComplete(Object initialMessage) {
+ }
+}
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/RemoteDirectoryPoller.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/RemoteDirectoryPoller.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/RemoteDirectoryPoller.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/RemoteDirectoryPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,284 @@
+/*
+* 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.old;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.actions.ActionProcessor;
+import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.helpers.KeyValuePair;
+import org.jboss.soa.esb.util.FtpClientUtil;
+import org.jboss.soa.esb.util.Util;
+
+public class RemoteDirectoryPoller extends AbstractPoller
+{
+ public static final String FILE_INPUT_DIR = "inputDir";
+ public static final String FILE_INPUT_SFX = "inputSuffix";
+ public static final String FILE_WORK_SFX = "workSuffix";
+ public static final String FILE_ERROR_DIR = "errorDir";
+ public static final String FILE_ERROR_SFX = "errorSuffix";
+ public static final String FILE_POST_DIR = "postDir";
+ public static final String FILE_POST_SFX = "postSuffix";
+ public static final String FILE_POST_DEL = "postDelete";
+
+ private DomElement _params;
+ private Logger _logger = Logger.getLogger(this.getClass());
+ FtpClientUtil _ftpClient;
+
+ public RemoteDirectoryPoller(GpListener p_oDad, DomElement p_oParms,ActionDefinitionFactory actionDF)
+ throws Exception
+ {
+ super(p_oDad,p_oParms,actionDF);
+ _params = p_oParms;
+ checkMyParms();
+ } //__________________________________
+
+
+ protected File m_oInpDir ,m_oErrorDir ,m_oPostDir;
+ protected String m_sInpSfx ,m_sWrkSfx ,m_sErrSfx ,m_sPostSfx;
+ protected boolean m_bPostDel;
+ private List <KeyValuePair> m_ftpProps = new ArrayList<KeyValuePair>();
+
+ /**
+ *
+ * @param p_o Object - Must be a File representing the file that has to be processed
+ * @return Object - an instance of the internal WorkingFile class
+ */
+ @Override
+ public Object preProcess(Object p_o)
+ {
+ if (!(p_o instanceof File))
+ return null;
+ File oF = (File)p_o;
+ WorkingFile oCurr = new WorkingFile(oF,m_sWrkSfx,m_bPostDel);
+ oCurr.errorFile = new File (m_oErrorDir ,oF.getName()+m_sErrSfx);
+ oCurr.outputFile = new File (m_oPostDir ,oF.getName()+m_sPostSfx);
+ oCurr.setFtpProps(m_ftpProps);
+
+ try
+ {
+ _ftpClient = new FtpClientUtil(_params,true);
+ _ftpClient.remoteRename(oF,oCurr);
+ }
+ catch (Exception e)
+ {
+ _logger.error("Can't FTP rename",e);
+ return null;
+ }
+ finally
+ {
+ if (null!=_ftpClient)
+ _ftpClient.quit();
+ _ftpClient = null;
+ }
+
+ return oCurr;
+ } //________________________________
+
+ @Override
+ protected List<Object> pollForCandidates()
+ {
+ List<Object> oRet = new ArrayList<Object>();
+ FtpClientUtil _ftpClient = null;
+ try
+ {
+ _ftpClient = new FtpClientUtil(_params,true);
+ _ftpClient.setRemoteDir(FtpClientUtil.fileToFtpString(m_oInpDir));
+ String[] sa = _ftpClient.getFileListFromRemoteDir(m_sInpSfx);
+ if (null!=sa)
+ for (String sCurr : sa)
+ oRet.add(new File(m_oInpDir,sCurr));
+ }
+ catch (Exception e)
+ {
+ _logger.error("Problems with FTP",e);
+ }
+ finally
+ {
+ if (null!=_ftpClient)
+ _ftpClient.quit();
+ _ftpClient = null;
+ }
+ return oRet;
+
+ } //________________________________
+
+ protected void checkMyParms() throws Exception
+ {
+ // INPUT directory and suffix (used for FileFilter)
+ String sInpDir = GpListener.obtainAtt(_params,FILE_INPUT_DIR,null);
+ m_oInpDir = new File(sInpDir);
+
+ m_sInpSfx = GpListener.obtainAtt(_params,FILE_INPUT_SFX,null);
+ m_sInpSfx = m_sInpSfx.trim();
+ if (m_sInpSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_INPUT_SFX+" attribute");
+
+ // WORK suffix (will rename in input directory)
+ m_sWrkSfx = GpListener.obtainAtt(_params,FILE_WORK_SFX,".esbWork").trim();
+ if (m_sWrkSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_WORK_SFX+" attribute");
+ if (m_sInpSfx.equals(m_sWrkSfx))
+ throw new Exception("Work suffix must differ from input suffix <"+m_sWrkSfx+">");
+
+ // ERROR directory and suffix (defaults to input dir and ".esbError" suffix)
+ String sErrDir = GpListener.obtainAtt(_params,FILE_ERROR_DIR,sInpDir);
+ m_oErrorDir = new File(sErrDir);
+
+ m_sErrSfx = GpListener.obtainAtt(_params,FILE_ERROR_SFX,".esbError").trim();
+ if (m_sErrSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_ERROR_SFX+" attribute");
+ if (m_oErrorDir.equals(m_oInpDir) && m_sInpSfx.equals(m_sErrSfx))
+ throw new Exception("Error suffix must differ from input suffix <"+m_sErrSfx+">");
+
+
+ // Do users wish to delete files that were processed OK ?
+ String sPostDel = GpListener.obtainAtt(_params,FILE_POST_DEL,"false").trim();
+ m_bPostDel = Boolean.parseBoolean(sPostDel);
+ if (m_bPostDel)
+ return;
+
+ // POST (done) directory and suffix (defaults to input dir and ".esbDone" suffix)
+ String sPostDir = GpListener.obtainAtt(_params,FILE_POST_DIR,sInpDir);
+ m_oPostDir = new File(sPostDir);
+ m_sPostSfx = GpListener.obtainAtt(_params,FILE_POST_SFX,".esbDone").trim();
+ if (m_oPostDir.equals(m_oInpDir))
+ { if (m_sPostSfx.length()<1)
+ throw new Exception ("Invalid "+FILE_POST_SFX+" attribute");
+ if (m_sPostSfx.equals(m_sInpSfx))
+ throw new Exception("Post process suffix must differ from input suffix <"+m_sPostSfx+">");
+ }
+
+
+ FtpClientUtil _ftpClient = new FtpClientUtil(_params,false);
+ _ftpClient.quit();
+
+ // Copy FTP parameters to be passed to the action class (inside the WorkingFile class)
+ // This is a kludge - we have to get back to this (ES)
+ String[] sa = new String[]
+ {FtpClientUtil.PARMS_FTP_SERVER
+ ,FtpClientUtil.PARMS_USER
+ ,FtpClientUtil.PARMS_PASSWD
+ ,FtpClientUtil.PARMS_PASSIVE
+ ,FtpClientUtil.PARMS_PORT
+ };
+ for (String sProp : sa)
+ {
+ String sVal = _params.getAttr(sProp);
+ if (!Util.isNullString(sVal))
+ m_ftpProps.add(new KeyValuePair(sProp,sVal));
+ }
+
+ } //________________________________
+
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#close()
+ */
+ @Override
+ protected void close() { }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
+ */
+ @Override
+ protected void processingError(Object initialMessage, ActionProcessor processor, Throwable error)
+ {
+ @SuppressWarnings("unused")
+ WorkingFile workingFile = (WorkingFile) initialMessage;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
+ */
+ @Override
+ protected void processingComplete(Object initialMessage)
+ {
+ @SuppressWarnings("unused")
+ WorkingFile workingFile = (WorkingFile) initialMessage;
+ }
+
+ /**
+ * Working file.
+ * <p/>
+ * Once the remote directory poller picks up on an input file, it immediately tries to rename
+ * it to a working file in order to avoid a situation where the file gets processed again.
+ *
+ * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
+ * @since Version 4.0
+ */
+ public static class WorkingFile extends File
+ {
+ private static final long serialVersionUID = 1L;
+
+ private boolean postDelete;
+ private File inputFile, errorFile, outputFile;
+ private List <KeyValuePair> ftpProps;
+ public void setFtpProps(List <KeyValuePair>props) {ftpProps = props; }
+ public List <KeyValuePair >getFtpProps() {return ftpProps; }
+
+ private WorkingFile(File pFile,String pWrkSfx, boolean pPostDelete)
+ {
+ super(pFile.getParentFile(), pFile.getName() + pWrkSfx);
+ inputFile = pFile;
+ }
+ /**
+ * Get the File instance representing the original input file.
+ * @return Original input file.
+ */
+ public File getInputFile() { return inputFile; }
+ /**
+ * is this working file to be deleted after successful processing ?
+ * @return boolean - true if this file can be deleted
+ */
+ public boolean isPostDelete() { return postDelete; }
+
+ public boolean localRenameToInput() { return super.renameTo(inputFile); }
+ public void remoteRenameToInput(FtpClientUtil util) throws Exception
+ {
+ util.remoteRename(this,inputFile);
+ }
+
+ public boolean localRenameToError() { return super.renameTo(errorFile); }
+ public void remoteRenameToError(FtpClientUtil util) throws Exception
+ {
+ util.remoteRename(this,errorFile);
+ }
+
+ public boolean localRenameToOutput() { return renameTo(outputFile); }
+ public void remoteRenameToOutput(FtpClientUtil util) throws Exception
+ {
+ util.remoteRename(this,outputFile);
+ }
+
+ public boolean localDelete() {return delete(); }
+ public void remoteDelete(FtpClientUtil util) throws Exception
+ {util.deleteRemoteFile(this.toString()); }
+
+ }
+} //____________________________________________________________________________
Copied: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/SqlTablePoller.java (from rev 7076, labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/SqlTablePoller.java)
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/SqlTablePoller.java 2006-10-24 12:47:05 UTC (rev 7076)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/old/SqlTablePoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -0,0 +1,505 @@
+/*
+* 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.old;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.sql.DataSource;
+
+import org.jboss.soa.esb.actions.ActionDefinitionFactory;
+import org.jboss.soa.esb.actions.ActionProcessor;
+import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.helpers.persist.JdbcCleanConn;
+import org.jboss.soa.esb.helpers.persist.SimpleDataSource;
+import org.jboss.soa.esb.util.Util;
+
+/**
+ * SqlTablePoller class
+ *
+ * The SQL table that is polled should have
+ * 1) a unique key (see "keyFields" parameter) that will be used to update status
+ * 2) a column to indicate the "processing status" of this trigger row (see ROW_STATE enum)
+ *
+ * Each retrieved row (see OPTIONAL_ATT.whereCondition) should be considered as a trigger
+ * that is intended to instantiate an object of "actionClass". The new instance will
+ * receive the full DomElement (level 1 for each child group)
+ *
+ * @author Esteban Schifman
+ */
+public class SqlTablePoller extends AbstractPoller
+{
+/* ___________________ Example XML configuration file for a SqlTablePoller_______________
+ *
+<DocumentElementName>
+ <ExampleListenChapter
+ maxThreads="2"
+ listenerClass="org.jboss.soa.esb.listeners.SqlTablePoller"
+ actionClass="org.jboss.soa.esb.actions.templates.MockSqlRowAction"
+
+ driver-class="org.postgresql.Driver"
+ connection-url="jdbc:postgresql://myhost:5432/myDB"
+ user-name="postgres"
+ password=""
+
+ tableName="test_notif_table"
+ selectFields="oid,ref,msg"
+ keyFields="oid,ref"
+ inProcessField="statusCol"
+ whereCondition="src='pepe'"
+ orderBy="oid desc"
+ >
+ <NotificationList type="OK">
+ <target class="NotifyFiles">
+ <file URI="file:///tmp/jbossEsb/notifyDir/ListenOnNotifTable.notifOK"
+ append="true"
+ />
+ </target>
+ </NotificationList>
+
+ <NotificationList type="err">
+ <target class="NotifyFiles">
+ <file URI="file:///tmp/jbossEsb/notifyDir/ListenOnNotifTable.notifErr"
+ append="true"
+ />
+ </target>
+ </NotificationList>
+ </ExampleListenChapter>
+</DocumentElementName>
+ *
+ */
+
+ /**
+ * Mandatory attributes needed for SqlTablePoller
+ * 1) Table name
+ * 2) Comma separated list of fields needed in the ResultSet
+ * 3) Comma separated list of fields that constitute a unique ID of the working row
+ * all fields in this list MUST also be in the "selectFields" list
+ * these fields will be used in the "where" clause of update statements
+ * 4) Name of table field used as indicator/semaphore to avoid concurrent update
+ *
+ */
+ public static enum TABLE_ATT
+ {
+ tableName
+ ,selectFields
+ ,keyFields
+ ,inProcessField
+ };
+
+ /**
+ * Optional fields that can be included in your parameter tree as attributes in the
+ * upper Element
+ * 1) 4 character long String that indicate status of each row for this poller
+ * 1st: Character that indicates "Pending" state = available for processing
+ * 2nd: "Working" : some poller is working on the row (or ab-ended while working)
+ * 3rd: "Error" : some poller tried to process, and found an error during processing
+ * 4th: "Done" : this row has already been processed successfully
+ * 2) if you wish to further filter your ResultSet, you can add an optional list of
+ * conditions that will be included in the "scan" SQL statement (without "where")
+ * 3) Comma separated list of fields to order ResultSet (without "order by")
+ *
+ */
+ public static enum OPTIONAL_ATT
+ {
+ inProcessVals
+ ,whereCondition
+ ,orderBy
+ };
+
+ /**
+ * First character of these values are the default states of a table row trigger
+ * the "inProcessVals" parameter can override these (if that were ever necessary)
+ * this is why the default value for that parameter is "PWED" (see below)
+ * The poller will only process rows that have the "inProcessField" first character
+ * equal to the first character of whatever the "Pending" state is (typically "P")
+ *
+ */
+ public static enum ROW_STATE
+ {Pending
+ ,Working
+ ,Error
+ ,Done
+ };
+ public static final String DEFAULT_STATES = "PWED";
+
+ protected Map<String,String> m_oVals = new HashMap<String,String>();
+ protected String[] m_saCols ,m_saKeys;
+ protected String m_sUpdStates;
+
+ /**
+ * In this constructor you can override default values for the following protected base class values:
+ * <br/>
+ * <p/>m_iMinPollMillis : minimum polling interval (default 3000)
+ * <br/>m_iDfltPollMillis : default polling interval (default 20000)
+ * <br/>m_iSleepForThreads : how long to sleep if all configured threads are in use (default 3000)
+ * <br/>m_iUpperThreadLimit : max number of threads allowed (default 10)
+ * @param p_oDad GpListener - The controlling process
+ * @param p_oParms DomElement - Sub tree that corresponds to this instance
+ * @throws Exception
+ */
+ public SqlTablePoller(GpListener p_oDad, DomElement p_oParms, ActionDefinitionFactory actionDefinitionFactory) throws Exception
+ {
+ super(p_oDad, p_oParms, actionDefinitionFactory);
+ try { checkMyParms(); }
+ catch (Exception e)
+ {
+ logger.error("checkMyParms() FAILED",e);
+ throw e;
+ }
+ } //__________________________________
+
+ private void checkAndStoreAtt(DomElement p_oP, String p_sName, String p_sDflt)
+ throws Exception
+ {
+ m_oVals.put(p_sName,GpListener.obtainAtt(p_oP,p_sName,p_sDflt));
+ } //________________________________
+
+ protected void checkMyParms() throws Exception
+ {
+ checkAndStoreAtt(listenerConfig,SimpleDataSource.DRIVER ,null);
+ checkAndStoreAtt(listenerConfig,SimpleDataSource.URL ,null);
+ checkAndStoreAtt(listenerConfig,SimpleDataSource.USER ,"");
+ checkAndStoreAtt(listenerConfig,SimpleDataSource.PASSWORD ,"");
+
+ for (TABLE_ATT oCurr : TABLE_ATT.values())
+ checkAndStoreAtt(listenerConfig,oCurr.toString(),null);
+
+ checkAndStoreAtt(listenerConfig,OPTIONAL_ATT.whereCondition.toString(),"");
+ checkAndStoreAtt(listenerConfig,OPTIONAL_ATT.orderBy.toString(),"");
+
+ String sAtt = OPTIONAL_ATT.inProcessVals.toString();
+ checkAndStoreAtt(listenerConfig,sAtt,DEFAULT_STATES);
+ m_sUpdStates = m_oVals.get(sAtt);
+ if (m_sUpdStates.length()<4)
+ throw new Exception("Parameter <"+sAtt+"> must be at least 4 characters long (PWED)");
+
+ StringTokenizer ST = new StringTokenizer
+ (m_oVals.get(TABLE_ATT.selectFields.toString()),",");
+ m_saCols = new String[ST.countTokens()];
+ Set<String> oSelFlds = new HashSet<String>();
+ int iCurr = 0;
+ while (ST.hasMoreElements())
+ {
+ String sColName = ST.nextToken().trim();
+ m_saCols[iCurr++] = sColName;
+ oSelFlds.add(sColName);
+ }
+
+ ST = new StringTokenizer
+ (m_oVals.get(TABLE_ATT.keyFields.toString()),",");
+ m_saKeys = new String[ST.countTokens()];
+ if (m_saKeys.length < 1)
+ throw new Exception("Empty list of keyFields");
+
+ for (iCurr = 0; ST.hasMoreTokens(); iCurr++)
+ { String sKeyCol = ST.nextToken().trim();
+ if (! oSelFlds.contains(sKeyCol))
+ throw new Exception("Key field <"+ sKeyCol + "> must also be in select list");
+ m_saKeys[iCurr] = sKeyCol;
+ }
+
+ } //________________________________
+
+ @Override
+ protected Object preProcess(Object p_o)
+ {
+ return p_o;
+ } //________________________________
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected List<Object> pollForCandidates()
+ {
+ String sSel4U = selectForUpdStatement();
+ String sUpdStmt = updateStatement();
+ JdbcCleanConn oConn = null;
+ List<Object> oResults = new ArrayList<Object>();
+ try
+ {
+ oConn = newDbConn();
+ String sScan = scanStatement();
+
+ PreparedStatement PS = oConn.prepareStatement(sScan);
+ ResultSet RS = oConn.execQueryWait(PS,1);
+ while (RS.next()) {
+ SQLPollResult rowParams = new SQLPollResult(sSel4U, sUpdStmt);
+ int iCurr = 0;
+
+ for (String sColName : m_saCols) {
+ rowParams.put(sColName,RS.getObject(++iCurr));
+ }
+
+ // Set up the parameter object for the SqlRowAction
+ rowParams.sUpdStates = m_sUpdStates;
+ rowParams.saKeys = m_saKeys;
+ rowParams.sSel4Upd = sSel4U;
+ rowParams.sUpdate = sUpdStmt;
+
+ // Mark the row as "working"...
+ rowParams.changeStatusToWorking();
+
+ oResults.add(rowParams);
+ }
+ }
+ catch (Exception e)
+ {
+ logger.warn("Some triggers might not have been returned",e);
+ }
+ finally
+ {
+ if (null!=oConn)
+ oConn.release();
+ }
+
+ logger.info("Returning " + oResults.size() + " rows.");
+ return oResults;
+ } //________________________________
+
+ /**
+ * Obtain a new database connection with parameter info
+ * @return A new connection
+ * @throws Exception - if problems are encountered
+ */
+ protected JdbcCleanConn newDbConn() throws Exception
+ { DataSource oDS = new SimpleDataSource
+ (m_oVals.get(SimpleDataSource.DRIVER)
+ ,m_oVals.get(SimpleDataSource.URL)
+ ,m_oVals.get(SimpleDataSource.USER)
+ ,m_oVals.get(SimpleDataSource.PASSWORD)
+ );
+ return new JdbcCleanConn(oDS);
+ } //________________________________
+
+ /**
+ * Assemble the SQL statement to scan (poll) the table
+ * @return - The resulting SQL statement
+ */
+ protected String scanStatement()
+ {
+ StringBuilder sb = new StringBuilder ()
+ .append("select ").append(m_oVals.get(TABLE_ATT.selectFields.toString()))
+ .append(" from ") .append(m_oVals.get(TABLE_ATT.tableName.toString()));
+
+ String sAux = m_oVals.get(OPTIONAL_ATT.whereCondition.toString());
+ boolean bWhere = ! Util.isNullString(sAux);
+ if (bWhere)
+ sb.append(" where ").append(sAux);
+ sb.append((bWhere) ? " and " : " where ");
+
+ String sLike = m_oVals.get(OPTIONAL_ATT.inProcessVals.toString())
+ .substring(0,1).toUpperCase();
+ sb.append(" upper(").append(m_oVals.get(TABLE_ATT.inProcessField.toString()))
+ .append(") like '").append(sLike).append("%'");
+
+
+ sAux = m_oVals.get(OPTIONAL_ATT.orderBy);
+ if (! Util.isNullString(sAux))
+ sb.append(" order by ").append(sAux);
+ return sb.toString();
+ } //________________________________
+
+ /**
+ * Assemble the SQL statement to update the field
+ * in the "inProcessField" parameter
+ *
+ * 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(m_oVals.get(TABLE_ATT.tableName.toString()))
+ .append(" set ") .append(m_oVals.get(TABLE_ATT.inProcessField.toString()))
+ .append(" = ? where ")
+ ;
+ int iCurr = 0;
+ for(String sCurr : m_saKeys)
+ { if (iCurr++ > 0)
+ sb.append(" and ");
+ sb.append(sCurr).append(" = ?");
+ }
+ return sb.toString();
+ } //________________________________
+
+ /**
+ * Assemble the SQL "select for update" statement
+ * for the "inProcessField" parameter
+ *
+ * in the table row uniquely identified by the list of fields
+ * in the "keyFields" parameter
+ *
+ * @return - The resulting SQL statement
+ */
+ protected String selectForUpdStatement()
+ {
+ StringBuilder sb = new StringBuilder ()
+ .append("select ").append(m_oVals.get(TABLE_ATT.inProcessField.toString()))
+ .append(" from ") .append(m_oVals.get(TABLE_ATT.tableName.toString()))
+ .append(" where ")
+ ;
+ int iCurr = 0;
+ for(String sCurr : m_saKeys)
+ { if (iCurr++ > 0)
+ sb.append(" and ");
+ sb.append(sCurr).append(" = ?");
+ }
+ return sb.append(" for update").toString();
+ } //________________________________
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#close()
+ */
+ @Override
+ protected void close() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingError(java.lang.Object, org.jboss.soa.esb.actions.ActionProcessor, java.lang.Throwable)
+ */
+ @Override
+ protected void processingError(Object initialMessage, ActionProcessor processor, Throwable error) {
+ // Mark the row as "error"...
+ ((SQLPollResult)initialMessage).changeStatusToError();
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.soa.esb.listeners.AbstractListener#processingComplete(java.lang.Object)
+ */
+ @Override
+ protected void processingComplete(Object initialMessage) {
+ // Mark the row as "working"...
+ ((SQLPollResult)initialMessage).changeStatusToDone();
+ }
+
+ private class SQLPollResult extends LinkedHashMap implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String sUpdStates;
+
+ private String[] saKeys;
+
+ private String sSel4Upd, sUpdate;
+
+ private SQLPollResult(String sSel4Upd, String sUpdate) throws Exception {
+ this.sSel4Upd = sSel4Upd;
+ this.sUpdate = sUpdate;
+ }
+
+ private String getStatus(ROW_STATE p_oState) {
+ int iPos = p_oState.ordinal();
+ return sUpdStates.substring(iPos, ++iPos);
+ }
+
+ private boolean changeStatusToWorking() {
+ return changeStatus(ROW_STATE.Pending, ROW_STATE.Working);
+ }
+
+ private boolean changeStatusToDone() {
+ return changeStatus(ROW_STATE.Working, ROW_STATE.Done);
+ }
+
+ private boolean changeStatusToError() {
+ return changeStatus(ROW_STATE.Working, ROW_STATE.Error);
+ }
+
+ private boolean changeStatus(ROW_STATE fromState, ROW_STATE toState) {
+ JdbcCleanConn dbConnection = null;
+
+ try {
+ // This is expensive at the moment but will be OK once we get proper connection pooling enabled!
+ dbConnection = newDbConn();
+ } catch (Exception e) {
+ logger.error("Unable to get DB connection.", e);
+ throw new IllegalStateException("Unable to get DB connection.", e);
+ }
+
+ try {
+ PreparedStatement m_PSsel4U;
+ PreparedStatement m_PSupd;
+
+ m_PSsel4U = dbConnection.prepareStatement(sSel4Upd);
+ m_PSupd = dbConnection.prepareStatement(sUpdate);
+
+ int iParm=1;
+ for (String sColName : saKeys) {
+ Object oVal = get(sColName);
+ m_PSsel4U.setObject (iParm ,oVal);
+ // parameters are +1 in update statement
+ // autoincrement leaves things ready for next SQL parameter
+ m_PSupd.setObject (++iParm,oVal);
+ }
+
+ try {
+ ResultSet resultSet = dbConnection.execQueryWait(m_PSsel4U, 5);
+
+ if (resultSet.next()) {
+ String sOldStatus = resultSet.getString(1).substring(0, 1);
+
+ if (sOldStatus.equalsIgnoreCase(getStatus(fromState))) {
+ m_PSupd.setString(1, getStatus(toState));
+ dbConnection.execUpdWait(m_PSupd, 5);
+ dbConnection.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 + ". Row not in state " + fromState);
+ return false;
+ }
+ }
+ logger.error("Row status change to " + toState + " has failed. Rolling back!!");
+ } catch(Exception e) {
+ logger.error("Row status change to " + toState + " has failed. Rolling back!!", e);
+ }
+
+ try {
+ dbConnection.rollback();
+ } catch (Exception e) {
+ logger.error("Unable to rollback row status change to " + fromState.name(), e);
+ }
+ } catch (Exception e) {
+ logger.error("Unexpected exception.", e);
+ } finally {
+ dbConnection.release();
+ }
+
+ return false;
+ }
+ }
+}
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/AbstractListenerUnitTest.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/AbstractListenerUnitTest.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/AbstractListenerUnitTest.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -29,6 +29,8 @@
import org.jboss.soa.esb.actions.ActionUtils;
import org.jboss.soa.esb.actions.BaseTestActionProcessor;
import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.listeners.old.AbstractListener;
+import org.jboss.soa.esb.listeners.old.GpListener;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.util.MockNonblockingListener;
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/DirectoryPollerUnitTest.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/DirectoryPollerUnitTest.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/DirectoryPollerUnitTest.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -22,6 +22,7 @@
package org.jboss.soa.esb.listeners;
import org.jboss.soa.esb.common.tests.BaseTest;
+import org.jboss.soa.esb.listeners.old.DirectoryPoller;
/**
* Test the DirectoryPoller
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/GpListenerUnitTest.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/GpListenerUnitTest.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/GpListenerUnitTest.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -27,6 +27,7 @@
import org.jboss.soa.esb.actions.ToNowhereRouter;
import org.jboss.soa.esb.common.tests.BaseTest;
import org.jboss.soa.esb.helpers.DomElement;
+import org.jboss.soa.esb.listeners.old.GpListener;
import org.jboss.soa.esb.util.ListenersManagerExecThread;
import org.jboss.soa.esb.util.MockPoller;
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/SqlTablePollerUnitTest.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/SqlTablePollerUnitTest.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/SqlTablePollerUnitTest.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -22,6 +22,7 @@
package org.jboss.soa.esb.listeners;
import org.jboss.soa.esb.common.tests.BaseTest;
+import org.jboss.soa.esb.listeners.old.SqlTablePoller;
/**
* Test the SqlTablePoller
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/AbstractMockListner.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/AbstractMockListner.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/AbstractMockListner.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -28,8 +28,8 @@
import org.jboss.soa.esb.actions.ActionDefinitionFactory;
import org.jboss.soa.esb.actions.ActionProcessor;
import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.listeners.AbstractListener;
-import org.jboss.soa.esb.listeners.GpListener;
+import org.jboss.soa.esb.listeners.old.AbstractListener;
+import org.jboss.soa.esb.listeners.old.GpListener;
/**
* Abstract Mock Listener implementation.
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/ListenersManagerExecThread.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/ListenersManagerExecThread.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/ListenersManagerExecThread.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -3,7 +3,7 @@
import junit.framework.TestCase;
import org.apache.log4j.Logger;
-import org.jboss.soa.esb.listeners.GpListener;
+import org.jboss.soa.esb.listeners.old.GpListener;
public class ListenersManagerExecThread extends Thread {
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockNonblockingListener.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockNonblockingListener.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockNonblockingListener.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -23,7 +23,7 @@
import org.jboss.soa.esb.actions.ActionDefinitionFactory;
import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.listeners.GpListener;
+import org.jboss.soa.esb.listeners.old.GpListener;
/**
* Non blocking mock Listener implementation.
Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockPoller.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockPoller.java 2006-10-24 13:49:34 UTC (rev 7082)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/util/MockPoller.java 2006-10-24 13:54:17 UTC (rev 7083)
@@ -9,11 +9,11 @@
import org.jboss.soa.esb.actions.ActionDefinitionFactory;
import org.jboss.soa.esb.actions.ActionProcessor;
import org.jboss.soa.esb.helpers.DomElement;
-import org.jboss.soa.esb.listeners.AbstractPoller;
-import org.jboss.soa.esb.listeners.GpListener;
+import org.jboss.soa.esb.listeners.old.AbstractPoller;
+import org.jboss.soa.esb.listeners.old.GpListener;
/**
- * Simple Mock {@link org.jboss.soa.esb.listeners.AbstractPoller} implementation that can be used for testing.
+ * Simple Mock {@link org.jboss.soa.esb.listeners.old.AbstractPoller} implementation that can be used for testing.
* <p/>
* Maintains a static in-memory queue into which objects can be dropped for processing by the configured action handler.
* @author tfennelly
More information about the jboss-svn-commits
mailing list