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.component;
018    
019    import com.ibm.wsdl.Constants;
020    import org.apache.servicemix.common.*;
021    import org.apache.servicemix.common.tools.wsdl.WSDLFlattener;
022    import org.apache.servicemix.wsn.EndpointManager;
023    import org.apache.servicemix.wsn.EndpointRegistrationException;
024    import org.apache.servicemix.wsn.jbi.JbiNotificationBroker;
025    import org.apache.servicemix.wsn.jms.JmsCreatePullPoint;
026    import org.springframework.core.io.Resource;
027    import org.w3c.dom.Document;
028    import org.xml.sax.InputSource;
029    
030    import javax.jbi.messaging.MessageExchange;
031    import javax.jbi.servicedesc.ServiceEndpoint;
032    import javax.jms.ConnectionFactory;
033    import javax.naming.Context;
034    import javax.naming.InitialContext;
035    import javax.naming.NamingException;
036    import javax.wsdl.Definition;
037    import javax.wsdl.factory.WSDLFactory;
038    import javax.wsdl.xml.WSDLLocator;
039    import javax.wsdl.xml.WSDLReader;
040    import javax.xml.namespace.QName;
041    import java.net.URL;
042    import java.util.*;
043    
044    public class WSNComponent extends DefaultComponent {
045    
046        private WSDLFlattener flattener;
047    
048        private Map<QName, Document> descriptions;
049    
050        private JbiNotificationBroker notificationBroker;
051    
052        private JmsCreatePullPoint createPullPoint;
053    
054        private WSNConfiguration configuration;
055    
056        private ConnectionFactory connectionFactory;
057    
058        private Resource[] resources;
059    
060        private Object[] requests;
061    
062        private List<Endpoint> endpoints;
063    
064        private WSNDeployer deployer;
065    
066        public WSNComponent() {
067            configuration = new WSNConfiguration();
068            serviceUnit = new DefaultServiceUnit(this);
069        }
070    
071        public JbiNotificationBroker getNotificationBroker() {
072            return notificationBroker;
073        }
074    
075        public JmsCreatePullPoint getCreatePullPoint() {
076            return createPullPoint;
077        }
078    
079        protected Object getExtensionMBean() throws Exception {
080            return configuration;
081        }
082    
083        @Override
084        public BaseServiceUnitManager createServiceUnitManager() {
085            deployer = new WSNDeployer(this);
086            return new BaseServiceUnitManager(this, new Deployer[] {deployer });
087        }
088    
089        public ConnectionFactory getConnectionFactory() {
090            return this.connectionFactory;
091        }
092    
093        public void setConnectionFactory(ConnectionFactory connectionFactory) {
094            this.connectionFactory = connectionFactory;
095        }
096    
097        protected List getConfiguredEndpoints() {
098            return endpoints;
099        }
100    
101        protected Class[] getEndpointClasses() {
102            return new Class[] {
103                WSNEndpoint.class,
104                WSNDeployableEndpoint.class,
105            };
106        }
107    
108        /**
109         * @return Returns the endpoints.
110         */
111        public Resource[] getResources() {
112            return resources;
113        }
114    
115        /**
116         * @param resources The resources to set.
117         */
118        public void setResources(Resource[] resources) {
119            this.resources = resources;
120        }
121    
122        /**
123         * @return Returns the requests.
124         */
125        public Object[] getRequests() {
126            return requests;
127        }
128    
129        /**
130         * @param requests The requests to set.
131         */
132        public void setRequests(Object[] requests) {
133            this.requests = requests;
134        }
135    
136        @Override
137        protected void doInit() throws Exception {
138            configuration.setRootDir(context.getWorkspaceRoot());
139            configuration.load();
140            // Notification Broker
141            notificationBroker = new JbiNotificationBroker(configuration.getBrokerName());
142            notificationBroker.setManager(new WSNEndpointManager());
143            if (connectionFactory == null) {
144                connectionFactory = lookupConnectionFactory();
145            }
146            notificationBroker.setConnectionFactory(connectionFactory);
147            notificationBroker.init();
148            // Create PullPoint
149            createPullPoint = new JmsCreatePullPoint(configuration.getBrokerName());
150            createPullPoint.setManager(new WSNEndpointManager());
151            if (connectionFactory == null) {
152                connectionFactory = lookupConnectionFactory();
153            }
154            createPullPoint.setConnectionFactory(connectionFactory);
155            createPullPoint.init();
156            // Create endpoints
157            endpoints = new ArrayList<Endpoint>();
158            if (resources != null) {
159                for (int i = 0; i < resources.length; i++) {
160                    Endpoint ep = deployer.createEndpoint(resources[i].getURL());
161                    endpoints.add(ep);
162                }
163            }
164            if (requests != null) {
165                for (int i = 0; i < requests.length; i++) {
166                    Endpoint ep = deployer.createEndpoint(requests[i]);
167                    endpoints.add(ep);
168                }
169            }
170            super.doInit();
171        }
172    
173        @Override
174        protected void doShutDown() throws Exception {
175            notificationBroker.destroy();
176            createPullPoint.destroy();
177            super.doShutDown();
178        }
179    
180        /*
181         * (non-Javadoc)
182         * 
183         * @see org.apache.servicemix.common.BaseComponent#getServiceDescription(javax.jbi.servicedesc.ServiceEndpoint)
184         */
185        @Override
186        public Document getServiceDescription(ServiceEndpoint endpoint) {
187            if (logger.isDebugEnabled()) {
188                logger.debug("Querying service description for " + endpoint);
189            }
190            String key = EndpointSupport.getKey(endpoint);
191            Endpoint ep = this.registry.getEndpoint(key);
192            if (ep != null) {
193                QName interfaceName = ep.getInterfaceName();
194                if (interfaceName == null) {
195                    if (logger.isDebugEnabled()) {
196                        logger.debug("Could not retrieve description for endpoint " + key + " (no interface defined)");
197                    }
198                    return null;
199                }
200                return getDescription(interfaceName);
201            } else {
202                if (logger.isDebugEnabled()) {
203                    logger.debug("No endpoint found for " + key);
204                }
205                return null;
206            }
207        }
208    
209        private synchronized Document getDescription(QName interfaceName) {
210            try {
211                if (descriptions == null) {
212                    descriptions = new HashMap<QName, Document>();
213                }
214                Document doc = descriptions.get(interfaceName);
215                if (doc == null) {
216                    if (flattener == null) {
217                        final URL resource = getClass().getClassLoader().getResource("org/apache/servicemix/wsn/wsn.wsdl");
218                        WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
219                        reader.setFeature(Constants.FEATURE_VERBOSE, false);
220                        // Do not let wsdl4j read imports, as it uses the URL getContent() which fails because wsdl
221                        // is not a known extension in OSGi
222                        Definition definition = reader.readWSDL(new WSDLLocator() {
223                            private String last = null;
224                            public InputSource getBaseInputSource() {
225                                return new InputSource(resource.toString());
226                            }
227                            public InputSource getImportInputSource(String parentLocation, String importLocation) {
228                                int idx = parentLocation.lastIndexOf('/');
229                                last = parentLocation.substring(0, idx + 1) + importLocation;
230                                return new InputSource(last);
231                            }
232                            public String getBaseURI() {
233                                return resource.toString();
234                            }
235                            public String getLatestImportURI() {
236                                return last;
237                            }
238                            public void close() {
239                            }
240                        });
241                        flattener = new WSDLFlattener(definition);
242                    }
243                    Definition flatDef = flattener.getDefinition(interfaceName);
244                    doc = WSDLFactory.newInstance().newWSDLWriter().getDocument(flatDef);
245                    descriptions.put(interfaceName, doc);
246                }
247                return doc;
248            } catch (Exception e) {
249                if (logger.isDebugEnabled()) {
250                    logger.debug("Error retrieving endpoint description", e);
251                }
252                return null;
253            }
254        }
255    
256        protected ConnectionFactory lookupConnectionFactory() throws NamingException {
257            Properties props = new Properties();
258            if (configuration.getInitialContextFactory() != null && configuration.getJndiProviderURL() != null) {
259                props.put(Context.INITIAL_CONTEXT_FACTORY, configuration.getInitialContextFactory());
260                props.put(Context.PROVIDER_URL, configuration.getJndiProviderURL());
261            }
262            InitialContext ctx = new InitialContext(props);
263            return (ConnectionFactory) ctx.lookup(configuration.getJndiConnectionFactoryName());
264        }
265    
266        public class WSNEndpointManager implements EndpointManager {
267    
268            public Object register(String address, Object service) throws EndpointRegistrationException {
269                try {
270                    WSNEndpoint endpoint = new WSNEndpoint(address, service);
271                    WSNComponent.this.addEndpoint(endpoint);
272                    return endpoint;
273                } catch (Exception e) {
274                    throw new EndpointRegistrationException("Unable to activate endpoint", e);
275                }
276            }
277    
278            public void unregister(final Object endpoint) throws EndpointRegistrationException {
279                WSNComponent.this.getExecutor(MessageExchange.Role.CONSUMER).execute(new Runnable() {
280                    public void run() {
281                        try {
282                            Endpoint ep = (Endpoint) endpoint;
283                            WSNComponent.this.removeEndpoint(ep);
284                        } catch (Exception e) {
285                            logger.error("Unable to deactivate endpoint", e);
286                        }
287                    }
288                });
289            }
290    
291        }
292    
293    }