org.pentaho.di.repository.pur.WebServiceManager.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.repository.pur.WebServiceManager.java

Source

/*!
 * Copyright 2010 - 2015 Pentaho Corporation.  All rights reserved.
 *
 * 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.
 *
 */
package org.pentaho.di.repository.pur;

import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.soap.SOAPBinding;

import org.apache.commons.lang.StringUtils;
import org.pentaho.di.core.util.ExecutorUtil;
import org.pentaho.di.repository.pur.WebServiceSpecification.ServiceType;
import org.pentaho.platform.repository2.unified.webservices.jaxws.IUnifiedRepositoryJaxwsWebService;
import org.pentaho.platform.security.policy.rolebased.ws.IAuthorizationPolicyWebService;
import org.pentaho.platform.security.policy.rolebased.ws.IRoleAuthorizationPolicyRoleBindingDaoWebService;
import org.pentaho.platform.security.userrole.ws.IUserRoleListWebService;
import org.pentaho.platform.security.userroledao.ws.IUserRoleWebService;

import com.pentaho.di.services.PentahoDiPlugin;
import com.pentaho.pdi.ws.IRepositorySyncWebService;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.xml.ws.developer.JAXWSProperties;

/**
 * Web service factory. Not a true factory in that the things that this factory can create are not configurable. But it
 * does cache the services.
 * 
 * @author mlowery
 */
public class WebServiceManager implements ServiceManager {

    /**
     * Header name must match that specified in ProxyTrustingFilter. Note that an header has the following form: initial
     * capital letter followed by all lowercase letters.
     */
    private static final String TRUST_USER = "_trust_user_"; //$NON-NLS-1$

    private static final String NAMESPACE_URI = "http://www.pentaho.org/ws/1.0"; //$NON-NLS-1$

    private static final ExecutorService executor = ExecutorUtil.getExecutor();

    private final Map<String, Future<Object>> serviceCache = new HashMap<String, Future<Object>>();

    private final Map<Class<?>, WebServiceSpecification> serviceNameMap;

    private final String baseUrl;

    private final String lastUsername;

    private Map<Class<?>, WebServiceSpecification> tempServiceNameMap; // hold the map while building

