content: /**
   *  Copyright (c) 2013-2014 Angelo ZERR.
   *  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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.server.nodejs;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.UnsupportedEncodingException;
  import java.util.List;
  
  import org.apache.http.HttpEntity;
  import org.apache.http.HttpResponse;
  import org.apache.http.HttpStatus;
  import org.apache.http.StatusLine;
  import org.apache.http.client.HttpClient;
  import org.apache.http.client.methods.HttpPost;
  import org.apache.http.entity.StringEntity;
  import org.apache.http.impl.client.DefaultHttpClient;
  
  import com.eclipsesource.json.Json;
  import com.eclipsesource.json.JsonObject;
  import com.eclipsesource.json.ParseException;
  
  import tern.TernException;
  import tern.server.IInterceptor;
  import tern.server.ITernServer;
  import tern.server.TernExceptionFactory;
  import tern.server.protocol.TernDoc;
  import tern.server.protocol.TernQuery;
  import tern.utils.IOUtils;
  import tern.utils.StringUtils;
  
  /**
   * Nodejs Tern helper.
   * 
   */
  public class NodejsTernHelper {
  
  	// properties for remote access
  	public static final boolean DEFAULT_REMOTE_ACCESS = false;
  	public static final int DEFAULT_REMOTE_PORT = 1234;
  
  	// properties for direct access
  	public static final long DEFAULT_TIMEOUT = 200L; // 200ms
  	public static final int DEFAULT_TEST_NUMBER = 50; // try to retrieve the
  														// node.js port 50
  														// each time on timeout
  														// (max=50*200ms=10000ms).
  
  	public static final boolean DEFAULT_PERSISTENT = false;
  
  	// tern uses UTF-8 encoding
  	private static final String UTF_8 = "UTF-8";
  
  	public NodejsTernHelper() {
  	}
  
  	public static JsonObject makeRequest(String baseURL, TernDoc doc, 
  			boolean silent, List<IInterceptor> interceptors, ITernServer server)
  			throws IOException, TernException {
  		TernQuery query = doc.getQuery();
  		String methodName = query != null ? query.getLabel() : "";
  		long startTime = 0;
  		if (interceptors != null) {
  			startTime = System.nanoTime();
  			for (IInterceptor interceptor : interceptors) {
  				interceptor.handleRequest(doc, server, methodName);
  			}
  		}
  		HttpClient httpClient = new DefaultHttpClient();
  		try {
  			// Post JSON Tern doc
  			HttpPost httpPost = createHttpPost(baseURL, doc);
  			HttpResponse httpResponse = httpClient.execute(httpPost);
  			HttpEntity entity = httpResponse.getEntity();
  			InputStream in = entity.getContent();
  			// Check the status
  			StatusLine statusLine = httpResponse.getStatusLine();
  			int statusCode = statusLine.getStatusCode();
  			if (statusCode != HttpStatus.SC_OK) {
  				// node.js server throws error
  				String message = IOUtils.toString(in);
  				if (StringUtils.isEmpty(message)) {
  					throw new TernException(statusLine.toString());
  				}
  				throw TernExceptionFactory.create(message);
  			}
  
  			try {
  				JsonObject response = (JsonObject) Json.parse(new InputStreamReader(in, UTF_8));
  				if (interceptors != null) {
  					for (IInterceptor interceptor : interceptors) {
  						interceptor.handleResponse(response, server,
  								methodName, getElapsedTimeInMs(startTime));
  					}
  				}
  				return response;
  			} catch (ParseException e) {
  				throw new IOException(e);
  			}
  		} catch (Exception e) {
  			if (interceptors != null) {
  				for (IInterceptor interceptor : interceptors) {
  					interceptor.handleError(e, server, methodName,
  							getElapsedTimeInMs(startTime));
  				}
  			}
  			if (e instanceof IOException) {
  				throw (IOException) e;
  			}
  			if (e instanceof TernException) {
  				throw (TernException) e;
  			}
  			throw new TernException(e);
  		} finally {
  			httpClient.getConnectionManager().shutdown();
  		}
  	}
  
  	private static HttpPost createHttpPost(String baseURL, JsonObject doc)
  			throws UnsupportedEncodingException {
  		HttpPost httpPost = new HttpPost(baseURL);
  		httpPost.setEntity(new StringEntity(doc.toString(), UTF_8));
  		return httpPost;
  	}
  
  	public static long getElapsedTimeInMs(long startTime) {
  		return ((System.nanoTime() - startTime) / 1000000L);
  	}
  
  }
  