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.jbi;
018    
019    import javax.jbi.JBIException;
020    import javax.jbi.component.ComponentContext;
021    import javax.jbi.messaging.DeliveryChannel;
022    import javax.jbi.messaging.InOnly;
023    import javax.jbi.messaging.MessageExchange;
024    import javax.jbi.messaging.MessageExchangeFactory;
025    import javax.jbi.messaging.NormalizedMessage;
026    import javax.jbi.servicedesc.ServiceEndpoint;
027    import javax.xml.bind.JAXBContext;
028    import javax.xml.namespace.QName;
029    import javax.xml.parsers.DocumentBuilder;
030    import javax.xml.parsers.DocumentBuilderFactory;
031    import javax.xml.transform.dom.DOMSource;
032    
033    import org.w3c.dom.Document;
034    import org.w3c.dom.DocumentFragment;
035    import org.w3c.dom.Element;
036    import org.w3c.dom.NodeList;
037    
038    import org.apache.commons.logging.Log;
039    import org.apache.commons.logging.LogFactory;
040    import org.apache.servicemix.common.ExchangeProcessor;
041    import org.apache.servicemix.wsn.component.WSNLifeCycle;
042    import org.apache.servicemix.wsn.jaxws.InvalidFilterFault;
043    import org.apache.servicemix.wsn.jaxws.InvalidMessageContentExpressionFault;
044    import org.apache.servicemix.wsn.jaxws.InvalidProducerPropertiesExpressionFault;
045    import org.apache.servicemix.wsn.jaxws.InvalidTopicExpressionFault;
046    import org.apache.servicemix.wsn.jaxws.SubscribeCreationFailedFault;
047    import org.apache.servicemix.wsn.jaxws.TopicExpressionDialectUnknownFault;
048    import org.apache.servicemix.wsn.jaxws.TopicNotSupportedFault;
049    import org.apache.servicemix.wsn.jaxws.UnacceptableInitialTerminationTimeFault;
050    import org.apache.servicemix.wsn.jms.JmsSubscription;
051    import org.oasis_open.docs.wsn.b_2.Subscribe;
052    import org.oasis_open.docs.wsn.b_2.SubscribeCreationFailedFaultType;
053    
054    public class JbiSubscription extends JmsSubscription {
055    
056        private static Log log = LogFactory.getLog(JbiSubscription.class);
057    
058        private WSNLifeCycle lifeCycle;
059    
060        private ServiceEndpoint endpoint;
061    
062        private ExchangeProcessor processor;
063    
064        public JbiSubscription(String name) {
065            super(name);
066            processor = new NoOpProcessor();
067        }
068    
069        @Override
070        protected void start() throws SubscribeCreationFailedFault {
071            super.start();
072        }
073    
074        @Override
075        protected void validateSubscription(Subscribe subscribeRequest) throws InvalidFilterFault,
076                InvalidMessageContentExpressionFault, InvalidProducerPropertiesExpressionFault,
077                InvalidTopicExpressionFault, SubscribeCreationFailedFault, TopicExpressionDialectUnknownFault,
078                TopicNotSupportedFault, UnacceptableInitialTerminationTimeFault {
079            super.validateSubscription(subscribeRequest);
080            try {
081                endpoint = resolveConsumer(subscribeRequest);
082            } catch (Exception e) {
083                SubscribeCreationFailedFaultType fault = new SubscribeCreationFailedFaultType();
084                throw new SubscribeCreationFailedFault("Unable to resolve consumer reference endpoint", fault, e);
085            }
086            if (endpoint == null) {
087                SubscribeCreationFailedFaultType fault = new SubscribeCreationFailedFaultType();
088                throw new SubscribeCreationFailedFault("Unable to resolve consumer reference endpoint", fault);
089            }
090        }
091    
092        protected ServiceEndpoint resolveConsumer(Subscribe subscribeRequest) throws Exception {
093            // Try to resolve the WSA endpoint
094            JAXBContext ctx = JAXBContext.newInstance(Subscribe.class);
095            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
096            dbf.setNamespaceAware(true);
097            DocumentBuilder db = dbf.newDocumentBuilder();
098            Document doc = db.newDocument();
099            ctx.createMarshaller().marshal(subscribeRequest, doc);
100            NodeList nl = doc.getDocumentElement().getElementsByTagNameNS("http://docs.oasis-open.org/wsn/b-2",
101                    "ConsumerReference");
102            if (nl.getLength() != 1) {
103                throw new Exception("Subscribe request must have exactly one ConsumerReference node");
104            }
105            Element el = (Element) nl.item(0);
106            DocumentFragment epr = doc.createDocumentFragment();
107            epr.appendChild(el);
108            ServiceEndpoint ep = getContext().resolveEndpointReference(epr);
109            if (ep == null) {
110                String[] parts = split(subscribeRequest.getConsumerReference().getAddress().getValue().trim());
111                ep = getContext().getEndpoint(new QName(parts[0], parts[1]), parts[2]);
112            }
113            return ep;
114        }
115    
116        protected String[] split(String uri) {
117            char sep;
118            if (uri.indexOf('/') > 0) {
119                sep = '/';
120            } else {
121                sep = ':';
122            }
123            int idx1 = uri.lastIndexOf(sep);
124            int idx2 = uri.lastIndexOf(sep, idx1 - 1);
125            String epName = uri.substring(idx1 + 1);
126            String svcName = uri.substring(idx2 + 1, idx1);
127            String nsUri = uri.substring(0, idx2);
128            return new String[] {nsUri, svcName, epName };
129        }
130    
131        @Override
132        protected void doNotify(final Element content) {
133            try {
134                DeliveryChannel channel = getContext().getDeliveryChannel();
135                MessageExchangeFactory factory = channel.createExchangeFactory(endpoint);
136                InOnly inonly = factory.createInOnlyExchange();
137                NormalizedMessage msg = inonly.createMessage();
138                inonly.setInMessage(msg);
139                msg.setContent(new DOMSource(content));
140                getLifeCycle().sendConsumerExchange(inonly, processor);
141            } catch (JBIException e) {
142                log.warn("Could not deliver notification", e);
143            }
144        }
145    
146        public ComponentContext getContext() {
147            return lifeCycle.getContext();
148        }
149    
150        public WSNLifeCycle getLifeCycle() {
151            return lifeCycle;
152        }
153    
154        public void setLifeCycle(WSNLifeCycle lifeCycle) {
155            this.lifeCycle = lifeCycle;
156        }
157    
158        protected class NoOpProcessor implements ExchangeProcessor {
159    
160            public void process(MessageExchange exchange) throws Exception {
161            }
162    
163            public void start() throws Exception {
164            }
165    
166            public void stop() throws Exception {
167            }
168        }
169    
170    }