org.eclipse.lyo.testsuite.server.trsutils.FetchUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.lyo.testsuite.server.trsutils.FetchUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2013 IBM Corporation.
 *
 * 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:
 * 
 *    Joseph Leong, Sujeet Mishra - Initial implementation
 *******************************************************************************/

package org.eclipse.lyo.testsuite.server.trsutils;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Properties;

import javax.ws.rs.HttpMethod;

import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthServiceProvider;

import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.protocol.HttpContext;
import org.apache.xerces.impl.dv.util.Base64;
import org.eclipse.lyo.core.trs.HttpConstants;

import com.hp.hpl.jena.rdf.model.Model;

/**
 * A class that provides a utility methods to fetch HTTP resources as well as
 * process fetch responses
 */
public class FetchUtil {
    /**
     * Fetches a resource. In case of success, this method
     * returns an instance of the {@link Model}. 
     * 
     * @param uri
     *            resource uri to fetch
     * @param httpClient
     *            client used to fetch the resource
     * @param httpContext
     *            http context to use for the call
     * @param acceptType 
     *            value to use in the accept header
     * @throws InterruptedException
     *             if the thread is interrupted
     * @throws FetchException
     *             if an error occurs while fetching the resource.
     * @throws IOException
     *             if an error occurs while updating the retryable error
     *             information into the error handler
     */
    public static Model fetchResource(String uri, HttpClient httpClient, HttpContext httpContext, String acceptType)
            throws InterruptedException, FetchException {
        if (uri == null)
            throw new IllegalArgumentException(Messages.getServerString("fetch.util.uri.null")); //$NON-NLS-1$
        if (httpClient == null)
            throw new IllegalArgumentException(Messages.getServerString("fetch.util.httpclient.null")); //$NON-NLS-1$

        Model model = null;

        try {
            new URL(uri); // Make sure URL is valid

            HttpGet get = new HttpGet(uri);

            get.setHeader(HttpConstants.ACCEPT, acceptType);

            // Caches must revalidate with origin server. This is to prevent a cache
            // from serving stale data. We may still get a cached response if the
            // origin server responds to the revalidation with a 304.
            // See Unspecified end-to-end revalidation:
            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4
            get.addHeader(HttpConstants.CACHE_CONTROL, "max-age=0"); //$NON-NLS-1$

            RDFModelResponseHandler handler = new RDFModelResponseHandler(uri);

            // Try to access the uri directly.  If this fails attempt to retry
            // using authentication.
            try {
                model = httpClient.execute(get, handler, httpContext);
            } catch (HttpResponseException e1) {
                if (e1.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
                    model = attemptAuthentication(uri, httpClient, httpContext, model, get, handler);
                }
            }
        } catch (Exception e) {
            String uriLocation = Messages.getServerString("fetch.util.uri.unidentifiable"); //$NON-NLS-1$

            if (uri != null && !uri.isEmpty()) {
                uriLocation = uri;
            }

            throw new FetchException(MessageFormat.format(Messages.getServerString("fetch.util.retrieve.error"), //$NON-NLS-1$
                    uriLocation), e);
        }

        return model;
    }

