JaxWsClientFactoryImpl.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2016 wcm.io
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package io.wcm.caravan.jaxws.consumer.impl;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.BusFactory;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import io.wcm.caravan.jaxws.consumer.JaxWsClientFactory;
import io.wcm.caravan.jaxws.consumer.JaxWsClientInitializer;
/**
* Factory for creating initializing JAX-WS SOAP clients.
*/
@Component(immediate = true, service = JaxWsClientFactory.class)
public final class JaxWsClientFactoryImpl implements JaxWsClientFactory, BundleListener {
// cache proxy factor beans per port class/url and initializer class
private ConcurrentHashMap<String, ConcurrentHashMap<JaxWsClientInitializer, Object>> cacheMap;
@Activate
protected void activate(BundleContext bundleContext) {
bundleContext.addBundleListener(this);
cacheMap = new ConcurrentHashMap<String, ConcurrentHashMap<JaxWsClientInitializer, Object>>();
}
@Deactivate
protected void deactivate(BundleContext bundleContext) {
bundleContext.removeBundleListener(this);
cacheMap = null;
}
@Override
public <T> T create(Class<T> clazz, String portUrl) {
return create(clazz, portUrl, new JaxWsClientInitializer());
}
@Override
public <T> T create(Class<T> clazz, String portUrl, JaxWsClientInitializer initializer) {
return create(clazz, portUrl, initializer, null);
}
@Override
@SuppressWarnings("unchecked")
public <T> T create(Class<T> clazz, String portUrl, JaxWsClientInitializer initializer, String cacheKeySuffix) {
if (StringUtils.isEmpty(portUrl)) {
throw new IllegalArgumentException("Missing port url");
}
if (initializer == null) {
throw new IllegalArgumentException("Missing initialize instance.");
}
// build key for port class and port url for cache map access
String key = clazz.getName() + "#" + portUrl
+ (StringUtils.isNotEmpty(cacheKeySuffix) ? "#" + cacheKeySuffix : "");
// try to get existing port object from cache
T portObject = null;
ConcurrentHashMap<JaxWsClientInitializer, Object> innerCacheMap = cacheMap.get(key);
if (innerCacheMap != null) {
portObject = (T)innerCacheMap.get(initializer);
}
// if no port object found create new factory and port object instance and put it to cache
if (portObject == null) {
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
try {
// set classloader to CXF bundle class loader to avoid OSGI classloader problems
Thread.currentThread().setContextClassLoader(BusFactory.class.getClassLoader());
// initialize factory and crate port object
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(initializer.createClientFactoryBean());
factory.setServiceClass(clazz);
factory.setAddress(portUrl);
initializer.initializeFactory(factory);
portObject = (T)initializer.createClient(factory);
// put to cache
if (innerCacheMap == null) {
innerCacheMap = new ConcurrentHashMap<JaxWsClientInitializer, Object>();
cacheMap.put(key, innerCacheMap);
}
innerCacheMap.put(initializer, portObject);
}
finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
}
// return port object/proxy client
return portObject;
}
/**
* Bundle changed
*/
@Override
public void bundleChanged(BundleEvent event) {
// clear all cache if any bundle changes
if (cacheMap != null) {
cacheMap.clear();
}
}
}