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                SubscribeCreationFailedFaultType fault = new SubscribeCreationFailedFaultType();
207                throw new SubscribeCreationFailedFault("Unable to register endpoint", fault, e);
208            } finally {
209                if (!success && subscription != null) {
210                    subscriptions.remove(subscription);
211                    try {
212                        subscription.unsubscribe();
213                    } catch (UnableToDestroySubscriptionFault e) {
214                        log.info("Error destroying subscription", e);
215                    }
216                }
217            }
218        }
219    
220        public void unsubscribe(String address) throws UnableToDestroySubscriptionFault {
221            AbstractSubscription subscription = (AbstractSubscription) subscriptions.remove(address);
222            if (subscription != null) {
223                subscription.unsubscribe();
224            }
225        }
226    
227        /**
228         * 
229         * @param getCurrentMessageRequest
230         * @return returns org.oasis_open.docs.wsn.b_1.GetCurrentMessageResponse
231         * @throws MultipleTopicsSpecifiedFault
232         * @throws TopicNotSupportedFault
233         * @throws InvalidTopicExpressionFault
234         * @throws ResourceUnknownFault
235         * @throws TopicExpressionDialectUnknownFault
236         * @throws NoCurrentMessageOnTopicFault
237         */
238        @WebMethod(operationName = "GetCurrentMessage")
239        @WebResult(name = "GetCurrentMessageResponse", 
240                   targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
241                   partName = "GetCurrentMessageResponse")
242        public GetCurrentMessageResponse getCurrentMessage(
243                @WebParam(name = "GetCurrentMessage", 
244                          targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
245                          partName = "GetCurrentMessageRequest")
246                GetCurrentMessage getCurrentMessageRequest) throws InvalidTopicExpressionFault,
247                MultipleTopicsSpecifiedFault, NoCurrentMessageOnTopicFault, ResourceUnknownFault,
248                TopicExpressionDialectUnknownFault, TopicNotSupportedFault {
249    
250            log.debug("GetCurrentMessage");
251            NoCurrentMessageOnTopicFaultType fault = new NoCurrentMessageOnTopicFaultType();
252            throw new NoCurrentMessageOnTopicFault("There is no current message on this topic.", fault);
253        }
254    
255        /**
256         * 
257         * @param registerPublisherRequest
258         * @return returns org.oasis_open.docs.wsn.br_1.RegisterPublisherResponse
259         * @throws PublisherRegistrationRejectedFault
260         * @throws InvalidTopicExpressionFault
261         * @throws TopicNotSupportedFault
262         * @throws ResourceUnknownFault
263         * @throws PublisherRegistrationFailedFault
264         */
265        @WebMethod(operationName = "RegisterPublisher")
266        @WebResult(name = "RegisterPublisherResponse", 
267                   targetNamespace = "http://docs.oasis-open.org/wsn/br-1", 
268                   partName = "RegisterPublisherResponse")
269        public RegisterPublisherResponse registerPublisher(
270                @WebParam(name = "RegisterPublisher", 
271                          targetNamespace = "http://docs.oasis-open.org/wsn/br-1", 
272                          partName = "RegisterPublisherRequest")
273                RegisterPublisher registerPublisherRequest) throws InvalidTopicExpressionFault,
274                PublisherRegistrationFailedFault, PublisherRegistrationRejectedFault, ResourceUnknownFault,
275                TopicNotSupportedFault {
276    
277            log.debug("RegisterPublisher");
278            return handleRegisterPublisher(registerPublisherRequest, null);
279        }
280    
281        public RegisterPublisherResponse handleRegisterPublisher(RegisterPublisher registerPublisherRequest,
282                EndpointManager manager) throws InvalidTopicExpressionFault, PublisherRegistrationFailedFault,
283                PublisherRegistrationRejectedFault, ResourceUnknownFault, TopicNotSupportedFault {
284            AbstractPublisher publisher = null;
285            boolean success = false;
286            try {
287                publisher = createPublisher(idGenerator.generateSanitizedId());
288                publishers.put(publisher.getAddress(), publisher);
289                if (manager != null) {
290                    publisher.setManager(manager);
291                }
292                publisher.register();
293                publisher.create(registerPublisherRequest);
294                RegisterPublisherResponse response = new RegisterPublisherResponse();
295                response.setPublisherRegistrationReference(AbstractWSAClient.createWSA(publisher.getAddress()));
296                success = true;
297                return response;
298            } catch (EndpointRegistrationException e) {
299                PublisherRegistrationFailedFaultType fault = new PublisherRegistrationFailedFaultType();
300                throw new PublisherRegistrationFailedFault("Unable to register new endpoint", fault, e);
301            } finally {
302                if (!success && publisher != null) {
303                    publishers.remove(publisher.getAddress());
304                    try {
305                        publisher.destroy();
306                    } catch (ResourceNotDestroyedFault e) {
307                        log.info("Error destroying publisher", e);
308                    }
309                }
310            }
311        }
312    
313        protected abstract AbstractPublisher createPublisher(String name);
314    
315        protected abstract AbstractSubscription createSubcription(String name);
316    
317        @WebResult(name = "GetResourcePropertyResponse", targetNamespace = "http://docs.oasis-open.org/wsrf/rp-2", partName = "GetResourcePropertyResponse")
318        @WebMethod(operationName = "GetResourceProperty")
319        public GetResourcePropertyResponse getResourceProperty(
320            @WebParam(partName = "GetResourcePropertyRequest", name = "GetResourceProperty", targetNamespace = "http://docs.oasis-open.org/wsrf/rp-2")
321            javax.xml.namespace.QName getResourcePropertyRequest
322        ) throws ResourceUnavailableFault, ResourceUnknownFault, InvalidResourcePropertyQNameFault {
323    
324            log.debug("GetResourceProperty");
325            return handleGetResourceProperty(getResourcePropertyRequest);
326        }
327    
328        protected GetResourcePropertyResponse handleGetResourceProperty(QName property)
329                throws ResourceUnavailableFault, ResourceUnknownFault, InvalidResourcePropertyQNameFault {
330            InvalidResourcePropertyQNameFaultType fault = new InvalidResourcePropertyQNameFaultType();
331            throw new InvalidResourcePropertyQNameFault("Invalid resource property QName: " + property, fault);
332        }
333    
334    }