    public WebServiceManager(String baseUrl, String username) {
        this.baseUrl = baseUrl;
        this.lastUsername = username;
        tempServiceNameMap = new HashMap<Class<?>, WebServiceSpecification>();
        registerWsSpecification(IUnifiedRepositoryJaxwsWebService.class, "unifiedRepository"); //$NON-NLS-1$
        registerWsSpecification(IRepositorySyncWebService.class, "repositorySync"); //$NON-NLS-1$
        registerWsSpecification(IUserRoleListWebService.class, "userRoleListService"); //$NON-NLS-1$
        registerWsSpecification(IUserRoleWebService.class, "userRoleService"); //$NON-NLS-1$
        registerWsSpecification(IRoleAuthorizationPolicyRoleBindingDaoWebService.class, "roleBindingDao"); //$NON-NLS-1$
        registerWsSpecification(IAuthorizationPolicyWebService.class, "authorizationPolicy"); //$NON-NLS-1$

        registerRestSpecification(PentahoDiPlugin.PurRepositoryPluginApiRevision.class,
                "purRepositoryPluginApiRevision"); //$NON-NLS-1$

        this.serviceNameMap = Collections.unmodifiableMap(tempServiceNameMap);
        tempServiceNameMap = null;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T createService(final String username, final String password, final Class<T> clazz)
            throws MalformedURLException {
        final Future<Object> resultFuture;
        synchronized (serviceCache) {
            // if this is true, a coder did not make sure that clearServices was called on disconnect
            if (lastUsername != null && !lastUsername.equals(username)) {
                throw new IllegalStateException();
            }

            final WebServiceSpecification webServiceSpecification = serviceNameMap.get(clazz);
            final String serviceName = webServiceSpecification.getServiceName();
            if (serviceName == null) {
                throw new IllegalStateException();
            }

            if (webServiceSpecification.getServiceType().equals(ServiceType.JAX_WS)) {
                // build the url handling whether or not baseUrl ends with a slash
                // String baseUrl = repositoryMeta.getRepositoryLocation().getUrl();
                final URL url = new URL(
                        baseUrl + (baseUrl.endsWith("/") ? "" : "/") + "webservices/" + serviceName + "?wsdl"); //$NON-NLS-1$ //$NON-NLS-2$

                String key = url.toString() + '_' + serviceName + '_' + clazz.getName();
                if (!serviceCache.containsKey(key)) {
                    resultFuture = executor.submit(new Callable<Object>() {

                        @Override
                        public Object call() throws Exception {
                            Service service = Service.create(url, new QName(NAMESPACE_URI, serviceName));
                            T port = service.getPort(clazz);
                            // add TRUST_USER if necessary
                            if (StringUtils
                                    .isNotBlank(System.getProperty("pentaho.repository.client.attemptTrust"))) {
                                ((BindingProvider) port).getRequestContext().put(
                                        MessageContext.HTTP_REQUEST_HEADERS,
                                        Collections.singletonMap(TRUST_USER, Collections.singletonList(username)));
                            } else {
                                // http basic authentication
                                ((BindingProvider) port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY,
                                        username);
                                ((BindingProvider) port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,
                                        password);
                            }
                            // accept cookies to maintain session on server
                            ((BindingProvider) port).getRequestContext()
                                    .put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);
                            // support streaming binary data
                            // TODO mlowery this is not portable between JAX-WS implementations (uses com.sun)
                            ((BindingProvider) port).getRequestContext()
                                    .put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
                            SOAPBinding binding = (SOAPBinding) ((BindingProvider) port).getBinding();
                            binding.setMTOMEnabled(true);
                            return port;
                        }
                    });
                    serviceCache.put(key, resultFuture);
                } else {
                    resultFuture = serviceCache.get(key);
                }
            } else {
                if (webServiceSpecification.getServiceType().equals(ServiceType.JAX_RS)) {

                    String key = baseUrl.toString() + '_' + serviceName + '_' + clazz.getName();
                    if (!serviceCache.containsKey(key)) {

                        resultFuture = executor.submit(new Callable<Object>() {

                            @Override
                            public Object call() throws Exception {
                                ClientConfig clientConfig = new DefaultClientConfig();
                                Client client = Client.create(clientConfig);
                                client.addFilter(new HTTPBasicAuthFilter(username, password));

                                Class<?>[] parameterTypes = new Class<?>[] { Client.class, URI.class };
                                String factoryClassName = webServiceSpecification.getServiceClass().getName();
                                factoryClassName = factoryClassName.substring(0, factoryClassName.lastIndexOf("$"));
                                Class<?> factoryClass = Class.forName(factoryClassName);
                                Method method = factoryClass.getDeclaredMethod(
                                        webServiceSpecification.getServiceName(), parameterTypes);
                                T port = (T) method.invoke(null,
                                        new Object[] { client, new URI(baseUrl + "/plugin") });

                                return port;
                            }
                        });
                        serviceCache.put(key, resultFuture);
                    } else {
                        resultFuture = serviceCache.get(key);
                    }
                } else {
                    resultFuture = null;
                }
            }

            try {
                if (clazz.isInterface()) {
                    return UnifiedRepositoryInvocationHandler.forObject((T) resultFuture.get(), clazz);
                } else {
                    return (T) resultFuture.get();
                }

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                Throwable cause = e.getCause();
                if (cause != null) {
                    if (cause instanceof RuntimeException) {
                        throw (RuntimeException) cause;
                    } else if (cause instanceof MalformedURLException) {
                        throw (MalformedURLException) cause;
                    }
                }
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public synchronized void close() {
        serviceCache.clear();
    }

    private void registerWsSpecification(Class<?> serviceClass, String serviceName) {
        registerSpecification(WebServiceSpecification.getWsServiceSpecification(serviceClass, serviceName));
    }

    private void registerRestSpecification(Class<?> serviceClass, String serviceName) {
        try {
            registerSpecification(WebServiceSpecification.getRestServiceSpecification(serviceClass, serviceName));
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void registerSpecification(WebServiceSpecification webServiceSpecification) {
        tempServiceNameMap.put(webServiceSpecification.getServiceClass(), webServiceSpecification);
    }

}