hk.hku.cecid.corvus.http.PartnershipSender.java Source code

Java tutorial

Introduction

Here is the source code for hk.hku.cecid.corvus.http.PartnershipSender.java

Source

/* 
 * Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
 * University of Hong Kong (HKU). All Rights Reserved.
 *
 * This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
 * 
 * [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 */

package hk.hku.cecid.corvus.http;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Iterator;

import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
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.PartSource;
import org.apache.commons.httpclient.methods.multipart.StringPart;

import hk.hku.cecid.corvus.ws.data.KVPairData;
import hk.hku.cecid.piazza.commons.util.FileLogger;

/**
 * The <code>PartnershipSender</code> is abstract base class for sending HTTP remote request
 * to H2O for executing partnership maintenance operation.
 * <br/><br/> 
 *
 * @author    Twinsen Tsang
 * @version 1.0.0 $STABLE$
 * @since   H2O 0908
 */
public abstract class PartnershipSender extends HttpSender implements PartnershipOp {
    // The operation for creating partnership.
    private int pOp = PartnershipOp.ADD;
    /* The result status line representing the operation result. */
    private String resultStatus = "Not yet run.";

    /**
     * Get the mapping of the partnership operation from integer to words.
     * <br/><br/>
     * By default, it is recommended to return a HashMap(Integer, String) with 3 mappings.
     * <br><br/>
     * HashMap.get(0) = A word representing the add partnership action.
     * HashMap.get(1) = A word representing the delete partnership action.
     * HashMap.get(2) = A word representing the update partnership action. 
     *  
     * @return The mapping of the partnership operation from integer to words. 
     */
    public abstract Map getPartnershipOperationMapping();

    /**
     * Get the mapping of the partnership data key to HTTP form parameter name.
     * <br/><br/>
     * For example, if there are 3 data (with keys) in your partnership data and
     * they are named as "dataKey0", "dataKey1" and "dataKey2", and you want the 
     * HTTP request going to execute containing multi-part parameters "formParam0", 
     * "formParam1" and "formParam2" with the value equal to the data value 
     * from "dataKey0", "dataKey1", "dataKey2" respectively, Then 
     * you should return the Map listed below: 
     * <br/><br/>
     * <pre>
     * Map m = new HashMap(); // Or LinkedHashMap() if you want to preserve the order.    
     * m.put("dataKey0", "fromParam0");
     * m.put("dataKey1", "fromParam1");
     * m.put("dataKey2", "fromParam2");
     * return m;
     * </pre> 
     * 
     * @return The mapping of the partnership data key to HTTP form parameter name.
     */
    public abstract Map getPartnershipMapping();

    /**
     * Explicit Constructor. Create an instance of <code>PartnershipSender</code>
     * 
     * @param logger The logger for log the sending process.
     * @param d The data used for generate HTTP multi-part request. It must be a kind of partnership data.  
     */
    protected PartnershipSender(FileLogger logger, KVPairData d) {
        super(logger, d);
    }

    /* (non-Javadoc)
     * @see hk.hku.cecid.corvus.http.PartnershipOperation#setExecuteOperation(int)
     */
    public void setExecuteOperation(int pOp) {
        if (pOp < 0 || pOp >= PartnershipOp.OP_LEN)
            throw new IllegalArgumentException("Expected operation value : 0, 1, 2");
        this.pOp = pOp;
    }

    /* (non-Javadoc)
     * @see hk.hku.cecid.corvus.http.PartnershipOperation#getExecuteOperation()
     */
    public int getExecuteOperation() {
        return this.pOp;
    }

    /**
     * Get the last status result description after executing the operation.
     * <br/><br/>
     * If the sender has not been invoked by other to execute partnership operation,
     * It returns "Not yet run".
     * 
     * @return the last status result description after executing the operation.
     */
    public String getStatus() {
        return this.resultStatus;
    }

