View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2016 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.caravan.jaxws.consumer.impl;
21  
22  import java.util.concurrent.ConcurrentHashMap;
23  
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.cxf.BusFactory;
26  import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
27  import org.osgi.framework.BundleContext;
28  import org.osgi.framework.BundleEvent;
29  import org.osgi.framework.BundleListener;
30  import org.osgi.service.component.annotations.Activate;
31  import org.osgi.service.component.annotations.Component;
32  import org.osgi.service.component.annotations.Deactivate;
33  
34  import io.wcm.caravan.jaxws.consumer.JaxWsClientFactory;
35  import io.wcm.caravan.jaxws.consumer.JaxWsClientInitializer;
36  
37  /**
38   * Factory for creating initializing JAX-WS SOAP clients.
39   */
40  @Component(immediate = true, service = JaxWsClientFactory.class)
41  public final class JaxWsClientFactoryImpl implements JaxWsClientFactory, BundleListener {
42  
43    // cache proxy factor beans per port class/url and initializer class
44    private ConcurrentHashMap<String, ConcurrentHashMap<JaxWsClientInitializer, Object>> cacheMap;
45  
46    @Activate
47    protected void activate(BundleContext bundleContext) {
48      bundleContext.addBundleListener(this);
49      cacheMap = new ConcurrentHashMap<String, ConcurrentHashMap<JaxWsClientInitializer, Object>>();
50    }
51  
52    @Deactivate
53    protected void deactivate(BundleContext bundleContext) {
54      bundleContext.removeBundleListener(this);
55      cacheMap = null;
56    }
57  
58    @Override
59    public <T> T create(Class<T> clazz, String portUrl) {
60      return create(clazz, portUrl, new JaxWsClientInitializer());
61    }
62  
63    @Override
64    public <T> T create(Class<T> clazz, String portUrl, JaxWsClientInitializer initializer) {
65      return create(clazz, portUrl, initializer, null);
66    }
67  
68    @Override
69    @SuppressWarnings("unchecked")
70    public <T> T create(Class<T> clazz, String portUrl, JaxWsClientInitializer initializer, String cacheKeySuffix) {
71      if (StringUtils.isEmpty(portUrl)) {
72        throw new IllegalArgumentException("Missing port url");
73      }
74      if (initializer == null) {
75        throw new IllegalArgumentException("Missing initialize instance.");
76      }
77  
78      // build key for port class and port url for cache map access
79      String key = clazz.getName() + "#" + portUrl
80          + (StringUtils.isNotEmpty(cacheKeySuffix) ? "#" + cacheKeySuffix : "");
81  
82      // try to get existing port object from cache
83      T portObject = null;
84      ConcurrentHashMap<JaxWsClientInitializer, Object> innerCacheMap = cacheMap.get(key);
85      if (innerCacheMap != null) {
86        portObject = (T)innerCacheMap.get(initializer);
87      }
88  
89      // if no port object found create new factory and port object instance and put it to cache
90      if (portObject == null) {
91        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
92        try {
93          // set classloader to CXF bundle class loader to avoid OSGI classloader problems
94          Thread.currentThread().setContextClassLoader(BusFactory.class.getClassLoader());
95  
96          // initialize factory and crate port object
97          JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(initializer.createClientFactoryBean());
98          factory.setServiceClass(clazz);
99          factory.setAddress(portUrl);
100         initializer.initializeFactory(factory);
101         portObject = (T)initializer.createClient(factory);
102 
103         // put to cache
104         if (innerCacheMap == null) {
105           innerCacheMap = new ConcurrentHashMap<JaxWsClientInitializer, Object>();
106           cacheMap.put(key, innerCacheMap);
107         }
108         innerCacheMap.put(initializer, portObject);
109 
110       }
111       finally {
112         Thread.currentThread().setContextClassLoader(oldClassLoader);
113       }
114     }
115 
116     // return port object/proxy client
117     return portObject;
118   }
119 
120   /**
121    * Bundle changed
122    */
123   @Override
124   public void bundleChanged(BundleEvent event) {
125     // clear all cache if any bundle changes
126     if (cacheMap != null) {
127       cacheMap.clear();
128     }
129   }
130 
131 }