/** * '$RCSfile$' * Copyright: 2010 Regents of the University of California and the * National Center for Ecological Analysis and Synthesis * * '$Author$' * '$Date$' * '$Revision$' * * 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; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.activation.MimetypesFileTypeMap; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.XmlStreamReader; import org.apache.commons.lang.StringEscapeUtils; import org.apache.log4j.Logger; import org.dataone.service.types.v1.AccessPolicy; import org.dataone.service.types.v1.Checksum; import org.dataone.service.types.v1.Event; import org.dataone.service.types.v1.Identifier; import org.dataone.service.types.v1.ObjectFormatIdentifier; import org.dataone.service.types.v1.Session; import org.dataone.service.types.v2.SystemMetadata; import org.ecoinformatics.eml.EMLParser; import au.com.bytecode.opencsv.CSVWriter; import edu.ucsb.nceas.metacat.accesscontrol.AccessControlException; import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile; import edu.ucsb.nceas.utilities.access.AccessControlInterface; import edu.ucsb.nceas.metacat.accesscontrol.AccessControlList; import edu.ucsb.nceas.metacat.cart.CartManager; import edu.ucsb.nceas.metacat.client.InsufficientKarmaException; import edu.ucsb.nceas.metacat.common.query.EnabledQueryEngines; import edu.ucsb.nceas.metacat.common.resourcemap.ResourceMapNamespaces; import edu.ucsb.nceas.metacat.database.DBConnection; import edu.ucsb.nceas.metacat.database.DBConnectionPool; import edu.ucsb.nceas.metacat.dataone.D1NodeService; import edu.ucsb.nceas.metacat.dataone.SyncAccessPolicy; import edu.ucsb.nceas.metacat.dataone.SystemMetadataFactory; import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService; import edu.ucsb.nceas.metacat.dataquery.DataQuery; import edu.ucsb.nceas.metacat.event.MetacatDocumentEvent; import edu.ucsb.nceas.metacat.event.MetacatEventService; import edu.ucsb.nceas.metacat.index.MetacatSolrIndex; import edu.ucsb.nceas.metacat.properties.PropertyService; import edu.ucsb.nceas.metacat.replication.ForceReplicationHandler; import edu.ucsb.nceas.metacat.service.SessionService; import edu.ucsb.nceas.metacat.service.XMLSchemaService; import edu.ucsb.nceas.metacat.shared.HandlerException; import edu.ucsb.nceas.metacat.shared.MetacatUtilException; import edu.ucsb.nceas.metacat.shared.ServiceException; import edu.ucsb.nceas.metacat.spatial.SpatialHarvester; import edu.ucsb.nceas.metacat.spatial.SpatialQuery; import edu.ucsb.nceas.metacat.util.AuthUtil; import edu.ucsb.nceas.metacat.util.DocumentUtil; import edu.ucsb.nceas.metacat.util.MetacatUtil; import edu.ucsb.nceas.metacat.util.RequestUtil; import edu.ucsb.nceas.metacat.util.SessionData; import edu.ucsb.nceas.metacat.util.SystemUtil; import edu.ucsb.nceas.utilities.FileUtil; import edu.ucsb.nceas.utilities.LSIDUtil; import edu.ucsb.nceas.utilities.ParseLSIDException; import edu.ucsb.nceas.utilities.PropertyNotFoundException; /** * General entry point for the Metacat server which is called from various * mechanisms such as the standard MetacatServlet class and the various web * service servlets such as RestServlet class. All application logic should be * encapsulated in this class, and the calling classes should only contain * parameter marshaling and demarshaling code, delegating all else to this * MetacatHandler instance. * @author Matthew Jones */ public class MetacatHandler { private static boolean _sitemapScheduled = false; private static Logger logMetacat = Logger.getLogger(MetacatHandler.class); // Constants -- these should be final in a servlet private static final String PROLOG = ""; private static final String SUCCESS = ""; private static final String SUCCESSCLOSE = ""; private static final String ERROR = ""; private static final String ERRORCLOSE = ""; public static final String FGDCDOCTYPE = "metadata"; private Timer timer; public MetacatHandler(Timer timer) { this.timer = timer; } protected void handleDataquery( Hashtable params, HttpServletResponse response, String sessionId) throws PropertyNotFoundException, IOException { DataQuery dq = null; if (sessionId != null) { dq = new DataQuery(sessionId); } else { dq = new DataQuery(); } String dataqueryXML = (params.get("dataquery"))[0]; ResultSet rs = null; try { rs = dq.executeQuery(dataqueryXML); } catch (Exception e) { //probably need to do something here e.printStackTrace(); return; } //process the result set String qformat = "csv"; String[] temp = params.get("qformat"); if (temp != null && temp.length > 0) { qformat = temp[0]; } String fileName = "query-results." + qformat; //get the results as csv file if (qformat != null && qformat.equalsIgnoreCase("csv")) { response.setContentType("text/csv"); //response.setContentType("application/csv"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); Writer writer = new OutputStreamWriter(response.getOutputStream()); CSVWriter csv = new CSVWriter(writer, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER); try { csv.writeAll(rs, true); csv.flush(); response.flushBuffer(); rs.close(); } catch (SQLException e) { e.printStackTrace(); } return; } } protected void handleEditCart( Hashtable params, HttpServletResponse response, String sessionId) throws PropertyNotFoundException, IOException { CartManager cm = null; if (sessionId != null) { cm = new CartManager(sessionId); } else { cm = new CartManager(); } String editOperation = (params.get("operation"))[0]; String[] docids = params.get("docid"); String[] field = params.get("field"); String[] path = params.get("path"); Map fields = null; if (field != null && path != null) { fields = new HashMap(); fields.put(field[0], path[0]); } //TODO handle attribute map (metadata fields) cm.editCart(editOperation, docids, fields); } // ///////////////////////////// METACAT SPATIAL /////////////////////////// /** * handles all spatial queries -- these queries may include any of the * queries supported by the WFS / WMS standards * * handleSQuery(out, params, response, username, groupnames, sess_id); * @throws HandlerException */ protected void handleSpatialQuery(Writer out, Hashtable params, HttpServletResponse response, String username, String[] groupnames, String sess_id) throws PropertyNotFoundException, HandlerException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); if ( !PropertyService.getProperty("spatial.runSpatialOption").equals("true") ) { response.setContentType("text/html"); try { out.write(" Metacat Spatial Option is turned off "); out.close(); } catch (IOException e) { throw new HandlerException(e.getMessage()); } return; } /* * Perform spatial query against spatial cache */ float _xmax = Float.valueOf( (params.get("xmax"))[0] ).floatValue(); float _ymax = Float.valueOf( (params.get("ymax"))[0] ).floatValue(); float _xmin = Float.valueOf( (params.get("xmin"))[0] ).floatValue(); float _ymin = Float.valueOf( (params.get("ymin"))[0] ).floatValue(); SpatialQuery sq = new SpatialQuery(); Vector docids = sq.filterByBbox( _xmin, _ymin, _xmax, _ymax ); // logMetacat.info(" --- Spatial Query completed. Passing on the SQuery // handler"); // logMetacat.warn("\n\n ******* after spatial query, we've got " + // docids.size() + " docids \n\n"); /* * Create an array matching docids */ String [] docidArray = new String[docids.size()]; docids.toArray(docidArray); /* * Create squery string */ String squery = DocumentIdQuery.createDocidQuery( docidArray ); // logMetacat.info("-----------\n" + squery + "\n------------------"); String[] queryArray = new String[1]; queryArray[0] = squery; params.put("query", queryArray); /* * Determine qformat */ String[] qformatArray = new String[1]; try { String _skin = (params.get("skin"))[0]; qformatArray[0] = _skin; } catch (java.lang.NullPointerException e) { // should be "default" but keep this for backwards compatibility // with knp site logMetacat.warn("MetacatHandler.handleSpatialQuery - No SKIN specified for metacat actions=spatial_query... defaulting to 'knp' skin !\n"); qformatArray[0] = "knp"; } params.put("qformat", qformatArray); // change the action String[] actionArray = new String[1]; actionArray[0] = "squery"; params.put("action", actionArray); /* * Pass the docids to the DBQuery contructor */ // This is a hack to get the empty result set to show... // Otherwise dbquery sees no docidOverrides and does a full % percent // query if (docids.size() == 0) docids.add(""); DBQuery queryobj = new DBQuery(docids); queryobj.findDocuments(response, out, params, username, groupnames, sess_id); } // LOGIN & LOGOUT SECTION /** * Handle the login request. Create a new session object. Do user * authentication through the session. * @throws IOException */ public void handleLoginAction(Writer out, Hashtable params, HttpServletRequest request, HttpServletResponse response) throws IOException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); AuthSession sess = null; if(params.get("username") == null){ response.setContentType("text/xml"); out.write(""); out.write(""); out.write("Username not specified"); out.write(""); return; } // } if(params.get("password") == null){ response.setContentType("text/xml"); out.write(""); out.write(""); out.write("Password not specified"); out.write(""); return; } String un = (params.get("username"))[0]; logMetacat.info("MetacatHandler.handleLoginAction - user " + un + " is trying to login"); String pw = (params.get("password"))[0]; String qformat = "xml"; if (params.get("qformat") != null) { qformat = (params.get("qformat"))[0]; } try { sess = new AuthSession(); } catch (Exception e) { String errorMsg = "MetacatServlet.handleLoginAction - Problem in MetacatServlet.handleLoginAction() authenicating session: " + e.getMessage(); logMetacat.error(errorMsg); out.write(errorMsg); e.printStackTrace(System.out); return; } boolean isValid = sess.authenticate(request, un, pw); //if it is authernticate is true, store the session if (isValid) { HttpSession session = sess.getSessions(); String id = session.getId(); logMetacat.debug("MetacatHandler.handleLoginAction - Store session id " + id + " which has username" + session.getAttribute("username") + " into hash in login method"); try { //System.out.println("registering session with id " + id); //System.out.println("username: " + (String) session.getAttribute("username")); SessionService.getInstance().registerSession(id, (String) session.getAttribute("username"), (String[]) session.getAttribute("groupnames"), (String) session.getAttribute("password"), (String) session.getAttribute("name")); } catch (ServiceException se) { String errorMsg = "MetacatServlet.handleLoginAction - service problem registering session: " + se.getMessage(); logMetacat.error("MetacatHandler.handleLoginAction - " + errorMsg); out.write(errorMsg); se.printStackTrace(System.out); return; } } // format and transform the output if (qformat.equals("xml")) { response.setContentType("text/xml"); out.write(sess.getMessage()); } else { try { DBTransform trans = new DBTransform(); response.setContentType("text/html"); trans.transformXMLDocument(sess.getMessage(), "-//NCEAS//login//EN", "-//W3C//HTML//EN", qformat, out, null, null); } catch (Exception e) { logMetacat.error("MetacatHandler.handleLoginAction - General error" + e.getMessage()); e.printStackTrace(System.out); } } } /** * Handle the logout request. Close the connection. * @throws IOException */ public void handleLogoutAction(Writer out, Hashtable params, HttpServletRequest request, HttpServletResponse response) throws IOException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); String qformat = "xml"; if(params.get("qformat") != null){ qformat = params.get("qformat")[0]; } // close the connection HttpSession sess = request.getSession(false); logMetacat.info("MetacatHandler.handleLogoutAction - After get session in logout request"); if (sess != null) { logMetacat.info("MetacatHandler.handleLogoutAction - The session id " + sess.getId() + " will be invalidate in logout action"); logMetacat.info("MetacatHandler.handleLogoutAction - The session contains user " + sess.getAttribute("username") + " will be invalidate in logout action"); sess.invalidate(); SessionService.getInstance().unRegisterSession(sess.getId()); } // produce output StringBuffer output = new StringBuffer(); output.append(""); output.append(""); output.append("User logged out"); output.append(""); //format and transform the output if (qformat.equals("xml")) { response.setContentType("text/xml"); out.write(output.toString()); } else { try { DBTransform trans = new DBTransform(); response.setContentType("text/html"); trans.transformXMLDocument(output.toString(), "-//NCEAS//login//EN", "-//W3C//HTML//EN", qformat, out, null, null); } catch (Exception e) { logMetacat.error( "MetacatHandler.handleLogoutAction - General error: " + e.getMessage()); e.printStackTrace(System.out); } } } // END OF LOGIN & LOGOUT SECTION // SQUERY & QUERY SECTION /** * Retreive the squery xml, execute it and display it * * @param out the output stream to the client * @param params the Hashtable of parameters that should be included in the * squery. * @param response the response object linked to the client * @param conn the database connection */ protected void handleSQuery(Writer out, Hashtable params, HttpServletResponse response, String user, String[] groups, String sessionid) throws PropertyNotFoundException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); long squeryWarnLimit = Long.parseLong(PropertyService.getProperty("database.squeryTimeWarnLimit")); long startTime = System.currentTimeMillis(); DBQuery queryobj = new DBQuery(); queryobj.findDocuments(response, out, params, user, groups, sessionid); long outPutTime = System.currentTimeMillis(); long runTime = outPutTime - startTime; if (runTime > squeryWarnLimit) { logMetacat.warn("MetacatHandler.handleSQuery - Long running squery. Total time: " + runTime + " ms, squery: " + ((String[])params.get("query"))[0]); } logMetacat.debug("MetacatHandler.handleSQuery - squery: " + ((String[])params.get("query"))[0] + " ran in " + runTime + " ms"); } /** * Create the xml query, execute it and display the results. * * @param out the output stream to the client * @param params the Hashtable of parameters that should be included in the * squery. * @param response the response object linked to the client * @throws IOException * @throws UnsupportedEncodingException */ protected void handleQuery(Writer out, Hashtable params, HttpServletResponse response, String user, String[] groups, String sessionid) throws PropertyNotFoundException, UnsupportedEncodingException, IOException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); long queryWarnLimit = Long.parseLong(PropertyService.getProperty("database.queryTimeWarnLimit")); //create the query and run it String xmlquery = DBQuery.createSQuery(params); String[] queryArray = new String[1]; queryArray[0] = xmlquery; params.put("query", queryArray); long startTime = System.currentTimeMillis(); DBQuery queryobj = new DBQuery(); queryobj.findDocuments(response, out, params, user, groups, sessionid); long outPutTime = System.currentTimeMillis(); long runTime = outPutTime -startTime; if (runTime > queryWarnLimit) { logMetacat.warn("MetacatHandler.handleQuery - Long running squery. Total time: " + runTime + " ms, squery: " + ((String[])params.get("query"))[0]); } logMetacat.debug("MetacatHandler.handleQuery - query: " + ((String[])params.get("query"))[0] + " ran in " + runTime + " ms"); } // END OF SQUERY & QUERY SECTION //Export section /** * Handle the "export" request of data package from Metacat in zip format * * @param params the Hashtable of HTTP request parameters * @param response the HTTP response object linked to the client * @param user the username sent the request * @param groups the user's groupnames */ protected void handleExportAction(Hashtable params, HttpServletResponse response, String user, String[] groups, String passWord) { Logger logMetacat = Logger.getLogger(MetacatHandler.class); // Output stream ServletOutputStream out = null; // Zip output stream ZipOutputStream zOut = null; DBQuery queryObj = null; String[] docs = new String[10]; String docId = ""; try { // read the params if (params.containsKey("docid")) { docs = params.get("docid"); } // Create a DBuery to handle export queryObj = new DBQuery(); String qformat = null; if (params.containsKey("qformat")) { qformat = params.get("qformat")[0]; queryObj.setQformat(qformat); } // Get the docid docId = docs[0]; // Make sure the client specify docid if (docId == null || docId.equals("")) { response.setContentType("text/xml"); //MIME type // Get a printwriter PrintWriter pw = response.getWriter(); // Send back message pw.println(""); pw.println(""); pw.println("You didn't specify requested docid"); pw.println(""); // Close printwriter pw.close(); return; } // Get output stream response.setContentType("application/zip"); //MIME type response.setHeader("Content-Disposition", "attachment; filename=" + docId + ".zip"); // Set the name of the zip file out = response.getOutputStream(); zOut = new ZipOutputStream(out); zOut = queryObj .getZippedPackage(docId, out, user, groups, passWord); zOut.finish(); //terminate the zip file zOut.close(); //close the zip stream } catch (Exception e) { try { response.setContentType("text/xml"); //MIME type // Send error message back if (out != null) { PrintWriter pw = new PrintWriter(out); pw.println(""); pw.println(""); pw.println(e.getMessage()); pw.println(""); // Close printwriter pw.close(); // Close output stream out.close(); } // Close zip output stream if (zOut != null) { zOut.close(); } } catch (IOException ioe) { logMetacat.error("MetacatHandler.handleExportAction - Problem with the servlet output: " + ioe.getMessage()); e.printStackTrace(System.out); } logMetacat.error("MetacatHandler.handleExportAction - General error: " + e.getMessage()); e.printStackTrace(System.out); } } /** * In eml2 document, the xml can have inline data and data was stripped off * and store in file system. This action can be used to read inline data * only * * @param params the Hashtable of HTTP request parameters * @param response the HTTP response object linked to the client * @param user the username sent the request * @param groups the user's groupnames */ protected void handleReadInlineDataAction(Hashtable params, HttpServletRequest request, HttpServletResponse response, String user, String passWord, String[] groups) { Logger logMetacat = Logger.getLogger(MetacatHandler.class); String[] docs = new String[10]; String inlineDataId = null; String docId = ""; ServletOutputStream out = null; try { // read the params if (params.containsKey("inlinedataid")) { docs = params.get("inlinedataid"); } // Get the docid inlineDataId = docs[0]; // Make sure the client specify docid if (inlineDataId == null || inlineDataId.equals("")) { throw new Exception("You didn't specify requested inlinedataid"); } // check for permission, use full docid with revision docId = DocumentUtil.getDocIdFromInlineDataID(inlineDataId); PermissionController controller = new PermissionController(docId); // check top level read permission if (!controller.hasPermission(user, groups, AccessControlInterface.READSTRING)) { throw new Exception("User " + user + " doesn't have permission " + " to read document " + docId); } else { //check data access level try { Hashtable unReadableInlineDataList = PermissionController.getUnReadableInlineDataIdList(docId, user, groups); if (unReadableInlineDataList.containsValue(inlineDataId)) { throw new Exception("User " + user + " doesn't have permission " + " to read inlinedata " + inlineDataId); }//if }//try catch (Exception e) { throw e; }//catch }//else // Get output stream out = response.getOutputStream(); // read the inline data from the file String inlinePath = PropertyService.getProperty("application.inlinedatafilepath"); File lineData = new File(inlinePath, inlineDataId); FileInputStream input = new FileInputStream(lineData); byte[] buffer = new byte[4 * 1024]; int bytes = input.read(buffer); while (bytes != -1) { out.write(buffer, 0, bytes); bytes = input.read(buffer); } out.close(); EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), user, inlineDataId, "readinlinedata"); } catch (Exception e) { try { PrintWriter pw = null; // Send error message back if (out != null) { pw = new PrintWriter(out); } else { pw = response.getWriter(); } pw.println(""); pw.println(""); pw.println(e.getMessage()); pw.println(""); // Close printwriter pw.close(); // Close output stream if out is not null if (out != null) { out.close(); } } catch (IOException ioe) { logMetacat.error("MetacatHandler.handleReadInlineDataAction - Problem with the servlet output: " + ioe.getMessage()); e.printStackTrace(System.out); } logMetacat.error("MetacatHandler.handleReadInlineDataAction - General error: " + e.getMessage()); e.printStackTrace(System.out); } } /** * Handle the "read" request of metadata/data files from Metacat or any * files from Internet; transformed metadata XML document into HTML * presentation if requested; zip files when more than one were requested. * * @param params the Hashtable of HTTP request parameters * @param request the HTTP request object linked to the client * @param response the HTTP response object linked to the client * @param user the username sent the request * @param groups the user's groupnames */ public void handleReadAction(Hashtable params, HttpServletRequest request, HttpServletResponse response, String user, String passWord, String[] groups) { Logger logMetacat = Logger.getLogger(MetacatHandler.class); ServletOutputStream out = null; ZipOutputStream zout = null; PrintWriter pw = null; boolean zip = false; boolean withInlineData = true; try { String[] docs = new String[0]; String docid = ""; String qformat = ""; // read the params if (params.containsKey("docid")) { docs = params.get("docid"); } if (params.containsKey("qformat")) { qformat = params.get("qformat")[0]; } // the param for only metadata (eml) // we don't support read a eml document without inline data now. /*if (params.containsKey("inlinedata")) { String inlineData = ((String[]) params.get("inlinedata"))[0]; if (inlineData.equalsIgnoreCase("false")) { withInlineData = false; } }*/ // handle special case where the PID was given if (params.containsKey("pid")) { docs = params.get("pid"); for (int i = 0; i < docs.length; i++) { String pid = docs[i]; // look up the pid if we have it String localId = IdentifierManager.getInstance().getLocalId(pid); docs[i] = localId; } // put docid in parms for downstream methods to use params.put("docid", docs); } if ((docs.length > 1) || qformat.equals("zip")) { zip = true; out = response.getOutputStream(); response.setContentType("application/zip"); //MIME type zout = new ZipOutputStream(out); } // go through the list of docs to read for (int i = 0; i < docs.length; i++) { String providedFileName = null; if (params.containsKey(docs[i])) { providedFileName = params.get(docs[i])[0]; } try { URL murl = new URL(docs[i]); Hashtable murlQueryStr = MetacatUtil.parseQuery( murl.getQuery()); // case docid="http://.../?docid=aaa" // or docid="metacat://.../?docid=bbb" if (murlQueryStr.containsKey("docid")) { // get only docid, eliminate the rest docid = murlQueryStr.get("docid"); if (zip) { addDocToZip(request, docid, providedFileName, zout, user, groups); } else { readFromMetacat(request.getRemoteAddr(), request.getHeader("User-Agent"), response, response.getOutputStream(), docid, qformat, user, groups, withInlineData, params); } // case docid="http://.../filename" } else { docid = docs[i]; if (zip) { addDocToZip(request, docid, providedFileName, zout, user, groups); } else { readFromURLConnection(response, docid); } } } catch (MalformedURLException mue) { docid = docs[i]; if (zip) { addDocToZip(request, docid, providedFileName, zout, user, groups); } else { if (out == null) { out = response.getOutputStream(); } readFromMetacat(request.getRemoteAddr(), request.getHeader("User-Agent"), response, out, docid, qformat, user, groups, withInlineData, params); } } } if (zip) { zout.finish(); //terminate the zip file zout.close(); //close the zip stream } } catch (McdbDocNotFoundException notFoundE) { // To handle doc not found exception // the docid which didn't be found String notFoundDocId = notFoundE.getUnfoundDocId(); String notFoundRevision = notFoundE.getUnfoundRevision(); logMetacat.warn("MetacatHandler.handleReadAction - Missed id: " + notFoundDocId); logMetacat.warn("MetacatHandler.handleReadAction - Missed rev: " + notFoundRevision); try { // read docid from remote server readFromRemoteMetaCat(response, notFoundDocId, notFoundRevision, user, passWord, out, zip, zout); // Close zout outputstream if (zout != null) { zout.close(); } // close output stream if (out != null) { out.close(); } } catch (Exception exc) { logMetacat.error("MetacatHandler.handleReadAction - General error: " + exc.getMessage()); exc.printStackTrace(System.out); try { if (out != null) { response.setContentType("text/xml"); // Send back error message by printWriter pw = new PrintWriter(out); pw.println(""); pw.println(""); pw.println(notFoundE.getMessage()); pw.println(""); pw.close(); out.close(); } else { response.setContentType("text/xml"); //MIME type // Send back error message if out = null if (pw == null) { // If pw is null, open the respnose pw = response.getWriter(); } pw.println(""); pw.println(""); pw.println(notFoundE.getMessage()); pw.println(""); pw.close(); } // close zout if (zout != null) { zout.close(); } } catch (IOException ie) { logMetacat.error("MetacatHandler.handleReadAction - Problem with the servlet output: " + ie.getMessage()); ie.printStackTrace(System.out); } } } catch (Exception e) { try { if (out != null) { response.setContentType("text/xml"); //MIME type pw = new PrintWriter(out); pw.println(""); pw.println(""); pw.println(e.getMessage()); pw.println(""); pw.close(); out.close(); } else { response.setContentType("text/xml"); //MIME type // Send back error message if out = null if (pw == null) { pw = response.getWriter(); } pw.println(""); pw.println(""); pw.println(e.getMessage()); pw.println(""); pw.close(); } // Close zip output stream if (zout != null) { zout.close(); } } catch (Exception e2) { logMetacat.error("MetacatHandler.handleReadAction - " + "Problem with the servlet output: "+ e2.getMessage()); e2.printStackTrace(System.out); } logMetacat.error("MetacatHandler.handleReadAction - General error: " + e.getMessage()); e.printStackTrace(System.out); } } /** * * @return */ public MetacatResultSet query(String metacatUrl, Hashtableparams, String username, String[] groups, String sessionid) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); // use UTF-8 encoding for DB query Writer out = new OutputStreamWriter(baos, MetaCatServlet.DEFAULT_ENCODING); handleQuery(out, params, null, username, groups, sessionid); out.flush(); baos.flush(); //baos.close(); //System.out.println("result from query: " + baos.toString()); MetacatResultSet rs = new MetacatResultSet(baos.toString(MetaCatServlet.DEFAULT_ENCODING)); return rs; } /** * set the access permissions on the document specified */ public void setAccess(String metacatUrl, String username, String docid, String principal, String permission, String permissionType, String permissionOrder) throws Exception { Hashtable params = new Hashtable(); params.put("principal", new String[] {principal}); params.put("permission", new String[] {permission}); params.put("permType", new String[] {permissionType}); params.put("permOrder", new String[] {permissionOrder}); params.put("docid", new String[]{docid}); //System.out.println("permission in MetacatHandler.setAccess: " + // params.get("permission")[0]); ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter out = new PrintWriter(baos); handleSetAccessAction(out, params, username, null, null); String resp = baos.toString(); //System.out.println("response from MetacatHandler.setAccess: " + resp); } /** * Read a document from metacat and return the InputStream. The XML or * data document should be on disk, but if not, read from the metacat database. * * @param docid - the metacat docid to read * @param username - the DN of the principal attempting the read * @param groups - the list of groups the DN belongs to as a String array * @return objectStream - the document as an InputStream * @throws InsufficientKarmaException * @throws ParseLSIDException * @throws PropertyNotFoundException * @throws McdbException * @throws SQLException * @throws ClassNotFoundException * @throws IOException */ public static InputStream read(String docid) throws ParseLSIDException, PropertyNotFoundException, McdbException, SQLException, ClassNotFoundException, IOException { logMetacat.debug("MetacatHandler.read() called."); InputStream inputStream = null; // be sure we have a local ID from an LSID if (docid.startsWith("urn:")) { try { docid = LSIDUtil.getDocId(docid, true); } catch (ParseLSIDException ple) { logMetacat.debug("There was a problem parsing the LSID. The " + "error message was: " + ple.getMessage()); throw ple; } } // accomodate old clients that send docids without revision numbers docid = DocumentUtil.appendRev(docid); DocumentImpl doc = new DocumentImpl(docid, false); // deal with data or metadata cases if (doc.getRootNodeID() == 0) { // this is a data file // get the path to the file to read try { String filepath = PropertyService.getProperty("application.datafilepath"); // ensure it is a directory path if (!(filepath.endsWith("/"))) { filepath += "/"; } String filename = filepath + docid; inputStream = readFromFilesystem(filename); } catch (PropertyNotFoundException pnf) { logMetacat.debug("There was a problem finding the " + "application.datafilepath property. The error " + "message was: " + pnf.getMessage()); throw pnf; } // end try() } else { // this is an metadata document // Get the xml (will try disk then DB) try { // force the InputStream to be returned OutputStream nout = null; inputStream = doc.toXml(nout, null, null, true); } catch (McdbException e) { // report the error logMetacat.error( "MetacatHandler.readFromMetacat() " + "- could not read document " + docid + ": " + e.getMessage(), e); } } return inputStream; } /** * Read a file from Metacat's configured file system data directory. * * @param filename The full path file name of the file to read * * @return fileInputStream The file to read as a FileInputStream */ private static FileInputStream readFromFilesystem(String filename) throws FileNotFoundException { logMetacat.debug("MetacatHandler.readFromFilesystem() called."); FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(filename); } catch ( FileNotFoundException fnfe ) { logMetacat.debug("There was an error reading the file " + filename + ". The error was: " + fnfe.getMessage()); throw fnfe; } return fileInputStream; } /* * Delete a document in metacat based on the docid. * * @param out - the print writer used to send output * @param response - the HTTP servlet response to be returned * @param docid - the internal docid as a String * @param user - the username of the principal doing the delete * @param groups - the groups list of the principal doing the delete * * @throws AccessionNumberException * @throws McdbDocNotFoundException * @throws InsufficientKarmaException * @throws SQLException * @throws Exception */ private void deleteFromMetacat(PrintWriter out, HttpServletRequest request, HttpServletResponse response, String docid, String user, String[] groups) throws McdbDocNotFoundException { // Delete a document from the database based on the docid try { DocumentImpl.delete(docid, user, groups, null, false); // null: don't notify server EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), user, docid, "delete"); response.setContentType("text/xml"); out.println(this.PROLOG); out.println(this.SUCCESS); out.println("Document deleted."); out.println(this.SUCCESSCLOSE); logMetacat.info("MetacatHandler.handleDeleteAction - " + "Document deleted."); try { // Delete from spatial cache if runningSpatialOption if ( PropertyService.getProperty("spatial.runSpatialOption").equals("true") ) { SpatialHarvester sh = new SpatialHarvester(); sh.addToDeleteQue( DocumentUtil.getSmartDocId( docid ) ); sh.destroy(); } } catch ( PropertyNotFoundException pnfe ) { logMetacat.error("MetacatHandler.deleteFromMetacat() - " + "Couldn't find spatial.runSpatialOption property during " + "document deletion."); } } catch (AccessionNumberException ane) { response.setContentType("text/xml"); out.println(this.PROLOG); out.println(this.ERROR); //out.println("Error deleting document!!!"); out.println(ane.getMessage()); out.println(this.ERRORCLOSE); logMetacat.error("MetacatHandler.deleteFromMetacat() - " + "Document could not be deleted: " + ane.getMessage()); ane.printStackTrace(System.out); } catch ( SQLException sqle ) { response.setContentType("text/xml"); out.println(this.PROLOG); out.println(this.ERROR); //out.println("Error deleting document!!!"); out.println(sqle.getMessage()); out.println(this.ERRORCLOSE); logMetacat.error("MetacatHandler.deleteFromMetacat() - " + "Document could not be deleted: " + sqle.getMessage()); sqle.printStackTrace(System.out); } catch ( McdbDocNotFoundException dnfe ) { throw dnfe; } catch ( InsufficientKarmaException ike ) { response.setContentType("text/xml"); out.println(this.PROLOG); out.println(this.ERROR); //out.println("Error deleting document!!!"); out.println(ike.getMessage()); out.println(this.ERRORCLOSE); logMetacat.error("MetacatHandler.deleteFromMetacat() - " + "Document could not be deleted: " + ike.getMessage()); ike.printStackTrace(System.out); } catch ( Exception e ) { response.setContentType("text/xml"); out.println(this.PROLOG); out.println(this.ERROR); //out.println("Error deleting document!!!"); out.println(e.getMessage()); out.println(this.ERRORCLOSE); logMetacat.error("MetacatHandler.deleteFromMetacat() - " + "Document could not be deleted: " + e.getMessage()); e.printStackTrace(System.out); } } /** read metadata or data from Metacat * @param userAgent * @throws PropertyNotFoundException * @throws ParseLSIDException * @throws InsufficientKarmaException */ public void readFromMetacat(String ipAddress, String userAgent, HttpServletResponse response, OutputStream out, String docid, String qformat, String user, String[] groups, boolean withInlineData, Hashtable params) throws ClassNotFoundException, IOException, SQLException, McdbException, PropertyNotFoundException, ParseLSIDException, InsufficientKarmaException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); try { if (docid.startsWith("urn:")) { docid = LSIDUtil.getDocId(docid, true); } // here is hack for handle docid=john.10(in order to tell mike.jim.10.1 // mike.jim.10, we require to provide entire docid with rev). But // some old client they only provide docid without rev, so we need // to handle this suituation. First we will check how many // seperator here, if only one, we will append the rev in xml_documents // to the id. docid = DocumentUtil.appendRev(docid); DocumentImpl doc = new DocumentImpl(docid, false); //check the permission for read if (!DocumentImpl.hasReadPermission(user, groups, docid)) { InsufficientKarmaException e = new InsufficientKarmaException("User " + user + " does not have permission" + " to read the document with the docid " + docid); throw e; } if (doc.getRootNodeID() == 0) { // this is data file, so find the path on disk for the file String filepath = PropertyService.getProperty("application.datafilepath"); if (!filepath.endsWith("/")) { filepath += "/"; } String filename = filepath + docid; FileInputStream fin = null; fin = new FileInputStream(filename); if (response != null) { // MIME type //String contentType = servletContext.getMimeType(filename); String contentType = (new MimetypesFileTypeMap()).getContentType(filename); if (contentType == null) { ContentTypeProvider provider = new ContentTypeProvider( docid); contentType = provider.getContentType(); logMetacat.info("MetacatHandler.readFromMetacat - Final contenttype is: " + contentType); } response.setContentType(contentType); // Set the output filename on the response String outputname = generateOutputName(docid, params, doc); response.setHeader("Content-Disposition", "attachment; filename=\"" + outputname + "\""); } // Write the data to the output stream try { byte[] buf = new byte[4 * 1024]; // 4K buffer int b = fin.read(buf); while (b != -1) { out.write(buf, 0, b); b = fin.read(buf); } fin.close(); } finally { IOUtils.closeQuietly(fin); } } else { // this is metadata doc if (qformat.equals("xml") || qformat.equals("")) { // if equals "", that means no qformat is specified. hence // by default the document should be returned in xml format // set content type first if (response != null) { response.setContentType("text/xml"); //MIME type response.setHeader("Content-Disposition", "attachment; filename=" + docid + ".xml"); } // Try to get the metadata file from disk. If it isn't // found, create it from the db and write it to disk then. try { doc.toXml(out, user, groups, withInlineData); } catch (McdbException e) { // any exceptions in reading the xml from disc, and we go back to the // old way of creating the xml directly. logMetacat.error("MetacatHandler.readFromMetacat - " + "could not read from document file " + docid + ": " + e.getMessage()); e.printStackTrace(System.out); doc.toXmlFromDb(out, user, groups, withInlineData); } } else { // TODO MCD, this should read from disk as well? //*** This is a metadata doc, to be returned in a skin/custom format. //*** Add param to indicate if public has read access or not. logMetacat.debug("User: \n" + user); if (!user.equals("public")) { if (DocumentImpl.hasReadPermission("public", null, docid)) params.put("publicRead", new String[] {"true"}); else params.put("publicRead", new String[] {"false"}); } if(doc.getDoctype() != null && doc.getDoctype().equals(FGDCDOCTYPE)) { //for fgdc doctype, we need to pass parameter enableFGDCediting PermissionController controller = new PermissionController(docid); if(controller.hasPermission(user, groups, AccessControlInterface.WRITESTRING)) { params.put("enableFGDCediting", new String[] {"true"}); } else { params.put("enableFGDCediting", new String[] {"false"}); } } if (response != null) { response.setContentType("text/html"); //MIME type } // detect actual encoding String docString = doc.toString(user, groups, withInlineData); XmlStreamReader xsr = new XmlStreamReader(new ByteArrayInputStream(doc.getBytes())); String encoding = xsr.getEncoding(); Writer w = null; if (encoding != null) { w = new OutputStreamWriter(out, encoding); } else { w = new OutputStreamWriter(out); } // Look up the document type String doctype = doc.getDoctype(); // Transform the document to the new doctype DBTransform dbt = new DBTransform(); dbt.transformXMLDocument( docString, doctype, "-//W3C//HTML//EN", qformat, w, params, null); } } EventLog.getInstance().log(ipAddress, userAgent, user, docid, "read"); } catch (PropertyNotFoundException except) { throw except; } } /** * Create a filename to be used for naming a downloaded document * @param docid the identifier of the document to be named * @param params the parameters of the request * @param doc the DocumentImpl of the document to be named * @return String containing a name for the download */ private String generateOutputName(String docid, Hashtable params, DocumentImpl doc) { SystemMetadata sysMeta = null; String guid = null; int rev = -1; String fileName = null; // First, if SystemMetadata.fileName is present, use it try { rev = Integer.valueOf(DocumentUtil.getRevisionStringFromString(docid)).intValue(); docid = DocumentUtil.getDocIdFromAccessionNumber(docid); if (rev > 0 ) { guid = IdentifierManager.getInstance().getGUID(docid, rev); if ( guid != null ) { sysMeta = IdentifierManager.getInstance().getSystemMetadata(guid); if ( sysMeta != null ) { fileName = sysMeta.getFileName(); } } } } catch (McdbDocNotFoundException e) { logMetacat.debug("Couldn't find the given docid: " + e.getMessage()); } if (fileName != null ) { return fileName; } // Otherwise, generate a name String outputname = null; // check for the existence of a metadatadocid parameter, // if this is sent, then send a filename which contains both // the metadata docid and the data docid, so the link with // metadata is explicitly encoded in the filename. String metadatadocid = null; Vector nameparts = new Vector(); if(params.containsKey("metadatadocid")) { metadatadocid = params.get("metadatadocid")[0]; } if (metadatadocid != null && !metadatadocid.equals("")) { nameparts.add(metadatadocid); } // we'll always have the docid, include it in the name String doctype = doc.getDoctype(); // TODO: fix this to lookup the associated FGDC metadata document, // and grab the doctype tag for it. These should be set to something // consistent, not 'metadata' as it stands... //if (!doctype.equals("metadata")) { // nameparts.add(docid); //} nameparts.add(docid); // Set the name of the data file to the entity name plus docid, // or if that is unavailable, use the docid alone String docname = doc.getDocname(); if (docname != null && !docname.equals("")) { nameparts.add(docname); } // combine the name elements with a dash, using a 'join' equivalent String delimiter = "-"; Iterator iter = nameparts.iterator(); StringBuffer buffer = new StringBuffer(iter.next()); while (iter.hasNext()) buffer.append(delimiter).append(iter.next()); outputname = buffer.toString(); return outputname; } /** * read data from URLConnection */ private void readFromURLConnection(HttpServletResponse response, String docid) throws IOException, MalformedURLException { ServletOutputStream out = response.getOutputStream(); //String contentType = servletContext.getMimeType(docid); //MIME type String contentType = (new MimetypesFileTypeMap()).getContentType(docid); if (contentType == null) { if (docid.endsWith(".xml")) { contentType = "text/xml"; } else if (docid.endsWith(".css")) { contentType = "text/css"; } else if (docid.endsWith(".dtd")) { contentType = "text/plain"; } else if (docid.endsWith(".xsd")) { contentType = "text/xml"; } else if (docid.endsWith("/")) { contentType = "text/html"; } else { File f = new File(docid); if (f.isDirectory()) { contentType = "text/html"; } else { contentType = "application/octet-stream"; } } } response.setContentType(contentType); // if we decide to use "application/octet-stream" for all data returns // response.setContentType("application/octet-stream"); // this is http url URL url = new URL(docid); BufferedInputStream bis = null; try { bis = new BufferedInputStream(url.openStream()); byte[] buf = new byte[4 * 1024]; // 4K buffer int b = bis.read(buf); while (b != -1) { out.write(buf, 0, b); b = bis.read(buf); } } finally { if (bis != null) bis.close(); } } /** * read file/doc and write to ZipOutputStream * * @param docid * @param zout * @param user * @param groups * @throws ClassNotFoundException * @throws IOException * @throws SQLException * @throws McdbException * @throws Exception */ private void addDocToZip(HttpServletRequest request, String docid, String providedFileName, ZipOutputStream zout, String user, String[] groups) throws ClassNotFoundException, IOException, SQLException, McdbException, Exception { byte[] bytestring = null; ZipEntry zentry = null; try { URL url = new URL(docid); // this http url; read from URLConnection; add to zip //use provided file name if we have one if (providedFileName != null && providedFileName.length() > 1) { zentry = new ZipEntry(providedFileName); } else { zentry = new ZipEntry(docid); } zout.putNextEntry(zentry); BufferedInputStream bis = null; try { bis = new BufferedInputStream(url.openStream()); byte[] buf = new byte[4 * 1024]; // 4K buffer int b = bis.read(buf); while (b != -1) { zout.write(buf, 0, b); b = bis.read(buf); } } finally { if (bis != null) bis.close(); } zout.closeEntry(); } catch (MalformedURLException mue) { // this is metacat doc (data file or metadata doc) try { DocumentImpl doc = new DocumentImpl(docid, false); //check the permission for read if (!DocumentImpl.hasReadPermission(user, groups, docid)) { Exception e = new Exception("User " + user + " does not have " + "permission to read the document with the docid " + docid); throw e; } if (doc.getRootNodeID() == 0) { // this is data file; add file to zip String filepath = PropertyService.getProperty("application.datafilepath"); if (!filepath.endsWith("/")) { filepath += "/"; } String filename = filepath + docid; FileInputStream fin = null; fin = new FileInputStream(filename); try { //use provided file name if we have one if (providedFileName != null && providedFileName.length() > 1) { zentry = new ZipEntry(providedFileName); } else { zentry = new ZipEntry(docid); } zout.putNextEntry(zentry); byte[] buf = new byte[4 * 1024]; // 4K buffer int b = fin.read(buf); while (b != -1) { zout.write(buf, 0, b); b = fin.read(buf); } fin.close(); } finally { IOUtils.closeQuietly(fin); } zout.closeEntry(); } else { // this is metadata doc; add doc to zip bytestring = doc.getBytes(); //use provided file name if given if (providedFileName != null && providedFileName.length() > 1) { zentry = new ZipEntry(providedFileName); } else { zentry = new ZipEntry(docid + ".xml"); } zentry.setSize(bytestring.length); zout.putNextEntry(zentry); zout.write(bytestring, 0, bytestring.length); zout.closeEntry(); } EventLog.getInstance().log(request.getRemoteAddr(), request.getHeader("User-Agent"), user, docid, "read"); } catch (Exception except) { throw except; } } } /** * If metacat couldn't find a data file or document locally, it will read * this docid from its home server. This is for the replication feature */ private void readFromRemoteMetaCat(HttpServletResponse response, String docid, String rev, String user, String password, ServletOutputStream out, boolean zip, ZipOutputStream zout) throws Exception { // Create a object of RemoteDocument, "" is for zipEntryPath RemoteDocument remoteDoc = new RemoteDocument(docid, rev, user, password, ""); String docType = remoteDoc.getDocType(); // Only read data file if (docType.equals("BIN")) { // If it is zip format if (zip) { remoteDoc.readDocumentFromRemoteServerByZip(zout); } else { if (out == null) { out = response.getOutputStream(); } response.setContentType("application/octet-stream"); remoteDoc.readDocumentFromRemoteServer(out); } } else { throw new Exception("Docid: " + docid + "." + rev + " couldn't find"); } } /** * Handle the database putdocument request and write an XML document to the * database connection * @param userAgent * @param generateSystemMetadata */ public String handleInsertOrUpdateAction(String ipAddress, String userAgent, HttpServletResponse response, PrintWriter out, Hashtable params, String user, String[] groups, boolean generateSystemMetadata, boolean writeAccessRules, byte[] xmlBytes, String formatId, Checksum checksum) { Logger logMetacat = Logger.getLogger(MetacatHandler.class); DBConnection dbConn = null; int serialNumber = -1; String output = ""; String qformat = null; if(params.containsKey("qformat")) { qformat = params.get("qformat")[0]; } if(params.get("docid") == null){ String msg = this.PROLOG + this.ERROR + "Docid not specified" + this.ERRORCLOSE; if(out != null) { out.println(msg); logMetacat.error("MetacatHandler.handleInsertOrUpdateAction - Docid not specified"); } return msg; } try { if (!AuthUtil.canInsertOrUpdate(user, groups)) { String msg = this.PROLOG + this.ERROR + "User '" + user + "' is not allowed to insert and update" + this.ERRORCLOSE; if(out != null) { out.println(msg); } logMetacat.error("MetacatHandler.handleInsertOrUpdateAction - " + "User '" + user + "' not allowed to insert and update"); return msg; } } catch (MetacatUtilException ue) { logMetacat.error("MetacatHandler.handleInsertOrUpdateAction - " + "Could not determine if user could insert or update: " + ue.getMessage(), ue); String msg = this.PROLOG + this.ERROR + "MetacatHandler.handleInsertOrUpdateAction - " + "Could not determine if user could insert or update: " + ue.getMessage() + this.ERRORCLOSE; if(out != null) { out.println(msg); } return msg; } try { // Get the document indicated logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - params: " + params.toString()); String[] doctext = params.get("doctext"); String pub = null; if (params.containsKey("public")) { pub = params.get("public")[0]; } StringReader dtd = null; if (params.containsKey("dtdtext")) { String[] dtdtext = params.get("dtdtext"); try { if (!dtdtext[0].equals("")) { dtd = new StringReader(dtdtext[0]); } } catch (NullPointerException npe) { } } if(doctext == null){ String msg = this.PROLOG + this.ERROR + "Document text not submitted." + this.ERRORCLOSE; if(out != null) { out.println(msg); } // TODO: this should really throw an exception return msg; } logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - " + "the xml document in metacat servlet (before parsing):\n" + doctext[0]); StringReader xmlReader = new StringReader(doctext[0]); boolean validate = false; DocumentImplWrapper documentWrapper = null; String namespace = null; String schemaLocation = null; try { // look inside XML Document for // in order to decide whether to use validation parser validate = needDTDValidation(xmlReader); if (validate) { // set a dtd base validation parser logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - the xml object will be validate by a dtd"); String rule = DocumentImpl.DTD; documentWrapper = new DocumentImplWrapper(rule, validate, writeAccessRules); } else { XMLSchemaService.getInstance().doRefresh(); namespace = XMLSchemaService.findDocumentNamespace(xmlReader); if (namespace != null) { logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - the xml object will be validated by a schema which has a target namespace: "+namespace); schemaLocation = XMLSchemaService.getInstance().findNamespaceAndSchemaLocalLocation(formatId, namespace); if (namespace.compareTo(DocumentImpl.EML2_0_0NAMESPACE) == 0 || namespace.compareTo( DocumentImpl.EML2_0_1NAMESPACE) == 0) { // set eml2 base validation parser String rule = DocumentImpl.EML200; // using emlparser to check id validation @SuppressWarnings("unused") EMLParser parser = new EMLParser(doctext[0]); documentWrapper = new DocumentImplWrapper(rule, true, writeAccessRules); } else if ( namespace.compareTo(DocumentImpl.EML2_1_0NAMESPACE) == 0 || namespace.compareTo(DocumentImpl.EML2_1_1NAMESPACE) == 0) { // set eml2 base validation parser String rule = DocumentImpl.EML210; // using emlparser to check id validation @SuppressWarnings("unused") EMLParser parser = new EMLParser(doctext[0]); documentWrapper = new DocumentImplWrapper(rule, true, writeAccessRules); } else { if(!XMLSchemaService.isNamespaceRegistered(namespace)) { throw new Exception("The namespace "+namespace+" used in the xml object hasn't been registered in the Metacat. Metacat can't validate the object and rejected it. Please contact the operator of the Metacat for regsitering the namespace."); } // set schema base validation parser String rule = DocumentImpl.SCHEMA; documentWrapper = new DocumentImplWrapper(rule, true, writeAccessRules); } } else { xmlReader = new StringReader(doctext[0]); String noNamespaceSchemaLocationAttr = XMLSchemaService.findNoNamespaceSchemaLocationAttr(xmlReader); if(noNamespaceSchemaLocationAttr != null) { logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - the xml object will be validated by a schema which deoe NOT have a target namespace."); schemaLocation = XMLSchemaService.getInstance().findNoNamespaceSchemaLocalLocation(formatId, noNamespaceSchemaLocationAttr); String rule = DocumentImpl.NONAMESPACESCHEMA; documentWrapper = new DocumentImplWrapper(rule, true, writeAccessRules); } else { logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - the xml object will NOT be validated."); documentWrapper = new DocumentImplWrapper("", false, writeAccessRules); } } } String[] action = params.get("action"); String[] docid = params.get("docid"); String newdocid = null; String doAction = null; if (action[0].equals("insert") || action[0].equals("insertmultipart")) { doAction = "INSERT"; } else if (action[0].equals("update")) { doAction = "UPDATE"; } try { // get a connection from the pool dbConn = DBConnectionPool .getDBConnection("Metacathandler.handleInsertOrUpdateAction"); serialNumber = dbConn.getCheckOutSerialNumber(); // write the document to the database and disk String accNumber = docid[0]; logMetacat.debug("MetacatHandler.handleInsertOrUpdateAction - " + doAction + " " + accNumber + "..."); Identifier identifier = new Identifier(); identifier.setValue(accNumber); if(!D1NodeService.isValidIdentifier(identifier)) { String error = "The docid "+accNumber +" is not valid since it is null or contians the white space(s)."; logMetacat.warn("MetacatHandler.handleInsertOrUpdateAction - " +error); throw new Exception(error); } /*if (accNumber == null || accNumber.equals("")) { logMetacat.warn("MetacatHandler.handleInsertOrUpdateAction - " + "writing with null acnumber"); newdocid = documentWrapper.write(dbConn, doctext[0], pub, dtd, doAction, null, user, groups); EventLog.getInstance().log(ipAddress, userAgent, user, "", action[0]); } else {*/ newdocid = documentWrapper.write(dbConn, doctext[0], pub, dtd, doAction, accNumber, user, groups, xmlBytes, schemaLocation, checksum); EventLog.getInstance().log(ipAddress, userAgent, user, accNumber, action[0]); //} // alert listeners of this event MetacatDocumentEvent mde = new MetacatDocumentEvent(); mde.setDocid(accNumber); mde.setDoctype(namespace); mde.setAction(doAction); mde.setUser(user); mde.setGroups(groups); MetacatEventService.getInstance().notifyMetacatEventObservers(mde); // if it was called from Metacat API, we want to generate system metadata for it if ( generateSystemMetadata ) { SystemMetadata sysMeta = null; // it's possible that system metadata exists although // older clients don't support it. Try updates first. try { // get the docid parts String docidWithoutRev = DocumentUtil.getSmartDocId(newdocid); int rev = IdentifierManager.getInstance().getLatestRevForLocalId(newdocid); String guid = IdentifierManager.getInstance().getGUID(docidWithoutRev, rev); sysMeta = IdentifierManager.getInstance().getSystemMetadata(guid); // TODO: need to update? we just looked it up //IdentifierManager.getInstance().updateSystemMetadata(sysMeta); } catch ( McdbDocNotFoundException mnfe) { // handle inserts try { // create the system metadata. During the creatation, the data file in the eml may need to be reindexed. boolean reindexDataObject = true; sysMeta = SystemMetadataFactory.createSystemMetadata(reindexDataObject, newdocid, true, false); // save it to the map HazelcastService.getInstance().getSystemMetadataMap().put(sysMeta.getIdentifier(), sysMeta); // submit for indexing MetacatSolrIndex.getInstance().submit(sysMeta.getIdentifier(), sysMeta, null, true); // [re]index the resource map now that everything is saved // see: https://projects.ecoinformatics.org/ecoinfo/issues/6520 Identifier potentialOreIdentifier = new Identifier(); potentialOreIdentifier.setValue(SystemMetadataFactory.RESOURCE_MAP_PREFIX + sysMeta.getIdentifier().getValue()); SystemMetadata oreSystemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(potentialOreIdentifier); if (oreSystemMetadata != null) { MetacatSolrIndex.getInstance().submit(oreSystemMetadata.getIdentifier(), oreSystemMetadata, null, true); } } catch ( McdbDocNotFoundException dnfe ) { logMetacat.warn( "There was a problem finding the localId " + newdocid + "The error was: " + dnfe.getMessage()); throw dnfe; } catch ( AccessionNumberException ane ) { logMetacat.error( "There was a problem creating the accession number " + "for " + newdocid + ". The error was: " + ane.getMessage()); throw ane; } // end try() } } // end if() } finally { // Return db connection DBConnectionPool.returnDBConnection(dbConn, serialNumber); } // set content type and other response header fields first //response.setContentType("text/xml"); output += this.PROLOG; output += this.SUCCESS; output += "" + newdocid + ""; output += this.SUCCESSCLOSE; } catch (NullPointerException npe) { //response.setContentType("text/xml"); output += this.PROLOG; output += this.ERROR; output += npe.getMessage(); output += this.ERRORCLOSE; logMetacat.error("MetacatHandler.handleInsertOrUpdateAction - " + "Null pointer error when writing eml " + "document to the database: " + npe.getMessage()); npe.printStackTrace(); } } catch (Exception e) { //response.setContentType("text/xml"); output += this.PROLOG; output += this.ERROR; output += e.getMessage(); output += this.ERRORCLOSE; logMetacat.error("MetacatHandler.handleInsertOrUpdateAction - " + "General error when writing the xml object " + "document to the database: " + e.getMessage(), e); e.printStackTrace(); } if (qformat == null || qformat.equals("xml")) { if(response != null && out != null) { response.setContentType("text/xml"); out.println(output); } return output; } else { try { DBTransform trans = new DBTransform(); response.setContentType("text/html"); trans.transformXMLDocument(output, "message", "-//W3C//HTML//EN", qformat, out, null, null); return output; } catch (Exception e) { logMetacat.error("MetacatHandler.handleInsertOrUpdateAction - " + "General error: " + e.getMessage()); e.printStackTrace(System.out); } } return output; } /** * Parse XML Document to look for in * order to decide whether to use validation parser */ private static boolean needDTDValidation(StringReader xmlreader) throws IOException { Logger logMetacat = Logger.getLogger(MetacatHandler.class); StringBuffer cbuff = new StringBuffer(); java.util.Stack st = new java.util.Stack(); boolean validate = false; boolean commented = false; int c; int inx; // read from the stream until find the keywords while ((st.empty() || st.size() < 4) && ((c = xmlreader.read()) != -1)) { cbuff.append((char) c); if ((inx = cbuff.toString().indexOf("