Package org.eclipse.ecf.remoteservice.rest.client

Source Code of org.eclipse.ecf.remoteservice.rest.client.RestClientService

/*******************************************************************************
* Copyright (c) 2009 EclipseSource and others. All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*   EclipseSource - initial API and implementation
*******************************************************************************/
package org.eclipse.ecf.remoteservice.rest.client;

import java.io.*;
import java.util.*;
import org.apache.http.*;
import org.apache.http.auth.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.AbstractHttpMessage;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ecf.core.security.*;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.internal.remoteservice.rest.Activator;
import org.eclipse.ecf.remoteservice.IRemoteCall;
import org.eclipse.ecf.remoteservice.IRemoteService;
import org.eclipse.ecf.remoteservice.client.*;
import org.eclipse.ecf.remoteservice.rest.IRestCall;
import org.eclipse.ecf.remoteservice.rest.RestException;

/**
* This class represents a REST service from the client side of view. So a
* RESTful web service can be accessed via the methods provided by this class.
* Mostly the methods are inherited from {@link IRemoteService}.
*/
public class RestClientService extends AbstractClientService {

  protected final static int DEFAULT_RESPONSE_BUFFER_SIZE = 1024;

  protected final static String DEFAULT_HTTP_CONTENT_CHARSET = "UTF-8"; //$NON-NLS-1$

  private static final String CONNECTION_MANAGER_TIMEOUT = "http.connection-manager.timeout"; //$NON-NLS-1$

  protected HttpClient httpClient;
  protected int responseBufferSize = DEFAULT_RESPONSE_BUFFER_SIZE;

  public RestClientService(RestClientContainer container, RemoteServiceClientRegistration registration) {
    super(container, registration);
    this.httpClient = new DefaultHttpClient();
  }

  private boolean isResponseOk(HttpResponse response) {
    int isOkCode = response.getStatusLine().getStatusCode() - 200;
    return (isOkCode >= 0 && isOkCode < 100);
  }

  /**
   * Calls the Rest service with given URL of IRestCall. The returned value is
   * the response body as an InputStream.
   *
   * @param call
   *            The remote call to make.  Must not be <code>null</code>.
   * @param callable
   *            The callable with default parameters to use to make the call.
   * @return The InputStream of the response body or <code>null</code> if an
   *         error occurs.
   */
  protected Object invokeRemoteCall(final IRemoteCall call, final IRemoteCallable callable) throws ECFException {
    String uri = prepareEndpointAddress(call, callable);
    HttpRequestBase httpMethod = createAndPrepareHttpMethod(uri, call, callable);
    // execute method
    byte[] responseBody = null;
    int responseCode = 500;
    HttpResponse response = null;
    try {
      response = httpClient.execute(httpMethod);
      responseCode = response.getStatusLine().getStatusCode();
      if (isResponseOk(response)) {
        // Get responseBody as String
        responseBody = getResponseAsBytes(response);
      } else {
        // If this method returns true, we should retrieve the response body
        if (retrieveErrorResponseBody(response)) {
          responseBody = getResponseAsBytes(response);
        }
        // Now pass to the exception handler
        handleException("Http response not OK.  URL=" + uri + " responseCode=" + new Integer(responseCode), null, responseCode, responseBody); //$NON-NLS-1$ //$NON-NLS-2$
      }
    } catch (IOException e) {
      handleException("Transport IOException", e, responseCode); //$NON-NLS-1$
    }
    Object result = null;
    try {
      result = processResponse(uri, call, callable, convertResponseHeaders(response.getAllHeaders()), responseBody);
    } catch (NotSerializableException e) {
      handleException("Exception deserializing response.  URL=" + uri + " responseCode=" + new Integer(responseCode), e, responseCode); //$NON-NLS-1$ //$NON-NLS-2$
    }
    return result;
  }

  protected boolean retrieveErrorResponseBody(HttpResponse response) {
    // XXX this needs to be defined differently for
    return false;
  }

