org.eclipse.lyo.client.oslc.OslcClient.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.lyo.client.oslc.OslcClient.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2013 IBM Corporation and others.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 *  
 *  The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 *  and the Eclipse Distribution License is available at
 *  http://www.eclipse.org/org/documents/edl-v10.php.
 *  
 *  Contributors:
 *  
 *     Michael Fiedler                 - initial API and implementation
 *     Lars Ohlen (Tieto Corporation)  - Resolved Bugzilla 393875,389275
 *     Michael Fiedler                  - follow redirects.
 *******************************************************************************/
package org.eclipse.lyo.client.oslc;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import net.oauth.OAuthException;
import net.oauth.client.httpclient4.HttpClientPool;

import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpHeaders;
import org.apache.http.protocol.HttpContext;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.wink.client.ClientConfig;
import org.apache.wink.client.ClientResponse;
import org.apache.wink.client.RestClient;
import org.apache.wink.client.httpclient.ApacheHttpClientConfig;
import org.eclipse.lyo.client.exception.ResourceNotFoundException;
import org.eclipse.lyo.client.oslc.resources.OslcQuery;
import org.eclipse.lyo.oslc4j.core.model.CreationFactory;
import org.eclipse.lyo.oslc4j.core.model.QueryCapability;
import org.eclipse.lyo.oslc4j.core.model.Service;
import org.eclipse.lyo.oslc4j.core.model.ServiceProvider;
import org.eclipse.lyo.oslc4j.core.model.ServiceProviderCatalog;
import org.eclipse.lyo.oslc4j.provider.jena.JenaProvidersRegistry;
import org.eclipse.lyo.oslc4j.provider.json4j.Json4JProvidersRegistry;

/**
 * An OSLC Client.  Provides an Apache HttpClient, an Apache Wink REST ClientConfig and defines
 * a getResource method which returns an Apache Wink ClientResponse.
 * 
 * This class is not currently thread safe.
 *
 */

public class OslcClient {

    protected DefaultHttpClient httpClient;
    private HttpClientPool clientPool;
    private ClientConfig clientConfig;

