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