edu.ucsb.nceas.metacat.lsid.LSIDAuthorityMetaData.java Source code

Java tutorial

Introduction

Here is the source code for edu.ucsb.nceas.metacat.lsid.LSIDAuthorityMetaData.java

Source

/**
 *  '$RCSfile$'
 *  Copyright: 2000-2005 Regents of the University of California and the
 *             National Center for Ecological Analysis and Synthesis
 *
 *   '$Author: harris $'
 *     '$Date: 2006-01-26 10:42:52 +1000 (Thu, 26 Jan 2006) $'
 * '$Revision: 2904 $'
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.ucsb.nceas.metacat.lsid;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.Hashtable;
import java.util.ResourceBundle;
import java.util.Enumeration;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ibm.lsid.LSID;
import com.ibm.lsid.MalformedLSIDException;
import com.ibm.lsid.MetadataResponse;
import com.ibm.lsid.server.LSIDMetadataService;
import com.ibm.lsid.server.LSIDRequestContext;
import com.ibm.lsid.server.LSIDServerException;
import com.ibm.lsid.server.LSIDServiceConfig;

import edu.ucsb.nceas.metacat.client.Metacat;
import edu.ucsb.nceas.metacat.client.MetacatFactory;
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;

public class LSIDAuthorityMetaData implements LSIDMetadataService {
    private LSIDDataLookup lookup = null;
    private static Hashtable currentLSIDs = new Hashtable();
    private static Log logger = LogFactory.getLog("edu.ucsb.nceas.metacat.lsid");

    public void initService(LSIDServiceConfig cf) throws LSIDServerException {
        logger.info("Starting LSIDAuthorityMetadata.");
        lookup = new LSIDDataLookup();
    }

    private static final String RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    private static final String DC_NS = "http://purl.org/dc/elements/1.1/";
    private static final String I3CP_NS = "urn:lsid:i3c.org:predicates:";
    private static final String I3C_CONTENT = "urn:lsid:i3c.org:types:content";
    private static final String DEFAULT_STYLESHEET = "default.xslt";

    public MetadataResponse getMetadata(LSIDRequestContext req, String[] formats) throws LSIDServerException {
        LSID lsid = req.getLsid();
        ByteArrayInputStream theMetadata = doMetadataRequest(lsid);
        return new MetadataResponse(theMetadata, null, MetadataResponse.RDF_FORMAT);
    }

    private ByteArrayInputStream doMetadataRequest(LSID lsid) throws LSIDServerException {
        logger.debug("getting metadata for lsid " + lsid.getLsid());

        try {

            LSIDDataLookup myLookup = new LSIDDataLookup();
            InputStream content = myLookup.lsidData(lsid);
            InputStream content2 = myLookup.lsidData(lsid);
            if (!isEML(content2)) {
                content = getEML(lsid);
            }
            content2.close();
            setCurrentLSID(lsid);

            // based on the doctype choose the appropriate stylesheet
            String styleSheetName = null;
            String _docType = myLookup.getDocType(lsid);

            try {
                ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
                styleSheetName = rb.getString(_docType.replaceAll(":", ""));
            } catch (java.util.MissingResourceException mre) {
                logger.warn("there is no style corresponding to: '" + _docType + "' -- using default");
                styleSheetName = this.DEFAULT_STYLESHEET;
                mre.getMessage();
            }
            InputStream styleSheet = getClass().getResourceAsStream(styleSheetName);
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(new StreamSource(styleSheet));
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            transformer.transform(new StreamSource(content), new StreamResult(out));
            content.close();
            clearState();
            return new ByteArrayInputStream(out.toByteArray());
        } catch (Exception e) {
            throw new LSIDServerException(e, "Error transforming XML for: " + lsid);
        }
    }

    public static String getStringFromInputStream(InputStream input) {
        StringBuffer result = new StringBuffer();
        BufferedReader in = new BufferedReader(new InputStreamReader(input));
        String line;
        try {
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
            logger.error("IOexception " + e);
        }
        return result.toString();
    }

    /**
     * figure out is this inputstream is an eml document or not
     * TODO: need a better way to figure out if this is an eml document
     */
    private boolean isEML(InputStream input) {

        if (input == null) {
            return false;
        }

        int loop = 0;
        boolean itIsEML = false;
        String line = "";
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(input));
            while ((loop < 20) && (line != null) && (!itIsEML)) {
                line = in.readLine();
                line = line.toLowerCase();
                if (line.indexOf("eml:eml") != -1) {
                    itIsEML = true;
                }
                loop++;
            }
        } catch (IOException e) {
            logger.error("ioerror in LSIDAuthorityMetadata: " + e);
        }
        return itIsEML;
    }

    /**
     * this lsid points to a data object - get the metadata objects which refer
     * to this document
     */
    private InputStream getEML(LSID theLSID) {

        InputStream response = null;

        // need to find things with this object in any of the elements
        // using the metacat api
        // get back dataset/docid and dataset/title

        // create the query
        String theQuery = getMetaCatQuery(theLSID);

        // get the metacat record
        Reader metaCatResponse = getMetaCatResponse(theQuery);

        // parse the metadata to get the applicable rdf information
        response = parseMetaCatResponse(metaCatResponse, theLSID);

        return response;

    }

    /**
     * given an LSID return a metacat query which will return docs mentioning
     * this LSID
     */
    private String getMetaCatQuery(LSID lsid) {
        logger.debug("getting Metacat Query for: " + lsid.toString());
        String ns = lsid.getNamespace();
        String id = lsid.getObject();
        String ver = lsid.getRevision();
        String theName = ns + "." + id + "." + ver;

        String theQuery = null;
        theQuery = "<?xml version=\"1.0\"?>\n" + "<pathquery version=\"1.2\">\n" + "  <querytitle>" + theName
                + " search</querytitle>\n" + "  <returnfield>dataset/docid</returnfield>\n"
                + "  <returnfield>dataset/title</returnfield>\n" + "  <querygroup operator=\"UNION\">\n"
                + "    <queryterm searchmode=\"contains\" casesensitive=\"false\">\n" + "      <value>" + theName
                + "</value>\n" + "      <pathexpr>anyfield</pathexpr>\n" + "    </queryterm>\n"
                + "  </querygroup>\n" + "<pathquery>\n";

        return theQuery;

    }

    /**
     * given a query string, query MetaCat and return the response
     */
    private Reader getMetaCatResponse(String query) {
        logger.debug("Querying the metacat server.");
        // get the metacat server from the configuration file
        //
        ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
        String url = rb.getString("metacatserver");
        Reader r = null;
        try {

            Metacat m = MetacatFactory.createMetacatConnection(url);
            r = m.query(new StringReader(query));

        } catch (MetacatInaccessibleException mie) {
            logger.error("Metacat Inaccessible:\n" + mie.getMessage());
        } catch (Exception e) {
            logger.error("General exception:\n" + e.getMessage());
        }
        return r;
    }

    /**
     * Given a reader which is a metacat response, parse it and return the
     * appropriate rdf
     */
    private InputStream parseMetaCatResponse(Reader reader, LSID theLSID) {
        InputStream response = null;
        logger.debug("Parsing the metacat response.");
        // if there's more than one document, then return rdf listing the
        // documents
        // otherwise get the document and return rdf based on it

        String contents = getStringFromReader(reader);
        if (numberDocuments(contents) < 1) {
            response = noMetaDataResponse(theLSID);
        } else if (numberDocuments(contents) > 1) {
            response = metaDataList(contents, theLSID);
        } else {
            response = getMetaData(contents, theLSID);
        }
        return response;
    }

    /**
     * There's no metadata for this document
     */
    private ByteArrayInputStream noMetaDataResponse(LSID theLSID) {
        ResourceBundle rb = ResourceBundle.getBundle("metacat-lsid");
        String metadataLabels = rb.getString("metadatalabels");

        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
                + "   xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
                + "   xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:" + metadataLabels
                + ":predicates:\"> \n" + "<rdf:Description rdf:about=\"" + theLSID.getLsid() + "\"> \n"
                + "   <pred:title xmlns:pred=\"http://purl.org/dc/elements/1.1/\">There is no metadata for this LSID.</pred:title>\n"
                + "</rdf:Description>\n" + "</rdf:RDF>\n";

        return new ByteArrayInputStream(result.getBytes());
    }

    /**
     * There's more than one metdata document
     */
    private ByteArrayInputStream metaDataList(String contents, LSID theLSID) {
        ResourceBundle rb = ResourceBundle.getBundle("metacat");
        String metadataLabels = rb.getString("metadatalabels");

        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" \n"
                + "   xmlns:dc=\"http://purl.org/dc/elements/1.1/\" \n"
                + "   xmlns:pred=\"urn:lsid:i3c.org:predicates:\" xmlns=\"urn:lsid:" + metadataLabels
                + ":predicates:\"> \n" + "<rdf:Description rdf:about=\"" + theLSID.getLsid() + "\"> \n"
                + "   <pred:title xmlns:pred=\"http://purl.org/dc/elements/1.1/\">There is more than one metadata document for this LSID - which confuses me right now.  Try again soon and I'll be less confused.</pred:title>\n"
                + "</rdf:Description>\n" + "</rdf:RDF>\n";

        return new ByteArrayInputStream(result.getBytes());
    }

    /**
     * There's just one metadata document
     */
    private ByteArrayInputStream getMetaData(String contents, LSID theLSID) {
        String paramString = "<param name=\"dataset/title\">";
        ByteArrayInputStream result = null;

        if (contents.indexOf(paramString) == -1) {
            return noMetaDataResponse(theLSID);
        } else {
            String parts[] = contents.split(paramString);
            String parts2[] = parts[1].split("</param>");
            try {
                LSID newLSID = new LSID(parts2[0]);
                result = doMetadataRequest(newLSID);

            } catch (MalformedLSIDException e) {
                logger.error("problem generating LSID: " + e);
                e.printStackTrace();
            } catch (LSIDServerException e) {
                logger.error("problem generating LSID: " + e);
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * Find out how many contents are in this metacat response I'm just using
     * string stuff for this - sort of lame, but does the trick more cool would
     * be to use xml stuff
     */
    private int numberDocuments(String contents) {

        String[] docSplit = contents.split("<document>");
        return (docSplit.length - 1);
    }

    /**
     * Given a reader, return a string
     */
    private String getStringFromReader(Reader reader) {
        StringBuffer response = new StringBuffer();

        try {
            BufferedReader bufReader = new BufferedReader(reader);

            String line = null;
            while ((line = bufReader.readLine()) != null) {
                response.append(line);
            }
            bufReader.close();

        } catch (IOException e) {
            logger.error("error getting string from reader " + e);
        }
        return response.toString();
    }

    /**
     * set the LSID for the current thread
     */
    static void setCurrentLSID(LSID lsid) {
        currentLSIDs.put(Thread.currentThread(), lsid);
    }

    static void clearState() {
        currentLSIDs.remove(Thread.currentThread());
    }

    /**
     * get the current LSID for the given thread, for use in XSLT so return a
     * string
     */
    public static String getLSID(org.apache.xalan.extensions.XSLProcessorContext foo,
            org.apache.xalan.templates.ElemExtensionCall bar) throws MalformedLSIDException {
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
    }

    public static String getLSID() throws MalformedLSIDException {
        return ((LSID) currentLSIDs.get(Thread.currentThread())).toString();
    }
}