cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From un...@apache.org
Subject svn commit: rev 36341 - in cocoon/branches/BRANCH_2_1_X: . src/blocks/eventcache/java/org/apache/cocoon/caching/impl src/blocks/jms/java/org/apache/cocoon/acting src/blocks/jms/java/org/apache/cocoon/components/jms
Date Fri, 13 Aug 2004 12:32:04 GMT
Author: unico
Date: Fri Aug 13 05:32:03 2004
New Revision: 36341

Added:
   cocoon/branches/BRANCH_2_1_X/src/blocks/eventcache/java/org/apache/cocoon/caching/impl/JMSEventMessageListener.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/acting/
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/acting/JMSPublisherAction.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/AbstractMessageListener.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/AbstractMessagePublisher.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionManager.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionManagerImpl.java
Removed:
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnection.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionImpl.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSEventListener.java
   cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSPublisherAction.java
Modified:
   cocoon/branches/BRANCH_2_1_X/blocks.properties
   cocoon/branches/BRANCH_2_1_X/gump.xml
   cocoon/branches/BRANCH_2_1_X/status.xml
Log:
port changes from 2.2: enhanced JMS support

Modified: cocoon/branches/BRANCH_2_1_X/blocks.properties
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/blocks.properties	(original)
+++ cocoon/branches/BRANCH_2_1_X/blocks.properties	Fri Aug 13 05:32:03 2004
@@ -81,7 +81,6 @@
 #-----[dependency]: "session-fw" depends on "xsp".
 #-----[dependency]: "session-fw" is needed by "authentication-fw", "portal", "portal-fw".
 #include.block.session-fw=false
-#include.block.swf=false
 #-----[dependency]: "velocity" is needed by "petstore", "scratchpad".
 #include.block.velocity=false
 #include.block.web3=false
@@ -109,14 +108,14 @@
 #include.block.cron=false
 #include.block.deli=false
 #-----[dependency]: "eventcache" depends on "xsp" (for samples).
-#-----[dependency]: "eventcache" is needed by "jms", "repository".
+#-----[dependency]: "eventcache" is needed by "jms" (for samples), "repository".
 #include.block.eventcache=false
 #-----[dependency]: "forms" depends on "xsp" (for samples).
 #-----[dependency]: "forms" is needed by "apples", "javaflow", "ojb", "petstore", "tour".
 #include.block.forms=false
 #-----[dependency]: "javaflow" depends on "forms", "ojb".
 #include.block.javaflow=false
-#-----[dependency]: "jms" depends on "databases" (for samples), "eventcache", "hsqldb".
+#-----[dependency]: "jms" depends on "databases" (for samples), "hsqldb", "eventcache" (for
samples).
 #-----[dependency]: "jms" is needed by "slide".
 #include.block.jms=false
 #include.block.linotype=false
@@ -153,8 +152,9 @@
 
 # Although some of these blocks may have been stable, they are now deprecated
 # in favour of other blocks and therefore are excluded by default from the build.
-# For including one of them you have to set the include property to true in
-# local.blocks.properties.
+# For including one of them you have to set the exclude property into comment in
+# blocks.properties.
 
+include.block.swf=false
 #-----[dependency]: "woody" depends on "xsp" (for samples).
 include.block.woody=false

Modified: cocoon/branches/BRANCH_2_1_X/gump.xml
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/gump.xml	(original)
+++ cocoon/branches/BRANCH_2_1_X/gump.xml	Fri Aug 13 05:32:03 2004
@@ -17,7 +17,7 @@
 <!--+
     | Cocoon GUMP Descriptor
     |
-    | CVS $Id: gump.xml,v 1.155 2004/05/24 08:00:55 cziegeler Exp $
+    | CVS $Id$
     +-->
 
 <module name="cocoon-2.1">
@@ -1047,7 +1047,8 @@
     </ant>
 
     <depend project="cocoon" inherit="all"/>
