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;
018    
019    import java.util.Map;
020    import java.util.concurrent.ConcurrentHashMap;
021    
022    import javax.jws.Oneway;
023    import javax.jws.WebMethod;
024    import javax.jws.WebParam;
025    import javax.jws.WebResult;
026    import javax.jws.WebService;
027    import javax.xml.ws.wsaddressing.W3CEndpointReference;
028    import javax.xml.namespace.QName;
029    
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    import org.apache.servicemix.id.IdGenerator;
033    import org.apache.servicemix.wsn.client.AbstractWSAClient;
034    import org.oasis_open.docs.wsn.b_2.GetCurrentMessage;
035    import org.oasis_open.docs.wsn.b_2.GetCurrentMessageResponse;
036    import org.oasis_open.docs.wsn.b_2.NoCurrentMessageOnTopicFaultType;
037    import org.oasis_open.docs.wsn.b_2.NotificationMessageHolderType;
038    import org.oasis_open.docs.wsn.b_2.Notify;
039    import org.oasis_open.docs.wsn.b_2.Subscribe;
040    import org.oasis_open.docs.wsn.b_2.SubscribeCreationFailedFaultType;
041    import org.oasis_open.docs.wsn.b_2.SubscribeResponse;
042    import org.oasis_open.docs.wsn.b_2.InvalidTopicExpressionFaultType;
043    import org.oasis_open.docs.wsn.br_2.PublisherRegistrationFailedFaultType;
044    import org.oasis_open.docs.wsn.br_2.RegisterPublisher;
045    import org.oasis_open.docs.wsn.br_2.RegisterPublisherResponse;
046    import org.oasis_open.docs.wsn.brw_2.NotificationBroker;
047    import org.oasis_open.docs.wsn.brw_2.PublisherRegistrationFailedFault;
048    import org.oasis_open.docs.wsn.brw_2.PublisherRegistrationRejectedFault;
049    import org.oasis_open.docs.wsn.brw_2.ResourceNotDestroyedFault;
050    import org.oasis_open.docs.wsn.bw_2.InvalidFilterFault;
051    import org.oasis_open.docs.wsn.bw_2.InvalidMessageContentExpressionFault;
052    import org.oasis_open.docs.wsn.bw_2.InvalidProducerPropertiesExpressionFault;
053    import org.oasis_open.docs.wsn.bw_2.InvalidTopicExpressionFault;
054    import org.oasis_open.docs.wsn.bw_2.MultipleTopicsSpecifiedFault;
055    import org.oasis_open.docs.wsn.bw_2.NoCurrentMessageOnTopicFault;
056    import org.oasis_open.docs.wsn.bw_2.SubscribeCreationFailedFault;
057    import org.oasis_open.docs.wsn.bw_2.TopicExpressionDialectUnknownFault;
058    import org.oasis_open.docs.wsn.bw_2.TopicNotSupportedFault;
059    import org.oasis_open.docs.wsn.bw_2.UnableToDestroySubscriptionFault;
060    import org.oasis_open.docs.wsn.bw_2.UnacceptableInitialTerminationTimeFault;
061    import org.oasis_open.docs.wsn.bw_2.UnsupportedPolicyRequestFault;
062    import org.oasis_open.docs.wsn.bw_2.UnrecognizedPolicyRequestFault;
063    import org.oasis_open.docs.wsrf.rw_2.ResourceUnknownFault;
064    import org.oasis_open.docs.wsrf.rw_2.ResourceUnavailableFault;
065    import org.oasis_open.docs.wsrf.rpw_2.GetResourceProperty;
066    import org.oasis_open.docs.wsrf.rpw_2.InvalidResourcePropertyQNameFault;
067    import org.oasis_open.docs.wsrf.rp_2.GetResourcePropertyResponse;
068    import org.oasis_open.docs.wsrf.rp_2.InvalidResourcePropertyQNameFaultType;
069    
070    @WebService(endpointInterface = "org.oasis_open.docs.wsn.brw_2.NotificationBroker")
071    public abstract class AbstractNotificationBroker extends AbstractEndpoint implements NotificationBroker, GetResourceProperty {
072    
073        public static final String NAMESPACE_URI = "http://docs.oasis-open.org/wsn/b-2";
074        public static final String PREFIX = "wsnt";
075        public static final QName TOPIC_EXPRESSION_QNAME = new QName(NAMESPACE_URI, "TopicExpression", PREFIX);
076        public static final QName FIXED_TOPIC_SET_QNAME = new QName(NAMESPACE_URI, "FixedTopicSet", PREFIX);
077        public static final QName TOPIC_EXPRESSION_DIALECT_QNAME = new QName(NAMESPACE_URI, "TopicExpressionDialect", PREFIX);
078        public static final QName TOPIC_SET_QNAME = new QName(NAMESPACE_URI, "TopicSet", PREFIX);
079    
080    
081        private static Log log = LogFactory.getLog(AbstractNotificationBroker.class);
082    
083        private IdGenerator idGenerator;
084    
085        private AbstractPublisher anonymousPublisher;
086    
087        private Map<String, AbstractPublisher> publishers;
088    
089        private Map<String, AbstractSubscription> subscriptions;
090    
091        public AbstractNotificationBroker(String name) {
092            super(name);
093            idGenerator = new IdGenerator();
094            subscriptions = new ConcurrentHashMap<String, AbstractSubscription>();
095            publishers = new ConcurrentHashMap<String, AbstractPublisher>();
096        }
097    
098        public void init() throws Exception {
099            register();
100            anonymousPublisher = createPublisher("Anonymous");
101            anonymousPublisher.register();
102        }
103    
104        public void destroy() throws Exception {
105            anonymousPublisher.destroy();
106            unregister();
107        }
108    
109        protected String createAddress() {
110            return "http://servicemix.org/wsnotification/NotificationBroker/" + getName();
111        }
112    
113        /**
114         * 
115         * @param notify
116         */
117        @WebMethod(operationName = "Notify")
118        @Oneway
119        public void notify(
120                @WebParam(name = "Notify", 
121                          targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
122                          partName = "Notify")
123                Notify notify) {
124    
125            log.debug("Notify");
126            handleNotify(notify);
127        }
128    
129        protected void handleNotify(Notify notify) {
130            for (NotificationMessageHolderType messageHolder : notify.getNotificationMessage()) {
131                W3CEndpointReference producerReference = messageHolder.getProducerReference();
132                AbstractPublisher publisher = getPublisher(producerReference);
133                if (publisher != null) {
134                    publisher.notify(messageHolder);
135                }
136            }
137        }
138    
139        protected AbstractPublisher getPublisher(W3CEndpointReference producerReference) {
140            AbstractPublisher publisher = null;
141            if (producerReference != null) {
142                String address = AbstractWSAClient.getWSAAddress(producerReference);
143                publisher = publishers.get(address);
144            }
145            if (publisher == null) {
146                publisher = anonymousPublisher;
147            }
148            return publisher;
149        }
150    
151        /**
152         * 
153         * @param subscribeRequest
154         * @return returns org.oasis_open.docs.wsn.b_1.SubscribeResponse
155         * @throws SubscribeCreationFailedFault
156         * @throws InvalidTopicExpressionFault
157         * @throws TopicNotSupportedFault
158         * @throws InvalidFilterFault
159         * @throws InvalidProducerPropertiesExpressionFault
160         * @throws ResourceUnknownFault
161         * @throws InvalidUseRawValueFault
162         * @throws InvalidMessageContentExpressionFault
163         * @throws TopicExpressionDialectUnknownFault
164         * @throws UnacceptableInitialTerminationTimeFault
165         */
166        @WebMethod(operationName = "Subscribe")
167        @WebResult(name = "SubscribeResponse", 
168                   targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
169                   partName = "SubscribeResponse")
170        public SubscribeResponse subscribe(
171                @WebParam(name = "Subscribe", 
172                          targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
173                          partName = "SubscribeRequest")
174                Subscribe subscribeRequest) throws InvalidFilterFault, InvalidMessageContentExpressionFault,
175                InvalidProducerPropertiesExpressionFault, InvalidTopicExpressionFault, ResourceUnknownFault,
176                SubscribeCreationFailedFault, TopicExpressionDialectUnknownFault, TopicNotSupportedFault,
177                UnacceptableInitialTerminationTimeFault, UnsupportedPolicyRequestFault, UnrecognizedPolicyRequestFault {
178    
179            log.debug("Subscribe");
180            return handleSubscribe(subscribeRequest, null);
181        }
182    
183        public SubscribeResponse handleSubscribe(
184                    Subscribe subscribeRequest, 
185                    EndpointManager manager) throws InvalidFilterFault, InvalidMessageContentExpressionFault,
186                InvalidProducerPropertiesExpressionFault, InvalidTopicExpressionFault,
187                SubscribeCreationFailedFault, TopicExpressionDialectUnknownFault,
188                TopicNotSupportedFault, UnacceptableInitialTerminationTimeFault,
189                UnsupportedPolicyRequestFault, UnrecognizedPolicyRequestFault {
190            AbstractSubscription subscription = null;
191            boolean success = false;
192            try {
193                subscription = createSubcription(idGenerator.generateSanitizedId());
194                subscription.setBroker(this);
195                subscriptions.put(subscription.getAddress(), subscription);
196                subscription.create(subscribeRequest);
197                if (manager != null) {
198                    subscription.setManager(manager);
199                }
200                subscription.register();
201                SubscribeResponse response = new SubscribeResponse();
202                response.setSubscriptionReference(AbstractWSAClient.createWSA(subscription.getAddress()));
203                success = true;
204                return response;
205            } catch (EndpointRegistrationException e) {
206                log.warn("Unable to register new endpoint", e);
207                SubscribeCreationFailedFaultType fault = new SubscribeCreationFailedFaultType();
208                throw new SubscribeCreationFailedFault("Unable to register new endpoint", fault, e);
209            } finally {
210                if (!success && subscription != null) {
211                    subscriptions.remove(subscription);
212                    try {
213                        subscription.unsubscribe();
214                    } catch (UnableToDestroySubscriptionFault e) {
215                        log.info("Error destroying subscription", e);
216                    }
217                }
218            }
219        }
220    
221        public void unsubscribe(String address) throws UnableToDestroySubscriptionFault {
222            AbstractSubscription subscription = (AbstractSubscription) subscriptions.remove(address);
223            if (subscription != null) {
224                subscription.unsubscribe();
225            }
226        }
227    
228        /**
229         * 
230         * @param getCurrentMessageRequest
231         * @return returns org.oasis_open.docs.wsn.b_1.GetCurrentMessageResponse
232         * @throws MultipleTopicsSpecifiedFault
233         * @throws TopicNotSupportedFault
234         * @throws InvalidTopicExpressionFault
235         * @throws ResourceUnknownFault
236         * @throws TopicExpressionDialectUnknownFault
237         * @throws NoCurrentMessageOnTopicFault
238         */
239        @WebMethod(operationName = "GetCurrentMessage")
240        @WebResult(name = "GetCurrentMessageResponse", 
241                   targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
242                   partName = "GetCurrentMessageResponse")
243        public GetCurrentMessageResponse getCurrentMessage(
244                @WebParam(name = "GetCurrentMessage", 
245                          targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
246                          partName = "GetCurrentMessageRequest")
247                GetCurrentMessage getCurrentMessageRequest) throws InvalidTopicExpressionFault,
248                MultipleTopicsSpecifiedFault, NoCurrentMessageOnTopicFault, ResourceUnknownFault,
249                TopicExpressionDialectUnknownFault, TopicNotSupportedFault {
250    
251            log.debug("GetCurrentMessage");
252            NoCurrentMessageOnTopicFaultType fault = new NoCurrentMessageOnTopicFaultType();
253            throw new NoCurrentMessageOnTopicFault("There is no current message on this topic.", fault);
254        }
255    
256        /**
257         * 
258         * @param registerPublisherRequest
259         * @return returns org.oasis_open.docs.wsn.br_1.RegisterPublisherResponse
260         * @throws PublisherRegistrationRejectedFault
261         * @throws InvalidTopicExpressionFault
262         * @throws TopicNotSupportedFault
263         * @throws ResourceUnknownFault
264         * @throws PublisherRegistrationFailedFault
265         */
266        @WebMethod(operationName = "RegisterPublisher")
267        @WebResult(name = "RegisterPublisherResponse", 
268                   targetNamespace = "http://docs.oasis-open.org/wsn/br-1", 
269                   partName = "RegisterPublisherResponse")
270        public RegisterPublisherResponse registerPublisher(
271                @WebParam(name = "RegisterPublisher", 
272                          targetNamespace = "http://docs.oasis-open.org/wsn/br-1", 
273                          partName = "RegisterPublisherRequest")
274                RegisterPublisher registerPublisherRequest) throws InvalidTopicExpressionFault,
275                PublisherRegistrationFailedFault, PublisherRegistrationRejectedFault, ResourceUnknownFault,
276                TopicNotSupportedFault {
277    
278            log.debug("RegisterPublisher");
279            return handleRegisterPublisher(registerPublisherRequest, null);
280        }
281    
282        public RegisterPublisherResponse handleRegisterPublisher(RegisterPublisher registerPublisherRequest,
283                EndpointManager manager) throws InvalidTopicExpressionFault, PublisherRegistrationFailedFault,
284                PublisherRegistrationRejectedFault, ResourceUnknownFault, TopicNotSupportedFault {
285            AbstractPublisher publisher = null;
286            boolean success = false;
287            try {
288                publisher = createPublisher(idGenerator.generateSanitizedId());
289                publishers.put(publisher.getAddress(), publisher);
290                if (manager != null) {
291                    publisher.setManager(manager);
292                }
293                publisher.register();
294                publisher.create(registerPublisherRequest);
295                RegisterPublisherResponse response = new RegisterPublisherResponse();
296                response.setPublisherRegistrationReference(AbstractWSAClient.createWSA(publisher.getAddress()));
297                success = true;
298                return response;
299            } catch (EndpointRegistrationException e) {
300                log.warn("Unable to register new endpoint", e);
301                PublisherRegistrationFailedFaultType fault = new PublisherRegistrationFailedFaultType();
302                throw new PublisherRegistrationFailedFault("Unable to register new endpoint", fault, e);
303            } finally {
304                if (!success && publisher != null) {
305                    publishers.remove(publisher.getAddress());
306                    try {
307                        publisher.destroy();
308                    } catch (ResourceNotDestroyedFault e) {
309                        log.info("Error destroying publisher", e);
310                    }
311                }
312            }
313        }
314    
315        protected abstract AbstractPublisher createPublisher(String name);
316    
317        protected abstract AbstractSubscription createSubcription(String name);
318    
319        @WebResult(name = "GetResourcePropertyResponse", targetNamespace = "http://docs.oasis-open.org/wsrf/rp-2", partName = "GetResourcePropertyResponse")
320        @WebMethod(operationName = "GetResourceProperty")
321        public GetResourcePropertyResponse getResourceProperty(
322            @WebParam(partName = "GetResourcePropertyRequest", name = "GetResourceProperty", targetNamespace = "http://docs.oasis-open.org/wsrf/rp-2")
323            javax.xml.namespace.QName getResourcePropertyRequest
324        ) throws ResourceUnavailableFault, ResourceUnknownFault, InvalidResourcePropertyQNameFault {
325    
326            log.debug("GetResourceProperty");
327            return handleGetResourceProperty(getResourcePropertyRequest);
328        }
329    
330        protected GetResourcePropertyResponse handleGetResourceProperty(QName property)
331                throws ResourceUnavailableFault, ResourceUnknownFault, InvalidResourcePropertyQNameFault {
332            InvalidResourcePropertyQNameFaultType fault = new InvalidResourcePropertyQNameFaultType();
333            throw new InvalidResourcePropertyQNameFault("Invalid resource property QName: " + property, fault);
334        }
335    
336    }