001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.wsn.jms;
018
019 import java.io.StringReader;
020
021 import javax.jms.Connection;
022 import javax.jms.JMSException;
023 import javax.jms.Message;
024 import javax.jms.MessageConsumer;
025 import javax.jms.MessageListener;
026 import javax.jms.Session;
027 import javax.jms.TextMessage;
028 import javax.jms.Topic;
029 import javax.xml.datatype.XMLGregorianCalendar;
030 import javax.xml.parsers.DocumentBuilderFactory;
031 import javax.xml.xpath.XPath;
032 import javax.xml.xpath.XPathConstants;
033 import javax.xml.xpath.XPathExpression;
034 import javax.xml.xpath.XPathExpressionException;
035 import javax.xml.xpath.XPathFactory;
036
037 import org.w3c.dom.Document;
038 import org.w3c.dom.Element;
039 import org.xml.sax.InputSource;
040
041 import org.apache.commons.logging.Log;
042 import org.apache.commons.logging.LogFactory;
043 import org.apache.servicemix.wsn.AbstractSubscription;
044 import org.oasis_open.docs.wsn.b_2.InvalidTopicExpressionFaultType;
045 import org.oasis_open.docs.wsn.b_2.PauseFailedFaultType;
046 import org.oasis_open.docs.wsn.b_2.ResumeFailedFaultType;
047 import org.oasis_open.docs.wsn.b_2.Subscribe;
048 import org.oasis_open.docs.wsn.b_2.SubscribeCreationFailedFaultType;
049 import org.oasis_open.docs.wsn.b_2.UnableToDestroySubscriptionFaultType;
050 import org.oasis_open.docs.wsn.b_2.UnacceptableTerminationTimeFaultType;
051 import org.oasis_open.docs.wsn.bw_2.InvalidFilterFault;
052 import org.oasis_open.docs.wsn.bw_2.InvalidMessageContentExpressionFault;
053 import org.oasis_open.docs.wsn.bw_2.InvalidProducerPropertiesExpressionFault;
054 import org.oasis_open.docs.wsn.bw_2.InvalidTopicExpressionFault;
055 import org.oasis_open.docs.wsn.bw_2.PauseFailedFault;
056 import org.oasis_open.docs.wsn.bw_2.ResumeFailedFault;
057 import org.oasis_open.docs.wsn.bw_2.SubscribeCreationFailedFault;
058 import org.oasis_open.docs.wsn.bw_2.TopicExpressionDialectUnknownFault;
059 import org.oasis_open.docs.wsn.bw_2.TopicNotSupportedFault;
060 import org.oasis_open.docs.wsn.bw_2.UnableToDestroySubscriptionFault;
061 import org.oasis_open.docs.wsn.bw_2.UnacceptableInitialTerminationTimeFault;
062 import org.oasis_open.docs.wsn.bw_2.UnacceptableTerminationTimeFault;
063 import org.oasis_open.docs.wsn.bw_2.UnsupportedPolicyRequestFault;
064 import org.oasis_open.docs.wsn.bw_2.UnrecognizedPolicyRequestFault;
065
066 public abstract class JmsSubscription extends AbstractSubscription implements MessageListener {
067
068 private static Log log = LogFactory.getLog(JmsSubscription.class);
069
070 private Connection connection;
071
072 private Session session;
073
074 private JmsTopicExpressionConverter topicConverter;
075
076 private Topic jmsTopic;
077
078 public JmsSubscription(String name) {
079 super(name);
080 topicConverter = new JmsTopicExpressionConverter();
081 }
082
083 protected void start() throws SubscribeCreationFailedFault {
084 try {
085 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
086 MessageConsumer consumer = session.createConsumer(jmsTopic);
087 consumer.setMessageListener(this);
088 } catch (JMSException e) {
089 SubscribeCreationFailedFaultType fault = new SubscribeCreationFailedFaultType();
090 throw new SubscribeCreationFailedFault("Error starting subscription", fault, e);
091 }
092 }
093
094 @Override
095 protected void validateSubscription(Subscribe subscribeRequest) throws InvalidFilterFault,
096 InvalidMessageContentExpressionFault, InvalidProducerPropertiesExpressionFault,
097 InvalidTopicExpressionFault, SubscribeCreationFailedFault, TopicExpressionDialectUnknownFault,
098 TopicNotSupportedFault, UnacceptableInitialTerminationTimeFault,
099 UnsupportedPolicyRequestFault, UnrecognizedPolicyRequestFault {
100 super.validateSubscription(subscribeRequest);
101 try {
102 jmsTopic = topicConverter.toActiveMQTopic(topic);
103 } catch (InvalidTopicException e) {
104 InvalidTopicExpressionFaultType fault = new InvalidTopicExpressionFaultType();
105 throw new InvalidTopicExpressionFault(e.getMessage(), fault);
106 }
107 }
108
109 @Override
110 protected void pause() throws PauseFailedFault {
111 if (session == null) {
112 PauseFailedFaultType fault = new PauseFailedFaultType();
113 throw new PauseFailedFault("Subscription is already paused", fault);
114 } else {
115 try {
116 session.close();
117 } catch (JMSException e) {
118 PauseFailedFaultType fault = new PauseFailedFaultType();
119 throw new PauseFailedFault("Error pausing subscription", fault, e);
120 } finally {
121 session = null;
122 }
123 }
124 }
125
126 @Override
127 protected void resume() throws ResumeFailedFault {
128 if (session != null) {
129 ResumeFailedFaultType fault = new ResumeFailedFaultType();
130 throw new ResumeFailedFault("Subscription is already running", fault);
131 } else {
132 try {
133 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
134 MessageConsumer consumer = session.createConsumer(jmsTopic);
135 consumer.setMessageListener(this);
136 } catch (JMSException e) {
137 ResumeFailedFaultType fault = new ResumeFailedFaultType();
138 throw new ResumeFailedFault("Error resuming subscription", fault, e);
139 }
140 }
141 }
142
143 @Override
144 protected void renew(XMLGregorianCalendar terminationTime) throws UnacceptableTerminationTimeFault {
145 UnacceptableTerminationTimeFaultType fault = new UnacceptableTerminationTimeFaultType();
146 throw new UnacceptableTerminationTimeFault("TerminationTime is not supported", fault);
147 }
148
149 @Override
150 protected void unsubscribe() throws UnableToDestroySubscriptionFault {
151 super.unsubscribe();
152 if (session != null) {
153 try {
154 session.close();
155 } catch (JMSException e) {
156 UnableToDestroySubscriptionFaultType fault = new UnableToDestroySubscriptionFaultType();
157 throw new UnableToDestroySubscriptionFault("Unable to unsubscribe", fault, e);
158 } finally {
159 session = null;
160 }
161 }
162 }
163
164 public Connection getConnection() {
165 return connection;
166 }
167
168 public void setConnection(Connection connection) {
169 this.connection = connection;
170 }
171
172 public void onMessage(Message jmsMessage) {
173 try {
174 TextMessage text = (TextMessage) jmsMessage;
175 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
176 factory.setNamespaceAware(true);
177 Document doc = factory.newDocumentBuilder().parse(new InputSource(new StringReader(text.getText())));
178 Element root = doc.getDocumentElement();
179 Element holder = (Element) root.getElementsByTagNameNS(WSN_URI, "NotificationMessage").item(0);
180 Element message = (Element) holder.getElementsByTagNameNS(WSN_URI, "Message").item(0);
181 Element content = null;
182 for (int i = 0; i < message.getChildNodes().getLength(); i++) {
183 if (message.getChildNodes().item(i) instanceof Element) {
184 content = (Element) message.getChildNodes().item(i);
185 break;
186 }
187 }
188 boolean match = doFilter(content);
189 if (match) {
190 if (useRaw) {
191 doNotify(content);
192 } else {
193 doNotify(root);
194 }
195 }
196 } catch (Exception e) {
197 log.warn("Error notifying consumer", e);
198 }
199 }
200
201 protected boolean doFilter(Element content) {
202 if (contentFilter != null) {
203 if (!contentFilter.getDialect().equals(XPATH1_URI)) {
204 throw new IllegalStateException("Unsupported dialect: " + contentFilter.getDialect());
205 }
206 try {
207 XPathFactory xpfactory = XPathFactory.newInstance();
208 XPath xpath = xpfactory.newXPath();
209 XPathExpression exp = xpath.compile(contentFilter.getContent().get(0).toString());
210 Boolean ret = (Boolean) exp.evaluate(content, XPathConstants.BOOLEAN);
211 return ret.booleanValue();
212 } catch (XPathExpressionException e) {
213 log.warn("Could not filter notification", e);
214 }
215 return false;
216 }
217 return true;
218 }
219
220 protected abstract void doNotify(Element content);
221
222 }