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