com.googlecode.fascinator.common.PythonUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.fascinator.common.PythonUtils.java

Source

/*
 * The Fascinator - Python Utils
 * Copyright (C) 2008-2011 University of Southern Queensland
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.googlecode.fascinator.common;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.commons.lang.StringEscapeUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.io.SAXReader;
import org.ontoware.rdf2go.Reasoning;
import org.ontoware.rdf2go.exception.ModelRuntimeException;
import org.ontoware.rdf2go.impl.jena24.ModelImplJena24;
import org.ontoware.rdf2go.model.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.fascinator.api.PluginException;
import com.googlecode.fascinator.api.PluginManager;
import com.googlecode.fascinator.api.access.AccessControlException;
import com.googlecode.fascinator.api.access.AccessControlManager;
import com.googlecode.fascinator.api.access.AccessControlSchema;
import com.googlecode.fascinator.api.storage.DigitalObject;
import com.googlecode.fascinator.api.storage.Payload;
import com.googlecode.fascinator.api.storage.PayloadType;
import com.googlecode.fascinator.api.storage.StorageException;

/**
 * The purpose of this class is to expose common Java classes and methods we use
 * to Python scripts.
 * 
 * Messaging is a duplicate of com.googlecode.fascinator.MessagingServices since
 * Common library cannot acces it.
 * 
 * @author Greg Pendlebury
 */
public class PythonUtils {
    private static Logger log = LoggerFactory.getLogger(PythonUtils.class);
    private static String DEFAULT_ACCESS_PLUGIN = "hibernateAccessControl";

    /** Security */
    private AccessControlManager access;

    /** XML Parsing */
    private Map<String, String> namespaces;
    private SAXReader saxReader;

    /** Message Queues */
    private ActiveMQConnectionFactory connectionFactory;
    private Connection connection;
    private Session session;
    private MessageProducer producer;
    private Map<String, Destination> destinations;
    private JsonSimple config;
    private String current_access_plugin;

    public PythonUtils(JsonSimpleConfig config) throws PluginException {
        this.config = config;
        // Security
        String accessControlType = "accessmanager";
        access = PluginManager.getAccessManager(accessControlType);
        access.init(config.toString());

        // XML parsing
        namespaces = new HashMap<String, String>();
        DocumentFactory docFactory = new DocumentFactory();
        docFactory.setXPathNamespaceURIs(namespaces);
        saxReader = new SAXReader(docFactory);

        // Message Queues
        String brokerUrl = config.getString(ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL, "messaging", "url");
        connectionFactory = new ActiveMQConnectionFactory(brokerUrl);
        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            // create single producer for multiple destinations
            producer = session.createProducer(null);
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);

