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.soap;
018    
019    import java.net.URI;
020    import java.util.Collections;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    
026    import javax.jbi.component.ComponentContext;
027    import javax.jbi.messaging.MessageExchange.Role;
028    import javax.jbi.servicedesc.ServiceEndpoint;
029    import javax.wsdl.Definition;
030    import javax.wsdl.Import;
031    import javax.wsdl.Types;
032    import javax.wsdl.WSDLException;
033    import javax.wsdl.extensions.ExtensibilityElement;
034    import javax.wsdl.extensions.ExtensionRegistry;
035    import javax.wsdl.extensions.schema.Schema;
036    import javax.wsdl.extensions.schema.SchemaImport;
037    import javax.wsdl.factory.WSDLFactory;
038    import javax.wsdl.xml.WSDLReader;
039    import javax.wsdl.xml.WSDLWriter;
040    import javax.xml.namespace.QName;
041    
042    import org.apache.servicemix.common.Endpoint;
043    import org.apache.servicemix.common.ExchangeProcessor;
044    import org.apache.servicemix.common.wsdl1.JbiExtension;
045    import org.apache.servicemix.common.xbean.XBeanServiceUnit;
046    import org.apache.servicemix.jbi.messaging.MessageExchangeSupport;
047    import org.apache.servicemix.jbi.security.auth.AuthenticationService;
048    import org.apache.servicemix.jbi.security.keystore.KeystoreManager;
049    import org.apache.servicemix.soap.handlers.addressing.AddressingHandler;
050    import org.springframework.core.io.Resource;
051    import org.w3c.dom.Document;
052    
053    import com.ibm.wsdl.Constants;
054    
055    public abstract class SoapEndpoint extends Endpoint {
056    
057        protected ServiceEndpoint activated;
058        protected ExchangeProcessor processor;
059        protected Role role;
060        protected URI defaultMep = MessageExchangeSupport.IN_OUT;
061        protected boolean soap;
062        protected String soapVersion;
063        protected Resource wsdlResource;
064        protected QName defaultOperation;
065        protected QName targetInterfaceName;
066        protected QName targetService;
067        protected String targetEndpoint;
068        protected List policies;
069        protected Map wsdls = new HashMap();
070        
071        public SoapEndpoint() {
072            policies = Collections.singletonList(new AddressingHandler());
073        }
074        
075        public AuthenticationService getAuthenticationService() {
076            return null;
077        }
078        
079        public KeystoreManager getKeystoreManager() {
080            return null;
081        }
082        
083        /**
084         * @return the policies
085         */
086        public List getPolicies() {
087            return policies;
088        }
089        /**
090         * @param policies the policies to set
091         */
092        public void setPolicies(List policies) {
093            this.policies = policies;
094        }
095        /**
096         * @return Returns the defaultMep.
097         */
098        public URI getDefaultMep() {
099            return defaultMep;
100        }
101        /**
102         * @param defaultMep The defaultMep to set.
103         */
104        public void setDefaultMep(URI defaultMep) {
105            this.defaultMep = defaultMep;
106        }
107        /**
108         * @return Returns the defaultOperation.
109         */
110        public QName getDefaultOperation() {
111            return defaultOperation;
112        }
113        /**
114         * @param defaultOperation The defaultOperation to set.
115         */
116        public void setDefaultOperation(QName defaultOperation) {
117            this.defaultOperation = defaultOperation;
118        }
119        /**
120         * @return Returns the role.
121         */
122        public Role getRole() {
123            return role;
124        }
125        /**
126         * @param role The role to set.
127         */
128        public void setRole(Role role) {
129            this.role = role;
130        }
131        /**
132         * @return Returns the soap.
133         */
134        public boolean isSoap() {
135            return soap;
136        }
137        /**
138         * @param soap The soap to set.
139         */
140        public void setSoap(boolean soap) {
141            this.soap = soap;
142        }
143        /**
144         * @return Returns the soapVersion.
145         */
146        public String getSoapVersion() {
147            return soapVersion;
148        }
149        /**
150         * @param soapVersion The soapVersion to set.
151         */
152        public void setSoapVersion(String soapVersion) {
153            this.soapVersion = soapVersion;
154        }
155        /**
156         * @return Returns the targetEndpoint.
157         */
158        public String getTargetEndpoint() {
159            return targetEndpoint;
160        }
161        /**
162         * @param targetEndpoint The targetEndpoint to set.
163         */
164        public void setTargetEndpoint(String targetEndpoint) {
165            this.targetEndpoint = targetEndpoint;
166        }
167        /**
168         * @return Returns the targetInterfaceName.
169         */
170        public QName getTargetInterfaceName() {
171            return targetInterfaceName;
172        }
173        /**
174         * @param targetInterfaceName The targetInterfaceName to set.
175         */
176        public void setTargetInterfaceName(QName targetInterfaceName) {
177            this.targetInterfaceName = targetInterfaceName;
178        }
179        /**
180         * @return Returns the targetServiceName.
181         */
182        public QName getTargetService() {
183            return targetService;
184        }
185        /**
186         * @param targetServiceName The targetServiceName to set.
187         */
188        public void setTargetService(QName targetServiceName) {
189            this.targetService = targetServiceName;
190        }
191        /**
192         * @return Returns the wsdlResource.
193         */
194        public Resource getWsdlResource() {
195            return wsdlResource;
196        }
197        /**
198         * @param wsdlResource The wsdlResource to set.
199         */
200        public void setWsdlResource(Resource wsdlResource) {
201            this.wsdlResource = wsdlResource;
202        }
203        /**
204         * @org.apache.xbean.Property alias="role"
205         * @param role
206         */
207        public void setRoleAsString(String role) {
208            if (role == null) {
209                throw new IllegalArgumentException("Role must be specified");
210            } else if (JbiExtension.ROLE_CONSUMER.equals(role)) {
211                setRole(Role.CONSUMER);
212            } else if (JbiExtension.ROLE_PROVIDER.equals(role)) {
213                setRole(Role.PROVIDER);
214            } else {
215                throw new IllegalArgumentException("Unrecognized role: " + role);
216            }
217        }
218    
219        /**
220         * Load the wsdl for this endpoint.
221         */
222        protected void loadWsdl() {
223            // Load WSDL from the resource
224            if (description == null && wsdlResource != null) {
225                ClassLoader cl = Thread.currentThread().getContextClassLoader();
226                try {
227                    Thread.currentThread().setContextClassLoader(serviceUnit.getConfigurationClassLoader());
228                    WSDLReader reader = WSDLFactory.newInstance().newWSDLReader(); 
229                    reader.setFeature(Constants.FEATURE_VERBOSE, false);
230                    Definition def = reader.readWSDL(wsdlResource.getURL().toString());
231                    overrideDefinition(def);
232                } catch (Exception e) {
233                    logger.warn("Could not load description from resource", e);
234                } finally {
235                    Thread.currentThread().setContextClassLoader(cl);
236                }
237            }
238            // If the endpoint is a consumer, try to find
239            // the proxied endpoint description
240            if (description == null && definition == null && getRole() == Role.CONSUMER) {
241                retrieveProxiedEndpointDefinition();
242            }
243            // If the wsdl definition is provided,
244            // convert it to a DOM document
245            if (description == null && definition != null) {
246                try {
247                    description = WSDLFactory.newInstance().newWSDLWriter().getDocument(definition);
248                } catch (Exception e) {
249                    logger.warn("Could not create document from wsdl description", e);
250                }
251            }
252            // If the dom description is provided
253            // convert it to a WSDL definition
254            if (definition == null && description != null) {
255                try {
256                    definition = WSDLFactory.newInstance().newWSDLReader().readWSDL(null, description);
257                } catch (Exception e) {
258                    logger.warn("Could not create wsdl definition from dom document", e);
259                }
260            }
261            if (definition != null) {
262                try {
263                    mapDefinition(definition);
264                } catch (Exception e) {
265                    logger.warn("Could not map wsdl definition to documents", e);
266                }
267            }
268        }
269    
270        /**
271         * Create a wsdl definition for a consumer endpoint.
272         * Loads the target endpoint definition and add http binding
273         * informations to it.
274         */
275        protected void retrieveProxiedEndpointDefinition() {
276            if (logger.isDebugEnabled()) {
277                logger.debug("Retrieving proxied endpoint definition");
278            }
279            try {
280                ComponentContext ctx = this.serviceUnit.getComponent().getComponentContext();
281                ServiceEndpoint ep = null;
282                if (targetService != null && targetEndpoint != null) {
283                    ep = ctx.getEndpoint(targetService, targetEndpoint);
284                    if (ep == null && logger.isDebugEnabled()) {
285                        logger.debug("Could not retrieve endpoint targetService/targetEndpoint");
286                    }
287                }
288                if (ep == null && targetService != null) {
289                    ServiceEndpoint[] eps = ctx.getEndpointsForService(targetService);
290                    if (eps != null && eps.length > 0) {
291                        ep = eps[0];
292                    }
293                    if (ep == null && logger.isDebugEnabled()) {
294                        logger.debug("Could not retrieve endpoint for targetService");
295                    }
296                }
297                if (ep == null && targetInterfaceName != null) {
298                    ServiceEndpoint[] eps = ctx.getEndpoints(targetInterfaceName);
299                    if (eps != null && eps.length > 0) {
300                        ep = eps[0];
301                    }
302                    if (ep == null && logger.isDebugEnabled()) {
303                        logger.debug("Could not retrieve endpoint for targetInterfaceName");
304                    }
305                }
306                if (ep == null && service != null && endpoint != null) {
307                    ep = ctx.getEndpoint(service, endpoint);
308                    if (ep == null && logger.isDebugEnabled()) {
309                        logger.debug("Could not retrieve endpoint for service/endpoint");
310                    }
311                }
312                if (ep != null) {
313                    Document doc = ctx.getEndpointDescriptor(ep);
314                    if (doc != null) {
315                        WSDLReader reader = WSDLFactory.newInstance().newWSDLReader(); 
316                        reader.setFeature(Constants.FEATURE_VERBOSE, false);
317                        Definition def = reader.readWSDL(null, doc);
318                        if (def != null) {
319                            overrideDefinition(def);
320                        }
321                    }
322                }
323            } catch (Exception e) {
324                logger.debug("Unable to retrieve target endpoint descriptor", e);
325            }
326        }
327        
328        /* (non-Javadoc)
329         * @see org.apache.servicemix.common.Endpoint#getProcessor()
330         */
331        public ExchangeProcessor getProcessor() {
332            return this.processor;
333        }
334    
335        /* (non-Javadoc)
336         * @see org.servicemix.common.Endpoint#activate()
337         */
338        public void activate() throws Exception {
339            ComponentContext ctx = this.serviceUnit.getComponent().getComponentContext();
340            loadWsdl();
341            if (getRole() == Role.PROVIDER) {
342                activated = ctx.activateEndpoint(service, endpoint);
343                processor = createProviderProcessor();
344            } else {
345                activated = createExternalEndpoint();
346                ctx.registerExternalEndpoint(activated);
347                processor = createConsumerProcessor();
348            }
349            processor.start();
350        }
351        
352        public void activateDynamic() throws Exception {
353            if (getRole() == Role.PROVIDER) {
354                processor = createProviderProcessor();
355            } else {
356                processor = createConsumerProcessor();
357            }
358            processor.start();
359        }
360    
361        /* (non-Javadoc)
362         * @see org.servicemix.common.Endpoint#deactivate()
363         */
364        public void deactivate() throws Exception {
365            if (activated != null) {
366                ComponentContext ctx = this.serviceUnit.getComponent().getComponentContext();
367                if (getRole() == Role.PROVIDER) {
368                    ServiceEndpoint ep = activated;
369                    activated = null;
370                    ctx.deactivateEndpoint(ep);
371                } else {
372                    ServiceEndpoint ep = activated;
373                    activated = null;
374                    ctx.deregisterExternalEndpoint(ep);
375                }
376            }
377            processor.stop();
378        }
379    
380        protected abstract void overrideDefinition(Definition def) throws Exception;
381        
382        protected abstract ExchangeProcessor createProviderProcessor();
383        
384        protected abstract ExchangeProcessor createConsumerProcessor();
385        
386        protected abstract ServiceEndpoint createExternalEndpoint();
387    
388        protected WSDLReader createWsdlReader() throws WSDLException {
389            WSDLFactory factory = WSDLFactory.newInstance();
390            ExtensionRegistry registry = factory.newPopulatedExtensionRegistry();
391            registerExtensions(registry);
392            WSDLReader reader = factory.newWSDLReader();
393            reader.setFeature(Constants.FEATURE_VERBOSE, false);
394            reader.setExtensionRegistry(registry);
395            return reader;
396        }
397        
398        protected WSDLWriter createWsdlWriter() throws WSDLException {
399            WSDLFactory factory = WSDLFactory.newInstance();
400            ExtensionRegistry registry = factory.newPopulatedExtensionRegistry();
401            registerExtensions(registry);
402            WSDLWriter writer = factory.newWSDLWriter();
403            //writer.setExtensionRegistry(registry);
404            return writer;
405        }
406        
407        protected void registerExtensions(ExtensionRegistry registry) {
408            JbiExtension.register(registry);
409        }
410    
411        
412        protected void mapDefinition(Definition def) throws WSDLException {
413            wsdls.put("main.wsdl", createWsdlWriter().getDocument(def));
414            mapImports(def);
415        }
416    
417        protected void mapImports(Definition def) throws WSDLException {
418            // Add other imports to mapping
419            Map imports = def.getImports();
420            for (Iterator iter = imports.values().iterator(); iter.hasNext();) {
421                List imps = (List) iter.next();
422                for (Iterator iterator = imps.iterator(); iterator.hasNext();) {
423                    Import imp = (Import) iterator.next();
424                    Definition impDef = imp.getDefinition();
425                    String impLoc = imp.getLocationURI();
426                    if (impDef != null && impLoc != null && !URI.create(impLoc).isAbsolute()) {
427                        wsdls.put(impLoc, createWsdlWriter().getDocument(impDef));
428                        mapImports(impDef);
429                    }
430                }
431            }
432            // Add schemas to mapping
433            Types types = def.getTypes();
434            if (types != null) {
435                for (Iterator it = types.getExtensibilityElements().iterator(); it.hasNext();) {
436                    ExtensibilityElement ee = (ExtensibilityElement) it.next();
437                    if (ee instanceof Schema) {
438                        Schema schema = (Schema) ee;
439                        Map schemaImports = schema.getImports();
440                        for (Iterator iter = schemaImports.values().iterator(); iter.hasNext();) {
441                            List imps = (List) iter.next();
442                            for (Iterator iterator = imps.iterator(); iterator.hasNext();) {
443                                SchemaImport schemaImport = (SchemaImport) iterator.next();
444                                Schema schemaImp = schemaImport.getReferencedSchema();
445                                String schemaLoc = schemaImport.getSchemaLocationURI();
446                                if (schemaLoc != null && schemaImp != null && schemaImp.getElement() != null && !URI.create(schemaLoc).isAbsolute()) {
447                                    wsdls.put(schemaLoc, schemaImp.getElement());
448                                }
449                            }
450                        }
451                    }
452                }
453            }
454        }
455    
456        /**
457         * @return Returns the wsdls.
458         */
459        public Map getWsdls() {
460            return wsdls;
461        }
462        
463    }