    /**
     * This method performs authentication based on the config.properties' 
     * AuthType setting.
     * 
     * @param uri
     * @param httpClient
     * @param httpContext
     * @param model
     * @param get
     * @param handler
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     * @throws ClientProtocolException
     * @throws URISyntaxException
     */
    private static Model attemptAuthentication(String uri, HttpClient httpClient, HttpContext httpContext,
            Model model, HttpGet get, RDFModelResponseHandler handler)
            throws FileNotFoundException, IOException, ClientProtocolException, URISyntaxException {
        // Check the config.properties to see if the user is overriding
        // the WWW-Authenticate header.
        String override = TestCore.getConfigPropertiesInstance().getProperty("AuthType");
        AuthenticationTypes overrideType = AuthenticationTypes.valueOf(override.toUpperCase());

        switch (overrideType) {
        case OAUTH:
            return perform2LeggedOauth(httpClient, httpContext, get, uri);

        case BASIC:
            return performBasicAuthentication(httpClient, httpContext, get, uri);

        case HEADER:
            Header authTypes[] = handler.getAuthTypes();

            // Determine the authentication type to attempt based on the
            // server's response. Attempt the first type encountered that
            // both the server and the tests support.
            for (Header authType : authTypes) {
                if (authType.getValue().startsWith("OAuth ")) {
                    return perform2LeggedOauth(httpClient, httpContext, get, uri);
                } else if (authType.getValue().startsWith("Basic ")) {
                    return performBasicAuthentication(httpClient, httpContext, get, uri);
                }
            }
        }

        throw new InvalidRDFResourceException(Messages.getServerString("fetch.util.authentication.unknown"));
    }

    /**
     * This method uses the username and password specified in config.properties
     * to attempt basic authentication against a resource server.
     * 
     * @param httpClient
     * @param httpContext
     * @param get
     * @param uri
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static Model performBasicAuthentication(HttpClient httpClient, HttpContext httpContext, HttpGet get,
            String uri) throws FileNotFoundException, IOException {
        // Obtain the username and password from the config.properties file
        Properties prop = TestCore.getConfigPropertiesInstance();
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");

        // Construct the authentication header by using Base64 encoding on the
        // supplied username and password
        String authString = username + ":" + password;
        authString = new String(Base64.encode(authString.getBytes(HttpConstants.DEFAULT_ENCODING)));
        authString = "Basic " + authString;

        get.setHeader("Authorization", authString);
        get.setHeader("OSLC-Core-Version", "2.0");

        Model model = null;

        try {
            model = httpClient.execute(get, new RDFModelResponseHandler(uri), httpContext);
        } catch (Exception e) {
            TestCore.terminateTest(Messages.getServerString("fetch.util.authentication.failure"), e);
        }

        return model;
    }

    /**
     * This method attempts to authenticate with a server using OAuth two 
     * legged authentication.  A functional user with a consumer key and secret
     * must have already been created on the resource server and specified in
     * the config.properties file.
     * 
     * @param httpClient
     * @param httpContext
     * @param get
     * @param uri
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    private static Model perform2LeggedOauth(HttpClient httpClient, HttpContext httpContext, HttpGet get,
            String uri) throws ClientProtocolException, IOException, URISyntaxException {
        // Get the necessary OAuth values from the config.properties file
        Properties prop = TestCore.getConfigPropertiesInstance();
        String consumerKey = prop.getProperty("consumerKey");
        String consumerSecret = prop.getProperty("consumerSecret");
        String authorizationTokenURL = prop.getProperty("OAuthURL");
        String oAuthRealm = prop.getProperty("OAuthRealm");

        // Using the information from the config.properties file
        // construct the authentication header to use in our GET request
        OAuthServiceProvider provider = new OAuthServiceProvider(null, authorizationTokenURL, null);
        OAuthConsumer consumer = new OAuthConsumer("", consumerKey, consumerSecret, provider);
        OAuthAccessor accessor = new OAuthAccessor(consumer);
        accessor.accessToken = "";

        Model model = null;

        try {
            OAuthMessage message = accessor.newRequestMessage(HttpMethod.GET, uri, null);
            String authHeader = message.getAuthorizationHeader(oAuthRealm);

            get.setHeader("Authorization", authHeader);
            get.setHeader("OSLC-Core-Version", "2.0");

            model = httpClient.execute(get, new RDFModelResponseHandler(uri), httpContext);
        } catch (OAuthException e) {
            TestCore.terminateTest(Messages.getServerString("fetch.util.authentication.failure"), e);
        }

        return model;
    }

    /**
     * A list of the currently supported authentication types.  The user specifies
     * the desired type in the config.properties' AuthType property.
     */
    private enum AuthenticationTypes {
        HEADER, OAUTH, BASIC
    }
}