KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > event > JMSBridge


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.event;
21
22 import java.io.Serializable JavaDoc;
23 import java.util.Collection JavaDoc;
24
25 import javax.jms.Message JavaDoc;
26 import javax.jms.MessageFormatException JavaDoc;
27 import javax.jms.MessageListener JavaDoc;
28 import javax.jms.ObjectMessage JavaDoc;
29 import javax.jms.Session JavaDoc;
30 import javax.jms.Topic JavaDoc;
31 import javax.jms.TopicConnection JavaDoc;
32 import javax.jms.TopicConnectionFactory JavaDoc;
33 import javax.jms.TopicPublisher JavaDoc;
34 import javax.jms.TopicSession JavaDoc;
35 import javax.jms.TopicSubscriber JavaDoc;
36 import javax.naming.Context JavaDoc;
37 import javax.naming.InitialContext JavaDoc;
38 import javax.naming.NameNotFoundException JavaDoc;
39 import javax.naming.NamingException JavaDoc;
40
41 import org.apache.cayenne.util.IDUtil;
42
43 /**
44  * Implementation of EventBridge that passes and receives events via JMS (Java Messaging
45  * Service). JMSBridge uses "publish/subscribe" model for communication with external
46  * agents.
47  *
48  * @author Andrus Adamchik
49  * @since 1.1
50  */