-    <depend project="cocoon-block-eventcache"/>
+    <!-- commented out because of circular dependency -->
+    <!--depend project="cocoon-block-eventcache" type="samples"/-->
     <depend project="cocoon-block-databases" type="samples"/>
     <depend project="cocoon-block-hsqldb"/>
 

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/eventcache/java/org/apache/cocoon/caching/impl/JMSEventMessageListener.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/eventcache/java/org/apache/cocoon/caching/impl/JMSEventMessageListener.java
Fri Aug 13 05:32:03 2004
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */package org.apache.cocoon.caching.impl;
+
+import javax.jms.Message;
+
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.caching.Cache;
+import org.apache.cocoon.caching.EventAware;
+import org.apache.cocoon.caching.validity.Event;
+import org.apache.cocoon.caching.validity.NamedEvent;
+import org.apache.cocoon.components.jms.AbstractMessageListener;
+
+/**
+ * JMS listener will notify an {@link org.apache.cocoon.caching.EventAware} component
+ * of external events. This could be used for example to do external cache invalidation.
+ * 
+ * <p>
+ * Besides those inherited from 
+ * {@link org.apache.cocoon.components.jms.AbstractMessageListener} 
+ * parameters are:
+ * </p>
+ * <table border="1">
+ *  <tbody>
+ *   <tr>
+ *     <th align="left">parameter</th>
+ *     <th align="left">required</th>
+ *     <th align="left">default</th>
+ *     <th align="left">description</th>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">eventcache-role</td>
+ *     <td valign="top">no</td>
+ *     <td valign="top">org.apache.cocoon.caching.Cache/EventAware</td>
+ *     <td valign="top">The role name to lookup the event cache from the service manager.</td>
+ *   </tr>
+ *  </tbody>
+ * </table>
+ */
+public class JMSEventMessageListener extends AbstractMessageListener implements ThreadSafe
{
+
+    // ---------------------------------------------------- Constants
+
+    private static final String DEFAULT_EVENTCACHE_ROLE = Cache.ROLE + "/EventAware";
+    private static final String EVENTCACHE_ROLE_PARAM = "eventcache-role";
+
+    // ---------------------------------------------------- Instance variables
+
+    private String m_eventAwareRole;
+    private EventAware m_eventCache;
+
+    // ---------------------------------------------------- Lifecycle
+
+    public JMSEventMessageListener() {
+    }
+
+    public void parameterize(Parameters parameters) throws ParameterException {
+        super.parameterize(parameters);
+        m_eventAwareRole = parameters.getParameter(EVENTCACHE_ROLE_PARAM, DEFAULT_EVENTCACHE_ROLE);
+    }
+
+    public void dispose() {
+        super.dispose();
+        this.m_manager.release(m_eventCache);
+    }
+
+    /**
+     * Notifies the event cache of events occurred.
+     */
+    public synchronized void onMessage(Message message) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Receiving message: " + message);
+        }
+        final Event[] events = eventsFromMessage(message);
+        for (int i = 0; i < events.length; i++) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Notifying " + m_eventAwareRole + " of " + events[i]);
+            }
+            m_eventCache.processEvent(events[i]);
+        }
+    }
+
+    /**
+     * Convert the message contents to (a series of) cache event. The default implementation

+     * assumes that the message contains the trigger name, a '|', and a table name. 
+     * It extracts the tablename and creates a NamedEvent with it. 
+     * Override this method to provide a custom message to event mapping.
+     * 
+     * @param message  the JMS message.
+     * @return  the cache event.
+     */
+    protected Event[] eventsFromMessage(Message message) {
+        String name = message.toString();
+        int pos = name.indexOf('|');
+        return new Event[] { new NamedEvent(name.substring(pos + 1)) };
+    }
+    
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/acting/JMSPublisherAction.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/acting/JMSPublisherAction.java
Fri Aug 13 05:32:03 2004
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.acting;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.jms.Message;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.SourceResolver;
+
+import org.apache.cocoon.components.jms.AbstractMessagePublisher;
+
+/**
+ * Action to publish TextMessages to a JMS Topic. For description of static
+ * parameter configuration see {@link org.apache.cocoon.components.jms.AbstractMessagePublisher}
+ * 
+ * <p>Sitemap parameters:</p>
+ * <table border="1">
+ *  <tbody>
+ *   <tr>
+ *     <th align="left">parameter</th>
+ *     <th align="left">required</th>
+ *     <th align="left">default</th>
+ *     <th align="left">description</th>
+ *   </tr>
+ *  <tbody>
+ *   <tr>
+ *     <td>message</td>
+ *     <td>required</td>
+ *     <td>&nbsp;</td>
+ *     <td>Content of TextMessage to publish</td>
+ *   </tr>
+ *  </tbody>
+ * </table>
+ */
+public class JMSPublisherAction extends AbstractMessagePublisher implements Action, ThreadSafe
{
+
+    // ---------------------------------------------------- Constants
+
+    private static final String MESSAGE_PARAM = "message";
+
+    // ---------------------------------------------------- Lifecycle
+
+    public JMSPublisherAction () {
+    }
+
+    // ---------------------------------------------------- Action
+
+    public Map act(Redirector redirector,
+                   SourceResolver resolver,
+                   Map objectModel,
+                   String source,
+                   Parameters parameters) throws Exception {
+
+        Map result = null;
+        try {
+            // publish the message
+            final String event = parameters.getParameter(MESSAGE_PARAM);
+            final Message message = m_session.createTextMessage(event);
+            publishMessage(message);
+            result = Collections.EMPTY_MAP;
+        } catch (Exception e) {
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("Error delivering message.", e);
+            }
+        }
+
+        return result;
+    }
+
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/AbstractMessageListener.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/AbstractMessageListener.java
Fri Aug 13 05:32:03 2004
@@ -0,0 +1,183 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.jms;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameterizable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+
+/**
+ * Abstract JMS MessageListener. Use this as a basis for concrete
+ * MessageListener implementations.
+ * 
+ * <p>Parameters:</p>
+ * <table border="1">
+ *  <tbody>
+ *   <tr>
+ *     <th align="left">parameter</th>
+ *     <th align="left">required/default</th>
+ *     <th align="left">description</th>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">connection</td>
+ *     <td valign="top">required</td>
+ *     <td valign="top">
+ *       Name of the connection registered with 
+ *       {@link org.apache.cocoon.components.jms.JMSConnectionManager}. 
+ *       This must be a topic connection.
+ *     </td>
+ *   </tr>
+ *   <tr>
+ *     <td>topic</td>
+ *     <td>required</td>
+ *     <td>The name of the topic to subscribe to.</td>
+ *   </tr>
+ *   <tr>
+ *     <td>subscription-id</td>
+ *     <td>(<code>null</code>)</td>
+ *     <td>An optional durable subscription id.</td>
+ *   </tr>
+ *   <tr>
+ *     <td>message-selector</td>
+ *     <td>(<code>null</code>)</td>
+ *     <td>An optional message selector.</td>
+ *   </tr>
+ *  </tbody>
+ * </table>
+ * 
+ * @version CVS $Id: AbstractMessageListener.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public abstract class AbstractMessageListener extends AbstractLogEnabled
+implements MessageListener, ExceptionListener, Serviceable, Parameterizable, Initializable,
Disposable {
+
+    // ---------------------------------------------------- Constants
+
+    private static final String CONNECTION_PARAM = "connection";
+    private static final String TOPIC_PARAM = "topic";
+    private static final String SUBSCRIPTION_ID_PARAM = "subscription-id";
+    private static final String MESSAGE_SELECTOR_PARAM = "message-selector";
+
+    // ---------------------------------------------------- Instance variables
+
+    protected ServiceManager m_manager;
+
+    /* configuration */
+    private String m_connectionName;
+    private String m_topicName;
+    private String m_subscriptionId;
+    private String m_selector;
+
+    protected int m_acknowledgeMode;
+
+    /* connection manager component */
+    private JMSConnectionManager m_jmsConnectionManager;
+
+    /* our session */
+    private TopicSession m_session;
+
+    /* our subscriber */
+    private TopicSubscriber m_subscriber;
+
+    // ---------------------------------------------------- Lifecycle
+
+    public AbstractMessageListener () {
+    }
+
+    public void service(ServiceManager manager) throws ServiceException {
+        m_manager = manager;
+        m_jmsConnectionManager = (JMSConnectionManager) m_manager.lookup(JMSConnectionManager.ROLE);
+    }
+
+    public void parameterize(Parameters parameters) throws ParameterException {
+
+        m_connectionName = parameters.getParameter(CONNECTION_PARAM);
+        m_topicName = parameters.getParameter(TOPIC_PARAM);
+
+        m_subscriptionId = parameters.getParameter(SUBSCRIPTION_ID_PARAM, null);
+        m_selector = parameters.getParameter(MESSAGE_SELECTOR_PARAM, null);
+
+    }
+
+    /**
+     * Registers this MessageListener as a TopicSubscriber to the configured Topic.
+     */
+    public void initialize() throws Exception {
+
+        // set the default acknowledge mode to dups
+        // concrete implementations may want to override this
+        m_acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE;
+
+        // register this MessageListener with a TopicSubscriber
+        final TopicConnection connection = (TopicConnection) m_jmsConnectionManager.getConnection(m_connectionName);
+        if (connection != null) {
+            m_session = connection.createTopicSession(false, m_acknowledgeMode);
+            final Topic topic = m_session.createTopic(m_topicName);
+            if (m_subscriptionId != null) {
+                m_subscriber = m_session.createDurableSubscriber(topic, m_subscriptionId,
m_selector, false);
+            }
+            else {
+                m_subscriber = m_session.createSubscriber(topic, m_selector, false);
+            }
+            m_subscriber.setMessageListener(this);
+        }
+        else {
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("Could not obtain JMS connection '" + m_connectionName +
"'");
+            }
+        }
+
+    }
+
+    public void dispose() {
+        if (m_subscriber != null) {
+            try {
+                m_subscriber.close();
+            } catch (JMSException e) {
+                getLogger().error("Error closing subscriber", e);
+            }
+        }
+        if (m_session != null) {
+            try {
+                m_session.close();
+            }
+            catch (JMSException e) {
+                getLogger().error("Error closing session", e);
+            }
+        }
+        this.m_manager.release(m_jmsConnectionManager);
+    }
+
+    public void onException(JMSException exception) {
+        if (getLogger().isWarnEnabled()) {
+            getLogger().warn("JMS problem detected", exception);
+        }
+    }
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/AbstractMessagePublisher.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/AbstractMessagePublisher.java
Fri Aug 13 05:32:03 2004
@@ -0,0 +1,194 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.jms;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameterizable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+
+/**
+ * Abstract JMS message publisher. Use this as a basis for components 
+ * that want to publish JMS messages.
+ * 
+ * <p>Parameters:</p>
+ * <table border="1">
+ *  <tbody>
+ *   <tr>
+ *     <th align="left">parameter</th>
+ *     <th align="left">required</th>
+ *     <th align="left">default</th>
+ *     <th align="left">description</th>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">connection</td>
+ *     <td valign="top">yes</td>
+ *     <td>&nbsp;</td>
+ *     <td valign="top">
+ *       Name of the connection registered with 
+ *       {@link org.apache.cocoon.components.jms.JMSConnectionManager}. 
+ *       This must be a topic connection.
+ *     </td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">topic</td>
+ *     <td valign="top">yes</td>
+ *     <td>&nbsp;</td>
+ *     <td valign="top">The name of the topic to publish messages to.</td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">priority</td>
+ *     <td valign="top">no</td>
+ *     <td>4</td>
+ *     <td valign="top">the priority of the published messages</td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">time-to-live</td>
+ *     <td valign="top">no</td>
+ *     <td>10000</td>
+ *     <td valign="top">the message's lifetime in milliseconds</td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top">persistent-delivery</td>
+ *     <td valign="top">no</td>
+ *     <td>false</td>
+ *     <td valign="top">whether to use persistent delivery mode when publishing messages</td>
+ *   </tr>
+ *  </tbody>
+ * </table>
+ * 
+ * @version CVS $Id: AbstractMessagePublisher.java 30941 2004-07-29 19:56:58Z vgritsenko
$
+ */
+public abstract class AbstractMessagePublisher extends AbstractLogEnabled
+implements Serviceable, Parameterizable, Initializable, Disposable {
+
+    // ---------------------------------------------------- Constants
+
+    private static final String CONNECTION_PARAM = "connection";
+    private static final String TOPIC_PARAM = "topic";
+    private static final String PRIORITY_PARAM = "priority";
+    private static final String TIME_TO_LIVE_PARAM = "time-to-live";
+    private static final String PERSISTENT_DELIVERY_PARAM = "persistent-delivery";
+    
+    private static final int DEFAULT_PRIORITY = 4;
+    private static final int DEFAULT_TIME_TO_LIVE = 10000;
+
+    // ---------------------------------------------------- Instance variables
+
+    private ServiceManager m_manager;
+    private JMSConnectionManager m_connectionManager;
+
+    protected TopicSession m_session;
+    protected TopicPublisher m_publisher;
+
+    private int m_mode;
+    private int m_priority;
+    private int m_timeToLive;
+    private String m_topicName;
+    private int m_acknowledgeMode;
+
+    private String m_connectionName;
+
+    // ---------------------------------------------------- Lifecycle
+
+    public AbstractMessagePublisher() {
+    }
+
+    public void service(ServiceManager manager) throws ServiceException {
+        m_manager = manager;
+        m_connectionManager = (JMSConnectionManager) m_manager.lookup(JMSConnectionManager.ROLE);
+    }
+
+    public void parameterize(Parameters parameters) throws ParameterException {
+        m_connectionName = parameters.getParameter(CONNECTION_PARAM);
+        m_topicName = parameters.getParameter(TOPIC_PARAM);
+        m_priority = parameters.getParameterAsInteger(PRIORITY_PARAM, DEFAULT_PRIORITY);
+        boolean persistent = parameters.getParameterAsBoolean(PERSISTENT_DELIVERY_PARAM,
false);
+        m_mode = (persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
+        m_timeToLive = parameters.getParameterAsInteger(TIME_TO_LIVE_PARAM, DEFAULT_TIME_TO_LIVE);
+    }
+
+    public void initialize() throws Exception {
+
+        // set the default acknowledge mode
+        // concrete implementations may override this
+        m_acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE;
+
+        // create the message publisher
+        final TopicConnection connection = (TopicConnection) m_connectionManager.getConnection(m_connectionName);
+        if (connection != null) {
+            m_session = connection.createTopicSession(false, m_acknowledgeMode);
+            final Topic topic = m_session.createTopic(m_topicName);
+            m_publisher = m_session.createPublisher(topic);
+        }
+        else {
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("Could not obtain JMS connection '" + m_connectionName +
"'");
+            }
+        }
+
+    }
+
+    public void dispose() {
+        if (m_publisher != null) {
+            try {
+                m_publisher.close();
+            } catch (JMSException e) {
+                getLogger().error("Error closing publisher.", e);
+            }
+        }
+        if (m_session != null) {
+            try {
+                m_session.close();
+            }
+            catch (JMSException e) {
+                getLogger().warn("Error closing session.", e);
+            }
+        }
+        if (m_manager != null) {
+            if (m_connectionManager != null) {
+                m_manager.release(m_connectionManager);
+            }
+        }
+    }
+
+    // ---------------------------------------------------- Implementation
+
+    /**
+     * Concrete classes call this method to publish messages.
+     */
+    protected synchronized void publishMessage(Message message) throws JMSException {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Publishing message '" + message + "'");
+        }
+        m_publisher.publish(message, m_mode, m_priority, m_timeToLive);
+    }
+
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionManager.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionManager.java
Fri Aug 13 05:32:03 2004
@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.jms;
+
+import javax.jms.Connection;
+
+/**
+ * Manages a set of JMS Connections.
+ */
+public interface JMSConnectionManager {
+
+    public static final String ROLE = JMSConnectionManager.class.getName();
+
+    public Connection getConnection(String name);
+
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionManagerImpl.java
==============================================================================
--- (empty file)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/jms/java/org/apache/cocoon/components/jms/JMSConnectionManagerImpl.java
Fri Aug 13 05:32:03 2004
@@ -0,0 +1,312 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.jms;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.cocoon.components.jms.JMSConnectionManager;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.activity.Startable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+
+/**
+ * {@link org.apache.cocoon.components.jms.JMSConnectionManager} implementation.
+ */
+public class JMSConnectionManagerImpl extends AbstractLogEnabled 
+implements JMSConnectionManager, Configurable, Initializable, Startable, Disposable, ThreadSafe
{
+
+    // ---------------------------------------------------- Constants
+    
+    private static final int TOPIC_CONNECTION_TYPE = 1;
+    private static final int QUEUE_CONNECTION_TYPE = 2;
+    private static final int CONNECTION_TYPE = 3;
+
+    private static final String CONNECTION_CONFIG = "connection";
+    private static final String TOPIC_CONNECTION_CONFIG = "topic-connection";
+    private static final String QUEUE_CONNECTION_CONFIG = "queue-connection";
+    private static final String NAME_ATTR = "name";
+    
+    private static final String CONNECTION_FACTORY_PARAM = "connection-factory";
+    private static final String USERNAME_PARAM = "username";
+    private static final String PASSWORD_PARAM = "password";
+    
+    private static final String JNDI_PROPERTY_PREFIX = "java.naming.";
+
+    // ---------------------------------------------------- Instance variables
+
+    private Map m_configurations;
+    private Map m_connections;
+
+    // ---------------------------------------------------- Lifecycle
+
+    public JMSConnectionManagerImpl() {
+    }
+
+    public void configure(Configuration configuration) throws ConfigurationException {
+        m_configurations = new HashMap(configuration.getChildren().length);
+        // <connection>s
+        Configuration[] configurations = configuration.getChildren(CONNECTION_CONFIG);
+        configureConnections(configurations, CONNECTION_TYPE);
+        // <topic-connection>s
+        configurations = configuration.getChildren(TOPIC_CONNECTION_CONFIG);
+        configureConnections(configurations, TOPIC_CONNECTION_TYPE);
+        // <queue-connection>s
+        configurations = configuration.getChildren(QUEUE_CONNECTION_CONFIG);
+        configureConnections(configurations, QUEUE_CONNECTION_TYPE);
+    }
+    
+    private void configureConnections(Configuration[] connections, int type) throws ConfigurationException
{
+        for (int i = 0; i < connections.length; i++) {
+            final String name = connections[i].getAttribute(NAME_ATTR);
+            if (m_configurations.containsKey(name)) {
+                throw new ConfigurationException("Duplicate connection name '" + name + "'."
+
+                        " Connection names must be unique.");
+            }
+            final Parameters parameters = Parameters.fromConfiguration(connections[i]);
+            ConnectionConfiguration cc = new ConnectionConfiguration(name, parameters, type);
+            m_configurations.put(name, cc);
+        }
+    }
+
+    public void initialize() throws Exception {
+        m_connections = new HashMap(m_configurations.size());
+        final Iterator iter = m_configurations.values().iterator();
+        try {
+            while (iter.hasNext()) {
+                final ConnectionConfiguration cc = (ConnectionConfiguration) iter.next();
+                final InitialContext context = createInitialContext(cc.getJNDIProperties());
+                final ConnectionFactory factory = (ConnectionFactory) context.lookup(cc.getConnectionFactory());
+                final Connection connection = createConnection(factory, cc);
+                m_connections.put(cc.getName(), connection);
+            }
+        }
+        catch (NamingException e) {
+            if (getLogger().isWarnEnabled()) {
+                Throwable rootCause = e.getRootCause();
+                if (rootCause != null) {
+                    String message = e.getRootCause().getMessage();
+                    if (rootCause instanceof ClassNotFoundException) {
+                        String info = "WARN! *** JMS block is installed but jms client library
not found. ***\n" + 
+                            "- For the jms block to work you must install and start a JMS
server and " +
+                            "place the client jar in WEB-INF/lib.";
+                            if (message.indexOf("exolab") > 0 ) {
+                                info += "\n- The default server, OpenJMS is configured in
cocoon.xconf but is not bundled with Cocoon.";
+                            }
+                        System.err.println(info);
+                        getLogger().warn(info,e);
+                    } else {
+                        System.out.println(message);
+                        getLogger().warn("Cannot get Initial Context. Is the JNDI server
reachable?",e);
+                    }
+                }
+                else {
+                    getLogger().warn("Failed to initialize JMS.",e);
+                }
+            }
+        }
+        m_configurations = null;
+    }
+
+    public void start() throws Exception {
+        final Iterator iter = m_connections.entrySet().iterator();
+        while (iter.hasNext()) {
+            final Map.Entry entry = (Map.Entry) iter.next();
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Starting JMS connection " + entry.getKey());
+            }
+            final Connection connection = (Connection) entry.getValue();
+            connection.start();
+        }
+    }
+
+    public void stop() throws Exception {
+        final Iterator iter = m_connections.entrySet().iterator();
+        while (iter.hasNext()) {
+            final Map.Entry entry = (Map.Entry) iter.next();
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Stopping JMS connection " + entry.getKey());
+            }
+            try {
+                final Connection connection = (Connection) entry.getValue();
+                connection.stop();
+            }
+            catch (JMSException e) {
+                getLogger().error("Error stopping JMS connection " + entry.getKey(), e);
+            }
+        }
+    }
+
+    public void dispose() {
+        final Iterator iter = m_connections.entrySet().iterator();
+        while (iter.hasNext()) {
+            final Map.Entry entry = (Map.Entry) iter.next();
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Closing JMS connection " + entry.getKey());
+            }
+            try {
+                final Connection connection = (Connection) entry.getValue();
+                connection.close();
+            }
+            catch (JMSException e) {
+                getLogger().error("Error closing JMS connection " + entry.getKey(), e);
+            }
+        }
+    }
+
+    // ---------------------------------------------------- ConnectionManager
+
+    public Connection getConnection(String name) {
+        return (Connection) m_connections.get(name);
+    }
+
+    public TopicConnection getTopicConnection(String name) {
+        return (TopicConnection) m_connections.get(name);
+    }
+
+    public QueueConnection getQueueConnection(String name) {
+        return (QueueConnection) m_connections.get(name);
+    }
+
+    // ---------------------------------------------------- Implementation
+
+    private InitialContext createInitialContext(Properties properties) throws NamingException
{
+        if (properties != null) {
+            return new InitialContext(properties);
+        }
+        return new InitialContext();
+    }
+
+    private Connection createConnection(ConnectionFactory factory, ConnectionConfiguration
cc) throws JMSException {
+        if (cc.getUserName() != null) {
+            switch (cc.getType()) {
+                case CONNECTION_TYPE: {
+                    return factory.createConnection(cc.getUserName(), cc.getPassword());
+                }
+                case TOPIC_CONNECTION_TYPE: {
+                    TopicConnectionFactory topicFactory = (TopicConnectionFactory) factory;
+                    return topicFactory.createTopicConnection(cc.getUserName(), cc.getPassword());
+                }
+                case QUEUE_CONNECTION_TYPE: {
+                    QueueConnectionFactory queueFactory = (QueueConnectionFactory) factory;
+                    return queueFactory.createQueueConnection(cc.getUserName(), cc.getPassword());
+                }
+            }
+        }
+        switch (cc.getType()) {
+            case CONNECTION_TYPE: {
+                return factory.createConnection();
+            }
+            case TOPIC_CONNECTION_TYPE: {
+                TopicConnectionFactory topicFactory = (TopicConnectionFactory) factory;
+                return topicFactory.createTopicConnection();
+            }
+            case QUEUE_CONNECTION_TYPE: {
+                QueueConnectionFactory queueFactory = (QueueConnectionFactory) factory;
+                return queueFactory.createQueueConnection();
+            }
+        }
+        return null;
+    }
+
+    private static final class ConnectionConfiguration {
+        
+        // ------------------------------------------------ Instance variables
+
+        private final String m_name;
+        private final int m_type;
+        private final String m_connectionFactory;
+        private final String m_username;
+        private final String m_password;
+        private Properties m_jndiProperties;
+
+        private ConnectionConfiguration(String name, Parameters parameters, int type) 
+        throws ConfigurationException {
+            m_name = name;
+            try {
+                m_connectionFactory = parameters.getParameter(CONNECTION_FACTORY_PARAM);
+                m_username = parameters.getParameter(USERNAME_PARAM, null);
+                m_password = parameters.getParameter(PASSWORD_PARAM, null);
+                
+                // parse the jndi property parameters
+                String[] names = parameters.getNames();
+                for (int i = 0; i < names.length; i++) {
+                    if (names[i].startsWith(JNDI_PROPERTY_PREFIX)) {
+                        if (m_jndiProperties == null) {
+                            m_jndiProperties = new Properties();
+                        }
+                        m_jndiProperties.put(names[i], parameters.getParameter(names[i]));
+                    }
+                }
+                
+            }
+            catch (ParameterException e) {
+                throw new ConfigurationException(e.getLocalizedMessage());
+            }
+            m_type = type;
+        }
+
+        private String getName() {
+            return m_name;
+        }
+
+        private int getType() {
+            return m_type;
+        }
+
+        private Properties getJNDIProperties() {
+            return m_jndiProperties;
+        }
+
+        private String getConnectionFactory() {
+            return m_connectionFactory;
+        }
+
+        private String getUserName() {
+            return m_username;
+        }
+
+        private String getPassword() {
+            return m_password;
+        }
+
+        public int hashCode() {
+            return m_name.hashCode();
+        }
+
+    }
+
+}

Modified: cocoon/branches/BRANCH_2_1_X/status.xml
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/status.xml	(original)
+++ cocoon/branches/BRANCH_2_1_X/status.xml	Fri Aug 13 05:32:03 2004
@@ -203,6 +203,13 @@
 
   <changes>
  <release version="@version@" date="@date@">
+   <action dev="UH" type="add">
+     Enhanced JMS support by adding a JMSConnectionManager component to the JMS block.
+     This component replaces the JMSConnection component which only supported 
+     publish/subscribe messaging and which mixed some concerns. Two abstract classes: 
+     AbstractMessageListener and AbstractMessagePublisher should be used as basis for
+     custom publish/subscribe components.
+   </action>
    <action dev="CZ" type="fix" fixes-bug="27260">
      Make implementation of Cocoon protocol compliant with the Source interface.
    </action>

Mime
View raw message