Package com.ibm.sbt.services.client

Source Code of com.ibm.sbt.services.client.ClientService$HandlerRaw

/*
* © Copyright IBM Corp. 2012
*
* 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 com.ibm.sbt.services.client;

import static com.ibm.sbt.services.client.base.CommonConstants.APPLICATION_JSON;
import static com.ibm.sbt.services.client.base.CommonConstants.APPLICATION_OCTET_STREAM;
import static com.ibm.sbt.services.client.base.CommonConstants.APPLICATION_XML;
import static com.ibm.sbt.services.client.base.CommonConstants.BINARY;
import static com.ibm.sbt.services.client.base.CommonConstants.BINARY_OCTET_STREAM;
import static com.ibm.sbt.services.client.base.CommonConstants.CH_SLASH;
import static com.ibm.sbt.services.client.base.CommonConstants.CONTENT_ENCODING;
import static com.ibm.sbt.services.client.base.CommonConstants.CONTENT_TYPE;
import static com.ibm.sbt.services.client.base.CommonConstants.GZIP;
import static com.ibm.sbt.services.client.base.CommonConstants.HTML;
import static com.ibm.sbt.services.client.base.CommonConstants.INIT_URL_PARAM;
import static com.ibm.sbt.services.client.base.CommonConstants.JSON;
import static com.ibm.sbt.services.client.base.CommonConstants.LOCATION_HEADER;
import static com.ibm.sbt.services.client.base.CommonConstants.MULTIPART_RELATED;
import static com.ibm.sbt.services.client.base.CommonConstants.SLUG;
import static com.ibm.sbt.services.client.base.CommonConstants.TEXT_PLAIN;
import static com.ibm.sbt.services.client.base.CommonConstants.TRANSFER_ENCODING;
import static com.ibm.sbt.services.client.base.CommonConstants.URL_PARAM;
import static com.ibm.sbt.services.client.base.CommonConstants.UTF8;
import static com.ibm.sbt.services.client.base.CommonConstants.XML;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import javax.servlet.http.HttpServletResponse;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.Node;

import com.ibm.commons.runtime.Context;
import com.ibm.commons.runtime.NoAccessSignal;
import com.ibm.commons.runtime.util.UrlUtil;
import com.ibm.commons.util.FastStringBuffer;
import com.ibm.commons.util.PathUtil;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.io.StreamUtil;
import com.ibm.commons.util.io.json.JsonArray;
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonFactory;
import com.ibm.commons.util.io.json.JsonGenerator;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonObject;
import com.ibm.commons.util.io.json.JsonParser;
import com.ibm.commons.util.profiler.Profiler;
import com.ibm.commons.util.profiler.ProfilerAggregator;
import com.ibm.commons.util.profiler.ProfilerType;
import com.ibm.commons.xml.DOMUtil;
import com.ibm.commons.xml.XMLException;
import com.ibm.commons.xml.util.XMIConverter;
import com.ibm.sbt.plugin.SbtCoreLogger;
import com.ibm.sbt.service.debug.ProxyDebugUtil;
import com.ibm.sbt.service.proxy.Proxy;
import com.ibm.sbt.service.proxy.ProxyConfigException;
import com.ibm.sbt.service.proxy.ProxyFactory;
import com.ibm.sbt.services.endpoints.Endpoint;
import com.ibm.sbt.services.endpoints.EndpointFactory;
import com.ibm.sbt.services.util.HttpDeleteWithBody;
import com.ibm.sbt.services.util.SSLUtil;

/**
* Base class for a REST service client.
*
* @author Philippe Riand
* @author Mark Wallace
*/
public abstract class ClientService {

  protected Endpoint endpoint;

  // Constants for the methods
  public static final String METHOD_GET = "get"; //$NON-NLS-1$
  public static final String METHOD_PUT = "put"; //$NON-NLS-1$
  public static final String METHOD_POST = "post"; //$NON-NLS-1$
  public static final String METHOD_DELETE = "delete"; //$NON-NLS-1$
  public static final String METHOD_DELETE_BODY = "deleteBody"; //$NON-NLS-1$

  // These represents how the result should be formatted to the caller
  public static final Handler FORMAT_UNKNOWN = null;
  public static final Handler FORMAT_NULL = new HandlerNull();
  public static final Handler FORMAT_TEXT = new HandlerString();
  public static final Handler FORMAT_INPUTSTREAM = new HandlerInputStream();
  public static final Handler FORMAT_XML = new HandlerXml();
  public static final Handler FORMAT_JSON = new HandlerJson();

  // TODO: Should be moved elsewhere? What is it for?
  public static final Handler FORMAT_CONNECTIONS_OUTPUT = new HandlerConnectionHeader();
 
  private static final ProfilerType profilerRequest = new ProfilerType("Executing REST request, "); //$NON-NLS-1$

  private static final String sourceClass = ClientService.class.getName();
  protected static final Logger logger = Logger.getLogger(sourceClass);

  /**
   * Default constructor
   */
  public ClientService() {
  }

  /**
   * Construct a ClientService with the specified Endpoint
   *
   * @param endpoint
   */
  public ClientService(Endpoint endpoint) {
    this.endpoint = endpoint;
  }

  /**
   * Construct a ClientService with the Endpoint with the specified name
   *
   * @param endpoint
   */
  public ClientService(String endpointName) {
    this.endpoint = EndpointFactory.getEndpoint(endpointName);
  }

  /**
   * Return the associated Endpoint
   *
   * @return
   */
  public Endpoint getEndpoint() {
    return endpoint;
  }

  /**
   * Set the associated Endpoint
   *
   * @param endpoint
   */
  public void setEndpoint(Endpoint endpoint) {
    this.endpoint = endpoint;
  }