51 public class JMSBridge extends EventBridge implements MessageListener JavaDoc {
52
53     static final String JavaDoc VM_ID = new String JavaDoc(IDUtil.pseudoUniqueByteSequence16());
54     static final String JavaDoc VM_ID_PROPERRTY = "VM_ID";
55
56     protected String JavaDoc topicConnectionFactoryName;
57
58     protected TopicConnection JavaDoc sendConnection;
59     protected TopicSession JavaDoc sendSession;
60     protected TopicConnection JavaDoc receivedConnection;
61     protected TopicPublisher JavaDoc publisher;
62     protected TopicSubscriber JavaDoc subscriber;
63
64     public JMSBridge(EventSubject localSubject, String JavaDoc externalSubject) {
65         super(localSubject, externalSubject);
66     }
67
68     /**
69      * @since 1.2
70      */

71     public JMSBridge(Collection JavaDoc localSubjects, String JavaDoc externalSubject) {
72         super(localSubjects, externalSubject);
73     }
74
75     /**
76      * JMS MessageListener implementation. Injects received events to the EventManager
77      * local event queue.
78      */

79     public void onMessage(Message JavaDoc message) {
80
81         try {
82             Object JavaDoc vmID = message.getObjectProperty(JMSBridge.VM_ID_PROPERRTY);
83             if (JMSBridge.VM_ID.equals(vmID)) {
84                 return;
85             }
86
87             if (!(message instanceof ObjectMessage JavaDoc)) {
88                 return;
89             }
90
91             ObjectMessage JavaDoc objectMessage = (ObjectMessage JavaDoc) message;
92             CayenneEvent event = messageObjectToEvent(objectMessage.getObject());
93             if (event != null) {
94                 onExternalEvent(event);
95             }
96
97         }
98         catch (MessageFormatException JavaDoc mfex) {
99             // TODO: Andrus, 2/8/2006 logging... Log4J was removed to make this usable on
100
// the client
101
}
102         catch (Exception JavaDoc ex) {
103             // TODO: Andrus, 2/8/2006 logging... Log4J was removed to make this usable on
104
// the client
105
}
106     }
107
108     /**
109      * @return Name of javax.jms.TopicConnectionFactory accessible via JNDI.
110      */

111     public String JavaDoc getTopicConnectionFactoryName() {
112         return topicConnectionFactoryName;
113     }
114
115     public void setTopicConnectionFactoryName(String JavaDoc name) {
116         this.topicConnectionFactoryName = name;
117     }
118
119     /**
120      * Starts up JMS machinery for "publish/subscribe" model.
121      */

122     protected void startupExternal() throws Exception JavaDoc {
123         Context JavaDoc jndiContext = new InitialContext JavaDoc();
124         TopicConnectionFactory JavaDoc connectionFactory = (TopicConnectionFactory JavaDoc) jndiContext
125                 .lookup(topicConnectionFactoryName);
126
127         Topic JavaDoc topic = null;
128
129         try {
130             topic = (Topic JavaDoc) jndiContext.lookup(externalSubject);
131         }
132         catch (NameNotFoundException JavaDoc ex) {
133             // can't find topic, try to create it
134
topic = topicNotFound(jndiContext, ex);
135
136             if (topic == null) {
137                 throw ex;
138             }
139         }
140
141         // config publisher
142
if (receivesLocalEvents()) {
143             this.sendConnection = connectionFactory.createTopicConnection();
144             this.sendSession = sendConnection.createTopicSession(
145                     false,
146                     Session.AUTO_ACKNOWLEDGE);
147             this.publisher = sendSession.createPublisher(topic);
148         }
149
150         // config subscriber
151
if (receivesExternalEvents()) {
152             this.receivedConnection = connectionFactory.createTopicConnection();
153             this.subscriber = receivedConnection.createTopicSession(
154                     false,
155                     Session.AUTO_ACKNOWLEDGE).createSubscriber(topic);
156             this.subscriber.setMessageListener(this);
157             this.receivedConnection.start();
158         }
159     }
160
161     /**
162      * Attempts to create missing Topic. Since Topic creation is JMS-implementation
163      * specific, this task is left to subclasses. Current implementation simply rethrows
164      * the exception.
165      */

166     protected Topic JavaDoc topicNotFound(Context JavaDoc jndiContext, NamingException JavaDoc ex)
167             throws Exception JavaDoc {
168         throw ex;
169     }
170
171     /**
172      * Closes all resources used to communicate via JMS.
173      */

174     protected void shutdownExternal() throws Exception JavaDoc {
175         Exception JavaDoc lastException = null;
176
177         if (publisher != null) {
178             try {
179                 publisher.close();
180             }
181             catch (Exception JavaDoc ex) {
182                 lastException = ex;
183             }
184         }
185
186         if (subscriber != null) {
187             try {
188                 subscriber.close();
189             }
190             catch (Exception JavaDoc ex) {
191                 lastException = ex;
192             }
193         }
194
195         if (receivedConnection != null) {
196             try {
197                 receivedConnection.close();
198             }
199             catch (Exception JavaDoc ex) {
200                 lastException = ex;
201             }
202         }
203
204         if (sendSession != null) {
205             try {
206                 sendSession.close();
207             }
208             catch (Exception JavaDoc ex) {
209                 lastException = ex;
210             }
211         }
212
213         if (sendConnection != null) {
214             try {
215                 sendConnection.close();
216             }
217             catch (Exception JavaDoc ex) {
218                 lastException = ex;
219             }
220         }
221
222         publisher = null;
223         subscriber = null;
224         receivedConnection = null;
225         sendConnection = null;
226         sendSession = null;
227
228         if (lastException != null) {
229             throw lastException;
230         }
231     }
232
233     protected void sendExternalEvent(CayenneEvent localEvent) throws Exception JavaDoc {
234         ObjectMessage JavaDoc message = sendSession
235                 .createObjectMessage(eventToMessageObject(localEvent));
236         message.setObjectProperty(JMSBridge.VM_ID_PROPERRTY, JMSBridge.VM_ID);
237         publisher.publish(message);
238     }
239
240     /**
241      * Converts CayenneEvent to a serializable object that will be sent via JMS. Default
242      * implementation simply returns the event, but subclasses can customize this
243      * behavior.
244      */

245     protected Serializable JavaDoc eventToMessageObject(CayenneEvent event) throws Exception JavaDoc {
246         return event;
247     }
248
249     /**
250      * Converts a Serializable instance to CayenneEvent. Returns null if the object is not
251      * supported. Default implementation simply tries to cast the object to CayenneEvent,
252      * but subclasses can customize this behavior.
253      */

254     protected CayenneEvent messageObjectToEvent(Serializable JavaDoc object) throws Exception JavaDoc {
255         return (object instanceof CayenneEvent) ? (CayenneEvent) object : null;
256     }
257 }
258
Popular Tags