/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.webservices;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import nl.strohalm.cyclos.webservices.access.AccessWebService;
import nl.strohalm.cyclos.webservices.accounts.AccountWebService;
import nl.strohalm.cyclos.webservices.ads.AdWebService;
import nl.strohalm.cyclos.webservices.fields.FieldWebService;
import nl.strohalm.cyclos.webservices.infotexts.InfoTextWebService;
import nl.strohalm.cyclos.webservices.members.MemberWebService;
import nl.strohalm.cyclos.webservices.payments.PaymentWebService;
import nl.strohalm.cyclos.webservices.pos.PosWebService;
import nl.strohalm.cyclos.webservices.sms.SmsWebService;
import nl.strohalm.cyclos.webservices.webshop.WebShopWebService;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.BusFactory;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transport.http.auth.DefaultBasicAuthSupplier;
/**
* A class capable of generating proxies to the various Cyclos web services
*
* @author luis
*/
public class CyclosWebServicesClientFactory implements Serializable {
private static final long serialVersionUID = 8877667897548825737L;
private static final Map<Class<?>, String> SERVICES;
static {
final Map<Class<?>, String> services = new HashMap<Class<?>, String>();
services.put(MemberWebService.class, "members");
services.put(AdWebService.class, "ads");
services.put(FieldWebService.class, "fields");
services.put(WebShopWebService.class, "webshop");
services.put(AccessWebService.class, "access");
services.put(AccountWebService.class, "account");
services.put(PaymentWebService.class, "payment");
services.put(PosWebService.class, "pos");
services.put(SmsWebService.class, "sms");
services.put(InfoTextWebService.class, "infoTexts");
SERVICES = Collections.unmodifiableMap(services);
}
public static Class<?> serviceInterfaceForName(final String name) {
for (final Map.Entry<Class<?>, String> entry : SERVICES.entrySet()) {
if (entry.getValue().equals(name)) {
return entry.getKey();
}
}
return null;
}
private transient Map<Class<?>, Object> cachedProxies = new HashMap<Class<?>, Object>();
private String serverRootUrl;
private String username;
private String password;
/**
* Indicates whether that the hostname given in the HTTPS URL will be checked against the service's Common Name (CN) given in its certificate
* during SOAP client requests NOT recommended for production time
*/
private boolean disableCNCheck;
/**
* Used to connect to servers with self-signed certificates (not issued by a CA) You can set this to true or set the following system properties
* (-D):
* <ul>
* <li>javax.net.ssl.trustStore (the path to the keystore containing the certificate)
* <li>javax.net.ssl.trustStorePassword (the keystore password to open the keystore)
* </ul>
*/
private boolean trustAllCerts;
/**
* Set the read timeout value in milliseconds. A timeout of zero is interpreted as an infinite timeout Defaults to 60000 ms
*/
private long readTimeout = 60000L;
/**
* Set the connection timeout value in milliseconds. A timeout of zero is interpreted as an infinite timeout Defaults to 60000 ms
*/
private long connectionTimeout = 60000L;
/**
* Empty constructor
*/
public CyclosWebServicesClientFactory() {
}
/**
* Constructs the factory with the server root url
*/
public CyclosWebServicesClientFactory(final String serverRootUrl) {
setServerRootUrl(serverRootUrl);
}
/**
* Constructs the factory with the server root url and credentials
*/
public CyclosWebServicesClientFactory(final String serverRootUrl, final String username, final String password) {
this(serverRootUrl);
setUsername(username);
setPassword(password);
}
/**
* Returns a proxy for the accounts web service
*/
public AccessWebService getAccessWebService() {
return proxyFor(AccessWebService.class);
}
/**
* Returns a proxy for the account web service
*/
public AccountWebService getAccountWebService() {
return proxyFor(AccountWebService.class);
}
/**
* Returns a proxy for the ads web service
*/
public AdWebService getAdWebService() {
return proxyFor(AdWebService.class);
}
public long getConnectionTimeout() {
return connectionTimeout;
}
/**
* Returns a proxy for the fields web service
*/
public FieldWebService getFieldWebService() {
return proxyFor(FieldWebService.class);
}
/**
* Returns a proxy for the info text web service
*/
public InfoTextWebService getInfoTextWebService() {
return proxyFor(InfoTextWebService.class);
}
/**
* Returns a proxy for the members web service
*/
public MemberWebService getMemberWebService() {
return proxyFor(MemberWebService.class);
}
/**
* Returns a proxy for the payment web service
*/
public PaymentWebService getPaymentWebService() {
return proxyFor(PaymentWebService.class);
}
/**
* Returns a proxy for the pos web service
*/
public PosWebService getPosWebService() {
return proxyFor(PosWebService.class);
}
public long getReadTimeout() {
return readTimeout;
}
/**
* Returns a proxy for the sms web service
*/
public SmsWebService getSmsWebService() {
return proxyFor(SmsWebService.class);
}
/**
* Returns a proxy for the web shop web service
*/
public WebShopWebService getWebShopWebService() {
return proxyFor(WebShopWebService.class);
}
/**
* Creates a proxy for the given interface without
* @param <T> The type bound to the service interface
* @param serviceInterface The service interface
* @return The proxy for the given interface
*/
@SuppressWarnings("unchecked")
public synchronized <T> T proxyFor(final Class<T> serviceInterface) {
// Check for a cached instance
final Object cached = cachedProxies.get(serviceInterface);
if (cached != null) {
return (T) cached;
}
// Cache miss. Create the proxy
final String url = resolveUrlFor(serviceInterface);
if (url == null) {
throw new IllegalStateException("Cannot resolve url for service " + serviceInterface.getName() + " for server root url " + serverRootUrl);
}
// Create a proxy factory
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(serviceInterface);
factory.setAddress(url);
// Create the proxy
final Object proxy = factory.create();
final Client client = ClientProxy.getClient(proxy);
final HTTPConduit http = (HTTPConduit) client.getConduit();
// If the username / password are set, use them
if (username != null || password != null) {
final AuthorizationPolicy authorization = new AuthorizationPolicy();
authorization.setUserName(username);
authorization.setPassword(password);
http.setAuthorization(authorization);
http.setAuthSupplier(new DefaultBasicAuthSupplier());
}
http.setTlsClientParameters(getTLSClientParameters());
http.getClient().setConnectionTimeout(connectionTimeout);
http.getClient().setReceiveTimeout(readTimeout);
// The proxy is ready. Store it on the cache
cachedProxies.put(serviceInterface, proxy);
return (T) proxy;
}
/**
* Resolves the service url for the given interface
*/
public String resolveUrlFor(final Class<?> serviceInterface) {
final String service = SERVICES.get(serviceInterface);
if (serverRootUrl == null || service == null) {
throw new IllegalArgumentException("Unknown web service interface: " + serviceInterface.getName());
}
return serverRootUrl + "/services/" + service;
}
public void setConnectionTimeout(final long connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public void setDisableCNCheck(final boolean disableCNCheck) {
this.disableCNCheck = disableCNCheck;
}
/**
* Sets the service client password
*/
public void setPassword(final String password) {
this.password = StringUtils.trimToNull(password);
invalidateCache();
}
public void setReadTimeout(final long readTimeout) {
this.readTimeout = readTimeout;
}
/**
* Sets the server root url
*/
public void setServerRootUrl(final String serverRootUrl) {
this.serverRootUrl = StringUtils.trimToNull(serverRootUrl);
// Remove the trailing slash, if any
if (this.serverRootUrl != null && this.serverRootUrl.endsWith("/")) {
this.serverRootUrl = this.serverRootUrl.substring(0, this.serverRootUrl.length() - 1);
}
invalidateCache();
}
public void setTrustAllCerts(final boolean trustAllCerts) {
this.trustAllCerts = trustAllCerts;
}
/**
* Sets the service client username
*/
public void setUsername(final String username) {
this.username = StringUtils.trimToNull(username);
invalidateCache();
}
/**
*
*/
public void shutdown() {
for (final Object proxy : cachedProxies.values()) {
try {
final Client client = ClientProxy.getClient(proxy);
client.destroy();
} catch (final Exception e) {
// Ignore
}
}
cachedProxies.clear();
BusFactory.getDefaultBus().shutdown(true);
}
private TLSClientParameters getTLSClientParameters() {
final TLSClientParameters tlsCP = new TLSClientParameters();
if (trustAllCerts) {
final TrustManager[] myTrustStoreKeyManagers = getTrustManagers();
tlsCP.setTrustManagers(myTrustStoreKeyManagers);
}
tlsCP.setDisableCNCheck(disableCNCheck);
return tlsCP;
}
private TrustManager[] getTrustManagers() {
final TrustManager[] trustManagers = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
}
@Override
public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
} };
return trustManagers;
}
/**
* Invalidate the cache proxies
*/
private void invalidateCache() {
cachedProxies.clear();
}
}