org.opencastproject.workflow.handler.mediapackagepost.MediaPackagePostOperationHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.opencastproject.workflow.handler.mediapackagepost.MediaPackagePostOperationHandler.java

Source

/**
 *  Copyright 2009, 2010 The Regents of the University of California
 *  Licensed under the Educational Community 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.osedu.org/licenses/ECL-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 org.opencastproject.workflow.handler.mediapackagepost;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONObject;
import org.json.XML;
import org.opencastproject.job.api.JobContext;
import org.opencastproject.mediapackage.MediaPackage;
import org.opencastproject.mediapackage.MediaPackageParser;
import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
import org.opencastproject.workflow.api.WorkflowInstance;
import org.opencastproject.workflow.api.WorkflowOperationException;
import org.opencastproject.workflow.api.WorkflowOperationInstance;
import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
import org.opencastproject.workflow.api.WorkflowOperationResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.opencastproject.search.api.SearchService;
import org.opencastproject.search.api.SearchQuery;
import org.opencastproject.search.api.SearchResult;

/**
 * Workflow Operation for POSTing a MediaPackage via HTTP
 */
public class MediaPackagePostOperationHandler extends AbstractWorkflowOperationHandler {

    /** The logging facility */
    private static final Logger logger = LoggerFactory.getLogger(MediaPackagePostOperationHandler.class);

    /** search service **/
    private SearchService searchService;

