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    
029    import org.apache.activemq.util.IdGenerator;
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    import org.apache.servicemix.wsn.client.AbstractWSAClient;
033    import org.oasis_open.docs.wsn.b_2.GetCurrentMessage;
034    import org.oasis_open.docs.wsn.b_2.GetCurrentMessageResponse;
035    import org.oasis_open.docs.wsn.b_2.NoCurrentMessageOnTopicFaultType;
036    import org.oasis_open.docs.wsn.b_2.NotificationMessageHolderType;
037    import org.oasis_open.docs.wsn.b_2.Notify;
038    import org.oasis_open.docs.wsn.b_2.Subscribe;
039    import org.oasis_open.docs.wsn.b_2.SubscribeCreationFailedFaultType;
040    import org.oasis_open.docs.wsn.b_2.SubscribeResponse;
041    import org.oasis_open.docs.wsn.br_2.PublisherRegistrationFailedFaultType;
042    import org.oasis_open.docs.wsn.br_2.RegisterPublisher;
043    import org.oasis_open.docs.wsn.br_2.RegisterPublisherResponse;
044    import org.oasis_open.docs.wsn.brw_2.NotificationBroker;
045    import org.oasis_open.docs.wsn.brw_2.PublisherRegistrationFailedFault;
046    import org.oasis_open.docs.wsn.brw_2.PublisherRegistrationRejectedFault;
047    import org.oasis_open.docs.wsn.brw_2.ResourceNotDestroyedFault;
048    import org.oasis_open.docs.wsn.bw_2.InvalidFilterFault;
049    import org.oasis_open.docs.wsn.bw_2.InvalidMessageContentExpressionFault;
050    import org.oasis_open.docs.wsn.bw_2.InvalidProducerPropertiesExpressionFault;
051    import org.oasis_open.docs.wsn.bw_2.InvalidTopicExpressionFault;
052    import org.oasis_open.docs.wsn.bw_2.MultipleTopicsSpecifiedFault;
053    import org.oasis_open.docs.wsn.bw_2.NoCurrentMessageOnTopicFault;
054    import org.oasis_open.docs.wsn.bw_2.SubscribeCreationFailedFault;
055    import org.oasis_open.docs.wsn.bw_2.TopicExpressionDialectUnknownFault;
056    import org.oasis_open.docs.wsn.bw_2.TopicNotSupportedFault;
057    import org.oasis_open.docs.wsn.bw_2.UnableToDestroySubscriptionFault;
058    import org.oasis_open.docs.wsn.bw_2.UnacceptableInitialTerminationTimeFault;
059    import org.oasis_open.docs.wsrf.rw_2.ResourceUnknownFault;
060    
061    @WebService(endpointInterface = "org.oasis_open.docs.wsn.brw_2.NotificationBroker")
062    public abstract class AbstractNotificationBroker extends AbstractEndpoint implements NotificationBroker {
063    
064        private static Log log = LogFactory.getLog(AbstractNotificationBroker.class);
065    
066        private IdGenerator idGenerator;
067    
068        private AbstractPublisher anonymousPublisher;
069    
070        private Map<String, AbstractPublisher> publishers;
071    
072        private Map<String, AbstractSubscription> subscriptions;
073    
074        public AbstractNotificationBroker(String name) {
075            super(name);
076            idGenerator = new IdGenerator();
077            subscriptions = new ConcurrentHashMap<String, AbstractSubscription>();
078            publishers = new ConcurrentHashMap<String, AbstractPublisher>();
079        }
080    
081        public void init() throws Exception {
082            register();
083            anonymousPublisher = createPublisher("Anonymous");
084            anonymousPublisher.register();
085        }
086    
087        public void destroy() throws Exception {
088            anonymousPublisher.destroy();
089            unregister();
090        }
091    
092        protected String createAddress() {
093            return "http://servicemix.org/wsnotification/NotificationBroker/" + getName();
094        }
095    
096        /**
097         * 
098         * @param notify
099         */
100        @WebMethod(operationName = "Notify")
101        @Oneway
102        public void notify(
103                @WebParam(name = "Notify", 
104                          targetNamespace = "http://docs.oasis-open.org/wsn/b-1", 
105                          partName = "Notify")
106                Notify notify) {
107    
108            log.debug("Notify");
109            handleNotify(notify);
110        }
111    
112        protected void handleNotify(Notify notify) {
113            for (NotificationMessageHolderType messageHolder : notify.getNotificationMessage()) {
114                W3CEndpointReference producerReference = messageHolder.getProducerReference();
115                AbstractPublisher publisher = getPublisher(producerReference);
116                if (publisher != null) {
117                    publisher.notify(messageHolder);
118                }
119            }
120        }
121    
122        protected AbstractPublisher getPublisher(W3CEndpointReference producerReference) {
123            AbstractPublisher publisher = null;
124            if (producerReference != null) {
125                String address = AbstractWSAClient.getWSAAddress(producerReference);
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(AbstractWSAClient.createWSA(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(AbstractWSAClient.createWSA(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    }