com.cloudbees.api.BeesClientBase.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudbees.api.BeesClientBase.java

Source

/*
 *  Copyright 2013 Cloud4SOA, www.cloud4soa.eu
 *
 *  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.
 */

/*
 * Copyright 2010-2011, CloudBees Inc.
 *
 * 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.cloudbees.api;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.params.HttpParams;

public class BeesClientBase {
    Logger logger = Logger.getLogger(getClass().getSimpleName());
    protected String format = "xml";

    private String serverApiUrl = "http://localhost:8080/api";

    private String api_key;

    private String secret;

    private String version = "1.0";

    private String sigVersion = "1";

    private boolean verbose = true;

    private BeesClientConfiguration beesClientConfiguration;

    public BeesClientBase(BeesClientConfiguration beesClientConfiguration) {
        if (beesClientConfiguration == null) {
            throw new IllegalArgumentException("BeesClientConfiguration cannot be null");
        }
        this.beesClientConfiguration = beesClientConfiguration;
        if (beesClientConfiguration.getServerApiUrl() != null) {
            this.serverApiUrl = beesClientConfiguration.getServerApiUrl();
        }
        if (beesClientConfiguration.getApiKey() != null) {
            this.api_key = beesClientConfiguration.getApiKey();
        }
        if (beesClientConfiguration.getSecret() != null) {
            this.secret = beesClientConfiguration.getSecret();
        }
        if (beesClientConfiguration.getFormat() != null) {
            this.format = beesClientConfiguration.getFormat();
        }
        if (beesClientConfiguration.getVersion() != null) {
            this.version = beesClientConfiguration.getVersion();
        }
    }

    public BeesClientBase(String serverApiUrl, String apiKey, String secret, String format, String version) {
        this(new BeesClientConfiguration(serverApiUrl, apiKey, secret, format, version));
    }

    public boolean isVerbose() {
        return verbose;
    }

    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }

    public String getRequestURL(String method, Map<String, String> methodParams) throws Exception {
        return getRequestURL(method, methodParams, true);
    }

    public String getRequestURL(String method, Map<String, String> methodParams, boolean asActionParam)
            throws Exception {
        HashMap<String, String> urlParams = getDefaultParameters();

        StringBuilder requestURL = getApiUrl(asActionParam ? null : method);
        requestURL.append("?");

        for (Map.Entry<String, String> entry : methodParams.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            urlParams.put(key, value);
        }

        if (asActionParam)
            urlParams.put("action", method);

        String signature = calculateSignature(urlParams);
        Iterator<Map.Entry<String, String>> it = urlParams.entrySet().iterator();
        for (int i = 0; it.hasNext(); i++) {
            Map.Entry<String, String> entry = it.next();
            String key = entry.getKey();
            String value = entry.getValue();
            if (i > 0)
                requestURL.append("&");
            requestURL.append(URLEncoder.encode(key, "UTF-8"));
            requestURL.append("=");
            requestURL.append(URLEncoder.encode(value, "UTF-8"));
        }

        requestURL.append("&");
        requestURL.append("sig");
        requestURL.append("=");
        requestURL.append(signature);

        return requestURL.toString();
    }

    private String calculateSignature(Map<String, String> entries) throws Exception {
        StringBuilder sigData = new StringBuilder();
        ArrayList<Map.Entry<String, String>> sortedParams = new ArrayList<Map.Entry<String, String>>(
                entries.entrySet());
        Collections.sort(sortedParams, new Comparator<Map.Entry<String, String>>() {
            public int compare(Entry<String, String> e1, Entry<String, String> e2) {
                return e1.getKey().compareTo(e2.getKey());
            }
        });
        for (Map.Entry<String, String> entry : sortedParams) {
            String key = entry.getKey();
            String value = entry.getValue();
            sigData.append(key);
            sigData.append(value);
        }

        // append the signature
        String signature = getSignature(sigData.toString(), secret);
        return signature;
    }

    protected StringBuilder getApiUrl(String method) {
        StringBuilder requestURL = new StringBuilder();
        requestURL.append(serverApiUrl);
        if (method != null) {
            requestURL.append("/");
            requestURL.append(method);
        }
        return requestURL;
    }

    private HashMap<String, String> getDefaultParameters() {
        HashMap<String, String> urlParams = new HashMap<String, String>();
        urlParams.put("format", format);
        urlParams.put("v", version);
        urlParams.put("api_key", api_key);
        urlParams.put("timestamp", new Long(System.currentTimeMillis() / 1000).toString());
        urlParams.put("sig_version", sigVersion);
        return urlParams;
    }

    public static String getSignature(String data, String secret) throws Exception {
        String s = data + secret;
        String sig = md5(s);
        return sig;
    }

    public static String md5(String message) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] md5Bytes = md5.digest(message.getBytes("CP1252"));
            StringBuffer hex = new StringBuffer();
            for (int i = 0; i < md5Bytes.length; ++i) {
                hex.append(Integer.toHexString((md5Bytes[i] & 0xFF) | 0x100).substring(1, 3));
            }

            return hex.toString();
        } catch (NoSuchAlgorithmException e) {
        } catch (UnsupportedEncodingException e) {
        }
        return null;
    }

    public String executeRequest(String url) throws Exception {
        HttpClient httpClient = HttpClientHelper.createClient(this.beesClientConfiguration);
        GetMethod getMethod = new GetMethod(url);
        httpClient.executeMethod(getMethod);

        return getResponseString(getMethod.getResponseBodyAsStream());
    }

    private String getResponseString(InputStream ins) throws IOException {
        StringBuffer response = new StringBuffer();
        try {
            InputStreamReader isr = new InputStreamReader(ins);
            char[] chars = new char[1024];
            int numRead = isr.read(chars, 0, chars.length);
            while (numRead != -1) {
                response.append(new String(chars, 0, numRead));
                numRead = isr.read(chars, 0, chars.length);
            }
        } finally {
            ins.close();
        }
        return response.toString();
    }

    public InputStream executeCometRequest(String url) throws Exception {
        HttpClient httpClient = HttpClientHelper.createClient(this.beesClientConfiguration);
        HttpParams params = httpClient.getParams();
        params.setIntParameter(HttpConnectionParams.SO_TIMEOUT, 0);
        GetMethod getMethod = new GetMethod(url);
        httpClient.executeMethod(getMethod);
        return getMethod.getResponseBodyAsStream();
    }

    protected void trace(String message) {
        if (verbose) {
            System.out.println(message);
        }
    }

    protected void traceResponse(String message) {
        if (verbose)
            System.out.println("xml response: " + message);
    }

    protected String executeUpload(String uploadURL, Map<String, String> params, Map<String, File> files,
            UploadProgress writeListener) throws Exception {
        HashMap<String, String> clientParams = getDefaultParameters();
        clientParams.putAll(params);

        PostMethod filePost = new PostMethod(uploadURL);
        try {
            ArrayList<Part> parts = new ArrayList<Part>();

            int fileUploadSize = 0;
            for (Map.Entry<String, File> fileEntry : files.entrySet()) {
                FilePart filePart = new FilePart(fileEntry.getKey(), fileEntry.getValue());
                parts.add(filePart);
                fileUploadSize += filePart.length();
                //TODO: file params are not currently included in the signature,
                //      we should hash the file contents so we can verify them
            }

            for (Map.Entry<String, String> entry : clientParams.entrySet()) {
                parts.add(new StringPart(entry.getKey(), entry.getValue()));
            }

            // add the signature
            String signature = calculateSignature(clientParams);
            parts.add(new StringPart("sig", signature));

            ProgressUploadEntity uploadEntity = new ProgressUploadEntity(parts.toArray(new Part[parts.size()]),
                    filePost.getParams(), writeListener, fileUploadSize);
            filePost.setRequestEntity(uploadEntity);
            HttpClient client = HttpClientHelper.createClient(this.beesClientConfiguration);
            client.getHttpConnectionManager().getParams().setConnectionTimeout(10000);

            int status = client.executeMethod(filePost);
            String response = getResponseString(filePost.getResponseBodyAsStream());
            if (status == HttpStatus.SC_OK) {
                trace("upload complete, response=" + response);
            } else {
                trace("upload failed, response=" + HttpStatus.getStatusText(status));
            }
            return response;
        } finally {
            filePost.releaseConnection();
        }
    }

    class ProgressUploadEntity extends MultipartRequestEntity {
        private UploadProgress listener;
        long length;

        public ProgressUploadEntity(Part[] parts, HttpMethodParams params, UploadProgress listener, long length) {
            super(parts, params);
            this.listener = listener;
            this.length = length;
        }

        @Override
        public void writeRequest(OutputStream out) throws IOException {
            WriteListenerOutputStream listenStream = new WriteListenerOutputStream(out, listener, length);
            super.writeRequest(listenStream);
        }
    }

    class WriteListenerOutputStream extends OutputStream {
        private OutputStream targetStream;
        private long bytesWritten;
        private boolean isClosed;
        private long bytesToSend;
        private UploadProgress writeListener;

        public WriteListenerOutputStream(OutputStream targetStream, UploadProgress writeListener, long length) {
            super();
            this.targetStream = targetStream;
            this.writeListener = writeListener;
            this.bytesToSend = length;
        }

        public void close() throws IOException {
            isClosed = true;
            targetStream.close();
        }

        public void flush() throws IOException {
            targetStream.flush();
        }

        public void write(byte[] b, int off, int len) throws IOException {
            targetStream.write(b, off, len);
            trackBytesWritten(len);
        }

        public void write(byte[] b) throws IOException {
            targetStream.write(b);
            trackBytesWritten(b.length);
        }

        public void write(int b) throws IOException {
            targetStream.write(b);
            trackBytesWritten(1);
        }

        public boolean isClosed() {
            return isClosed;
        }

        public long getBytesWritten() {
            return bytesWritten;
        }

        private void trackBytesWritten(long count) {
            bytesWritten += count;
            if (writeListener != null) {
                writeListener.handleBytesWritten(count, bytesWritten, bytesToSend);
            }
        }
    }

}