    /**
     * [@EVENT] The method <code>onStart</code> log all new configuration. 
     */
    protected void onStart() {
        // Get the data,
        KVPairData data = (KVPairData) this.properties;
        super.onStart();
        if (this.log != null) {
            FileLogger l = this.log;
            // Log all information for this sender.
            l.log("Partnership HTTP Client init at " + new Date().toString());
            l.log("");
            l.log("Sending Partnership HTTP Request with following configuration");
            l.log("------------------------------------------------------------------");
            l.log("Partnership Operation : " + this.getPartnershipOperationMapping().get(new Integer(pOp)));
            if (data != null)
                l.log(data.toString());
            l.log("------------------------------------------------------------------");
            l.log("");
        }
    }

    /** 
     * [@EVENT] This method is invoked when the sender is required to create a HTTP Request from configuration.
     * <br/><br/>
     * It generates a multi-part content embedded in the HTTP POST request. The multi-part content
     * contains all partnership data with the parameter name retrieved from the partnership mapping.
     * {@link #getPartnershipMapping()}. Also the type of partnership operation is appended 
     * at the end of multi-part with parameter name equal to 'request_action' and it's value 
     * is extracted thru {@link #getPartnershipOperationMapping()}.
     */
    protected HttpMethod onCreateRequest() throws Exception {
        // Validate main parameter.
        Map data = ((KVPairData) this.properties).getProperties();
        Map data2webFormName = this.getPartnershipMapping();

        if (data2webFormName == null)
            throw new NullPointerException("Missing partnership mapping for creating HTTP request");

        // Create the HTTP POST method targeted to service end-point.
        PostMethod post = new PostMethod(this.getServiceEndPoint().toExternalForm());
        List parts = new ArrayList(); // An array for multi-part;       

        /* 
         * For each data key in the partnership data, create a String multi-part
         * with the request parameter name equal to the mapping from the data key.  
         * 
         * For the field like verification / encryption certificates, it creates
         * a byte array multi-part source. 
         */
        Iterator itr = data2webFormName.entrySet().iterator();
        Map.Entry e; // an entry representing the partnership data to web form name mapping.
        String formParamName; // a temporary pointer pointing to the value in the entry.
        Object dataValue; // a temporary pointer pointing to the value in the partnership data.
        Part newPart; // a temporary pointer pointing to a multi-part part.

        while (itr.hasNext()) {
            e = (Map.Entry) itr.next();
            formParamName = (String) e.getValue();
            // Add new part if the mapped key is not null.
            if (e.getValue() != null) {
                dataValue = data.get(e.getKey());
                if (dataValue == null) // Use empty string when the key is not filled.
                    dataValue = "";
                if (dataValue instanceof String) { // Create literal part               
                    newPart = new StringPart(formParamName, (String) dataValue);
                } else if (dataValue instanceof byte[]) { // Create streaming multi-part
                    PartSource source = new ByteArrayPartSource((String) e.getKey(), (byte[]) dataValue);
                    newPart = new FilePart(formParamName, source);
                } else if (dataValue instanceof Boolean) {
                    newPart = new StringPart(formParamName, String.valueOf((Boolean) dataValue));
                } else {
                    newPart = new StringPart(formParamName, dataValue.toString());
                }
                // Add the new part.
                parts.add(newPart);
            }
        }

        Map partnershipOpMap = this.getPartnershipOperationMapping();
        /* Add HTTP request action to the web form parameter. */
        parts.add(new StringPart("request_action", (String) partnershipOpMap.get(new Integer(this.pOp))));

        MultipartRequestEntity multipartRequest = new MultipartRequestEntity((Part[]) parts.toArray(new Part[] {}),
                post.getParams());

        post.setRequestEntity(multipartRequest);
        return post;
    }

    /**
     * [@EVENT] This method is invoked when receivedas2 the reply HTTP response from the server.
     * <br/><br/>
     * Verify the HTTP response (expected a HTML content) by PartnershipOpVerifer to check
     * whether the partnership operation execute successfully or not.
     * 
     * @throws SAXException 
     *          When fail to verify by PartnershipOpVerifer.
     */
    protected void onResponse() throws Exception {
        try {
            HttpMethod method = this.getExecutedMethod();
            InputStream ins = method.getResponseBodyAsStream();
            new PartnershipOpVerifer().validate(ins);
            ins.close();
            this.resultStatus = "Operation executed successfully.";
        } catch (Exception ex) {
            this.resultStatus = "ERROR: " + ex.getMessage();
            throw ex; // Re-throw 
        }
    }
}