    private static final String SECURE_SOCKET_PROTOCOL[] = new String[] { "TLS", "SSL", "SSL_TLS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$  //$NON-NLS-4$

    /**
     * Initialize a new OslcClient using an Apache Http Components 4 Http client and configuration.
     */
    public OslcClient() {
        this((TrustManager[]) null, (X509HostnameVerifier) null);
    }

    /**
     * Initialize a new OslcClient using an Apache Http Components 4 Http client and configuration.
     * Use the provided TrustManagers and X509HostnameVerifiers instead of the defaults which do no verification;
     */
    public OslcClient(TrustManager[] trustManagers, X509HostnameVerifier hostnameVerifier) {
        httpClient = new DefaultHttpClient();
        httpClient.setRedirectStrategy(new RedirectStrategy() {
            public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) {
                return null;
            }

            public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) {
                return false;
            }
        });
        setupSSLSupport(trustManagers, hostnameVerifier);
        clientPool = new OAuthHttpPool();
        clientConfig = new ApacheHttpClientConfig(httpClient);
        javax.ws.rs.core.Application app = new javax.ws.rs.core.Application() {
            public Set<Class<?>> getClasses() {
                Set<Class<?>> classes = new HashSet<Class<?>>();
                classes.addAll(JenaProvidersRegistry.getProviders());
                classes.addAll(Json4JProvidersRegistry.getProviders());
                return classes;
            }
        };
        clientConfig = clientConfig.applications(app);

    }

    /**
     * Returns the HTTP client associated with this OSLC Client
     * @return the HTTP client
     */
    public HttpClient getHttpClient() {
        return httpClient;
    }

    protected HttpClientPool getClientPool() {
        return clientPool;
    }

    protected ClientConfig getClientConfig() {
        return clientConfig;
    }

    /**
     * Abstract method get an OSLC resource and return a Wink ClientResponse
     * @param url
     * @param method
     * @param mediaType
     * @return a Wink ClientResponse
     * @throws IOException
     * @throws OAuthException
     * @throws URISyntaxException
     */
    public ClientResponse getResource(String url, final String mediaType)
            throws IOException, OAuthException, URISyntaxException {

        ClientResponse response = null;
        RestClient restClient = new RestClient(clientConfig);
        boolean redirect = false;
        do {
            response = restClient.resource(url).accept(mediaType).header(OSLCConstants.OSLC_CORE_VERSION, "2.0")
                    .get();

            if ((response.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY)
                    || (response.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)) {
                url = response.getHeaders().getFirst("Location");
                response.consumeContent();
                redirect = true;
            } else {
                redirect = false;
            }
        } while (redirect);

        return response;
    }

    /**
     * Delete an OSLC resource and return a Wink ClientResponse
     * @param url
     * @return a Wink ClientResponse
     * @throws IOException
     * @throws OAuthException
     * @throws URISyntaxException
     */
    public ClientResponse deleteResource(String url) throws IOException, OAuthException, URISyntaxException {

        ClientResponse response = null;
        RestClient restClient = new RestClient(clientConfig);
        boolean redirect = false;

        do {
            response = restClient.resource(url).delete();

            if ((response.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY)
                    || (response.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)) {
                url = response.getHeaders().getFirst("Location");
                response.consumeContent();
                redirect = true;
            } else {
                redirect = false;
            }
        } while (redirect);

        return response;

    }

    /**
     * Create (POST) an artifact to a URL - usually an OSLC Creation Factory
     * @param url
     * @param artifact
     * @param mediaType
     * @return
     * @throws URISyntaxException 
     * @throws OAuthException 
     * @throws IOException 
     */
    public ClientResponse createResource(String url, final Object artifact, String mediaType)
            throws IOException, OAuthException, URISyntaxException {
        return createResource(url, artifact, mediaType, "*/*");
    }

    /**
     * Create (POST) an artifact to a URL - usually an OSLC Creation Factory
     * @param url
     * @param artifact
     * @param mediaType
     * @param acceptType
     * @return
     * @throws URISyntaxException 
     * @throws OAuthException 
     * @throws IOException 
     */
    public ClientResponse createResource(String url, final Object artifact, String mediaType, String acceptType)
            throws IOException, OAuthException, URISyntaxException {

        ClientResponse response = null;
        RestClient restClient = new RestClient(clientConfig);
        boolean redirect = false;

        do {
            response = restClient.resource(url).contentType(mediaType).accept(acceptType)
                    .header(OSLCConstants.OSLC_CORE_VERSION, "2.0").post(artifact);

            if ((response.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY)
                    || (response.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)) {
                url = response.getHeaders().getFirst("Location");
                response.consumeContent();
                redirect = true;
            } else {
                redirect = false;
            }
        } while (redirect);

        return response;
    }

    /**
     * Update (PUT) an artifact to a URL - usually the URL for an existing OSLC artifact
     * @param url
     * @param artifact
     * @param mediaType
     * @return
     */
    public ClientResponse updateResource(String url, final Object artifact, String mediaType) {

        return updateResource(url, artifact, mediaType, "*/*");
    }

    /**
     * Update (PUT) an artifact to a URL - usually the URL for an existing OSLC artifact
     * @param url
     * @param artifact
     * @param mediaType
     * @param acceptType
     * @return
     */
    public ClientResponse updateResource(String url, final Object artifact, String mediaType, String acceptType) {

        ClientResponse response = null;
        RestClient restClient = new RestClient(clientConfig);
        boolean redirect = false;

        do {
            response = restClient.resource(url).contentType(mediaType).accept(acceptType)
                    .header(OSLCConstants.OSLC_CORE_VERSION, "2.0").put(artifact);

            if ((response.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY)
                    || (response.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)) {
                url = response.getHeaders().getFirst("Location");
                response.consumeContent();
                redirect = true;
            } else {
                redirect = false;
            }
        } while (redirect);

        return response;
    }

    /**
     * Update (PUT) an artifact to a URL - usually the URL for an existing OSLC artifact
     * @param url
     * @param artifact
     * @param mediaType
     * @param acceptType
     * @return
     * @throws URISyntaxException 
     * @throws OAuthException 
     * @throws IOException 
     */
    public ClientResponse updateResource(String url, final Object artifact, String mediaType, String acceptType,
            String ifMatch) throws IOException, OAuthException, URISyntaxException {

        ClientResponse response = null;
        RestClient restClient = new RestClient(clientConfig);
        boolean redirect = false;

        do {
            response = restClient.resource(url).contentType(mediaType).accept(acceptType)
                    .header(OSLCConstants.OSLC_CORE_VERSION, "2.0").header(HttpHeaders.IF_MATCH, ifMatch)
                    .put(artifact);

            if ((response.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY)
                    || (response.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)) {
                url = response.getHeaders().getFirst("Location");
                response.consumeContent();
                redirect = true;
            } else {
                redirect = false;
            }
        } while (redirect);

        return response;
    }

    /**
     * Create a Wink Resource for the given OslcQuery object
     * @param query
     * @return
     */
    public org.apache.wink.client.Resource getQueryResource(final OslcQuery query) {
        RestClient restClient = new RestClient(clientConfig);
        org.apache.wink.client.Resource resource = restClient.resource(query.getCapabilityUrl());
        return resource;
    }

    protected class OAuthHttpPool implements HttpClientPool {
        public HttpClient getHttpClient(URL url) {
            return httpClient;
        }

    }

    /**
     * Lookup the URL of a specific OSLC Service Provider in an OSLC Catalog using the service provider's title
     * 
     * @param catalogUrl
     * @param serviceProviderTitle
     * @return
     * @throws IOException
     * @throws OAuthException
     * @throws URISyntaxException
     * @throws ResourceNotFoundException 
     */
    public String lookupServiceProviderUrl(final String catalogUrl, final String serviceProviderTitle)
            throws IOException, OAuthException, URISyntaxException, ResourceNotFoundException {
        String retval = null;
        ClientResponse response = getResource(catalogUrl, OSLCConstants.CT_RDF);
        ServiceProviderCatalog catalog = response.getEntity(ServiceProviderCatalog.class);

        if (catalog != null) {
            for (ServiceProvider sp : catalog.getServiceProviders()) {
                if (sp.getTitle() != null && sp.getTitle().equalsIgnoreCase(serviceProviderTitle)) {
                    retval = sp.getAbout().toString();
                    break;
                }

            }
        }

        if (retval == null) {
            throw new ResourceNotFoundException(catalogUrl, serviceProviderTitle);
        }

        return retval;
    }

    /**
     * Find the OSLC Query Capability URL for a given OSLC resource type.  If no resource type is given, returns
     * the default Query Capability, if it exists.
     *
     * @param serviceProviderUrl
     * @param oslcDomain
     * @param oslcResourceType - the resource type of the desired query capability.   This may differ from the OSLC artifact type.
     * @return URL of requested Query Capablility or null if not found.
     * @throws IOException
     * @throws OAuthException
     * @throws URISyntaxException
     * @throws ResourceNotFoundException 
     */
    public String lookupQueryCapability(final String serviceProviderUrl, final String oslcDomain,
            final String oslcResourceType)
            throws IOException, OAuthException, URISyntaxException, ResourceNotFoundException {
        QueryCapability defaultQueryCapability = null;
        QueryCapability firstQueryCapability = null;

        ClientResponse response = getResource(serviceProviderUrl, OSLCConstants.CT_RDF);
        ServiceProvider serviceProvider = response.getEntity(ServiceProvider.class);

        if (serviceProvider != null) {
            for (Service service : serviceProvider.getServices()) {
                URI domain = service.getDomain();
                if (domain != null && domain.toString().equals(oslcDomain)) {
                    QueryCapability[] queryCapabilities = service.getQueryCapabilities();
                    if (queryCapabilities != null && queryCapabilities.length > 0) {
                        firstQueryCapability = queryCapabilities[0];
                        for (QueryCapability queryCapability : service.getQueryCapabilities()) {
                            for (URI resourceType : queryCapability.getResourceTypes()) {

                                //return as soon as domain + resource type are matched
                                if (resourceType.toString() != null
                                        && resourceType.toString().equals(oslcResourceType)) {
                                    return queryCapability.getQueryBase().toString();
                                }
                            }
                            //Check if this is the default capability
                            for (URI usage : queryCapability.getUsages()) {
                                if (usage.toString() != null
                                        && usage.toString().equals(OSLCConstants.USAGE_DEFAULT_URI)) {
                                    defaultQueryCapability = queryCapability;
                                }
                            }
                        }
                    }
                }
            }
        }

        //If we reached this point, there was no resource type match
        if (defaultQueryCapability != null) {
            //return default, if present
            return defaultQueryCapability.getQueryBase().toString();
        } else if (firstQueryCapability != null && firstQueryCapability.getResourceTypes().length == 0) {
            //return the first for the domain, if present
            return firstQueryCapability.getQueryBase().toString();
        }

        throw new ResourceNotFoundException(serviceProviderUrl, "QueryCapability");
    }

    /**
     * Find the OSLC Creation Factory URL for a given OSLC resource type.  If no resource type is given, returns
     * the default Creation Factory, if it exists.  
     *
     * @param serviceProviderUrl
     * @param oslcDomain
     * @param oslcResourceType - the resource type of the desired query capability.   This may differ from the OSLC artifact type.
     * @return URL of requested Creation Factory or null if not found.
     * @throws IOException
     * @throws OAuthException
     * @throws URISyntaxException
     * @throws ResourceNotFoundException 
     */
    public String lookupCreationFactory(final String serviceProviderUrl, final String oslcDomain,
            final String oslcResourceType)
            throws IOException, OAuthException, URISyntaxException, ResourceNotFoundException {
        CreationFactory defaultCreationFactory = null;
        CreationFactory firstCreationFactory = null;

        ClientResponse response = getResource(serviceProviderUrl, OSLCConstants.CT_RDF);
        ServiceProvider serviceProvider = response.getEntity(ServiceProvider.class);

        if (serviceProvider != null) {
            for (Service service : serviceProvider.getServices()) {
                URI domain = service.getDomain();
                if (domain != null && domain.toString().equals(oslcDomain)) {
                    CreationFactory[] creationFactories = service.getCreationFactories();
                    if (creationFactories != null && creationFactories.length > 0) {
                        firstCreationFactory = creationFactories[0];
                        for (CreationFactory creationFactory : creationFactories) {
                            for (URI resourceType : creationFactory.getResourceTypes()) {

                                //return as soon as domain + resource type are matched
                                if (resourceType.toString() != null
                                        && resourceType.toString().equals(oslcResourceType)) {
                                    return creationFactory.getCreation().toString();
                                }
                            }
                            //Check if this is the default factory
                            for (URI usage : creationFactory.getUsages()) {
                                if (usage.toString() != null
                                        && usage.toString().equals(OSLCConstants.USAGE_DEFAULT_URI)) {
                                    defaultCreationFactory = creationFactory;
                                }
                            }
                        }
                    }
                }
            }
        }

        //If we reached this point, there was no resource type match
        if (defaultCreationFactory != null) {
            //return default, if present
            return defaultCreationFactory.getCreation().toString();
        } else if (firstCreationFactory != null && firstCreationFactory.getResourceTypes().length == 0) {
            //return the first for the domain, if present
            return firstCreationFactory.getCreation().toString();
        }

        throw new ResourceNotFoundException(serviceProviderUrl, "CreationFactory");
    }

    /**
     * Looks up and select an installed security context provider
     *  
     * @return An installed SSLContext Provider
     * @throws NoSuchAlgorithmException when no suitable provider is installed
     */
    private SSLContext findInstalledSecurityContext() throws NoSuchAlgorithmException {

        // walks through list of secure socked protocols and picks the first found
        // the list is arranged in level of security order
        for (String aSecuredProtocol : SECURE_SOCKET_PROTOCOL) {
            try {
                return SSLContext.getInstance(aSecuredProtocol);
            } catch (NoSuchAlgorithmException e) {
                continue;
            }
        }

        throw new NoSuchAlgorithmException("No suitable secured socket provider is installed"); //$NON-NLS-1$
    }

    private void setupSSLSupport(TrustManager[] trustManagers, X509HostnameVerifier hostnameVerifier) {
        ClientConnectionManager connManager = httpClient.getConnectionManager();
        SchemeRegistry schemeRegistry = connManager.getSchemeRegistry();
        schemeRegistry.unregister("https");
        /** Create a trust manager that does not validate certificate chains */
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
                /** Ignore Method Call */
            }

            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
                /** Ignore Method Call */
            }

            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        } };

        try {
            SSLContext sc = findInstalledSecurityContext();
            if (trustManagers == null) {
                trustManagers = trustAllCerts;
            }
            if (hostnameVerifier == null) {
                hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
            }
            sc.init(null, trustManagers, new java.security.SecureRandom());
            SSLSocketFactory sf = new SSLSocketFactory(sc, hostnameVerifier);
            Scheme https = new Scheme("https", 443, sf); //$NON-NLS-1$
            schemeRegistry.register(https);
        } catch (NoSuchAlgorithmException e) {
            /* Fail Silently */
        } catch (KeyManagementException e) {
            /* Fail Silently */
        }

    }

}