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