  protected byte[] getResponseAsBytes(HttpResponse response) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    response.getEntity().writeTo(os);
    return os.toByteArray();
  }

  protected void handleException(String message, Throwable e, int responseCode, byte[] responseBody) throws RestException {
    logException(message, e);
    throw new RestException(message, e, responseCode, responseBody);
  }

  protected void handleException(String message, Throwable e, int responseCode) throws RestException {
    handleException(message, e, responseCode, null);
  }

  protected void setupTimeouts(HttpClient httpClient, IRemoteCall call, IRemoteCallable callable) {
    long callTimeout = call.getTimeout();
    if (callTimeout == IRemoteCall.DEFAULT_TIMEOUT)
      callTimeout = callable.getDefaultTimeout();

    int timeout = (int) callTimeout;
    httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
    httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
    httpClient.getParams().setIntParameter(CONNECTION_MANAGER_TIMEOUT, timeout);
  }

  private Map convertResponseHeaders(Header[] headers) {
    Map result = new HashMap();
    if (headers == null)
      return result;
    for (int i = 0; i < headers.length; i++) {
      String name = headers[i].getName();
      String value = headers[i].getValue();
      result.put(name, value);
    }
    return result;
  }

  protected void addRequestHeaders(AbstractHttpMessage httpMethod, IRemoteCall call, IRemoteCallable callable) {
    // Add request headers from the callable
    Map requestHeaders = (callable.getRequestType() instanceof AbstractRequestType) ? ((AbstractRequestType) callable.getRequestType()).getDefaultRequestHeaders() : new HashMap();
    if (requestHeaders == null)
      requestHeaders = new HashMap();

    if (call instanceof IRestCall) {
      Map callHeaders = ((IRestCall) call).getRequestHeaders();
      if (callHeaders != null)
        requestHeaders.putAll(requestHeaders);
    }

    Set keySet = requestHeaders.keySet();
    Object[] headers = keySet.toArray();
    for (int i = 0; i < headers.length; i++) {
      String key = (String) headers[i];
      String value = (String) requestHeaders.get(key);
      httpMethod.addHeader(key, value);
    }
  }

  protected HttpRequestBase createAndPrepareHttpMethod(String uri, IRemoteCall call, IRemoteCallable callable) throws RestException {
    HttpRequestBase httpMethod = null;

    IRemoteCallableRequestType requestType = callable.getRequestType();
    if (requestType == null)
      throw new RestException("Request type for call cannot be null"); //$NON-NLS-1$
    try {
      if (requestType instanceof HttpGetRequestType) {
        httpMethod = prepareGetMethod(uri, call, callable);
      } else if (requestType instanceof HttpPostRequestType) {
        httpMethod = preparePostMethod(uri, call, callable);
      } else if (requestType instanceof HttpPutRequestType) {
        httpMethod = preparePutMethod(uri, call, callable);
      } else if (requestType instanceof HttpDeleteRequestType) {
        httpMethod = prepareDeleteMethod(uri, call, callable);
      } else {
        throw new RestException("HTTP method " + requestType + " not supported"); //$NON-NLS-1$ //$NON-NLS-2$
      }
    } catch (NotSerializableException e) {
      String message = "Could not serialize parameters for uri=" + uri + " call=" + call + " callable=" + callable; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      logException(message, e);
      throw new RestException(message);
    } catch (UnsupportedEncodingException e) {
      String message = "Could not serialize parameters for uri=" + uri + " call=" + call + " callable=" + callable; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      logException(message, e);
      throw new RestException(message);
    }
    // add additional request headers
    addRequestHeaders(httpMethod, call, callable);
    // handle authentication
    setupAuthenticaton(httpClient, httpMethod);
    // needed because a resource can link to another resource
    httpClient.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, new Boolean(true));
    httpClient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, DEFAULT_HTTP_CONTENT_CHARSET);
    setupTimeouts(httpClient, call, callable);
    return httpMethod;
  }

  /**
   * @throws RestException 
   */
  protected HttpRequestBase prepareDeleteMethod(String uri, IRemoteCall call, IRemoteCallable callable) throws RestException {
    return new HttpDelete(uri);
  }

  protected HttpRequestBase preparePutMethod(String uri, IRemoteCall call, IRemoteCallable callable) throws NotSerializableException, UnsupportedEncodingException {
    HttpPut result = new HttpPut(uri);
    HttpPutRequestType putRequestType = (HttpPutRequestType) callable.getRequestType();

    IRemoteCallParameter[] defaultParameters = callable.getDefaultParameters();
    Object[] parameters = call.getParameters();

    if (putRequestType.useRequestEntity()) {
      if (defaultParameters != null && defaultParameters.length > 0 && parameters != null && parameters.length > 0) {
        HttpEntity requestEntity = putRequestType.generateRequestEntity(uri, call, callable, defaultParameters[0], parameters[0]);
        result.setEntity(requestEntity);
      }
    } else {
      NameValuePair[] params = toNameValuePairs(uri, call, callable);
      if (params != null) {
        result.setEntity(getUrlEncodedFormEntity(Arrays.asList(params), putRequestType));
      }
    }
    return result;
  }

  /**
   * @throws UnsupportedEncodingException
   * @throws ECFException 
   */
  protected HttpRequestBase preparePostMethod(String uri, IRemoteCall call, IRemoteCallable callable) throws NotSerializableException, UnsupportedEncodingException {
    HttpPost result = new HttpPost(uri);
    HttpPostRequestType postRequestType = (HttpPostRequestType) callable.getRequestType();

    IRemoteCallParameter[] defaultParameters = callable.getDefaultParameters();
    Object[] parameters = call.getParameters();
    if (postRequestType.useRequestEntity()) {
      if (defaultParameters != null && defaultParameters.length > 0 && parameters != null && parameters.length > 0) {
        HttpEntity requestEntity = postRequestType.generateRequestEntity(uri, call, callable, defaultParameters[0], parameters[0]);
        result.setEntity(requestEntity);
      }
    } else {
      NameValuePair[] params = toNameValuePairs(uri, call, callable);
      if (params != null) {
        result.setEntity(getUrlEncodedFormEntity(Arrays.asList(params), postRequestType));
      }
    }
    return result;
  }

  /**
   * @throws ECFException 
   */
  protected HttpRequestBase prepareGetMethod(String uri, IRemoteCall call, IRemoteCallable callable) {
    HttpRequestBase result = new HttpGet(uri);
    /**
     * FIXME: is this still supported in httpclient 4.0?
    NameValuePair[] params = toNameValuePairs(uri, call, callable);
    if (params != null)
      result.setQueryString(params);
    **/
    return result;
  }

  protected UrlEncodedFormEntity getUrlEncodedFormEntity(List list, AbstractEntityRequestType postRequestType) throws UnsupportedEncodingException {
    if (postRequestType.defaultCharset != null) {
      return new UrlEncodedFormEntity(list, postRequestType.defaultCharset);
    }
    return new UrlEncodedFormEntity(list);
  }

  protected NameValuePair[] toNameValuePairs(String uri, IRemoteCall call, IRemoteCallable callable) throws NotSerializableException {
    IRemoteCallParameter[] restParameters = prepareParameters(uri, call, callable);
    List nameValueList = new ArrayList();
    if (restParameters != null) {
      for (int i = 0; i < restParameters.length; i++) {
        String parameterValue = null;
        Object o = restParameters[i].getValue();
        if (o instanceof String) {
          parameterValue = (String) o;
        } else if (o != null) {
          parameterValue = o.toString();
        }
        if (parameterValue != null) {
          nameValueList.add(new BasicNameValuePair(restParameters[i].getName(), parameterValue));
        }
      }
    }
    return (NameValuePair[]) nameValueList.toArray(new NameValuePair[nameValueList.size()]);
  }

  protected void setupAuthenticaton(HttpClient httpClient, HttpRequestBase method) {
    IConnectContext connectContext = container.getConnectContextForAuthentication();
    if (connectContext != null) {
      NameCallback nameCallback = new NameCallback(""); //$NON-NLS-1$
      ObjectCallback passwordCallback = new ObjectCallback();
      Callback[] callbacks = new Callback[] {nameCallback, passwordCallback};
      CallbackHandler callbackHandler = connectContext.getCallbackHandler();
      if (callbackHandler == null)
        return;
      try {
        callbackHandler.handle(callbacks);
        String username = nameCallback.getName();
        String password = (String) passwordCallback.getObject();
        Credentials credentials = new UsernamePasswordCredentials(username, password);
        method.addHeader(new BasicScheme().authenticate(credentials, method));
      } catch (IOException e) {
        logException("IOException setting credentials for rest httpclient", e); //$NON-NLS-1$
      } catch (UnsupportedCallbackException e) {
        logException("UnsupportedCallbackException setting credentials for rest httpclient", e); //$NON-NLS-1$
      } catch (AuthenticationException e) {
        logException("AuthenticationException setting credentials for rest httpclient", e); //$NON-NLS-1$
      }

    }
  }

  protected void logException(String string, Throwable e) {
    Activator a = Activator.getDefault();
    if (a != null)
      a.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, string, e));
  }

  protected void logWarning(String string, Throwable e) {
    Activator a = Activator.getDefault();
    if (a != null)
      a.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, string));
  }

}
TOP

Related Classes of org.eclipse.ecf.remoteservice.rest.client.RestClientService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.