  /**
   * If there is an associated endpoint then check is authentication required
   * and if so trigger the authentication process.
   *
   * @param args
   * @throws ClientServicesException
   */
  protected void checkAuthentication(Args args) throws ClientServicesException {
    if (endpoint != null) {
      if (endpoint.isRequiresAuthentication() && !endpoint.isAuthenticated()) {
        endpoint.authenticate(false);
      }
    }
  }

  /**
   * Get the URL path for the specified arguments and check it is valid
   * i.e. not null. If it is a null throw a ClientServicesException.
   *
   * @param args
   * @throws ClientServicesException
   */
  protected void checkUrl(Args args) throws ClientServicesException {
    if (StringUtil.isEmpty(getUrlPath(args))) {
      throw new ClientServicesException(null, "The service URL is empty");
    }
  }

  /**
   * Check the read parameters and throw a ClientServicesException if
   * they are invalid.
   *
   * @param parameters
   * @throws ClientServicesException
   */
  protected void checkReadParameters(Map<String, String> parameters) throws ClientServicesException {
    // nothing for now...
  }

  /**
   * Return the URL from the associated endpoint.
   *
   * @return
   */
  public String getBaseUrl() {
    if (endpoint != null) {
      return endpoint.getUrl();
    }
    return null;
  }

  /**
   * Initialize the associated Endpoint with the specified HttpClient.
   *
   * @param httpClient
   * @throws ClientServicesException
   */
    protected void initialize(DefaultHttpClient httpClient) throws ClientServicesException {
        if (endpoint != null) {
            CookieStore cookies = endpoint.getCookies();
            httpClient.setCookieStore(cookies);
            endpoint.initialize(httpClient);
        }
    }

  /**
   * Return true if force trust SSL certificate is set for the associated Endpoint.
   *
   * @return
   * @throws ClientServicesException
   */
  protected boolean isForceTrustSSLCertificate() throws ClientServicesException {
    if (endpoint != null) {
      return endpoint.isForceTrustSSLCertificate();
    }
    return false;
  }

  /**
   * Return true if force trust SSL certificate is set for the associated Endpoint.
   *
   * @return
   * @throws ClientServicesException
   */
  protected boolean isForceDisableExpectedContinue() throws ClientServicesException {
    if (endpoint != null) {
      return endpoint.isForceDisableExpectedContinue();
    }
    return false;
  }

 
  /**
   * Return the proxy info from the associated Endpoint or an empty string
   *
   * @return
   * @throws ClientServicesException
   */
  protected String getHttpProxy() throws ClientServicesException {
    if (endpoint != null) {
      String proxyinfo = endpoint.getHttpProxy();
      if (StringUtil.isEmpty(proxyinfo)) {
        Context context = Context.getUnchecked();
          if (context != null) {
          proxyinfo = Context.get().getProperty("sbt.httpProxy");
          }
      }
      return proxyinfo;
    }
    return ""; // TODO should this be null?
  }

  /**
   * Force authentication for the associated Endpoint.
   *
   * @param args
   * @throws ClientServicesException
   */
  protected void forceAuthentication(Args args) throws ClientServicesException {
    if (endpoint != null) {
      endpoint.authenticate(true);
    } else {
      String msg = StringUtil.format("Authorization needed for service {0}", getUrlPath(args));
      throw new NoAccessSignal(msg);
    }
  }

  // =================================================================
  // Generic access
  // =================================================================

  public static class Args implements Serializable{

    private String serviceUrl; // Service URL to call, relative to the endpoint
    private Map<String, String> parameters; // Query String parameters
    private Map<String, String> headers; // HTTP Headers
    private Handler handler; // Format of the result

    public Args() {
    }

    public String getServiceUrl() {
      return serviceUrl;
    }

    public Args setServiceUrl(String url) {
      this.serviceUrl = url;
      return this;
    }

    public Map<String, String> getParameters() {
      return parameters;
    }

    public Args setParameters(Map<String, String> parameters) {
      this.parameters = parameters;
      return this;
    }

    public Args addParameter(String name, String value) {
      if (parameters == null) {
        this.parameters = new HashMap<String, String>();
      }
      parameters.put(name, value);
      return this;
    }

    public Map<String, String> getHeaders() {
      return headers;
    }

    public Args setHeaders(Map<String, String> headers) {
      this.headers = headers;
      return this;
    }

    public Args addHeader(String name, String value) {
      if (headers == null) {
        this.headers = new HashMap<String, String>();
      }
      headers.put(name, value);
      return this;
    }

    public boolean hasHeader(String name) {
      return (headers == null) ? false : headers.containsKey(name);
    }

    public Handler getHandler() {
      return handler;
    }

