View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.bindings.spi.webservices;
20  
21  import java.io.BufferedInputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.lang.ref.SoftReference;
25  import java.lang.reflect.Constructor;
26  import java.lang.reflect.InvocationTargetException;
27  import java.math.BigInteger;
28  import java.net.MalformedURLException;
29  import java.net.URL;
30  import java.util.ArrayDeque;
31  import java.util.Collections;
32  import java.util.EnumMap;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.concurrent.locks.ReentrantLock;
38  
39  import javax.xml.namespace.QName;
40  import javax.xml.parsers.ParserConfigurationException;
41  import javax.xml.ws.BindingProvider;
42  import javax.xml.ws.Service;
43  import javax.xml.ws.WebServiceFeature;
44  import javax.xml.ws.handler.HandlerResolver;
45  import javax.xml.ws.handler.MessageContext;
46  import javax.xml.ws.http.HTTPException;
47  
48  import org.apache.chemistry.opencmis.client.bindings.impl.ClientVersion;
49  import org.apache.chemistry.opencmis.client.bindings.impl.CmisBindingsHelper;
50  import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
51  import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpInvoker;
52  import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
53  import org.apache.chemistry.opencmis.commons.SessionParameter;
54  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
55  import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
56  import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
57  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
58  import org.apache.chemistry.opencmis.commons.exceptions.CmisProxyAuthenticationException;
59  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
60  import org.apache.chemistry.opencmis.commons.exceptions.CmisTooManyRequestsException;
61  import org.apache.chemistry.opencmis.commons.exceptions.CmisUnauthorizedException;
62  import org.apache.chemistry.opencmis.commons.impl.IOUtils;
63  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
64  import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
65  import org.apache.chemistry.opencmis.commons.impl.jaxb.ACLService;
66  import org.apache.chemistry.opencmis.commons.impl.jaxb.ACLServicePort;
67  import org.apache.chemistry.opencmis.commons.impl.jaxb.DiscoveryService;
68  import org.apache.chemistry.opencmis.commons.impl.jaxb.DiscoveryServicePort;
69  import org.apache.chemistry.opencmis.commons.impl.jaxb.MultiFilingService;
70  import org.apache.chemistry.opencmis.commons.impl.jaxb.MultiFilingServicePort;
71  import org.apache.chemistry.opencmis.commons.impl.jaxb.NavigationService;
72  import org.apache.chemistry.opencmis.commons.impl.jaxb.NavigationServicePort;
73  import org.apache.chemistry.opencmis.commons.impl.jaxb.ObjectService;
74  import org.apache.chemistry.opencmis.commons.impl.jaxb.ObjectServicePort;
75  import org.apache.chemistry.opencmis.commons.impl.jaxb.PolicyService;
76  import org.apache.chemistry.opencmis.commons.impl.jaxb.PolicyServicePort;
77  import org.apache.chemistry.opencmis.commons.impl.jaxb.RelationshipService;
78  import org.apache.chemistry.opencmis.commons.impl.jaxb.RelationshipServicePort;
79  import org.apache.chemistry.opencmis.commons.impl.jaxb.RepositoryService;
80  import org.apache.chemistry.opencmis.commons.impl.jaxb.RepositoryServicePort;
81  import org.apache.chemistry.opencmis.commons.impl.jaxb.VersioningService;
82  import org.apache.chemistry.opencmis.commons.impl.jaxb.VersioningServicePort;
83  import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
84  import org.slf4j.Logger;
85  import org.slf4j.LoggerFactory;
86  import org.w3c.dom.Document;
87  import org.w3c.dom.Element;
88  import org.w3c.dom.NodeList;
89  import org.xml.sax.SAXException;
90  
91  public abstract class AbstractPortProvider {
92  
93      private static final Logger LOG = LoggerFactory.getLogger(AbstractPortProvider.class);
94  
95      private static final int PORT_CACHE_SIZE = 5;
96  
97      protected static final int CHUNK_SIZE = (64 * 1024) - 1;
98  
99      protected enum CmisWebSerivcesService {
100         REPOSITORY_SERVICE("RepositoryService", false, RepositoryService.class, RepositoryServicePort.class,
101                 SessionParameter.WEBSERVICES_REPOSITORY_SERVICE,
102                 SessionParameter.WEBSERVICES_REPOSITORY_SERVICE_ENDPOINT),
103 
104         NAVIGATION_SERVICE("NavigationService", false, NavigationService.class, NavigationServicePort.class,
105                 SessionParameter.WEBSERVICES_NAVIGATION_SERVICE,
106                 SessionParameter.WEBSERVICES_NAVIGATION_SERVICE_ENDPOINT),
107 
108         OBJECT_SERVICE("ObjectService", true, ObjectService.class, ObjectServicePort.class,
109                 SessionParameter.WEBSERVICES_OBJECT_SERVICE, SessionParameter.WEBSERVICES_OBJECT_SERVICE_ENDPOINT),
110 
111         VERSIONING_SERVICE("VersioningService", true, VersioningService.class, VersioningServicePort.class,
112                 SessionParameter.WEBSERVICES_VERSIONING_SERVICE,
113                 SessionParameter.WEBSERVICES_VERSIONING_SERVICE_ENDPOINT),
114 
115         DISCOVERY_SERVICE("DiscoveryService", false, DiscoveryService.class, DiscoveryServicePort.class,
116                 SessionParameter.WEBSERVICES_DISCOVERY_SERVICE, SessionParameter.WEBSERVICES_DISCOVERY_SERVICE_ENDPOINT),
117 
118         MULTIFILING_SERVICE("MultiFilingService", false, MultiFilingService.class, MultiFilingServicePort.class,
119                 SessionParameter.WEBSERVICES_MULTIFILING_SERVICE,
120                 SessionParameter.WEBSERVICES_MULTIFILING_SERVICE_ENDPOINT),
121 
122         RELATIONSHIP_SERVICE("RelationshipService", false, RelationshipService.class, RelationshipServicePort.class,
123                 SessionParameter.WEBSERVICES_RELATIONSHIP_SERVICE,
124                 SessionParameter.WEBSERVICES_RELATIONSHIP_SERVICE_ENDPOINT),
125 
126         POLICY_SERVICE("PolicyService", false, PolicyService.class, PolicyServicePort.class,
127                 SessionParameter.WEBSERVICES_POLICY_SERVICE, SessionParameter.WEBSERVICES_POLICY_SERVICE_ENDPOINT),
128 
129         ACL_SERVICE("ACLService", false, ACLService.class, ACLServicePort.class,
130                 SessionParameter.WEBSERVICES_ACL_SERVICE, SessionParameter.WEBSERVICES_ACL_SERVICE_ENDPOINT);
131 
132         private final String name;
133         private final QName qname;
134         private final boolean handlesContent;
135         private final Class<? extends Service> serviceClass;
136         private final Class<?> portClass;
137         private final String wsdlKey;
138         private final String endpointKey;
139 
140         CmisWebSerivcesService(String localname, boolean handlesContent, Class<? extends Service> serviceClass,
141                 Class<?> port11Class, String wsdlKey, String endpointKey) {
142             this.name = localname;
143             this.qname = new QName("http://docs.oasis-open.org/ns/cmis/ws/200908/", localname);
144             this.handlesContent = handlesContent;
145             this.serviceClass = serviceClass;
146             this.portClass = port11Class;
147             this.wsdlKey = wsdlKey;
148             this.endpointKey = endpointKey;
149         }
150 
151         public String getServiceName() {
152             return name;
153         }
154 
155         public QName getQName() {
156             return qname;
157         }
158 
159         public boolean handlesContent() {
160             return handlesContent;
161         }
162 
163         public Class<? extends Service> getServiceClass() {
164             return serviceClass;
165         }
166 
167         public Class<?> getPortClass() {
168             return portClass;
169         }
170 
171         public String getWsdlKey() {
172             return wsdlKey;
173         }
174 
175         public String getEndpointKey() {
176             return endpointKey;
177         }
178     }
179 
180     class CmisServiceHolder {
181         private final CmisWebSerivcesService service;
182         private SoftReference<Service> serviceObject;
183         private final URL endpointUrl;
184 
185         public CmisServiceHolder(final CmisWebSerivcesService service, final URL endpointUrl)
186                 throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
187             this.service = service;
188             this.endpointUrl = endpointUrl;
189             this.serviceObject = new SoftReference<Service>(createServiceObject());
190         }
191 
192         private Service createServiceObject() throws InstantiationException, IllegalAccessException,
193                 InvocationTargetException, NoSuchMethodException {
194             final Constructor<? extends Service> serviceConstructor = service.getServiceClass().getConstructor(
195                     new Class<?>[] { URL.class, QName.class });
196 
197             URL wsdlUrl = service.getPortClass().getResource("/wsdl/cmis11/CMISWS-Service.wsdl");
198             if (LOG.isDebugEnabled()) {
199                 LOG.debug("Session {}: WSDL URL: {}", getSession().getSessionId(), wsdlUrl.toExternalForm());
200             }
201 
202             Service newService = serviceConstructor.newInstance(new Object[] { wsdlUrl, service.getQName() });
203 
204             AuthenticationProvider authProvider = CmisBindingsHelper.getAuthenticationProvider(getSession());
205             if (authProvider != null) {
206                 HandlerResolver handlerResolver = authProvider.getHandlerResolver();
207                 if (handlerResolver != null) {
208                     newService.setHandlerResolver(handlerResolver);
209                 }
210             }
211 
212             return newService;
213         }
214 
215         public CmisWebSerivcesService getService() {
216             return service;
217         }
218 
219         public Service getServiceObject() throws InstantiationException, IllegalAccessException,
220                 InvocationTargetException, NoSuchMethodException {
221             Service result = serviceObject.get();
222             if (result == null) {
223                 result = createServiceObject();
224                 serviceObject = new SoftReference<Service>(result);
225             }
226 
227             return result;
228         }
229 
230         public URL getEndpointUrl() {
231             return endpointUrl;
232         }
233 
234         public String getServiceName() {
235             return service.getServiceName();
236         }
237     }
238 
239     private BindingSession session;
240     private boolean useCompression;
241     private boolean useClientCompression;
242     private String acceptLanguage;
243 
244     private final ReentrantLock portObjectLock = new ReentrantLock();
245     private final EnumMap<CmisWebSerivcesService, ArrayDeque<SoftReference<BindingProvider>>> portObjectCache = new EnumMap<CmisWebSerivcesService, ArrayDeque<SoftReference<BindingProvider>>>(
246             CmisWebSerivcesService.class);
247 
248     public BindingSession getSession() {
249         return session;
250     }
251 
252     public void setSession(BindingSession session) {
253         this.session = session;
254 
255         final Object compression = session.get(SessionParameter.COMPRESSION);
256         useCompression = (compression != null) && Boolean.parseBoolean(compression.toString());
257 
258         final Object clientCompression = session.get(SessionParameter.CLIENT_COMPRESSION);
259         useClientCompression = (clientCompression != null) && Boolean.parseBoolean(clientCompression.toString());
260 
261         if (session.get(CmisBindingsHelper.ACCEPT_LANGUAGE) instanceof String) {
262             acceptLanguage = session.get(CmisBindingsHelper.ACCEPT_LANGUAGE).toString();
263         }
264     }
265 
266     public boolean useCompression() {
267         return useCompression;
268     }
269 
270     public boolean useClientCompression() {
271         return useClientCompression;
272     }
273 
274     public String getAcceptLanguage() {
275         return acceptLanguage;
276     }
277 
278     /**
279      * Return the Repository Service port object.
280      */
281     public RepositoryServicePort getRepositoryServicePort(CmisVersion cmisVersion, String soapAction) {
282         BindingProvider portObject = getPortObject(CmisWebSerivcesService.REPOSITORY_SERVICE);
283         setSoapAction(portObject, soapAction, cmisVersion);
284 
285         return (RepositoryServicePort) portObject;
286     }
287 
288     /**
289      * Return the Navigation Service port object.
290      */
291     public NavigationServicePort getNavigationServicePort(CmisVersion cmisVersion, String soapAction) {
292         BindingProvider portObject = getPortObject(CmisWebSerivcesService.NAVIGATION_SERVICE);
293         setSoapAction(portObject, soapAction, cmisVersion);
294 
295         return (NavigationServicePort) portObject;
296     }
297 
298     /**
299      * Return the Object Service port object.
300      */
301     public ObjectServicePort getObjectServicePort(CmisVersion cmisVersion, String soapAction) {
302         BindingProvider portObject = getPortObject(CmisWebSerivcesService.OBJECT_SERVICE);
303         setSoapAction(portObject, soapAction, cmisVersion);
304 
305         return (ObjectServicePort) portObject;
306     }
307 
308     /**
309      * Return the Versioning Service port object.
310      */
311     public VersioningServicePort getVersioningServicePort(CmisVersion cmisVersion, String soapAction) {
312         BindingProvider portObject = getPortObject(CmisWebSerivcesService.VERSIONING_SERVICE);
313         setSoapAction(portObject, soapAction, cmisVersion);
314 
315         return (VersioningServicePort) portObject;
316     }
317 
318     /**
319      * Return the Discovery Service port object.
320      */
321     public DiscoveryServicePort getDiscoveryServicePort(CmisVersion cmisVersion, String soapAction) {
322         BindingProvider portObject = getPortObject(CmisWebSerivcesService.DISCOVERY_SERVICE);
323         setSoapAction(portObject, soapAction, cmisVersion);
324 
325         return (DiscoveryServicePort) portObject;
326     }
327 
328     /**
329      * Return the MultiFiling Service port object.
330      */
331     public MultiFilingServicePort getMultiFilingServicePort(CmisVersion cmisVersion, String soapAction) {
332         BindingProvider portObject = getPortObject(CmisWebSerivcesService.MULTIFILING_SERVICE);
333         setSoapAction(portObject, soapAction, cmisVersion);
334 
335         return (MultiFilingServicePort) portObject;
336     }
337 
338     /**
339      * Return the Relationship Service port object.
340      */
341     public RelationshipServicePort getRelationshipServicePort(CmisVersion cmisVersion, String soapAction) {
342         BindingProvider portObject = getPortObject(CmisWebSerivcesService.RELATIONSHIP_SERVICE);
343         setSoapAction(portObject, soapAction, cmisVersion);
344 
345         return (RelationshipServicePort) portObject;
346     }
347 
348     /**
349      * Return the Policy Service port object.
350      */
351     public PolicyServicePort getPolicyServicePort(CmisVersion cmisVersion, String soapAction) {
352         BindingProvider portObject = getPortObject(CmisWebSerivcesService.POLICY_SERVICE);
353         setSoapAction(portObject, soapAction, cmisVersion);
354 
355         return (PolicyServicePort) portObject;
356     }
357 
358     /**
359      * Return the ACL Service port object.
360      */
361     public ACLServicePort getACLServicePort(CmisVersion cmisVersion, String soapAction) {
362         BindingProvider portObject = getPortObject(CmisWebSerivcesService.ACL_SERVICE);
363         setSoapAction(portObject, soapAction, cmisVersion);
364 
365         return (ACLServicePort) portObject;
366     }
367 
368     public void endCall(Object portObject) {
369         AuthenticationProvider authProvider = CmisBindingsHelper.getAuthenticationProvider(session);
370         if (authProvider != null && portObject instanceof BindingProvider) {
371             BindingProvider bp = (BindingProvider) portObject;
372             String url = (String) bp.getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
373             if (bp.getResponseContext() != null) {
374                 @SuppressWarnings("unchecked")
375                 Map<String, List<String>> headers = (Map<String, List<String>>) bp.getResponseContext().get(
376                         MessageContext.HTTP_RESPONSE_HEADERS);
377                 Integer statusCode = (Integer) bp.getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE);
378                 authProvider.putResponseHeaders(url, statusCode == null ? -1 : statusCode, headers);
379             }
380 
381             CmisWebSerivcesService service = null;
382 
383             if (portObject instanceof RepositoryServicePort) {
384                 service = CmisWebSerivcesService.REPOSITORY_SERVICE;
385             } else if (portObject instanceof NavigationServicePort) {
386                 service = CmisWebSerivcesService.NAVIGATION_SERVICE;
387             } else if (portObject instanceof ObjectServicePort) {
388                 service = CmisWebSerivcesService.OBJECT_SERVICE;
389             } else if (portObject instanceof VersioningServicePort) {
390                 service = CmisWebSerivcesService.VERSIONING_SERVICE;
391             } else if (portObject instanceof DiscoveryServicePort) {
392                 service = CmisWebSerivcesService.DISCOVERY_SERVICE;
393             } else if (portObject instanceof MultiFilingServicePort) {
394                 service = CmisWebSerivcesService.MULTIFILING_SERVICE;
395             } else if (portObject instanceof RelationshipServicePort) {
396                 service = CmisWebSerivcesService.RELATIONSHIP_SERVICE;
397             } else if (portObject instanceof PolicyServicePort) {
398                 service = CmisWebSerivcesService.POLICY_SERVICE;
399             } else if (portObject instanceof ACLServicePort) {
400                 service = CmisWebSerivcesService.ACL_SERVICE;
401             }
402 
403             if (service == null) {
404                 return;
405             }
406 
407             portObjectLock.lock();
408             try {
409                 ArrayDeque<SoftReference<BindingProvider>> queue = portObjectCache.get(service);
410                 if (queue == null) {
411                     throw new CmisRuntimeException("This is a bug!");
412                 }
413 
414                 if (queue.size() < PORT_CACHE_SIZE) {
415                     queue.push(new SoftReference<BindingProvider>(bp));
416                 } else {
417                     Iterator<SoftReference<BindingProvider>> iter = queue.iterator();
418                     while (iter.hasNext()) {
419                         SoftReference<BindingProvider> ref = iter.next();
420                         if (ref.get() == null) {
421                             iter.remove();
422                             queue.push(new SoftReference<BindingProvider>(bp));
423                             break;
424                         }
425                     }
426                 }
427             } finally {
428                 portObjectLock.unlock();
429             }
430         }
431     }
432 
433     // ---- internal ----
434 
435     @SuppressWarnings("unchecked")
436     protected BindingProvider getPortObject(final CmisWebSerivcesService service) {
437         Map<CmisWebSerivcesService, CmisServiceHolder> serviceMap = (Map<CmisWebSerivcesService, CmisServiceHolder>) session
438                 .get(SpiSessionParameter.SERVICES);
439 
440         // does the service map exist?
441         if (serviceMap == null) {
442             session.writeLock();
443             try {
444                 // try again
445                 serviceMap = (Map<CmisWebSerivcesService, CmisServiceHolder>) session.get(SpiSessionParameter.SERVICES);
446                 if (serviceMap == null) {
447                     serviceMap = new EnumMap<CmisWebSerivcesService, CmisServiceHolder>(CmisWebSerivcesService.class);
448                     session.put(SpiSessionParameter.SERVICES, serviceMap, true);
449                 }
450 
451                 if (serviceMap.containsKey(service)) {
452                     return createPortObject(serviceMap.get(service));
453                 }
454 
455                 // create service object
456                 CmisServiceHolder serviceholder = initServiceObject(service);
457                 serviceMap.put(service, serviceholder);
458 
459                 // create port object
460                 return createPortObject(serviceholder);
461             } finally {
462                 session.writeUnlock();
463             }
464         }
465 
466         // is the service in the service map?
467         if (!serviceMap.containsKey(service)) {
468             session.writeLock();
469             try {
470                 // try again
471                 if (serviceMap.containsKey(service)) {
472                     return createPortObject(serviceMap.get(service));
473                 }
474 
475                 // create object
476                 CmisServiceHolder serviceholder = initServiceObject(service);
477                 serviceMap.put(service, serviceholder);
478 
479                 return createPortObject(serviceholder);
480             } finally {
481                 session.writeUnlock();
482             }
483         }
484 
485         return createPortObject(serviceMap.get(service));
486     }
487 
488     /**
489      * Creates a service object.
490      */
491     protected CmisServiceHolder initServiceObject(final CmisWebSerivcesService service) {
492         if (LOG.isDebugEnabled()) {
493             LOG.debug("Session {}: Initializing Web Service {} ...", getSession().getSessionId(),
494                     service.getServiceName());
495         }
496 
497         try {
498             // get URLs
499             URL endpointUrl = null;
500 
501             String wsdlUrlStr = (String) session.get(service.getWsdlKey());
502             if (wsdlUrlStr != null) {
503                 endpointUrl = getEndpointUrlFromWsdl(wsdlUrlStr, service);
504             } else {
505                 String endpointUrlStr = (String) session.get(service.getEndpointKey());
506                 if (endpointUrlStr != null) {
507                     endpointUrl = new URL(endpointUrlStr);
508                 }
509             }
510 
511             if (endpointUrl == null) {
512                 throw new CmisRuntimeException("Neither a WSDL URL nor an endpoint URL is specified for the service "
513                         + service.getServiceName() + "!");
514             }
515 
516             // build the requested service object
517             return new CmisServiceHolder(service, endpointUrl);
518         } catch (CmisBaseException ce) {
519             throw ce;
520         } catch (HTTPException he) {
521             String message = "Cannot connect to Web Services [" + service.getServiceName() + "]: " + he.getMessage();
522             if (he.getStatusCode() == 401) {
523                 throw new CmisUnauthorizedException(message, he);
524             } else if (he.getStatusCode() == 404) {
525                 throw new CmisObjectNotFoundException(message, he);
526             } else if (he.getStatusCode() == 407) {
527                 throw new CmisProxyAuthenticationException(message, he);
528             } else if (he.getStatusCode() == 429) {
529                 throw new CmisTooManyRequestsException(message, he);
530             } else if (he.getStatusCode() == 301 || he.getStatusCode() == 302 || he.getStatusCode() == 303
531                     || he.getStatusCode() == 307) {
532                 throw new CmisConnectionException("Redirects are not supported (HTTP status code " + he.getStatusCode()
533                         + "): " + message, he);
534             } else {
535                 throw new CmisConnectionException(message, he);
536             }
537         } catch (InvocationTargetException ite) {
538             String message = "Cannot initalize Web Services service object [" + service.getServiceName() + "]: "
539                     + ite.getCause().getMessage();
540             throw new CmisConnectionException(message, ite);
541         } catch (Exception e) {
542             String message = "Cannot initalize Web Services service object [" + service.getServiceName() + "]: "
543                     + e.getMessage();
544             throw new CmisConnectionException(message, e);
545         }
546     }
547 
548     /**
549      * Reads the URL and extracts the endpoint URL of the given service.
550      */
551     private URL getEndpointUrlFromWsdl(final String wsdlUrl, final CmisWebSerivcesService service) {
552         InputStream wsdlStream;
553         URL url;
554 
555         // check the WSDL URL
556         try {
557             url = new URL(wsdlUrl);
558         } catch (MalformedURLException e) {
559             throw new CmisConnectionException("Invalid WSDL URL: " + wsdlUrl, e);
560         }
561 
562         // check protocol
563         if (url.getProtocol().equalsIgnoreCase("http") || url.getProtocol().equalsIgnoreCase("https")) {
564             // HTTP URL -> use HttpInvoker to enable authentication
565             HttpInvoker hi = CmisBindingsHelper.getHttpInvoker(session);
566             Response wsdlResponse = hi.invokeGET(new UrlBuilder(wsdlUrl), session);
567 
568             if (wsdlResponse.getResponseCode() != 200) {
569                 throw new CmisConnectionException("Cannot access WSDL: " + wsdlUrl, BigInteger.ZERO,
570                         wsdlResponse.getErrorContent());
571             } else {
572                 wsdlStream = wsdlResponse.getStream();
573             }
574         } else {
575             // non-HTTP URL -> just open the stream
576             try {
577                 wsdlStream = url.openStream();
578             } catch (IOException e) {
579                 throw new CmisConnectionException("Cannot access WSDL: " + wsdlUrl, e);
580             }
581         }
582 
583         // parse the WSDL
584         try {
585             final Document doc = XMLUtils.parseDomDocument(new BufferedInputStream(wsdlStream, 64 * 1024));
586 
587             NodeList serivceList = doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "service");
588             for (int i = 0; i < serivceList.getLength(); i++) {
589                 Element serviceNode = (Element) serivceList.item(i);
590 
591                 String name = serviceNode.getAttribute("name");
592                 if (name == null) {
593                     continue;
594                 }
595 
596                 if (!service.getQName().getLocalPart().equals(name)) {
597                     continue;
598                 }
599 
600                 NodeList portList = serviceNode.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "port");
601                 if (portList.getLength() < 1) {
602                     throw new CmisRuntimeException("This service has no ports: " + service.getServiceName());
603                 }
604 
605                 Element port = (Element) portList.item(0);
606 
607                 NodeList addressList = port.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/soap/", "address");
608                 if (addressList.getLength() < 1) {
609                     // see CMIS-908
610                     addressList = port.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/soap12/", "address");
611                 }
612                 if (addressList.getLength() < 1) {
613                     throw new CmisRuntimeException("This service has no endpoint address: " + service.getServiceName());
614                 }
615 
616                 Element address = (Element) addressList.item(0);
617 
618                 String location = address.getAttribute("location");
619                 if (location == null) {
620                     throw new CmisRuntimeException("This service has no endpoint address: " + service.getServiceName());
621                 }
622 
623                 try {
624                     return new URL(location);
625                 } catch (MalformedURLException e) {
626                     throw new CmisRuntimeException("This service provides an invalid endpoint address: "
627                             + service.getServiceName(), e);
628                 }
629             }
630 
631             throw new CmisRuntimeException("This service does not provide an endpoint address: "
632                     + service.getServiceName());
633         } catch (ParserConfigurationException pe) {
634             throw new CmisRuntimeException("Cannot parse this WSDL: " + wsdlUrl, pe);
635         } catch (SAXException se) {
636             throw new CmisRuntimeException("Cannot parse this WSDL: " + wsdlUrl, se);
637         } catch (IOException ioe) {
638             throw new CmisRuntimeException("Cannot read this WSDL: " + wsdlUrl, ioe);
639         } finally {
640             IOUtils.closeQuietly(wsdlStream);
641         }
642     }
643 
644     /**
645      * Sets the default HTTP headers on a {@link BindingProvider} object.
646      */
647     protected void setHTTPHeaders(BindingProvider portObject, Map<String, List<String>> httpHeaders) {
648         if (httpHeaders == null) {
649             httpHeaders = new HashMap<String, List<String>>();
650         }
651 
652         // CMIS client header
653         httpHeaders.put("X-CMIS-Client", Collections.singletonList((String) session.get(SessionParameter.USER_AGENT,
654                 ClientVersion.OPENCMIS_USER_AGENT)));
655 
656         // compression
657         if (useCompression) {
658             httpHeaders.put("Accept-Encoding", Collections.singletonList("gzip"));
659         }
660 
661         // client compression
662         if (useClientCompression) {
663             httpHeaders.put("Content-Encoding", Collections.singletonList("gzip"));
664         }
665 
666         // locale
667         if (acceptLanguage != null) {
668             httpHeaders.put("Accept-Language", Collections.singletonList(acceptLanguage));
669         }
670 
671         portObject.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, httpHeaders);
672     }
673 
674     /**
675      * Sets the endpoint URL if the URL is not <code>null</code>.
676      */
677     protected void setEndpointUrl(BindingProvider portObject, URL endpointUrl) {
678         if (endpointUrl == null) {
679             return;
680         }
681 
682         portObject.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl.toString());
683     }
684 
685     /**
686      * Sets the SOAP Action header.
687      */
688     protected void setSoapAction(BindingProvider portObject, String soapAction, CmisVersion cmisVersion) {
689         portObject.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
690 
691         if (cmisVersion == CmisVersion.CMIS_1_0) {
692             portObject.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, "");
693         } else {
694             portObject.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, soapAction);
695         }
696     }
697 
698     /**
699      * Creates a simple port object from a CmisServiceHolder object.
700      */
701     protected BindingProvider createPortObjectFromServiceHolder(final CmisServiceHolder serviceHolder,
702             WebServiceFeature... features) throws Exception {
703         portObjectLock.lock();
704         try {
705             ArrayDeque<SoftReference<BindingProvider>> queue = portObjectCache.get(serviceHolder.getService());
706             if (queue == null) {
707                 queue = new ArrayDeque<SoftReference<BindingProvider>>();
708                 portObjectCache.put(serviceHolder.getService(), queue);
709             }
710 
711             while (!queue.isEmpty()) {
712                 BindingProvider bp = queue.pop().get();
713                 if (bp != null) {
714                     return bp;
715                 }
716             }
717         } finally {
718             portObjectLock.unlock();
719         }
720 
721         return (BindingProvider) serviceHolder.getServiceObject().getPort(serviceHolder.getService().getPortClass(),
722                 features);
723     }
724 
725     /**
726      * Creates a port object.
727      */
728     protected abstract BindingProvider createPortObject(CmisServiceHolder serviceHolder);
729 }