net.zypr.api.Protocol.java Source code

Java tutorial

Introduction

Here is the source code for net.zypr.api.Protocol.java

Source

/**
 * 
 * Initial version of this code (c) 2009-2011 Media Tuners LLC with a full license to Pioneer Corporation.
 * 
 * Pioneer Corporation licenses this file to you 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 net.zypr.api;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.GZIPInputStream;

import net.zypr.api.enums.APIVerbs;
import net.zypr.api.enums.StatusCode;
import net.zypr.api.exceptions.APICommunicationException;
import net.zypr.api.exceptions.APIProtocolException;
import net.zypr.api.exceptions.APIRuntimeException;
import net.zypr.api.utils.Debug;
import net.zypr.api.utils.NumberUtils;
import net.zypr.api.vo.ServiceDetailsVO;
import net.zypr.api.vo.ServiceVO;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HttpContext;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

class Protocol {
    private String _apiEntity;
    private Hashtable<String, ServiceVO> _services = new Hashtable<String, ServiceVO>();
    private Hashtable<APIVerbs, String> _defaultServices = new Hashtable<APIVerbs, String>();
    private Hashtable<APIVerbs, String> _allServices = new Hashtable<APIVerbs, String>();
    private SocketFactory _socketFactory;
    public static final String SERVICE_NAME_ALL = "all";
    public static final String SERVICE_NAME_DEFAULT = "default";

    public Protocol() {
        super();
        initSocketFactory();
        _apiEntity = this.getClass().getCanonicalName()
                .substring(this.getClass().getPackage().getName().length() + 1).toLowerCase();
    }

    public Protocol(boolean runDescribe) throws APICommunicationException, APIProtocolException {
        this();
        if (runDescribe)
            setServices(describe());
    }

    public Protocol(ServiceVO[] services) {
        this();
        setServices(services);
    }

    public void setServices(ServiceVO[] services) {
        _services.clear();
        _defaultServices.clear();
        _allServices.clear();
        for (int index = 0; index < services.length; index++) {
            String serviceName = services[index].getServiceName();
            if (serviceName.equalsIgnoreCase(SERVICE_NAME_DEFAULT)) {
                String[] verbs = services[index].getVerbs();
                for (int verbsIndex = 0; verbsIndex < verbs.length; verbsIndex++)
                    try {
                        _defaultServices.put(APIVerbs.valueOf(_apiEntity, verbs[verbsIndex]), services[index]
                                .getVerbParameter(verbs[verbsIndex], "service_name").getValueAsString());
                    } catch (Exception expection) {
                        Debug.displayWarning(this,
                                "Invalid APIVerbs default service : " + _apiEntity + "/" + verbs[verbsIndex]);
                    }
            } else if (serviceName.equalsIgnoreCase(SERVICE_NAME_ALL)) {
                String[] verbs = services[index].getVerbs();
                for (int verbsIndex = 0; verbsIndex < verbs.length; verbsIndex++)
                    try {
                        _allServices.put(APIVerbs.valueOf(_apiEntity, verbs[verbsIndex]), services[index]
                                .getVerbParameter(verbs[verbsIndex], "service_name").getValueAsString());
                    } catch (Exception expection) {
                        Debug.displayWarning(this,
                                "Invalid APIVerbs all service : " + _apiEntity + "/" + verbs[verbsIndex]);
                    }
            } else {
                _services.put(serviceName, services[index]);
            }
        }
    }

    public SocketFactory initSocketFactory() {
        if (_socketFactory == null)
            _socketFactory = SSLSocketFactory.getSocketFactory();
        return (_socketFactory);
    }

    public String getAPIEntity() {
        return (_apiEntity);
    }

    public String getDefaultService(APIVerbs apiVerb, String defaultServiceName) {
        String service = getDefaultService(apiVerb);
        return (service == null ? defaultServiceName : service);
    }

    public String getDefaultService(APIVerbs apiVerb) {
        if (apiVerb == null)
            return (null);
        return (_defaultServices.get(apiVerb));
    }

    public String getAllService(APIVerbs apiVerb, String defaultServiceName) {
        String allService = getAllService(apiVerb);
        return (allService == null ? defaultServiceName : allService);
    }

    public String getAllService(APIVerbs apiVerb) {
        if (apiVerb == null)
            return (null);
        return (_allServices.get(apiVerb));
    }

    @Override
    public boolean equals(Object object) {
        if (this == object)
            return (true);
        else if (!(object instanceof Protocol))
            return (false);
        final Protocol other = (Protocol) object;
        return (_apiEntity.equals(other._apiEntity));
    }

    @Override
    public int hashCode() {
        return (37 + (_apiEntity.hashCode()));
    }

    public String buildURL(APIVerbs apiVerb, Hashtable<String, String> parameters) {
        String urlString = API.SERVER_URL + apiVerb.toPath() + "/";
        if (parameters != null) {
            boolean first = true;
            for (Enumeration keys = parameters.keys(); keys.hasMoreElements();) {
                String key = (String) keys.nextElement();
                String value = parameters.get(key);
                try {
                    urlString += (first ? "?" : "&") + URLEncoder.encode(key, "UTF-8") + "="
                            + URLEncoder.encode(value, "UTF-8");
                    first = false;
                } catch (UnsupportedEncodingException unsupportedEncodingException) {
                    throw new APIRuntimeException(unsupportedEncodingException);
                }
            }
        }
        return (urlString);
    }

    public JSONObject getJSON(APIVerbs apiVerb, Hashtable<String, String> parameters)
            throws APICommunicationException, APIProtocolException {
        return (doGetJSON(buildURL(apiVerb, parameters)));
    }

    public byte[] doGetBytes(String url) throws APICommunicationException {
        Session.getInstance().addActiveRequestCount();
        long t1 = System.currentTimeMillis();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            DefaultHttpClient httpclient = getHTTPClient();
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));
            if (httpResponse.getStatusLine().getStatusCode() != 200)
                throw new APICommunicationException("HTTP Error " + httpResponse.getStatusLine().getStatusCode()
                        + " - " + httpResponse.getStatusLine().getReasonPhrase() + " at " + url);
            HttpEntity httpEntity = httpResponse.getEntity();
            InputStream inputStream = httpEntity.getContent();
            byte[] buffer = new byte[4096];
            int readCount = 0;
            while ((readCount = inputStream.read(buffer)) != -1)
                byteArrayOutputStream.write(buffer, 0, readCount);
            httpclient.getConnectionManager().shutdown();
        } catch (IOException ioException) {
            throw new APICommunicationException(ioException);
        } finally {
            Session.getInstance().removeActiveRequestCount();
            long t2 = System.currentTimeMillis();
            Debug.print(url + " : " + t1 + "-" + t2 + "=" + (t2 - t1) + " : " + byteArrayOutputStream.size()
                    + " bytes");
        }
        return (byteArrayOutputStream.toByteArray());
    }

    public byte[] doGetBytes(APIVerbs apiVerb, Hashtable<String, String> parameters)
            throws APICommunicationException {
        return (doGetBytes(buildURL(apiVerb, parameters)));
    }

    public JSONObject doFilePost(APIVerbs apiVerb, Hashtable<String, String> urlParameters,
            Hashtable<String, String> postParameters, File file)
            throws APICommunicationException, APIProtocolException {
        try {
            return (doStreamPost(apiVerb, urlParameters, postParameters, new FileInputStream(file)));
        } catch (IOException ioException) {
            throw new APICommunicationException(ioException);
        }
    }

    public JSONObject doStreamPost(APIVerbs apiVerb, Hashtable<String, String> urlParameters,
            Hashtable<String, String> postParameters, InputStream inputStream)
            throws APICommunicationException, APIProtocolException {
        if (!_apiEntity.equalsIgnoreCase("voice"))
            Session.getInstance().addActiveRequestCount();
        long t1 = System.currentTimeMillis();
        JSONObject jsonObject = null;
        JSONParser jsonParser = new JSONParser();
        try {
            DefaultHttpClient httpclient = getHTTPClient();
            HttpPost httpPost = new HttpPost(buildURL(apiVerb, urlParameters));
            HttpProtocolParams.setUseExpectContinue(httpPost.getParams(), false);
            MultipartEntity multipartEntity = new MultipartEntity();
            if (postParameters != null)
                for (Enumeration enumeration = postParameters.keys(); enumeration.hasMoreElements();) {
                    String key = enumeration.nextElement().toString();
                    String value = postParameters.get(key);
                    multipartEntity.addPart(key, new StringBody(value));
                    Debug.print("HTTP POST : " + key + "=" + value);
                }
            if (inputStream != null) {
                InputStreamBody inputStreamBody = new InputStreamBody(inputStream, "binary/octet-stream");
                multipartEntity.addPart("audio", inputStreamBody);
            }
            httpPost.setEntity(multipartEntity);
            HttpResponse httpResponse = httpclient.execute(httpPost);
            if (httpResponse.getStatusLine().getStatusCode() != 200)
                throw new APICommunicationException("HTTP Error " + httpResponse.getStatusLine().getStatusCode()
                        + " - " + httpResponse.getStatusLine().getReasonPhrase());
            HttpEntity httpEntity = httpResponse.getEntity();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpEntity.getContent()));
            jsonObject = (JSONObject) jsonParser.parse(bufferedReader);
            bufferedReader.close();
            httpclient.getConnectionManager().shutdown();
        } catch (ParseException parseException) {
            throw new APIProtocolException(parseException);
        } catch (IOException ioException) {
            throw new APICommunicationException(ioException);
        } catch (ClassCastException classCastException) {
            throw new APIProtocolException(classCastException);
        } finally {
            if (!_apiEntity.equalsIgnoreCase("voice"))
                Session.getInstance().removeActiveRequestCount();
            long t2 = System.currentTimeMillis();
            Debug.print(buildURL(apiVerb, urlParameters) + " : " + t1 + "-" + t2 + "=" + (t2 - t1) + " : "
                    + jsonObject);
        }
        return (jsonObject);
    }

    public synchronized ServiceVO[] describe() throws APIProtocolException, APICommunicationException {
        Hashtable<String, String> parameters = buildParameters();
        ServiceVO[] services = null;
        try {
            JSONObject jsonObject = getJSON(APIVerbs.DESCRIBE, parameters);
            if (getStatusCode(jsonObject) == StatusCode.SUCCESSFUL) {
                JSONArray serviceVerbsJSONArray = getDataKeyedArrayJSON(jsonObject, "service_verbs");
                services = new ServiceVO[serviceVerbsJSONArray.size()];
                for (int index = 0; index < services.length; index++)
                    services[index] = new ServiceVO((JSONObject) serviceVerbsJSONArray.get(index));
            } else {
                throw new APIProtocolException(getStatusMessage(jsonObject));
            }
        } catch (ClassCastException classCastException) {
            throw new APIProtocolException(classCastException);
        } catch (NullPointerException nullPointerException) {
            throw new APIProtocolException(nullPointerException);
        }
        return (services);
    }

    public boolean doesVerbExist(String service, APIVerbs apiVerb) {
        if (service == null || service.trim().equals(""))
            return (false);
        ServiceVO serviceVO = _services.get(service);
        if (serviceVO == null)
            return (false);
        return (serviceVO.doesVerbExist(apiVerb.getVerb()));
    }

    public ServiceDetailsVO getDefaultServiceDetails(APIVerbs apiVerb, String defaultServiceName) {
        String service = getDefaultService(apiVerb, defaultServiceName);
        if (service == null)
            return (null);
        return (getServiceDetails(service));
    }

    public ServiceDetailsVO getDefaultServiceDetails(APIVerbs apiVerb) {
        return (getDefaultServiceDetails(apiVerb, null));
    }

    public ServiceDetailsVO getAllServiceDetails(APIVerbs apiVerb, String defaultServiceName) {
        String service = getAllService(apiVerb, defaultServiceName);
        if (service == null)
            return (null);
        return (getServiceDetails(service));
    }

    public ServiceDetailsVO getAllServiceDetails(APIVerbs apiVerb) {
        return (getAllServiceDetails(apiVerb, null));
    }

    public ServiceDetailsVO getServiceDetails(String service) {
        ServiceVO serviceVO = _services.get(service);
        if (serviceVO != null)
            return (serviceVO.getServiceDetails());
        return (null);
    }

    public ServiceVO[] getServices() {
        return (_services.values().toArray(new ServiceVO[0]));
    }

    public ServiceVO getService(String service) {
        return (_services.get(service));
    }

    public boolean hasAnyServices() {
        return (_services.size() > 0);
    }

    public String[] getAllVerbs() {
        SortedSet<String> sortedSet = new TreeSet<String>();
        for (Enumeration enumeration = _services.elements(); enumeration.hasMoreElements();) {
            String[] verbs = ((ServiceVO) (enumeration.nextElement())).getVerbs();
            for (int index = 0; index < verbs.length; index++)
                sortedSet.add(verbs[index]);
        }
        return (sortedSet.toArray(new String[0]));
    }

    protected Hashtable<String, String> buildParameters() {
        Hashtable<String, String> parameters = new Hashtable<String, String>();
        if (Session.getInstance().getToken() != null)
            parameters.put("token", Session.getInstance().getToken());
        else
            parameters.put("key", API.LICENCE_KEY);
        if (Session.getInstance().getPosition() != null) {
            parameters.put("lat",
                    "" + NumberUtils.roundToDecimals(Session.getInstance().getPosition().getLatitude()));
            parameters.put("lng",
                    "" + NumberUtils.roundToDecimals(Session.getInstance().getPosition().getLongitude()));
        }
        return (parameters);
    }

    protected JSONObject getResponseJSON(JSONObject jsonObject) throws APIProtocolException {
        try {
            return ((JSONObject) jsonObject.get("response"));
        } catch (Exception exception) {
            throw new APIProtocolException(exception);
        }
    }

    protected JSONObject getInformationJSON(JSONObject jsonObject) throws APIProtocolException {
        try {
            return ((JSONObject) getResponseJSON(jsonObject).get("information"));
        } catch (Exception exception) {
            throw new APIProtocolException(exception);
        }
    }

    protected JSONArray getDataArrayJSON(JSONObject jsonObject) throws APIProtocolException {
        try {
            return ((JSONArray) getResponseJSON(jsonObject).get("data"));
        } catch (Exception exception) {
            throw new APIProtocolException(exception);
        }
    }

    protected JSONObject getDataKeyedObjectJSON(JSONObject jsonObject, String objectKey)
            throws APIProtocolException {
        return (findJSONObjectInArray(getDataArrayJSON(jsonObject), objectKey));
    }

    protected JSONArray getDataKeyedArrayJSON(JSONObject jsonObject, String objectKey) throws APIProtocolException {
        return (findJSONArrayInArray(getDataArrayJSON(jsonObject), objectKey));
    }

    private JSONObject findJSONObjectInArray(JSONArray jsonArray, String key) {
        JSONObject jsonObject = null;
        for (int index = 0; index < jsonArray.size() && jsonObject == null; index++) {
            try {
                jsonObject = (JSONObject) ((JSONObject) jsonArray.get(index)).get(key);
            } catch (Exception exception) {
                jsonObject = null;
            }
        }
        return (jsonObject);
    }

    private JSONArray findJSONArrayInArray(JSONArray jsonArray, String key) {
        JSONArray jsonFoundArray = null;
        for (int index = 0; index < jsonArray.size() && jsonFoundArray == null; index++) {
            try {
                jsonFoundArray = (JSONArray) ((JSONObject) jsonArray.get(index)).get(key);
            } catch (Exception exception) {
                jsonFoundArray = null;
            }
        }
        return (jsonFoundArray);
    }

    protected JSONArray getActionArrayJSON(JSONObject jsonObject) throws APIProtocolException {
        try {
            return ((JSONArray) getResponseJSON(jsonObject).get("action"));
        } catch (Exception exception) {
            throw new APIProtocolException(exception);
        }
    }

    protected JSONObject getActionKeyedObjectJSON(JSONObject jsonObject, String objectKey)
            throws APIProtocolException {
        return (findJSONObjectInArray(getActionArrayJSON(jsonObject), objectKey));
    }

    protected StatusCode getStatusCode(JSONObject jsonObject, APIVerbs apiVerb) throws APIProtocolException {
        try {
            StatusCode statusCode = StatusCode.valueOf((java.lang.Long) getInformationJSON(jsonObject).get("code"));
            if (apiVerb != null)
                if (statusCode == StatusCode.SUCCESSFUL)
                    Session.getInstance().addPartialAPICall(apiVerb);
                else if (statusCode == StatusCode.PARTIAL_CONTENT)
                    Session.getInstance().removePartialAPICall(apiVerb);
            return (statusCode);
        } catch (Exception exception) {
            throw new APIProtocolException(exception);
        }
    }

    protected StatusCode getStatusCode(JSONObject jsonObject) throws APIProtocolException {
        return (getStatusCode(jsonObject, null));
    }

    protected String getStatusMessage(JSONObject jsonObject) throws APIProtocolException {
        try {
            return ((String) getInformationJSON(jsonObject).get("status"));
        } catch (Exception exception) {
            throw new APIProtocolException(exception);
        }
    }

    public JSONObject doGetJSON(String url) throws APICommunicationException, APIProtocolException {
        Session.getInstance().addActiveRequestCount();
        long t1 = System.currentTimeMillis();
        JSONObject jsonObject = null;
        JSONParser jsonParser = new JSONParser();
        try {
            DefaultHttpClient httpclient = getHTTPClient();
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));
            if (httpResponse.getStatusLine().getStatusCode() != 200)
                throw new APICommunicationException("HTTP Error " + httpResponse.getStatusLine().getStatusCode()
                        + " - " + httpResponse.getStatusLine().getReasonPhrase() + " at " + url);
            HttpEntity httpEntity = httpResponse.getEntity();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpEntity.getContent()));
            jsonObject = (JSONObject) jsonParser.parse(bufferedReader);
            bufferedReader.close();
            httpclient.getConnectionManager().shutdown();
        } catch (ParseException parseException) {
            throw new APIProtocolException(parseException);
        } catch (IOException ioException) {
            throw new APICommunicationException(ioException);
        } catch (ClassCastException classCastException) {
            throw new APIProtocolException(classCastException);
        } catch (IllegalArgumentException illegalArgumentException) {
            throw new APICommunicationException(illegalArgumentException);
        } finally {
            Session.getInstance().removeActiveRequestCount();
            long t2 = System.currentTimeMillis();
            Debug.print(url + " : " + t1 + "-" + t2 + "=" + (t2 - t1) + " : " + jsonObject);
        }
        return (jsonObject);
    }

    private DefaultHttpClient getHTTPClient() {
        DefaultHttpClient httpclient = new DefaultHttpClient();
        httpclient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", _socketFactory, 443));
        httpclient.addRequestInterceptor(new HttpRequestInterceptor() {

            public void process(final HttpRequest request, final HttpContext context)
                    throws HttpException, IOException {
                if (!request.containsHeader("Accept-Encoding")) {
                    request.addHeader("Accept-Encoding", "gzip");
                }
            }
        });
        httpclient.addResponseInterceptor(new HttpResponseInterceptor() {

            public void process(final HttpResponse response, final HttpContext context)
                    throws HttpException, IOException {
                HttpEntity entity = response.getEntity();
                Header ceheader = entity.getContentEncoding();
                if (ceheader != null) {
                    HeaderElement[] codecs = ceheader.getElements();
                    for (int index = 0; index < codecs.length; index++)
                        if (codecs[index].getName().equalsIgnoreCase("gzip")) {
                            response.setEntity(new GzipDecompressingEntity(response.getEntity()));
                            return;
                        }
                }
            }
        });
        return (httpclient);
    }

    private class GzipDecompressingEntity extends HttpEntityWrapper {

        public GzipDecompressingEntity(final HttpEntity entity) {
            super(entity);
        }

        @Override
        public InputStream getContent() throws IOException, IllegalStateException {
            InputStream wrappedin = wrappedEntity.getContent();
            return new GZIPInputStream(wrappedin);
        }

        @Override
        public long getContentLength() {
            return -1;
        }
    }
}