org.alfresco.wcm.client.impl.WebScriptCallerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.wcm.client.impl.WebScriptCallerImpl.java

Source

/*
 * #%L
 * Alfresco WCMQS Client API
 * %%
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 * %%
 * This file is part of the Alfresco software. 
 * If the software was purchased under a paid Alfresco license, the terms of 
 * the paid license agreement will prevail.  Otherwise, the software is 
 * provided under the following open source license terms:
 * 
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */
package org.alfresco.wcm.client.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class WebScriptCallerImpl implements WebScriptCaller {
    static Log log = LogFactory.getLog(WebScriptCallerImpl.class);

    private static ThreadLocal<byte[]> localBuffer = new ThreadLocal<byte[]>() {
        @Override
        protected byte[] initialValue() {
            return new byte[1024];
        }
    };

    private String baseUrl;
    HttpClient httpClient;
    private AuthScope authScope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);

    private String username = null;
    private String password = null;;

    public WebScriptCallerImpl() {
        httpClient = new HttpClient();
        httpClient.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
    }

    /**
     * Method that allows the default HttpClient instance to be replaced with one that is configured differently
     * @param httpClient
     */
    public void setHttpClient(HttpClient httpClient) {
        this.httpClient = httpClient;
    }

    public void setBaseUrl(String serviceLocation) throws URISyntaxException {
        this.baseUrl = serviceLocation;
        if (!baseUrl.endsWith("/")) {
            baseUrl += "/";
        }
    }

    public void setAuthScope(AuthScope authScope) {
        this.authScope = authScope;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void init() {
    }

    public String getTicket(String user, String password) {
        TicketResponseHandler responseHandler = new TicketResponseHandler();
        List<WebscriptParam> paramList = new ArrayList<WebscriptParam>();
        paramList.add(new WebscriptParam("u", user));
        paramList.add(new WebscriptParam("pw", password));
        get("login", responseHandler, paramList, true);
        Credentials credentials = new UsernamePasswordCredentials(user, password);
        if (responseHandler.ticket != null) {
            credentials = new UsernamePasswordCredentials("", responseHandler.ticket);
        }
        httpClient.getState().setCredentials(authScope, credentials);
        httpClient.getParams().setAuthenticationPreemptive(true);
        return responseHandler.ticket;
    }

    /* (non-Javadoc)
     * @see org.alfresco.wcm.client.impl.WebScriptCaller#getJsonObject(java.lang.String, java.util.List)
     */
    public JSONObject getJsonObject(String servicePath, List<WebscriptParam> params) {
        GetMethod getMethod = getGETMethod(servicePath, params);
        JsonResponseHandler handler = new JsonResponseHandler();
        executeRequest(handler, getMethod);
        return handler.jsonObject;
    }

    public void get(String servicePath, WebscriptResponseHandler handler, List<WebscriptParam> params) {
        get(servicePath, handler, params, false);
    }

    private void get(String servicePath, WebscriptResponseHandler handler, List<WebscriptParam> params,
            boolean ignoreUnauthorized) {
        GetMethod getMethod = getGETMethod(servicePath, params);
        executeRequest(handler, getMethod, ignoreUnauthorized);
    }

    public void post(String servicePath, WebscriptResponseHandler handler, List<WebscriptParam> params) {
        PostMethod postMethod = getPOSTMethod(servicePath, params);
        executeRequest(handler, postMethod);
    }

    private void executeRequest(WebscriptResponseHandler handler, HttpMethod httpMethod) {
        executeRequest(handler, httpMethod, false);
    }

    private void executeRequest(WebscriptResponseHandler handler, HttpMethod httpMethod,
            boolean ignoreUnauthorized) {
        long startTime = 0L;
        if (log.isDebugEnabled()) {
            startTime = System.currentTimeMillis();
        }
        try {
            httpClient.executeMethod(httpMethod);

            if ((httpMethod.getStatusCode() == 401 || httpMethod.getStatusCode() == 403) && !ignoreUnauthorized) {
                discardResponse(httpMethod);

                this.getTicket(username, password);
                httpClient.executeMethod(httpMethod);
            }

            if (httpMethod.getStatusCode() == 200) {
                handler.handleResponse(httpMethod.getResponseBodyAsStream());
            } else {
                // Must read the response, even though we don't use it
                discardResponse(httpMethod);
            }
        } catch (RuntimeException ex) {
            log.error("Rethrowing runtime exception.", ex);
            throw ex;
        } catch (Exception ex) {
            log.error("Failed to make request to Alfresco web script", ex);
        } finally {
            if (log.isDebugEnabled()) {
                log.debug(httpMethod.getName() + " request to " + httpMethod.getPath() + "?"
                        + httpMethod.getQueryString() + " completed in " + (System.currentTimeMillis() - startTime)
                        + "ms");
            }
            httpMethod.releaseConnection();
        }
    }

    void discardResponse(HttpMethod httpMethod) throws IOException {
        if (log.isDebugEnabled()) {
            log.debug("Received non-OK response when invoking method on path " + httpMethod.getPath()
                    + ". Response was:\n" + httpMethod.getResponseBodyAsString());
        } else {
            byte[] buf = localBuffer.get();
            InputStream responseStream = httpMethod.getResponseBodyAsStream();
            while (responseStream.read(buf) != -1)
                ;
        }
    }

    GetMethod getGETMethod(String servicePath, List<WebscriptParam> params) {
        GetMethod getMethod = new GetMethod(this.baseUrl + servicePath);

        if (params != null) {
            List<NameValuePair> args = new ArrayList<NameValuePair>();
            for (WebscriptParam param : params) {
                args.add(new NameValuePair(param.getName(), param.getValue()));
            }
            getMethod.setQueryString(args.toArray(new NameValuePair[args.size()]));
        }
        return getMethod;
    }

    PostMethod getPOSTMethod(String servicePath, List<WebscriptParam> params) {
        PostMethod postMethod = new PostMethod(this.baseUrl + servicePath);

        if (params != null) {
            List<NameValuePair> args = new ArrayList<NameValuePair>();
            for (WebscriptParam param : params) {
                args.add(new NameValuePair(param.getName(), param.getValue()));
            }
            postMethod.addParameters(args.toArray(new NameValuePair[args.size()]));
        }
        return postMethod;
    }

    @Override
    public JSONObject getJsonObject(String servicePath, WebscriptParam... params) {
        return getJsonObject(servicePath, Arrays.asList(params));
    }

    @Override
    public void get(String servicePath, WebscriptResponseHandler handler, WebscriptParam... params) {
        get(servicePath, handler, Arrays.asList(params));
    }

    private static class JsonResponseHandler implements WebscriptResponseHandler {
        public JSONObject jsonObject;

        @Override
        public void handleResponse(InputStream in) {
            try {
                jsonObject = new JSONObject(new JSONTokener(new InputStreamReader(in, "UTF-8")));
            } catch (JSONException ex) {
                log.error("Failed to parse response from Alfresco", ex);
            } catch (UnsupportedEncodingException e) {
                //UTF-8 is always supported
            }
        }

    }

    private static class TicketResponseHandler extends DefaultHandler implements WebscriptResponseHandler {
        private String ticket = null;
        private StringBuilder ticketChars;

        @Override
        public void handleResponse(InputStream in) {
            SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
            SAXParser parser;
            try {
                parser = saxParserFactory.newSAXParser();
                parser.parse(in, this);
            } catch (Exception e) {
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if (ticketChars != null) {
                ticketChars.append(ch, start, length);
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if ("ticket".equals(qName) && ticketChars != null) {
                ticket = ticketChars.toString();
                ticketChars = null;
            }
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if ("ticket".equals(qName)) {
                ticketChars = new StringBuilder();
            }
        }
    }
}