            // cache destinations
            destinations = new HashMap<String, Destination>();
        } catch (JMSException ex) {
            throw new PluginException(ex);
        }
        String access_plugin = config.getString(DEFAULT_ACCESS_PLUGIN, "accesscontrol", "type");
        if (access_plugin.indexOf(",") >= 0) {
            String[] plugin_list = access_plugin.split(",");
            current_access_plugin = plugin_list[0];
        } else {
            current_access_plugin = access_plugin;
        }
    }

    // Static lists of mime type substrings used during indexing
    private static final Set<String> majors = Collections
            .unmodifiableSet(new HashSet<String>(Arrays.asList(new String[] { "audio", "video", "image" })));
    private static final Set<String> wordMinors = Collections
            .unmodifiableSet(new HashSet<String>(Arrays.asList(new String[] { "vnd.ms-word",
                    "vnd.oasis.opendocument.text", "vnd.openxmlformats-officedocument.wordprocessingml" })));
    private static final Set<String> pptMinors = Collections
            .unmodifiableSet(new HashSet<String>(Arrays.asList(new String[] { "vnd.ms-powerpoint",
                    "vnd.oasis.opendocument.presentation", "vnd.openxmlformats-officedocument.presentationml" })));

    /*****
     * Try to closing any objects that require closure
     * 
     */
    public void shutdown() {
        if (connection != null) {
            try {
                connection.close();
            } catch (JMSException jmse) {
                log.warn("Failed to close connection: {}", jmse.getMessage());
            }
        }
        if (session != null) {
            try {
                session.close();
            } catch (JMSException jmse) {
                log.warn("Failed to close session: {}", jmse.getMessage());
            }
        }
        if (producer != null) {
            try {
                producer.close();
            } catch (JMSException jmse) {
                log.warn("Failed to close producer: {}", jmse.getMessage());
            }
        }
        if (access != null) {
            try {
                access.shutdown();
            } catch (PluginException ex) {
                log.warn("Failed shutting down access control manager:", ex);
            }
        }
    }

    /*****
     * Send a message to the given message queue
     * 
     * @param messageQueue to connect to
     * @param message to send
     * @return boolean flag for success
     */
    public boolean sendMessage(String messageQueue, String message) {
        try {
            // log.debug("Queuing '{}' to '{}'", msg, name);
            sendMessage(getDestination(messageQueue, true), message);
            return true;
        } catch (JMSException jmse) {
            log.error("Failed to queue message", jmse);
            return false;
        }
    }

    /**
     * Sends a message to a JMS destination.
     * 
     * @param name destination name
     * @param msg message to send
     */
    private void sendMessage(Destination destination, String msg) throws JMSException {
        TextMessage message = session.createTextMessage(msg);
        producer.send(destination, message);
    }

    /**
     * Gets a JMS destination with the given name. If the destination doesn't
     * exist it is created and cached for reuse.
     * 
     * @param name name of the destination
     * @param queue true if the destination is a queue, false for topic
     * @return a JMS destination
     * @throws JMSException if an error occurred creating the destination
     */
    private Destination getDestination(String name, boolean queue) throws JMSException {
        Destination destination = destinations.get(name);
        if (destination == null) {
            destination = queue ? session.createQueue(name) : session.createTopic(name);
            destinations.put(name, destination);
        }
        return destination;
    }

    /*****
     * Get a resource from one of the compiled classes on the classpath
     * 
     * @param path To the requested resource
     * @return InputStream to the resource
     */
    public InputStream getResource(String path) {
        return getClass().getResourceAsStream(path);
    }

    /*****
     * Parse an XML document stored in a payload
     * 
     * @param payload holding the document
     * @return Document object after parsing
     */
    public Document getXmlDocument(Payload payload) {
        try {
            Document doc = getXmlDocument(payload.open());
            payload.close();
            return doc;
        } catch (StorageException ex) {
            log.error("Failed to access payload", ex);
        }
        return null;
    }

    /*****
     * Parse an XML document from a string
     * 
     * @param xmlData to parse
     * @return Document object after parsing
     */
    public Document getXmlDocument(String xmlData) {
        Reader reader = null;
        try {
            ByteArrayInputStream in = new ByteArrayInputStream(xmlData.getBytes("utf-8"));
            return saxReader.read(in);
        } catch (UnsupportedEncodingException uee) {
        } catch (DocumentException de) {
            log.error("Failed to parse XML", de);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ioe) {
                }
            }
        }
        return null;
    }

    /*****
     * Parse an XML document from an inputstream
     * 
     * @param xmlIn, the inputstream to read and parse
     * @return Document object after parsing
     */
    public Document getXmlDocument(InputStream xmlIn) {
        Reader reader = null;
        try {
            reader = new InputStreamReader(xmlIn, "UTF-8");
            return saxReader.read(reader);
        } catch (UnsupportedEncodingException uee) {
        } catch (DocumentException de) {
            log.error("Failed to parse XML", de);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ioe) {
                }
            }
        }
        return null;
    }

    /*****
     * Register a namespace for our XML parser
     * 
     * @param prefix of the namespace
     * @param uri of the namespace
     */
    public void registerNamespace(String prefix, String uri) {
        namespaces.put(prefix, uri);
    }

    /*****
     * UN-register a namespace for our XML parser
     * 
     * @param prefix of the namespace
     */
    public void unregisterNamespace(String prefix) {
        namespaces.remove(prefix);
    }

    /*****
     * Parse a JSON object from an inputstream
     * 
     * @param in, the inputstream to read and parse
     * @return JsonConfigHelper object after parsing
     */
    public JsonSimple getJsonObject(InputStream in) {
        try {
            return new JsonSimple(in);
        } catch (IOException ex) {
            log.error("Failure during stream access", ex);
            return null;
        }
    }

    /*****
     * Parse RDF data stored in a payload
     * 
     * @param payload containing the data
     * @return Model object after parsing
     */
    public Model getRdfModel(Payload payload) {
        try {
            Model model = getRdfModel(payload.open());
            payload.close();
            return model;
        } catch (StorageException ioe) {
            log.info("Failed to read payload stream", ioe);
        }
        return null;
    }

    /*****
     * Parse RDF data from an inputstream
     * 
     * @param rdfIn, the inputstream to read and parse
     * @return Model object after parsing
     */
    public Model getRdfModel(InputStream rdfIn) {
        Model model = null;
        Reader reader = null;
        try {
            reader = new InputStreamReader(rdfIn, "UTF-8");
            model = new ModelImplJena24(Reasoning.rdfs);
            model.open();
            model.readFrom(reader);
        } catch (ModelRuntimeException mre) {
            log.error("Failed to create RDF model", mre);
        } catch (IOException ioe) {
            log.error("Failed to read RDF input", ioe);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ioe) {
                }
            }
        }
        return model;
    }

    /*****
     * Return an empty access control schema from the first plugin on the list
     * 
     * @return AccessControlSchema returned by the first plugin on the list
     */
    public AccessControlSchema getAccessSchema() {
        access.setActivePlugin(current_access_plugin);
        return access.getEmptySchema();
    }

    /*****
     * Return an empty access control schema from the given plugin
     * 
     * @param plugin to request the schema from
     * @return AccessControlSchema returned by the plugin
     */
    public AccessControlSchema getAccessSchema(String plugin) {
        if (access == null) {
            return null;
        }
        access.setActivePlugin(plugin);
        return access.getEmptySchema();
    }

    /*****
     * Submit a new access control schema to a security plugin
     * 
     * @param schema to submit
     * @param plugin to submit to
     */
    public void setAccessSchema(AccessControlSchema schema, String plugin) {
        if (access == null) {
            return;
        }

        try {
            access.setActivePlugin(plugin);
            access.applySchema(schema);
        } catch (AccessControlException ex) {
            log.error("Failed to add new access schema", ex);
        }
    }

    /*****
     * Submit a new access control schema to the current security plugin
     * 
     * @param schema to submit
     * @param plugin to submit to
     */
    public void setAccessSchema(AccessControlSchema schema) {
        if (access == null) {
            return;
        }

        try {
            access.setActivePlugin(current_access_plugin);
            access.applySchema(schema);
        } catch (AccessControlException ex) {
            log.error("Failed to add new access schema", ex);
        }
    }

    /*****
     * Remove an access control schema from a security plugin
     * 
     * @param schema to remove
     * @param plugin to remove to
     */
    public void removeAccessSchema(AccessControlSchema schema) {
        if (access == null) {
            return;
        }

        try {
            access.setActivePlugin(current_access_plugin);
            access.removeSchema(schema);
        } catch (AccessControlException ex) {
            log.error("Failed to revoke existing access schema", ex);
        }
    }

    /*****
     * Find the list of roles with access to the given object
     * 
     * @param recordId the object to query
     * @return List<String> of roles with access to the object
     */
    public List<String> getRolesWithAccess(String recordId) {
        if (access == null) {
            return null;
        }
        try {
            return access.getRoles(recordId);
        } catch (AccessControlException ex) {
            log.error("Failed to query security plugin for roles", ex);
            return null;
        }
    }

    /*****
     * Find the list of roles with access to the given object, but only looking
     * at a single plugin.
     * 
     * @param recordId the object to query
     * @param plugin the plugin we are interested in
     * @return List<String> of roles with access to the object
     */
    public List<String> getRolesWithAccess(String recordId, String plugin) {
        if (access == null) {
            return null;
        }
        try {
            List<String> roles = new ArrayList<String>();
            access.setActivePlugin(plugin);
            List<AccessControlSchema> schemas = access.getSchemas(recordId);
            for (AccessControlSchema schema : schemas) {
                String role = schema.get("role");
                if (role != null) {
                    roles.add(role);
                }
            }
            return roles;
        } catch (AccessControlException ex) {
            log.error("Failed to query security plugin for roles", ex);
            return null;
        }
    }

    /*****
     * Find the list of users with access to the given object
     * 
     * @param recordId the object to query
     * @return List<String> of users with access to the object
     */
    public List<String> getUsersWithAccess(String recordId) {
        if (access == null) {
            return null;
        }
        try {
            return access.getUsers(recordId);
        } catch (AccessControlException ex) {
            log.error("Failed to query security plugin for roles", ex);
            return null;
        }
    }

    /*****
     * Find the list of users with access to the given object, but only looking
     * at a single plugin.
     * 
     * @param recordId the object to query
     * @param plugin the plugin we are interested in
     * @return List<String> of users with access to the object
     */
    public List<String> getUsersWithAccess(String recordId, String plugin) {
        if (access == null) {
            return null;
        }
        try {
            List<String> users = new ArrayList<String>();
            access.setActivePlugin(plugin);
            List<AccessControlSchema> schemas = access.getSchemas(recordId);
            for (AccessControlSchema schema : schemas) {
                String user = schema.get("user");
                if (user != null) {
                    users.add(user);
                }
            }
            return users;
        } catch (AccessControlException ex) {
            log.error("Failed to query security plugin for roles", ex);
            return null;
        }
    }

    /*****
     * Find the MIME type to use at display time, giving first priority to the
     * preview payload, then to the source payload.
     * 
     * @param indexerFormats The list of types so far allocated by the rules
     *            script.
     * @param object The object being indexed.
     * @param preview The preview payload
     * @return String The MIME type to be used at display time.
     */
    public String getDisplayMimeType(String[] indexerFormats, DigitalObject object, String preview) {
        // The source should be the first type given by the indexer
        String result = indexerFormats[0];

        // Lets look for a preview payload
        if (preview != null) {
            try {
                Payload payload = object.getPayload(preview);
                PayloadType type = payload.getType();
                if (type != null && type.equals(PayloadType.Preview)) {
                    if (payload.getContentType() != null) {
                        result = payload.getContentType();
                    }
                }
            } catch (StorageException ex) {
                log.error("Error accessing payload: '{}'", preview, ex);
            }
        }

        return result;
    }

    /*****
     * A basic method for selecting common display templates from a given MIME
     * type. This simple algorithm is suitable for most rules files.
     * 
     * @param preview The MIME type.
     * @return String The display type.
     */
    public String basicDisplayType(String mimeType) {
        String[] parts = mimeType.split("/");
        // Invalid or unknown MIME types
        if (parts == null || parts.length != 2) {
            return "default";
        }
        // Otherwise, decide based on different parts
        String major = parts[0];
        String minor = parts[1];

        // Top level templates (like 'video')
        if (majors.contains(major)) {
            return major;
        }
        // Common applications
        if (major.equals("application")) {
            // PDF
            if (minor.equals("pdf")) {
                return minor;
            }
            // Word processors
            if (wordMinors.contains(minor)) {
                return "word-processing";
            }
            // Presentations
            if (pptMinors.contains(minor)) {
                return "presentation";
            }
            if (minor.equals("x-fascinator-package")) {
                return "package";
            }
        }
        // Text based: eg. 'plain', 'html'
        if (major.equals("text")) {
            return minor;
        }
        // Unknown
        return "default";
    }

    /*****
     * Add the provided key/value pair into the index.
     * 
     * @param index : Data structure to add data into
     * @param field : The field name
     * @param value : The value to store
     */
    public void add(Map<String, List<String>> index, String field, String value) {
        // Adding data
        if (index.containsKey(field)) {
            index.get(field).add(value);
            // New data
        } else {
            List<String> newList = new ArrayList<String>();
            newList.add(value);
            index.put(field, newList);
        }
    }

    /*****
     * Generate a Solr document from a map of provided key/value pairs.
     * 
     * @param fields : The lists of evaluated fields for the document
     * @return String : The generated XML snippet
     */
    public String solrDocument(Map<String, List<String>> fields) {
        StringBuffer resultBuffer = new StringBuffer("<doc>");
        for (Entry<String, List<String>> entry : fields.entrySet()) {
            for (String value : entry.getValue()) {
                resultBuffer.append(solrField(entry.getKey(), value));
            }
        }
        resultBuffer.append("</doc>");
        return resultBuffer.toString();
    }

    /*****
     * Generate an XML snippet representing a key/value pair in a Solr doc.
     * 
     * @param field : The field
     * @param value : The value
     * @return String : The generated XML snippet
     */
    public String solrField(String field, String value) {
        if (field == null || value == null) {
            return null;
        }
        return "<field name=\"" + field + "\">" + StringEscapeUtils.escapeXml(value) + "</field>";
    }
}