///////////////////////////////////////////////////////////////////////////// // Copyright (c) 1999, COAS, Oregon State University // ALL RIGHTS RESERVED. U.S. Government Sponsorship acknowledged. // // Please read the full copyright notice in the file COPYRIGHT // in this directory. // // Author: Nathan Potter (ndp@oce.orst.edu) // // College of Oceanic and Atmospheric Scieneces // Oregon State University // 104 Ocean. Admin. Bldg. // Corvallis, OR 97331-5503 // ///////////////////////////////////////////////////////////////////////////// /* $Id: dodsINFO.java,v 1.3 2004-02-06 15:23:50 donm Exp $ * */ package dods.servlet; import java.io.*; import java.text.*; import java.util.*; import java.util.zip.DeflaterOutputStream; import javax.servlet.*; import javax.servlet.http.*; import dods.dap.*; import dods.util.*; import dods.dap.Server.*; import dods.dap.parser.ParseException; /** * Default handler for DODS info requests. This class is used * by DODSServlet. This code exists as a seperate class in order to alleviate * code bloat in the DODSServlet class. As such, it contains virtually no * state, just behaviors. * * @author Nathan David Potter */ public class dodsINFO { private static final boolean _Debug = true; private String infoDir = null; /*************************************************************************** * Default handler for DODS info requests. Returns an html document * describing the contents of the servers datasets. * * The "info_cache_dir" directory specified in the [Server] section * of the DODSiniFile is the designated location for: * <ul> * <li>".info" response override files.</li> * <li>Server specific HTML* files.</li> * <li>Dataset specific HTML* files .</li> * </ul> * * The server specific HTML* files must be named #servlet#.html * where #servlet# is the name of the servlet that is running as * the DODS server in question. This name is determined at run time * by using the class called Class ( this.getClass().getName() ). * * <p>In the C++ code the analogy is the per-cgi file names.</p> * * <p> * The dataset specific HTML* files are located by catenating `.html' * to #name#, where #name# is the name of the dataset. If the filename part * of #name# is of the form [A-Za-z]+[0-9]*.* then this function also looks * for a file whose name is [A-Za-z].html For example, if #name# is * .../data/fnoc1.nc this function first looks for .../data/fnoc1.nc.html. * However, if that does not exist it will look for .../data/fnoc.html. This * allows one `per-dataset' file to be used for a collection of files with * the same root name. * </p> * * NB: An HTML* file contains HTML without the <html>, <head> or <body> tags * (my own notation). * * @memo Look for the user supplied Server- and dataset-specific HTML* documents. * * @param pw The PrintStream to which the output should be written. * @param dataSet The name of the dataset. Used to locate dataset * specific information files in the info directory. * @param dServ The DODSServlet object containing the correct getDDS(), getDAS), * and getServerName() methods for the dataSet. */ public void sendINFO(PrintStream pw, GuardedDataset gds, requestState rs) throws DODSException, ParseException { if(_Debug) System.out.println("dods.servlet.dodsINFO.sendINFO() reached."); String responseDoc = null; ServerDDS myDDS = null; DAS myDAS = null; myDDS = (ServerDDS) gds.getDDS(); myDAS = gds.getDAS(); infoDir = rs.getInitParameter("INFOcache"); if(infoDir == null) infoDir = rs.defaultINFOcache; responseDoc = loadOverrideDoc(infoDir, rs.getDataSet()); if( responseDoc != null ){ if(_Debug) System.out.println("override document: " + responseDoc); pw.print(responseDoc); } else { String user_html = get_user_supplied_docs(rs.getServerName(), rs.getDataSet()); String global_attrs = buildGlobalAttributes(myDAS, myDDS); String variable_sum = buildVariableSummaries(myDAS, myDDS); // Send the document back to the client. pw.println("<html><head><title>Dataset Information</title>"); pw.println("<style type=\"text/css\">"); pw.println("<!-- ul {list-style-type: none;} -->"); pw.println("</style>"); pw.println("</head>"); pw.println("<body>"); if (global_attrs.length()>0) { pw.println(global_attrs); pw.println("<hr>"); } pw.println(variable_sum); pw.println("<hr>"); pw.println(user_html); pw.println("</body></html>"); // Flush the output buffer. pw.flush(); } } /***************************************************************************/ /*************************************************************************** * Checks the info directory for user supplied override documents for the * passed dataset name. If there are overridedocuments present then the * contents are read and returned to the caller as a string. * * * @param dataSet The name of the dataset. * */ public String loadOverrideDoc(String infoDir, String dataSet) throws DODSException{ String userDoc = ""; String overrideFile = dataSet + ".ovr"; //Try to open and read the override file for this dataset. try { File fin = new File(infoDir + overrideFile); BufferedReader svIn = new BufferedReader(new InputStreamReader(new FileInputStream(fin))); boolean done = false; while(!done) { String line = svIn.readLine(); if(line == null){ done = true; } else { userDoc += line + "\n"; } } svIn.close(); } catch (FileNotFoundException fnfe) { userDoc += "<h2>No Could Not Open Override Document.</h2><hr>"; return(null); } catch (IOException ioe) { throw( new DODSException(DODSException.UNKNOWN_ERROR,ioe.getMessage())); } return(userDoc); } /***************************************************************************/ //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /** */ private String get_user_supplied_docs(String serverName, String dataSet) throws DODSException { String userDoc = ""; //Try to open and read the Dataset specific information file. try { File fin = new File(infoDir + dataSet + ".html"); BufferedReader svIn = new BufferedReader(new InputStreamReader(new FileInputStream(fin))); boolean done = false; while(!done) { String line = svIn.readLine(); if(line == null){ done = true; } else { userDoc += line + "\n"; } } svIn.close(); } catch (FileNotFoundException fnfe) { userDoc += "<h2>No Dataset Specific Information Available.</h2><hr>"; } catch (IOException ioe) { throw( new DODSException(DODSException.UNKNOWN_ERROR,ioe.getMessage())); } userDoc += "<hr>\n"; //Try to open and read the server specific information file. try { String serverFile = infoDir + serverName + ".html"; if(_Debug) System.out.println("Server Info File: "+serverFile); File fin = new File(serverFile); BufferedReader svIn = new BufferedReader(new InputStreamReader(new FileInputStream(fin))); boolean done = false; while(!done) { String line = svIn.readLine(); if(line == null){ done = true; } else { userDoc += line + "\n"; } } svIn.close(); } catch (FileNotFoundException fnfe) { userDoc += "<h2>No Server Specific Information Available.</h2><hr>"; } catch (IOException ioe) { throw( new DODSException(DODSException.UNKNOWN_ERROR,ioe.getMessage())); } return(userDoc); } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private String buildGlobalAttributes(DAS das, ServerDDS dds){ boolean found = false; String ga; ga = "<h3>Dataset Information</h3>\n<table>\n"; Enumeration edas = das.getNames(); while(edas.hasMoreElements()){ String name = (String)edas.nextElement(); if(!dasTools.nameInKillFile(name) && (dasTools.nameIsGlobal(name) || !dasTools.nameInDDS(name, dds)) ){ AttributeTable attr = das.getAttributeTable(name); if(attr != null){ Enumeration e = attr.getNames(); while(e.hasMoreElements()){ String aName = (String)e.nextElement(); Attribute a = attr.getAttribute(aName); found = true; ga += "\n<tr><td align=right valign=top><b>"; ga += aName + "</b>:</td>\n"; ga += "<td align=left>"; Enumeration es = a.getValues(); while(es.hasMoreElements()){ String val = (String)es.nextElement(); ga += val + "<br>"; } ga += "</td></tr>\n"; } } } } ga += "</table>\n<p>\n"; if(!found) ga = ""; return(ga); } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private String buildVariableSummaries(DAS das, ServerDDS dds){ String vs = "<h3>Variables in this Dataset</h3>\n<table>\n"; Enumeration e = dds.getVariables(); while( e.hasMoreElements() ) { BaseType bt = (BaseType)e.nextElement(); vs += "<tr>"; vs += summarizeVariable(bt, das); vs += "</tr>"; } vs += "</table>\n<p>\n";; return(vs); } private String summarizeAttributes(AttributeTable attr, String vOut ){ if(attr != null){ Enumeration e = attr.getNames(); while(e.hasMoreElements()){ String name = (String)e.nextElement(); Attribute a = attr.getAttribute(name); if(a.isContainer()){ vOut += "<li> <b> "+name + ": </b> </li>\n"; vOut += "<ul>\n"; vOut += summarizeAttributes(a.getContainer(),""); vOut += "</ul>\n"; } else { vOut += "<li> <b> " + name + ": </b> "; Enumeration es = a.getValues(); while(es.hasMoreElements()){ String val = (String)es.nextElement(); vOut += val; if(es.hasMoreElements()) vOut += ", "; } vOut += " </li>\n"; } } } return(vOut); } private String summarizeVariable(BaseType bt, DAS das){ String vOut; vOut = "<td align=right valign=top><b>" + bt.getName(); vOut += "</b>:</td>\n"; vOut += "<td align=left valign=top>" + dasTools.fancyTypeName(bt); AttributeTable attr = das.getAttributeTable(bt.getName()); // This will display the DAS variables (attributes) as a bulleted list. String s =""; vOut += "\n<ul>\n"; vOut += summarizeAttributes(attr, s); vOut += "\n</ul>\n"; if(bt instanceof DConstructor){ vOut += "<table>\n"; DConstructor dc = (DConstructor)bt; Enumeration e = dc.getVariables(); while(e.hasMoreElements()){ BaseType bt2 = (BaseType)e.nextElement(); vOut += "<tr>\n"; vOut += summarizeVariable(bt2,das); vOut += "</tr>\n"; } vOut += "</table>\n"; } else if(bt instanceof DVector){ DVector da = (DVector)bt; PrimitiveVector pv = da.getPrimitiveVector(); if(pv instanceof BaseTypePrimitiveVector){ BaseType bt2 = pv.getTemplate(); if(bt2 instanceof DArray || bt2 instanceof DString){ } else { vOut += "<table>\n"; vOut += "<tr>\n"; vOut += summarizeVariable(bt2,das); vOut += "</tr>\n"; vOut += "</table>\n"; } } } else{ /* In the C++ code the types are all checked here, and if an unknown type is recieved then an exception is thrown. I think it's not needed... James? ndp default: assert("Unknown type" && false); } */ vOut += "</td>\n"; } return(vOut); } /***************************************************************************/ }