    public Args setHandler(Handler handler) {
      this.handler = handler;
      return this;
    }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append("{ serviceUrl:").append(serviceUrl);
      sb.append(", parameters:").append(parameters);
      sb.append(", headers:").append(headers).append("}");
      return sb.toString();
    }
  }

  protected Args createArgs(String serviceUrl, Map<String, String> parameters)
      throws ClientServicesException {
    Args args = new Args();
    args.setServiceUrl(serviceUrl);
    args.setParameters(parameters);
    return args;
  }

  // =================================================================
  // Request content
  // =================================================================

  public static abstract class Content {

    private final String  contentType;

    protected Content(String contentType) {
      this.contentType = contentType;
    }

    protected String getContentType() {
      return contentType;
    }

    public void initRequestContent(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args)
        throws ClientServicesException {
      HttpEntity entity = createEntity();

      // set the http entity to the request, along with its content type
      if (entity != null && (httpRequestBase instanceof HttpEntityEnclosingRequestBase)) {
        setEntity(httpClient, httpRequestBase, args, entity);
      }
    }

    protected void setEntity(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args,
        HttpEntity entity) throws ClientServicesException {
      String contentType = getContentType();
      if (StringUtil.isNotEmpty(contentType)) {
        httpRequestBase.setHeader(CONTENT_TYPE, contentType);
      }
      ((HttpEntityEnclosingRequestBase) httpRequestBase).setEntity(entity);
    }

    protected HttpEntity createEntity() throws ClientServicesException {
      return null;
    }
  }
 
  public static class ContentHttpEntity extends Content {
   
    private final HttpEntity  content;

    public ContentHttpEntity(HttpEntity content) {
      super(content.getContentType().getValue());
      this.content = content;
    }

    public ContentHttpEntity(HttpEntity content, String contentType) {
      super(contentType);
      this.content = content;
    }

    @Override
    protected HttpEntity createEntity() throws ClientServicesException {
      try {
        return content;
      } catch (Exception ex) {
        throw new ClientServicesException(ex);
      }
    }
  }

  public static class ContentString extends Content {

    private final String  content;

    public ContentString(String content, String contentType) {
      super(contentType);
      this.content = content;
    }

    public ContentString(String content) {
      this(content, TEXT_PLAIN);
    }

    @Override
    protected HttpEntity createEntity() throws ClientServicesException {
      try {
        return new StringEntity(content, HTTP.UTF_8);
      } catch (Exception ex) {
        throw new ClientServicesException(ex);
      }
    }
  }

  public static class ContentJson extends Content {

    private final JsonFactory  factory;
    private final Object    content;

    public ContentJson(Object content, String contentType, JsonFactory factory) {
      super(contentType);
      this.content = content;
      this.factory = factory;
    }

    public ContentJson(Object content, String contentType) {
      this(content, contentType, JsonJavaFactory.instanceEx);
    }

    public ContentJson(Object content) {
      this(content, APPLICATION_JSON, JsonJavaFactory.instanceEx);
    }

    public ContentJson(Object content, JsonFactory factory) {
      this(content, APPLICATION_JSON, factory);
    }

    @Override
    protected HttpEntity createEntity() throws ClientServicesException {
      try {
        return new StringEntity(JsonGenerator.toJson(factory, content, true));
      } catch (Exception ex) {
        throw new ClientServicesException(ex);
      }
    }
  }

  public static class ContentXml extends Content {

    private Node  content;

    public ContentXml(Node content, String contentType) {
      super(contentType);
      this.content = content;
    }

    public ContentXml(Node content) {
      this(content, APPLICATION_XML);
      this.content = content;
    }

    @Override
    protected HttpEntity createEntity() throws ClientServicesException {
      try {
        return new StringEntity(DOMUtil.getXMLString(content, true));
      } catch (Exception ex) {
        throw new ClientServicesException(ex);
      }
    }
  }

  public static class ContentFile extends Content {

    private final File    content;
    private final String  name;

    public ContentFile(String name, File content, String contentType) {
      super(contentType);
      this.name = name;
      this.content = content;
    }

    public ContentFile(File content, String contentType) {
      this(content.getName(), content, contentType);
    }

    public ContentFile(File content) {
      this(content, APPLICATION_OCTET_STREAM);
    }

    public ContentFile(String name, File content) {
      this(name, content, APPLICATION_OCTET_STREAM);
    }

    @Override
    public HttpEntity createEntity() throws ClientServicesException {
      FileEntity fileEnt = new FileEntity(content, getContentType());
      fileEnt.setContentEncoding(BINARY); // Is that OK?
      return fileEnt;
    }

    @Override
    protected void setEntity(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args,
        HttpEntity entity) throws ClientServicesException {
      httpRequestBase.setHeader(SLUG, name);
      httpRequestBase.setHeader(CONTENT_TYPE, getContentType());
      super.setEntity(httpClient, httpRequestBase, args, entity);
    }
  }

  public static class ContentStream extends Content {

    private final long          length;
    private final java.io.InputStream  stream;
    private final String        name;
    private final boolean        markSupportedFromWrappedStream;

    public ContentStream(String name, InputStream stream, long length, String contentType) {
      super(contentType);
      this.length = length;
      this.markSupportedFromWrappedStream = stream.markSupported();
      if (stream instanceof BufferedInputStream) {
        this.stream = stream;
      } else {
        this.stream = new BufferedInputStream(stream);
      }
      if (!StringUtil.isEmpty(name)) {
        this.name = name.trim();
      } else {
        this.name = name;
      }
    }

    public ContentStream(InputStream stream) {
      this(null, stream, -1, BINARY_OCTET_STREAM);
    }

    public ContentStream(java.io.InputStream stream, String name) {
      this(name, stream, -1, BINARY_OCTET_STREAM);
    }

    public ContentStream(java.io.InputStream stream, long length, String name) {
      this(name, stream, length, BINARY_OCTET_STREAM);
    }

    @Override
    protected HttpEntity createEntity() throws ClientServicesException {
      InputStreamEntity inputStreamEntity = new InputStreamEntity(stream, length);
      inputStreamEntity.setContentEncoding(BINARY);
      if (length == -1) {
        inputStreamEntity.setChunked(true);
      }

      return inputStreamEntity;
    }

    @Override
    public void initRequestContent(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args)
        throws ClientServicesException {
      // TODO Auto-generated method stub
      super.initRequestContent(httpClient, httpRequestBase, args);
    }

    @Override
    protected void setEntity(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args,
        HttpEntity entity) throws ClientServicesException {
      if (name != null) {
        httpRequestBase.setHeader(SLUG, name);
      }
      httpRequestBase.setHeader(CONTENT_TYPE, getContentType());
      super.setEntity(httpClient, httpRequestBase, args, entity);
    }

  }

  public static class ContentList extends Content {
   
    private List<ContentPart> contentParts;

    protected ContentList(List<ContentPart> content) {
      this(content, MULTIPART_RELATED);
    }
   
    protected ContentList(List<ContentPart> content, String contentType) {
      super(contentType);
     
      this.contentParts = content;
    }
   
    @Override
    protected HttpEntity createEntity() throws ClientServicesException {
      MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
      for (ContentPart contentPart : contentParts) {
        if (contentPart.getData() instanceof InputStream) {
          entityBuilder.addBinaryBody(contentPart.getName(),
              (InputStream)contentPart.getData(),
              contentPart.getContentType(),
              contentPart.getFileName());
        }
        else if (contentPart.getData() instanceof byte[]) {
          entityBuilder.addBinaryBody(contentPart.getName(),
              (byte[])contentPart.getData(),
              contentPart.getContentType(),
              contentPart.getFileName());
        }
        else if (contentPart.getData() instanceof String) {
          entityBuilder.addTextBody(contentPart.getName(),
              (String)contentPart.getData(),
              contentPart.getContentType());
        }
      }
      return entityBuilder.build();
    }
   
  }
 
  public static class ContentPart {
   
    private String name;
    private Object data;
    private ContentType contentType;
    private String fileName;
   
    public ContentPart(String name, byte[] data, String fileName, String mimeType) {
      this.name = name;
      this.data = data;
      this.fileName = fileName;
      this.contentType = ContentType.create(mimeType);
    }
   
    public ContentPart(String name, InputStream data, String fileName, String mimeType) {
      this.name = name;
      this.data = data;
      this.fileName = fileName;
      this.contentType = ContentType.create(mimeType);
    }
   
    public ContentPart(String name, String data, String mimeType) {
      this.name = name;
      this.data = data;
      this.contentType = ContentType.create(mimeType);
    }
   
    public String getName() {
      return name;
    }
   
    public Object getData() {
      return data;
    }
   
    public ContentType getContentType() {
      return contentType;
    }
   
    public String getFileName() {
      return fileName;
    }
  }
 
  protected Content createRequestContent(Args args, Object content) throws ClientServicesException {
    if (args.getHeaders() != null && args.getHeaders().get(CONTENT_TYPE) != null) {
      String contentType = args.getHeaders().get(CONTENT_TYPE);
      if (content instanceof String) {
        return new ContentString((String) content, contentType);
      }
      if (content instanceof Node) {
        return new ContentXml((Node) content, contentType);
      }
      if ((content instanceof JsonObject) || (content instanceof JsonArray)) {
        return new ContentJson(content, contentType);
      }
      if (content instanceof File) {
        return new ContentFile((File) content, contentType);
      }
      if (content instanceof InputStream) {
        int length = getLength(args, (InputStream)content);
        return new ContentStream(args.getHeaders().get(SLUG), (InputStream)content, length, contentType);
      }
      if (content instanceof List) {
        return new ContentList((List) content, contentType);
      }
      if (content instanceof HttpEntity) {
        return new ContentHttpEntity((HttpEntity) content, contentType);
      }
    } else {
      if (content instanceof String) {
        return new ContentString((String) content);
      }
      if (content instanceof Node) {
        return new ContentXml((Node) content);
      }
      if ((content instanceof JsonObject) || (content instanceof JsonArray)) {
        return new ContentJson(content);
      }
      if (content instanceof File) {
        return new ContentFile((File) content);
      }
      if (content instanceof InputStream) {
        int length = getLength(args, (InputStream)content);
        return new ContentStream((InputStream) content, length, args.getHeaders().get(SLUG));
      }
      if (content instanceof List) {
        return new ContentList((List) content);
      }
      if (content instanceof HttpEntity) {
        return new ContentHttpEntity((HttpEntity) content);
      }
    }

    throw new ClientServicesException(null, "Cannot create HTTP content for object of type {0}",
        content.getClass());
  }
 
  protected int getLength(Args args, InputStream istream) throws ClientServicesException {
    try {
      return args.hasHeader(TRANSFER_ENCODING) ? -1 : istream.available();
    } catch (IOException e) {
      throw new ClientServicesException(e);
    }
  }

  // =================================================================
  // Response Handler
  // =================================================================

  public static abstract class Handler implements Serializable{
    public abstract Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException;
  }

  public static class HandlerNull extends Handler {
    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      if (entity != null) {
        InputStream is = getEntityContent(request, response, entity);
        try {
          // Just eat the entire content - requested for persistent http 1.1 sessions
          byte[] buffer = new byte[8192];
          while ((is.read(buffer)) > 0) {}
        } finally {}
      }
      return null;
    }
  }

  public static class HandlerString extends Handler {
    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      if (entity != null) {
        String encoding = EntityUtils.getContentCharSet(entity);
        if (encoding == null) {
          encoding = UTF8;
        }
        Reader reader = new InputStreamReader(getEntityContent(request, response, entity), encoding);
        try {
          FastStringBuffer b = new FastStringBuffer();
          b.append(reader);
          return b.toString();
        } finally {
          reader.close();
        }
      }
      return null;
    }
  }

  public static class HandlerJson extends Handler {
    private final JsonFactory  factory;

    public HandlerJson() {
      this.factory = JsonJavaFactory.instanceEx;
    }

    public HandlerJson(JsonFactory factory) {
      this.factory = factory;
    }

    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      if (entity != null) {
        String encoding = EntityUtils.getContentCharSet(entity);
        if (encoding == null) {
          encoding = UTF8;
        }
        Reader reader = createReader(request, response, entity, encoding);
        try {
          if(false) {
            String s= StreamUtil.readString(reader);
            try {
              return JsonParser.fromJson(factory, s);
            } catch (JsonException ex) {
              throw ex;
            }
          } else {
            return JsonParser.fromJson(factory, reader);
          }
        } catch (JsonException ex) {
          IOException e = new IOException();
          e.initCause(ex);
          throw e;
        } finally {
          reader.close();
        }
      }
      return null;
    }

    protected Reader createReader(HttpRequestBase request, HttpResponse response, HttpEntity entity,
        String encoding) throws IOException {
      return new InputStreamReader(getEntityContent(request, response, entity), encoding);
    }
  }

  public static class HandlerXml extends Handler {
    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      if (entity != null) {
        InputStream is = getEntityContent(request, response, entity);
        try {
          return DOMUtil.createDocument(is);
        } catch (XMLException ex) {
          IOException e = new IOException();
          e.initCause(ex);
          throw e;
        } finally {
          is.close();
        }
      }
      return null;
    }
  }

  public static class HandlerConnectionHeader extends Handler {
    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      Header[] headers = response.getHeaders(LOCATION_HEADER);
      if (headers != null) {
        if (headers.length > 0) {
          return headers[0].getValue();
        }
      }
      return null;
    }
  }

  public static class HandlerInputStream extends Handler {
    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      if (entity != null) {
        InputStream is = getEntityContent(request, response, entity);
        return is;
      }
      return null;
    }
  }

  public static class HandlerRaw extends Handler {
    @Override
    public Object parseContent(HttpRequestBase request, HttpResponse response, HttpEntity entity)
        throws ClientServicesException, IOException {
      return response;
    }
  }

  protected Handler findErrorHandler(HttpRequestBase request, HttpResponse response)
      throws ClientServicesException, UnsupportedEncodingException, IOException {
    throwClientServicesException(request, response);
    return null;
  }
 
  protected Handler findSuccessHandler(HttpRequestBase request, HttpResponse response)
      throws UnsupportedEncodingException, IOException {
    HttpEntity entity = response.getEntity();
    if (entity != null) {
      Header hd = entity.getContentType();
      if (hd != null) {
        String ct = hd.getValue();
        if (ct.indexOf(JSON) >= 0) {
          return FORMAT_JSON;
        }
        if (ct.indexOf(XML) >= 0) {
          return FORMAT_XML;
        }
        if (ct.indexOf(HTML) >= 0) {
          return FORMAT_TEXT;
        }
      }
    }
    return getDefaultFormat(response, entity);
  }

  // =================================================================
  // GET
  // =================================================================

  public final Response get(String serviceUrl) throws ClientServicesException {
    return get(serviceUrl, null, null);
  }

  public final Response get(String serviceUrl, Map<String, String> parameters) throws ClientServicesException {
    return get(serviceUrl, parameters, null);
  }

  public final Response get(String serviceUrl, Handler format) throws ClientServicesException {
    return get(serviceUrl, null, format);
  }

  public final Response get(String serviceUrl, Map<String, String> parameters, Handler format)
      throws ClientServicesException {
    return get(serviceUrl, parameters, null, format);
  }

  public final Response get(String serviceUrl, Map<String, String> parameters, Map<String, String> headers,
      Handler format) throws ClientServicesException {
    Args args = createArgs(serviceUrl, parameters);
    if (headers != null) {
      args.setHeaders(headers);
    }
    args.setHandler(format);
    return get(args);
  }

  public final Response get(Args args) throws ClientServicesException {
    return xhr(METHOD_GET, args, null);
  }

  // =================================================================
  // POST
  // =================================================================

  public final Response post(String serviceUrl, Object content) throws ClientServicesException {
    return post(serviceUrl, null, content, null);
  }

  public final Response post(String serviceUrl, Map<String, String> parameters, Object content)
      throws ClientServicesException {
    return post(serviceUrl, parameters, content, null);
  }

  public final Response post(String serviceUrl, Map<String, String> parameters, Object content, Handler format)
      throws ClientServicesException {
    Args args = createArgs(serviceUrl, parameters);
    args.setHandler(format);
    return post(args, content);
  }

  public final Response post(String serviceUrl, Map<String, String> parameters, Map<String, String> headers,
      Object content, Handler format) throws ClientServicesException {
    Args args = createArgs(serviceUrl, parameters);
    args.setHandler(format);
    args.setHeaders(headers);
    return post(args, content);
  }

  public final Response post(Args args, Object content) throws ClientServicesException {
    return xhr(METHOD_POST, args, content);
  }

  // =================================================================
  // PUT
  // =================================================================

  public final Response put(String serviceUrl, Object content) throws ClientServicesException {
    return put(serviceUrl, null, content, null);
  }

  public final Response put(String serviceUrl, Map<String, String> parameters, Object content)
      throws ClientServicesException {
    return put(serviceUrl, parameters, content, null);
  }

  public final Response put(String serviceUrl, Map<String, String> parameters, Object content, Handler format)
      throws ClientServicesException {
    Args args = createArgs(serviceUrl, parameters);
    args.setHandler(format);
    return put(args, content);
  }

  public final Response put(String serviceUrl, Map<String, String> parameters, Map<String, String> headers,
      Object content, Handler format) throws ClientServicesException {
    Args args = createArgs(serviceUrl, parameters);
    args.setHandler(format);
    args.setHeaders(headers);
    return put(args, content);
  }

  public final Response put(Args args, Object content) throws ClientServicesException {
    return xhr(METHOD_PUT, args, content);
  }

  // =================================================================
  // DELETE
  // =================================================================

  public final Response delete(String serviceUrl) throws ClientServicesException {
    return delete(serviceUrl, null, null);
  }

  public final Response delete(String serviceUrl, Map<String, String> parameters)
      throws ClientServicesException {
    return delete(serviceUrl, parameters, null);
  }

  public final Response delete(String serviceUrl, Map<String, String> parameters, Handler format)
      throws ClientServicesException {
    Args args = createArgs(serviceUrl, parameters);
    args.setHandler(format);
    return delete(args);
  }
    public final Response delete(String serviceUrl, Map<String, String> parameters, Map<String, String> headers,
            Handler format) throws ClientServicesException {
        Args args = createArgs(serviceUrl, parameters);
        args.setHandler(format);
        args.setHeaders(headers);
        return delete(args);       
    }
   
    public final Response delete(String serviceUrl, Map<String, String> parameters, Map<String, String> headers,
            Handler format,String content)throws ClientServicesException{
      Args args = createArgs(serviceUrl, parameters);
        args.setHandler(format);
        args.setHeaders(headers);
        return xhr(METHOD_DELETE_BODY, args, content);
    }

    public final Response delete(String serviceUrl, Map<String, String> parameters, Map<String, String> headers, Object content,
            Handler format)throws ClientServicesException{
      Args args = createArgs(serviceUrl, parameters);
        args.setHandler(format);
        args.setHeaders(headers);
        return xhr(METHOD_DELETE_BODY, args, content);
    }

  public final Response delete(Args args) throws ClientServicesException {
    return xhr(METHOD_DELETE, args, null);
  }

  // =================================================================
  // Actual request execution
  // =================================================================

  /**
   * Execute an XML Http request with the specified arguments
   *
   * @param method
   * @param args
   * @param content
   * @return
   * @throws ClientServicesException
   */
  public Response xhr(String method, Args args, Object content) throws ClientServicesException {
    if (logger.isLoggable(Level.FINEST)) {
      logger.entering(sourceClass, "xhr", new Object[] { method, args });
    }

    checkAuthentication(args);
    checkUrl(args);
    checkReadParameters(args.parameters);
    String url = composeRequestUrl(args);
    Response response = null;
    if (StringUtil.equalsIgnoreCase(method, METHOD_GET)) {
      HttpGet httpGet = new HttpGet(url);
      response = execRequest(httpGet, args, content);
    } else if (StringUtil.equalsIgnoreCase(method, METHOD_POST)) {
      HttpPost httpPost = new HttpPost(url);
      response = execRequest(httpPost, args, content);
    } else if (StringUtil.equalsIgnoreCase(method, METHOD_PUT)) {
      HttpPut httpPut = new HttpPut(url);
      response = execRequest(httpPut, args, content);
    } else if (StringUtil.equalsIgnoreCase(method, METHOD_DELETE)) {
      HttpDelete httpDelete = new HttpDelete(url);
      response = execRequest(httpDelete, args, content);
    } else if (StringUtil.equalsIgnoreCase(method,METHOD_DELETE_BODY)){
      HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(url);
      response = execRequest(httpDelete, args, content);
    } else {
      throw new ClientServicesException(null, "Unsupported HTTP method {0}", method);
    }
   
    if (logger.isLoggable(Level.FINEST)) {
      logger.exiting(sourceClass, "xhr", response);
    }
    return response;
  }

  /**
   * Execute the specified HttpRequest
   *
   * @param httpRequestBase
   * @param args
   * @param content
   * @return
   * @throws ClientServicesException
   */
  protected Response execRequest(HttpRequestBase httpRequestBase, Args args, Object content) throws ClientServicesException {
    if (Profiler.isEnabled()) {
      String msg = httpRequestBase.getMethod().toUpperCase() + " " + getUrlPath(args);
      ProfilerAggregator agg = Profiler.startProfileBlock(profilerRequest, msg);
      long ts = Profiler.getCurrentTime();
      try {
        return _xhr(httpRequestBase, args, content);
      } finally {
        Profiler.endProfileBlock(agg, ts);
      }
    } else {
      return _xhr(httpRequestBase, args, content);
    }
  }

  /**
   * Allows clients to override the process content section of {@link #_xhr(HttpRequestBase, Args)}. <br/>
   *
   * @param httpRequestBase
   *            the base HTTP request created by the service
   * @param content
   *            the content that is to be sent via the request
   * @param args
   *            the args (such as url params) that have been pushed through by the calling service
   * @return true if the client wants the super class to take care of processing the content
   */
  protected Response _xhr(HttpRequestBase httpRequestBase, Args args, Object content) throws ClientServicesException {
    DefaultHttpClient httpClient = createHttpClient(httpRequestBase, args);
    initialize(httpClient);

    // HttpClient 4.1
    // httpClient.addRequestInterceptor(new RequestAcceptEncoding());
    // httpClient.addResponseInterceptor(new ResponseContentEncoding());

    Content reqContent = null;
    if (content != null) {
      if (content instanceof Content) {
        reqContent = (Content) content;
      } else {
        reqContent = createRequestContent(args, content);
      }
    }

    prepareRequest(httpClient, httpRequestBase, args, reqContent);

    HttpResponse response = executeRequest(httpClient, httpRequestBase, args);
    return processResponse(httpClient, httpRequestBase, response, args);
  }

  protected void prepareRequest(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args,
      Content content) throws ClientServicesException {
    // TODO: add support for gzip content
    // httpClient.addRequestHeader("Accept-Encoding", "gzip");

    if (args.getHeaders() != null) {
      addHeaders(httpClient, httpRequestBase, args);
    }
    if (content != null) {
      content.initRequestContent(httpClient, httpRequestBase, args);
    }
  }

  protected void addHeaders(HttpClient httpClient, HttpRequestBase httpRequestBase, Args args) {
    for (Map.Entry<String, String> e : args.getHeaders().entrySet()) {
      String headerName = e.getKey();
      String headerValue = e.getValue();
      httpRequestBase.addHeader(headerName, headerValue);
    }
  }

  /**
   * Execute the specified the request.
   *
   * @param httpClient
   * @param httpRequestBase
   * @param args
   * @return
   * @throws ClientServicesException
   */
  protected HttpResponse executeRequest(HttpClient httpClient, HttpRequestBase httpRequestBase,
      Args args) throws ClientServicesException {
    try {
      return httpClient.execute(httpRequestBase);
    } catch (Exception ex) {
      if (logger.isLoggable(Level.FINE)) {
        String msg = "Exception ocurred while executing request {0} {1}";
        msg = StringUtil.format(msg, httpRequestBase.getMethod(), args);
        logger.log(Level.FINE, msg, ex);
      }
     
      if (ex instanceof ClientServicesException) {
        throw (ClientServicesException) ex;
      }
      String msg = "Error while executing the REST service {0}";
      String param = httpRequestBase.getURI().toString();
      throw new ClientServicesException(ex, msg, param);
    }
  }

  /**
   * Process the specified response
   *
   * @param httpClient
   * @param httpRequestBase
   * @param httpResponse
   * @param args
   * @return
   * @throws ClientServicesException
   */
  protected Response processResponse(HttpClient httpClient, HttpRequestBase httpRequestBase,
      HttpResponse httpResponse, Args args) throws ClientServicesException {
    if (logger.isLoggable(Level.FINEST)) {
      logger.entering(sourceClass, "processResponse", new Object[] { httpRequestBase.getURI(), httpResponse.getStatusLine() });
    }

    int statusCode = httpResponse.getStatusLine().getStatusCode();
    String reasonPhrase = httpResponse.getStatusLine().getReasonPhrase();
    if (!checkStatus(statusCode)) {
      if (SbtCoreLogger.SBT.isErrorEnabled()) {
        // Do not throw an exception here as some of the non OK responses are not error cases.
        String msg = "Client service request to: {0} did not return OK status. Status returned: {1}, reason: {2}, expected: {3}";
        msg = StringUtil.format(msg, httpRequestBase.getURI(), statusCode, reasonPhrase, HttpStatus.SC_OK);
        SbtCoreLogger.SBT.traceDebugp(this, "processResponse", msg);
      }
    }
   
    if(isResponseRequireAuthentication(httpResponse)){
      forceAuthentication(args);
      throw new ClientServicesException(new AuthenticationException());
    }
   
    Handler format = findHandler(httpRequestBase, httpResponse, args.handler);
   
    Response response = new Response(httpClient, httpResponse, httpRequestBase, args, format);

    if (logger.isLoggable(Level.FINEST)) {
      logger.exiting(sourceClass, "processResponse", response);
    }
    return response;
  }

  private boolean checkStatus(int statusCode) {
    if (statusCode >= 200 && statusCode < 300) {
      return true;
    }
    return false;
  }
  // Each endpoint provides its implementation whether an authentication is required based on response.
  protected boolean isResponseRequireAuthentication(HttpResponse httpResponse){
    int statusCode = httpResponse.getStatusLine().getStatusCode();
    if ((httpResponse.getStatusLine().getStatusCode() == HttpServletResponse.SC_UNAUTHORIZED) ||
        (endpoint != null && endpoint.getAuthenticationErrorCode() == statusCode)) {
        return true;
      }
    return false;
  }

  // =================================================================
  // URL composition
  // =================================================================

  protected String composeRequestUrl(Args args) throws ClientServicesException {
    // Compose the URL
    StringBuilder b = new StringBuilder(256);
   
    if(!(UrlUtil.isAbsoluteUrl(args.getServiceUrl()))){ // check if url supplied is absolute
      String url = getUrlPath(args);
      if (url.charAt(url.length() - 1) == CH_SLASH) {
        url = url.substring(0, url.length() - 1);
      }
      b.append(url);
      addUrlParts(b, args);
    }else{
      // Calling app has provided the complete url, do not do url manipulation in clientservice
      b.append(args.getServiceUrl());
    }
   
    if(endpoint!=null) { // The endpoint can be null
      Proxy proxy = null;
      try {
        proxy = ProxyFactory.getProxyConfig(endpoint.getProxyConfig());
      } catch (ProxyConfigException e) {
        if (logger.isLoggable(Level.FINE)) {
          String msg = "Exception ocurred while fetching proxy information : composeRequestUrl";
          logger.log(Level.FINE, msg, e);
        }
      }
      StringBuilder proxyUrl = new StringBuilder(proxy.rewriteUrl(b.toString()));
      addUrlParameters(proxyUrl, args);
      return proxyUrl.toString();
    }
    return b.toString();
  }

  protected String getUrlPath(Args args) {
    String baseUrl = getBaseUrl();
    String serviceUrl = args.getServiceUrl();
    serviceUrl = substituteServiceMapping(serviceUrl);
    return PathUtil.concat(baseUrl, serviceUrl, CH_SLASH);
  }
 
  protected String substituteServiceMapping(String url){
        String regex = "\\{(.*?)\\}";
       
        Pattern paramsPattern = Pattern.compile(regex);
        Matcher paramsMatcher = paramsPattern.matcher(url);
       
        while(paramsMatcher.find()){
            String subOut = paramsMatcher.group(1);
            String subIn = this.endpoint.getServiceMappings().get(subOut);
            if(subIn != null){
                return url.replaceFirst("\\{" + subOut + "\\}", subIn);
            }
        }
       
        return url.replace("{", "").replace("}", "");
    }

  protected void addUrlParts(StringBuilder b, Args args) throws ClientServicesException {
  }

  protected void addUrlParameters(StringBuilder b, Args args) throws ClientServicesException {
    Map<String, String> parameters = args.getParameters();
    if (parameters != null) {
      boolean first = !b.toString().contains("?");
      for (Map.Entry<String, String> e : parameters.entrySet()) {
        String name = e.getKey();
        if (StringUtil.isNotEmpty(name) && isValidUrlParameter(args, name)) {
          String value = e.getValue();
          first = addParameter(b, first, name, value);
        }
      }
    }
  }

  protected boolean isValidUrlParameter(Args args, String name) throws ClientServicesException {
    return true;
  }

  //
  // Url Utilities
  //
  protected boolean addParameter(StringBuilder b, boolean first, String name, Date value)
      throws ClientServicesException {
    if (value != null) {
      String date = XMIConverter.composeDate(value.getTime());
      return addParameter(b, first, name, date);
    }
    return first;
  }

  protected boolean addParameter(StringBuilder b, boolean first, String name, int value)
      throws ClientServicesException {
    if (value != 0) {
      return addParameter(b, first, name, Integer.toString(value));
    }
    return first;
  }

  protected boolean addParameter(StringBuilder b, boolean first, String name, String value)
      throws ClientServicesException {
    try {
      if (value != null) {
        b.append(first ? INIT_URL_PARAM : URL_PARAM);
        b.append(name);
        b.append('=');
        b.append(URLEncoder.encode(value, UTF8));
        return false;
      }
      return first;
    } catch (UnsupportedEncodingException ex) {
      throw new ClientServicesException(ex);
    }
  }

  // =================================================================
  // Content formatting
  // =================================================================

  protected Handler getDefaultFormat(HttpResponse response, HttpEntity entity) {
    return FORMAT_INPUTSTREAM;
  }

  /**
   * Find the handler for the specified response
   *
   * @param request
   * @param response
   * @param DateFormat
   * @return
   * @throws ClientServicesException
   */
  protected Handler findHandler(HttpRequestBase request, HttpResponse response, Handler handler)
      throws ClientServicesException {
    if (logger.isLoggable(Level.FINEST)) {
      logger.entering(sourceClass, "findHandler", new Object[] { request.getURI(), response.getStatusLine(), handler });
    }

    try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (response.getStatusLine().getStatusCode() == HttpServletResponse.SC_INTERNAL_SERVER_ERROR) {
        handler = findErrorHandler(request, response);
      }

      // Connections Delete API returns SC_NO_CONTENT for successful deletion.
      if (isErrorStatusCode(statusCode)) {
        handler = findErrorHandler(request, response);
      }

      if (handler == null) {
        handler = findSuccessHandler(request, response);
      }

      // SBT doesn't have a JS interpreter...
      if (handler == null) {
        handler = new HandlerRaw();
      }
    } catch (Exception ex) {
      if (ex instanceof ClientServicesException) {
        throw (ClientServicesException) ex;
      }
      throw new ClientServicesException(ex, "Error while parsing the REST service results");
    }

    if (logger.isLoggable(Level.FINEST)) {
      logger.exiting(sourceClass, "findHandler", handler);
    }
    return handler;
  }

  /**
   * @param statusCode
   * @return
   */
  protected boolean isErrorStatusCode(int statusCode) {
    return (statusCode != HttpStatus.SC_OK) &&
      (statusCode != HttpStatus.SC_CREATED) &&
      (statusCode != HttpStatus.SC_ACCEPTED) &&
      (statusCode != HttpStatus.SC_NO_CONTENT);
  }

  /**
   *
   * @param request
   * @param response
   * @throws ClientServicesException
   */
  protected void throwClientServicesException(HttpRequestBase request, HttpResponse response) throws ClientServicesException {
    throw new ClientServicesException(response, request);
  }

  // Until we move to HttpClient 4.1
  public static InputStream getEntityContent(HttpRequestBase request, HttpResponse response,
      HttpEntity entity) throws IOException {
    InputStream is = entity.getContent();
    if (is != null) {
      Header contentEncodingHeader = response.getFirstHeader(CONTENT_ENCODING);
      if (contentEncodingHeader != null && contentEncodingHeader.getValue().equalsIgnoreCase(GZIP)) {
        is = new GZIPInputStream(is);
      }
    }
    return is;
  }

  public DefaultHttpClient createHttpClient(HttpRequestBase httpRequestBase, Args args)
      throws ClientServicesException {
    // Check if we should trust the HTTPS certificates
    DefaultHttpClient httpClient = new DefaultHttpClient();
    if (isForceTrustSSLCertificate()) {
      // PHIL: we don't check the scheme here as the Apachae library will still verify the
      // certificate for some http requests...
      // String scheme = httpRequestBase.getURI().getScheme();
      // if(scheme!=null && scheme.equalsIgnoreCase("https")) {
      httpClient = SSLUtil.wrapHttpClient(httpClient);
      // }
    }
    if(isForceDisableExpectedContinue()) {
      logger.fine("Disabling Expected Continue Header");
      httpClient.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);
    }
   
    // Capture network traffic through a network proxy like Fiddler or WireShark for debug purposes
    if (StringUtil.isNotEmpty(getHttpProxy())) {
      return ProxyDebugUtil.wrapHttpClient(httpClient, getHttpProxy());
    }

    return httpClient;
  }
}
TOP

Related Classes of com.ibm.sbt.services.client.ClientService$HandlerRaw

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.