mitm.common.ws.AbstractWSProxyFactory.java Source code

Java tutorial

Introduction

Here is the source code for mitm.common.ws.AbstractWSProxyFactory.java

Source

/*
 * Copyright (c) 2008-2011, Martijn Brinkers, Djigzo.
 * 
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3, 19 November 2007 as published by the Free Software 
 * Foundation.
 *
 * Djigzo 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public 
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 * 
 * If you modify this Program, or any covered work, by linking or 
 * combining it with saaj-api-1.3.jar, saaj-impl-1.3.jar, 
 * wsdl4j-1.6.1.jar (or modified versions of these libraries), 
 * containing parts covered by the terms of Common Development and 
 * Distribution License (CDDL), Common Public License (CPL) the 
 * licensors of this Program grant you additional permission to 
 * convey the resulting work.
 */
package mitm.common.ws;

import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;

import org.apache.commons.lang.time.DateUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.handler.WSHandlerConstants;

/**
 * Base class for Webservice factories. This class is abstract because it must not be instantiated
 * but only extended. This is required because we need the class for the webservice 
 * (see persistentClass).
 * 
 * @author Martijn Brinkers
 *
 * @param <T>
 */
public abstract class AbstractWSProxyFactory<T> implements WSProxyFactory<T> {
    private final static long DEFAULT_RECEIVE_TIMEOUT = 5 * DateUtils.MILLIS_PER_MINUTE;

    private final static long DEFAULT_CONNECT_TIMEOUT = 30 * DateUtils.MILLIS_PER_SECOND;

    private final static String PASSWORD_FIELD = "password";

    private final Class<T> persistentClass;

    /*
     * URL of the WSDL.
     */
    private final URL wsdlURL;

    /*
     * Namespace of the service
     */
    private final String nsURI;

    /*
     * Local part of the service
     */
    private final String localPart;

    /*
     * SOAP receive timeout 
     */
    private long receiveTimeOut = DEFAULT_RECEIVE_TIMEOUT;

    /*
     * SOAP connection timeout 
     */
    private long connectTimeOut = DEFAULT_CONNECT_TIMEOUT;

    /*
     * The SOAP password mode to use
     */
    private SOAPPasswordMode passwordMode = SOAPPasswordMode.DIGEST;

    private T proxy;

    @SuppressWarnings("unchecked")
    public AbstractWSProxyFactory(URL wsdlURL, String nsURI, String localPart) {
        this.wsdlURL = wsdlURL;
        this.nsURI = nsURI;
        this.localPart = localPart;

        this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }

    private T internalCreateProxy() {
        QName SERVICE_NAME = new QName(nsURI, localPart);
        Service service = Service.create(wsdlURL, SERVICE_NAME);

        T proxy = service.getPort(persistentClass);

        /*
         * Make request context multithread safe. See http://markmail.org/message/lgldei2zt4trlyr6
         */
        ((BindingProvider) proxy).getRequestContext().put("thread.local.request.context", Boolean.TRUE);

        Client client = ClientProxy.getClient(proxy);

        HTTPConduit http = (HTTPConduit) client.getConduit();

        HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();

        httpClientPolicy.setConnectionTimeout(connectTimeOut);
        httpClientPolicy.setReceiveTimeout(receiveTimeOut);

        http.setClient(httpClientPolicy);

        Endpoint endpoint = client.getEndpoint();

        Map<String, Object> outProps = new HashMap<String, Object>();

        outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        outProps.put(WSHandlerConstants.PASSWORD_TYPE, passwordMode.getMode());

        WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
        endpoint.getOutInterceptors().add(wssOut);

        return proxy;
    }

    @Override
    public synchronized T createProxy(Credential credential) throws WSProxyFactoryException {
        if (proxy == null) {
            proxy = internalCreateProxy();
        }

        if (!(proxy instanceof BindingProvider)) {
            throw new WSProxyFactoryException("The proxy does not implement BindingProvider");
        }

        Map<String, Object> requestContext = ((BindingProvider) proxy).getRequestContext();

        /*
         * Make request context multithread safe. See http://markmail.org/message/lgldei2zt4trlyr6.
         * I'm not sure if I have to call it for every invocation but according to this post it 
         * should: 
         * http://www.nabble.com/Re%3A-Need-help-on-OutInterceptors%2C-authentiction-and-multiple-threads-p17866587.html
         */
        requestContext.put("thread.local.request.context", Boolean.TRUE);

        requestContext.put(WSHandlerConstants.USER, credential.getUsername());
        requestContext.put(PASSWORD_FIELD, credential.getPassword());

        return proxy;
    }

    public SOAPPasswordMode getPasswordMode() {
        return passwordMode;
    }

    public void setPasswordMode(SOAPPasswordMode passwordMode) {
        this.passwordMode = passwordMode;
    }
}