    public void setSearchService(SearchService searchService) {
        this.searchService = searchService;
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.opencastproject.workflow.api.WorkflowOperationHandler#getConfigurationOptions()
     */
    @Override
    public SortedMap<String, String> getConfigurationOptions() {
        return Configuration.OPTIONS;
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
     *      JobContext)
     */
    public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
            throws WorkflowOperationException {

        // get configuration
        WorkflowOperationInstance currentOperation = workflowInstance.getCurrentOperation();
        Configuration config = new Configuration(currentOperation);

        MediaPackage mp = workflowInstance.getMediaPackage();

        /* Check if we need to replace the Mediapackage we got with the published
         * Mediapackage from the Search Service */
        if (config.mpFromSearch) {
            SearchQuery searchQuery = new SearchQuery();
            searchQuery.withId(mp.getIdentifier().toString());
            SearchResult result = searchService.getByQuery(searchQuery);
            if (result.size() != 1) {
                throw new WorkflowOperationException("Received multiple results for identifier" + "\""
                        + mp.getIdentifier().toString() + "\" from search service. ");
            }
            logger.info("Getting Mediapackage from Search Service");
            mp = result.getItems()[0].getMediaPackage();
        }

        try {

            logger.info("Submitting \"" + mp.getTitle() + "\" (" + mp.getIdentifier().toString() + ") as "
                    + config.getFormat().name() + " to " + config.getUrl().toString());

            // serialize MediaPackage to target format
            OutputStream serOut = new ByteArrayOutputStream();
            MediaPackageParser.getAsXml(mp, serOut, false);
            String mpStr = serOut.toString();
            serOut.close();
            if (config.getFormat() == Configuration.Format.JSON) {
                JSONObject json = XML.toJSONObject(mpStr);
                mpStr = json.toString();
                if (mpStr.startsWith("{\"ns2:")) {
                    mpStr = (new StringBuilder()).append("{\"").append(mpStr.substring(6)).toString();
                }
            }

            // Log mediapackge
            if (config.debug()) {
                logger.info(mpStr);
            }

            // constrcut message body
            List<NameValuePair> data = new ArrayList<NameValuePair>();
            data.add(new BasicNameValuePair("mediapackage", mpStr));
            data.addAll(config.getAdditionalFields());

            // construct POST
            HttpPost post = new HttpPost(config.getUrl());
            post.setEntity(new UrlEncodedFormEntity(data, config.getEncoding()));

            // execute POST
            DefaultHttpClient client = new DefaultHttpClient();

            // Handle authentication
            if (config.authenticate()) {
                URL targetUrl = config.getUrl().toURL();
                client.getCredentialsProvider().setCredentials(
                        new AuthScope(targetUrl.getHost(), targetUrl.getPort()), config.getCredentials());
            }

            HttpResponse response = client.execute(post);

            // throw Exception if target host did not return 200
            int status = response.getStatusLine().getStatusCode();
            if (status == 200) {
                if (config.debug()) {
                    logger.info("Successfully submitted \"" + mp.getTitle() + "\" (" + mp.getIdentifier().toString()
                            + ") to " + config.getUrl().toString() + ": 200 OK");
                }
            } else if (status == 418) {
                logger.warn("Submitted \"" + mp.getTitle() + "\" (" + mp.getIdentifier().toString() + ") to "
                        + config.getUrl().toString() + ": The target claims to be a teapot. "
                        + "The Reason for this is probably an insane programmer.");
            } else {
                throw new WorkflowOperationException(
                        "Faild to submit \"" + mp.getTitle() + "\" (" + mp.getIdentifier().toString() + "), "
                                + config.getUrl().toString() + " answered with: " + Integer.toString(status));
            }
        } catch (Exception e) {
            if (e instanceof WorkflowOperationException) {
                throw (WorkflowOperationException) e;
            } else {
                throw new WorkflowOperationException(e);
            }
        }
        return createResult(mp, Action.CONTINUE);
    }

    /** Serialize XML Document to string
     *
     * @param doc
     * @return
     * @throws Exception
     */
    private String xmlToString(Document doc) throws Exception {
        Source source = new DOMSource(doc);
        StringWriter stringWriter = new StringWriter();
        Result result = new StreamResult(stringWriter);
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();
        transformer.transform(source, result);
        return stringWriter.getBuffer().toString();
    }

    /** Serialize XML Document to JSON string
     *
     * @param doc
     * @return
     * @throws Exception
     */
    private String xmlToJSONString(Document doc) throws Exception {
        JSONObject json = XML.toJSONObject(xmlToString(doc));
        return json.toString();
    }

    // <editor-fold defaultstate="collapsed" desc="Inner class that wraps around this WorkflowOperations Configuration">
    private static class Configuration {

        public static enum Format {
            XML, JSON
        };

        // Key for the WorkflowOperation Configuration
        public static final String PROPERTY_URL = "url";
        public static final String PROPERTY_FORMAT = "format";
        public static final String PROPERTY_ENCODING = "encoding";
        public static final String PROPERTY_AUTH = "auth.enabled";
        public static final String PROPERTY_AUTHUSER = "auth.username";
        public static final String PROPERTY_AUTHPASSWD = "auth.password";
        public static final String PROPERTY_DEBUG = "debug";
        public static final String PROPERTY_MEDIAPACKAGE_TYPE = "mediapackage.type";
        public static final TreeMap<String, String> OPTIONS;

        static {
            OPTIONS = new TreeMap<String, String>();
            OPTIONS.put(Configuration.PROPERTY_URL, "The URL to which the MediaPackage will be submitted");
            OPTIONS.put(Configuration.PROPERTY_FORMAT, "The output format for the MediaPackage (default: XML)");
            OPTIONS.put(Configuration.PROPERTY_ENCODING, "Message Encoding (default: UTF-8)");
            OPTIONS.put(Configuration.PROPERTY_AUTH, "The authentication method to use (no/http-digest)");
            OPTIONS.put(Configuration.PROPERTY_AUTHUSER, "The username to use for authentication");
            OPTIONS.put(Configuration.PROPERTY_AUTHPASSWD, "The password to use for authentication");
            OPTIONS.put(Configuration.PROPERTY_DEBUG,
                    "If this options is set the message body returned by target host is dumped to log (default: no)");
            OPTIONS.put(Configuration.PROPERTY_MEDIAPACKAGE_TYPE,
                    "Type of Mediapackage to send (workflow, search; default: search)");
        }

        // Configuration values
        private URI url;
        private Format format = Format.XML;
        private String encoding = "UTF-8";
        private boolean authenticate = false;
        private UsernamePasswordCredentials credentials = null;
        private List<NameValuePair> additionalFields = new ArrayList<NameValuePair>();
        private boolean debug = false;
        private boolean mpFromSearch = true;

        public Configuration(WorkflowOperationInstance operation) throws WorkflowOperationException {
            try {
                Set<String> keys = operation.getConfigurationKeys();

                // configure URL
                if (keys.contains(PROPERTY_URL)) {
                    url = new URI(operation.getConfiguration(PROPERTY_URL));
                } else {
                    throw new IllegalArgumentException("No target URL provided.");
                }

                // configure format
                if (keys.contains(PROPERTY_FORMAT)) {
                    format = Format.valueOf(operation.getConfiguration(PROPERTY_FORMAT).toUpperCase());
                }

                // configure message encoding
                if (keys.contains(PROPERTY_ENCODING)) {
                    encoding = operation.getConfiguration(PROPERTY_ENCODING);
                }

                // configure authentication
                if (keys.contains(PROPERTY_AUTH)) {
                    String auth = operation.getConfiguration(PROPERTY_AUTH).toUpperCase();
                    if (!("NO").equals(auth) && !("FALSE").equals(auth)) {
                        String username = operation.getConfiguration(PROPERTY_AUTHUSER);
                        String password = operation.getConfiguration(PROPERTY_AUTHPASSWD);
                        if (username == null || password == null) {
                            throw new WorkflowOperationException(
                                    "Username and Password must be provided for authentication!");
                        }
                        credentials = new UsernamePasswordCredentials(username, password);
                        authenticate = true;
                    }
                }

                // Configure debug mode
                if (keys.contains(PROPERTY_DEBUG)) {
                    String debugstr = operation.getConfiguration(PROPERTY_DEBUG).trim().toUpperCase();
                    debug = "YES".equals(debugstr) || "TRUE".equals(debugstr);
                }

                // Configure debug mode
                if (keys.contains(PROPERTY_MEDIAPACKAGE_TYPE)) {
                    String cfgval = operation.getConfiguration(PROPERTY_MEDIAPACKAGE_TYPE).trim().toUpperCase();
                    mpFromSearch = "SEARCH".equals(cfgval);
                }

                // get additional form fields
                for (Iterator<String> iter = operation.getConfigurationKeys().iterator(); iter.hasNext();) {
                    String key = iter.next();
                    if (key.startsWith("+")) {
                        String value = operation.getConfiguration(key);
                        additionalFields.add(new BasicNameValuePair(key.substring(1), value));
                    }
                }
            } catch (Exception e) {
                throw new WorkflowOperationException("Faild to configure operation instance.", e);
            }
        }

        public URI getUrl() {
            return url;
        }

        public Format getFormat() {
            return format;
        }

        public String getEncoding() {
            return encoding;
        }

        public boolean authenticate() {
            return authenticate;
        }

        public UsernamePasswordCredentials getCredentials() {
            return credentials;
        }

        public List<NameValuePair> getAdditionalFields() {
            return additionalFields;
        }

        public boolean debug() {
            return debug;
        }

        public boolean mpFromSearch() {
            return mpFromSearch;
        }
    }

    // </editor-fold>
}