Java tutorial
/* * Copyright (c) 2003-2012 The Regents of the University of California. * All rights reserved. * * '$Author: barseghian $' * '$Date: 2012-08-18 00:37:31 -0700 (Sat, 18 Aug 2012) $' * '$Revision: 30476 $' * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the above * copyright notice and the following two paragraphs appear in all copies * of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * ENHANCEMENTS, OR MODIFICATIONS. * */ package org.ecoinformatics.seek.ecogrid; import java.io.StringReader; import java.io.StringWriter; import java.util.UUID; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xml.serialize.XMLSerializer; import org.apache.xpath.XPathAPI; import org.ecoinformatics.ecogrid.EcogridObjType; import org.ecoinformatics.ecogrid.client.AuthenticationServiceClient; import org.ecoinformatics.ecogrid.client.PutServiceClient; import org.ecoinformatics.seek.datasource.eml.eml2.Eml200Parser; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import ptolemy.actor.TypedAtomicActor; import ptolemy.actor.TypedIOPort; import ptolemy.data.ObjectToken; import ptolemy.data.StringToken; import ptolemy.data.expr.Parameter; import ptolemy.data.expr.StringParameter; import ptolemy.data.type.BaseType; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.NameDuplicationException; import util.StaticUtil; /** * The EcogridWriter actor writes a data file and the EML metadata describing that * data file to a remote EcoGrid repositiory. Identifiers for the data and * metadata are created and these IDs are sent to the output ports. These IDs * might be used for future access to the data and metadata files. Note also * that the ID of the data file is inserted into the metadata file as a * reference (i.e., a pointer from the metadata to the data). * * The EcoGrid is a distributed network providing scientists access to * ecological, biodiversity, and environmental data and analytic resources. The * EcoGrid can be used to store ecological data, or to model or analyze it via * remote EcoGrid services. * * Ecological Metadata Language (EML) is a standard set of terms and definitions * used to describe ecological data. For example, EML metadata might contain * infomation about a data set's units of measurement, date of collection, * location, etc. * * @author tao */ public class EcogridWriter extends TypedAtomicActor { /** * Accepts the file name and path of the local data file to upload to the EcoGrid service. * WARNING: This port is ignored if you supply data to dataPort. */ public TypedIOPort sourceFileNamePort = null; /** * Can be used in lieu of supplying a file name to dataFileNamePort. * The byte[] of the input object will be uploaded. */ public TypedIOPort sourceDataPort; /** * Accepts a string of metadata describing the data file. This string will be uploaded to Ecogrid service as metadata */ public TypedIOPort metadataPort = null; /** * An output port that broadcasts the metadata doc ID, which is generated by the actor for future reference. */ public TypedIOPort metadataDocidPort = null; /** * Broadcasts the data docid, which is generated by the actor for future reference. */ public TypedIOPort dataDocidPort = null; private String metadataDocid = null; private String dataDocid = null; private String metadataUserName = null; private String metadataPasswd = null; private String metadataDestination = null; private String authenURL = null; private String localDataFileName = null; private byte[] localData; private String metadataContent = null; protected final static Log log; protected final static boolean isDebugging; static { log = LogFactory.getLog("org.ecoinformatics.seek.ecogrid.EcoGridServicesController"); isDebugging = log.isDebugEnabled(); } private String docIdSuffix = "doc"; private static final String DATAFILENAMEPORT = "dataFileNamePort"; private static final String DATAPORT = "dataPort"; private static final String METADATAPORT = "metadata"; private static final String METADATADOCIDPORT = "metadataDocid"; private static final String DATADOCIDPORT = "dataDocid"; private static final String METADATADESTINATION = "metadataDestination"; private static final String DISTRIBUTIONPATH = "physical/distribution/online/url"; private static final String SEPERATOR = "."; private static final String ECOGRIDPROTOCOL = "ecogrid://knb/"; private static final String DEFAULTECOGRIDPUTSERVER = "http://ecogrid.ecoinformatics.org/knb/services/PutService"; private static final String DEFAULTECOGRIDAUTHENSERVER = "http://ecogrid.ecoinformatics.org/knb/services/AuthenticationService"; private static final String AUTHENURL = "authenticationURL"; private static final String USERNAME = "userName"; private static final String PASSWORD = "passWord"; /** Ecogrid service URL for receiving metadata and data */ public StringParameter metadataDesParam = null; /** Ecogrid service URL for authenticating user */ public StringParameter authenURLParam = null; /** * User name for authenticatication. For example, it is a DN for knb ldap * server. uid=smith,o=NCEAS,dc=eocinformatics,dc=org */ public StringParameter usernameParam = null; /** Password for this user */ public StringParameter passwordParam = null; // public FileParameter localDataFileNameParameter = null; public EcogridWriter(CompositeEntity container, String name) throws IllegalActionException, NameDuplicationException { super(container, name); // input ports metadataPort = new TypedIOPort(this, METADATAPORT, true, false); metadataPort.setMultiport(false); metadataPort.setTypeEquals(BaseType.STRING); sourceFileNamePort = new TypedIOPort(this, DATAFILENAMEPORT, true, false); sourceFileNamePort.setMultiport(false); sourceFileNamePort.setTypeEquals(BaseType.STRING); sourceDataPort = new TypedIOPort(this, DATAPORT, true, false); sourceDataPort.setTypeEquals(BaseType.OBJECT); // output ports metadataDocidPort = new TypedIOPort(this, METADATADOCIDPORT, false, true); metadataDocidPort.setMultiport(false); metadataDocidPort.setTypeEquals(BaseType.STRING); dataDocidPort = new TypedIOPort(this, DATADOCIDPORT, false, true); dataDocidPort.setMultiport(false); dataDocidPort.setTypeEquals(BaseType.STRING); // parameters metadataDesParam = new StringParameter(this, METADATADESTINATION); metadataDesParam.setExpression(DEFAULTECOGRIDPUTSERVER); authenURLParam = new StringParameter(this, AUTHENURL); authenURLParam.setExpression(DEFAULTECOGRIDAUTHENSERVER); usernameParam = new StringParameter(this, USERNAME); passwordParam = new StringParameter(this, PASSWORD); // localDataFileNameParameter = new FileParameter(this, // LOCATDATFILENAME); _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-25\" y=\"-20\" " + "width=\"50\" height=\"40\" " + "style=\"fill:white\"/>\n" + "<polygon points=\"-15,-10 -12,-10 -8,-14 -1,-14 3,-10" + " 15,-10 15,10, -15,10\" " + "style=\"fill:red\"/>\n" + "</svg>\n"); } // ///////////////////////////////////////////////////////////////// // // public methods //// /** * If the specified attribute is <i>fileOrURL </i> and there is an open file * being read, then close that file and open the new one; if the attribute * is <i>numberOfLinesToSkip </i> and its value is negative, then throw an * exception. In the case of <i>fileOrURL </i>, do nothing if the file name * is the same as the previous value of this attribute. * * @param attribute * The attribute that has changed. * @exception IllegalActionException * If the specified attribute is <i>fileOrURL </i> and the * file cannot be opened, or the previously opened file * cannot be closed; or if the attribute is * <i>numberOfLinesToSkip </i> and its value is negative. */ /** * Determine the attribute changed value * * @param attribute * The attribute that changed. * @exception IllegalActionException * If the output type is not recognized. */ public void attributeChanged(Attribute attribute) throws IllegalActionException { if (attribute == metadataDesParam) { metadataDestination = getValueForAttributeChange(metadataDesParam); } else if (attribute == authenURLParam) { authenURL = getValueForAttributeChange(authenURLParam); } else if (attribute == usernameParam) { metadataUserName = getValueForAttributeChange(usernameParam); } else if (attribute == passwordParam) { metadataPasswd = getValueForAttributeChange(passwordParam); } } /** * Get new value for attribute changes. * * @param attribute * @return * @throws IllegalActionException */ private String getValueForAttributeChange(Parameter attribute) throws IllegalActionException { String newValue = null; if (attribute != null) { StringToken token = (StringToken) attribute.getToken(); if (token != null) { newValue = token.stringValue(); } } if (isDebugging) { log.debug("The value of attribute is " + newValue); } // System.out.println("======the value of attribute is "+newValue); return newValue; } /** * @return Description of the Returned Value * @exception IllegalActionException * Description of Exception * @since */ public boolean prefire() throws IllegalActionException { int revision = 1; if (sourceDataPort.numberOfSources() > 0) { ObjectToken object = (ObjectToken) sourceDataPort.get(0); localData = (byte[]) object.getValue(); } else if (sourceFileNamePort.numberOfSources() > 0) { // get data file name if (!sourceFileNamePort.hasToken(0)) { return false; } StringToken sourcefnToken = (StringToken) sourceFileNamePort.get(0); localDataFileName = sourcefnToken.stringValue(); // localDataFileNameParameter.setExpression(localDataFileName); if (isDebugging) { log.debug("The localDataFileName is " + localDataFileName); } } /* * else { localDataFileName = * localDataFileNameParameter.asFile().getPath(); } */ dataDocid = generateDocId(docIdSuffix, revision); // get metadata if (metadataPort.getWidth() > 0) { if (!metadataPort.hasToken(0)) { return false; } StringToken metadataToken = (StringToken) metadataPort.get(0); metadataContent = metadataToken.stringValue(); if (isDebugging) { log.debug("The original metadata is " + metadataContent); } // replace the url part String newURL = ECOGRIDPROTOCOL + dataDocid; metadataDocid = generateDocId(docIdSuffix, revision); try { metadataContent = replaceDistributionURLAndPackageID(metadataContent, newURL, metadataDocid); } catch (Exception e) { throw new IllegalActionException(e.getMessage()); } } return super.prefire(); } /** * Output the data lines into an array. * * @exception IllegalActionException * If there's no director. */ public void fire() throws IllegalActionException { super.fire(); try { long start = System.currentTimeMillis(); // load metadata and data to ecogrid String sessionId = loginEcoGrid(authenURL, metadataUserName, metadataPasswd); uploadDataFile(metadataDestination, localDataFileName, dataDocid, sessionId); uploadMetadata(metadataDestination, metadataContent, metadataDocid, sessionId); long end = System.currentTimeMillis(); System.out .println("**********EcogridWriter uploading data and metadata took " + (end - start) + " ms."); // output metadata docid and data docid TypedIOPort pp = (TypedIOPort) this.getPort(METADATADOCIDPORT); pp.send(0, new StringToken(metadataDocid)); TypedIOPort pp1 = (TypedIOPort) this.getPort(DATADOCIDPORT); pp1.send(0, new StringToken(dataDocid)); metadataDocid = null; dataDocid = null; } catch (Exception e) { throw new IllegalActionException(e.getMessage()); } } /** * This method will do login action and return a session id. * * @param authernURL * @param userName * @param password * @return * @throws Exception */ private String loginEcoGrid(String authernURL, String userName, String password) throws Exception { String sessionId = null; AuthenticationServiceClient client = new AuthenticationServiceClient(authernURL); sessionId = client.login_action(userName, password); if (isDebugging) { log.debug("The session id is " + sessionId); } // client.destory(); return sessionId; } /** * Upload Data. * * If localData is not null, localFileName * is ignored, you can set it null. * * @param destURL * @param localFileName * @param docid * @param sessionId * @throws Exception */ private void uploadDataFile(String destURL, String localFileName, String docid, String sessionId) throws Exception { int type = EcogridObjType.DATA; // client.createEcoGridPutLevelOnePortType(); byte[] data; if (localData != null) { data = localData; } else { data = StaticUtil.getBytesArrayFromFile(localFileName); } if (data.length < 10) { System.out.println("WARNING: read " + data.length + " bytes in data file"); } boolean error = true; int tries = 5; while (tries > 0 && error) { tries--; error = false; PutServiceClient client = new PutServiceClient(destURL); try { client.put(data, docid, type, sessionId); } catch (Exception e) { System.out.println("data exception: " + e.getMessage()); if (tries > 0) { error = true; } else { throw e; } } } // client.destroy(); } /** * Upload Metadata. * * @param destURL * @param metadataContent * @param docid * @param sessionId * @throws Exception */ private void uploadMetadata(String destURL, String metadataContent, String docid, String sessionId) throws Exception { int type = EcogridObjType.METADATA; byte[] content = metadataContent.getBytes(); if (content.length < 10) { System.out.println("WARNING: read " + content.length + " bytes in metadata file"); } PutServiceClient client = new PutServiceClient(destURL); // client.createEcoGridPutLevelOnePortType(); try { client.put(content, docid, type, sessionId); } catch (Exception e) { System.out.println("metadata exception: " + e.getMessage()); throw e; } // client.destroy(); } /** * After generate docid for data file, the original metadata need to replace * the distribution url by new value. Currently we just consider eml as * metadata. * * @param originalMetadata * @param newURL * @param newMetadataID * @return * @throws Exception */ private String replaceDistributionURLAndPackageID(String originalMetadata, String newURL, String newMetadataID) throws Exception { String newMetadata = null; if (originalMetadata != null) { DocumentBuilder parser = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // factory.setNamespaceAware(true); parser = factory.newDocumentBuilder(); if (parser == null) { throw new Exception("Could not create Document parser in " + "EcogridWriter"); } } catch (ParserConfigurationException pce) { throw new Exception("Could not create Document parser in " + "EcogridWriter: " + pce.getMessage()); } log.debug("after generate dom parser"); Document doc = null; StringReader reader = new StringReader(originalMetadata); InputSource in = new InputSource(reader); log.debug("after generate inputsource"); doc = parser.parse(in); log.debug("after parsing inputsource"); // we assuming the metadata only have one entity String tablePath = Eml200Parser.TABLEENTITY + "/" + DISTRIBUTIONPATH; NodeList tableNodeList = XPathAPI.selectNodeList(doc, tablePath); String rasterPath = Eml200Parser.SPATIALRASTERENTITY + "/" + DISTRIBUTIONPATH; NodeList rasterNodeList = XPathAPI.selectNodeList(doc, rasterPath); String vectorPath = Eml200Parser.SPATIALVECTORENTITY + "/" + DISTRIBUTIONPATH; NodeList vectorNodeList = XPathAPI.selectNodeList(doc, vectorPath); String procedurePath = Eml200Parser.STOREDPROCEDUREENTITY + "/" + DISTRIBUTIONPATH; NodeList procedureNodeList = XPathAPI.selectNodeList(doc, procedurePath); String viewPath = Eml200Parser.VIEWENTITY + "/" + DISTRIBUTIONPATH; NodeList viewNodeList = XPathAPI.selectNodeList(doc, viewPath); String otherEntityPath = Eml200Parser.OTHERENTITY + "/" + DISTRIBUTIONPATH; NodeList otherEntityNodeList = XPathAPI.selectNodeList(doc, otherEntityPath); if (tableNodeList != null && tableNodeList.getLength() != 0) { // have tableEntity log.debug("in data table path for replacement"); setNewValueForNode(tableNodeList, newURL); } else if (rasterNodeList != null && rasterNodeList.getLength() != 0) { setNewValueForNode(rasterNodeList, newURL); } else if (vectorNodeList != null && vectorNodeList.getLength() != 0) { setNewValueForNode(vectorNodeList, newURL); } else if (procedureNodeList != null && procedureNodeList.getLength() != 0) { setNewValueForNode(procedureNodeList, newURL); } else if (viewNodeList != null && viewNodeList.getLength() != 0) { setNewValueForNode(viewNodeList, newURL); } else if (otherEntityNodeList != null && otherEntityNodeList.getLength() != 0) { setNewValueForNode(otherEntityNodeList, newURL); } //replace package id String packagePath = "/*[local-name() = '" + Eml200Parser.EML + "']/@" + Eml200Parser.PACKAGEID; NodeList packageIDNodeList = XPathAPI.selectNodeList(doc, packagePath); setNewValueForAttribute(packageIDNodeList, newMetadataID); // serialize the DOM tree StringWriter writer = new StringWriter(); XMLSerializer serializer = new XMLSerializer(); serializer.setOutputCharStream(writer); // serializer.setOutputByteStream(System.out); serializer.serialize(doc); newMetadata = writer.toString(); // writer.write(newMetadata); log.debug("The new metadata with new data reference is \n" + newMetadata); } return newMetadata; } /** * Docid will look like suffix.id.rev. * Where id is a concat of currenttTimeMillis + random UUID * * @param suffix * @param rev * @return */ private String generateDocId(String suffix, int rev) { //double random = Math.random(); //int randomInt = (new Double(random*1000000)).intValue(); String docid = null; //Date currentTime = new Date(); //String id = Long.toString(currentTime.getTime()); //String id = Long.toString(System.currentTimeMillis()); //id= id+randomInt; String id = Long.toString(System.currentTimeMillis()); id = id.concat(UUID.randomUUID().toString()); docid = suffix + SEPERATOR + id + SEPERATOR + rev; log.debug("The generated docid is " + docid); return docid; } /** * This method will set up new value for the list. We only replace the first * one. * * @param list * @param newValue */ private void setNewValueForNode(NodeList list, String newValue) { Node cn = list.item(0).getFirstChild(); if ((cn != null) && (cn.getNodeType() == Node.TEXT_NODE)) { log.debug("set new value " + newValue + " for distribution url"); cn.setNodeValue(newValue); } } /** * Set a new value for an attribute node. * * @param list * @param newValue */ private void setNewValueForAttribute(NodeList list, String newValue) { if (list != null && list.getLength() > 0) { Node cn = list.item(0); if (cn != null && cn.getNodeType() == Node.ATTRIBUTE_NODE) { //System.out.println("Set new value "+newValue +" for attribute"+cn.getNodeName()); cn.setNodeValue(newValue); } } } }