funkman 2003/06/16 18:31:12 Modified: catalina/src/conf web.xml catalina/src/share/org/apache/catalina/servlets DefaultServlet.java Log: - Allow a site (webapp) wide xslt transformation for look (real file name) - Allow per directory xslt transformation for customized look - Allow a readme file to be rendered with the directory listing - fix typo in row color when trying to gray bar lines Any suggestions on not making globalXsltFile a real file but still cross webapp app friendly? Revision Changes Path 1.19 +17 -0 jakarta-tomcat-catalina/catalina/src/conf/web.xml Index: web.xml =================================================================== RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/conf/web.xml,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- web.xml 15 Jun 2003 13:12:44 -0000 1.18 +++ web.xml 17 Jun 2003 01:31:11 -0000 1.19 @@ -39,6 +39,23 @@ <!-- readonly Is this context "read only", so HTTP --> <!-- commands like PUT and DELETE are --> <!-- rejected? [true] --> + <!-- --> + <!-- readmeFile File name to display with the directory --> + <!-- contents. [null] --> + <!-- --> + <!-- For directory listing customization. Checks localXsltFile, then --> + <!-- globalXsltFile, then defaults to original behavior. --> + <!-- --> + <!-- localXsltFile Make directory listings an XML doc and --> + <!-- pass the result to this style sheet residing --> + <!-- in that directory. This overrides --> + <!-- globalXsltFile[null] --> + <!-- --> + <!-- globalXsltFile Site wide configuration version of --> + <!-- localXsltFile This argument is expected --> + <!-- to be a physical file. [null] --> + <!-- --> + <!-- --> <servlet> <servlet-name>default</servlet-name> 1.12 +248 -31 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java Index: DefaultServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- DefaultServlet.java 15 Jun 2003 08:17:37 -0000 1.11 +++ DefaultServlet.java 17 Jun 2003 01:31:12 -0000 1.12 @@ -1,4 +1,5 @@ /* + * ==================================================================== * $Header$ * $Revision$ * $Date$ @@ -76,6 +77,8 @@ import java.io.RandomAccessFile; import java.io.Reader; import java.io.InputStreamReader; +import java.io.StringReader; +import java.io.StringWriter; import java.io.Writer; import java.io.OutputStreamWriter; import java.net.MalformedURLException; @@ -110,6 +113,12 @@ import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.Transformer; + import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.naming.resources.Resource; @@ -193,6 +202,25 @@ protected static URLEncoder urlEncoder; + /** + * Allow customized directory listing per directory. + */ + protected String localXsltFile = null; + + + /** + * Allow customized directory listing per instance. + */ + protected String globalXsltFile = null; + + + /** + * Allow a readme file to be included. + */ + protected String readmeFile = null; + + + // ----------------------------------------------------- Static Initializer @@ -283,6 +311,11 @@ ; } + globalXsltFile = getServletConfig().getInitParameter("globalXsltFile"); + localXsltFile = getServletConfig().getInitParameter("localXsltFile"); + readmeFile = getServletConfig().getInitParameter("readmeFile"); + + // Sanity check on the specified buffer sizes if (input < 256) input = 256; @@ -623,12 +656,12 @@ /** - * Handle a partial PUT. New content specified in request is appended to - * existing content in oldRevisionContent (if present). This code does + * Handle a partial PUT. New content specified in request is appended to + * existing content in oldRevisionContent (if present). This code does * not support simultaneous partial updates to the same resource. */ - protected File executePartialPut(HttpServletRequest req, Range range, - String path) + protected File executePartialPut(HttpServletRequest req, Range range, + String path) throws IOException { // Append data specified in ranges to existing content for this @@ -644,7 +677,7 @@ contentFile.deleteOnExit(); } - RandomAccessFile randAccessContentFile = + RandomAccessFile randAccessContentFile = new RandomAccessFile(contentFile, "rw"); Resource oldResource = null; @@ -657,8 +690,8 @@ // Copy data in oldRevisionContent to contentFile if (oldResource != null) { - BufferedInputStream bufOldRevStream = - new BufferedInputStream(oldResource.streamContent(), + BufferedInputStream bufOldRevStream = + new BufferedInputStream(oldResource.streamContent(), BUFFER_SIZE); int numBytesRead; @@ -759,9 +792,9 @@ ResourceInfo resourceInfo) throws IOException { - return checkIfMatch(request, response, resourceInfo) - && checkIfModifiedSince(request, response, resourceInfo) - && checkIfNoneMatch(request, response, resourceInfo) + return checkIfMatch(request, response, resourceInfo) + && checkIfModifiedSince(request, response, resourceInfo) + && checkIfNoneMatch(request, response, resourceInfo) && checkIfUnmodifiedSince(request, response, resourceInfo); } @@ -780,7 +813,7 @@ } else if (resourceInfo.weakETag != null) { return resourceInfo.weakETag; } else { - return "W/\"" + resourceInfo.length + "-" + return "W/\"" + resourceInfo.length + "-" + resourceInfo.date + "\""; } } @@ -908,7 +941,7 @@ ResourceInfo resourceInfo = new ResourceInfo(path, resources); if (!resourceInfo.exists) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, + response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI()); return; } @@ -917,7 +950,7 @@ // ends with "/" or "\", return NOT FOUND if (!resourceInfo.collection) { if (path.endsWith("/") || (path.endsWith("\\"))) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, + response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI()); return; } @@ -957,7 +990,7 @@ // Checking If headers boolean included = (request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null); - if (!included + if (!included && !checkIfHeaders(request, response, resourceInfo)) { return; } @@ -1170,7 +1203,7 @@ try { range.start = Long.parseLong(rangeHeader.substring(0, dashPos)); - range.end = + range.end = Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos)); range.length = Long.parseLong (rangeHeader.substring(slashPos + 1, rangeHeader.length())); @@ -1284,7 +1317,7 @@ currentRange.start = fileLength + offset; currentRange.end = fileLength - 1; } catch (NumberFormatException e) { - response.addHeader("Content-Range", + response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse @@ -1304,7 +1337,7 @@ else currentRange.end = fileLength - 1; } catch (NumberFormatException e) { - response.addHeader("Content-Range", + response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse @@ -1347,13 +1380,177 @@ /** + * Decide which way to render. HTML or XML. + */ + protected InputStream render + (String contextPath, ResourceInfo resourceInfo) { + InputStream xsltInputStream = null; + try { + if (localXsltFile!=null) { + DirContext resources = getResources(); + String xsltFile = resourceInfo.path + localXsltFile; + ResourceInfo xsltInfo = new ResourceInfo(xsltFile, resources); + + if (xsltInfo.exists) + xsltInputStream = xsltInfo.getStream(); + } + + if (xsltInputStream==null && globalXsltFile!=null) + xsltInputStream = new FileInputStream(globalXsltFile); + + } catch(Throwable e) { + xsltInputStream = null; + } + + + if (xsltInputStream==null) { + return renderHtml(contextPath, resourceInfo); + } else { + try { + return renderXml(contextPath, resourceInfo, xsltInputStream); + } finally { + try { + xsltInputStream.close(); + } catch(Throwable e){ + ; + } + } + } + + } + + /** * Return an InputStream to an HTML representation of the contents * of this directory. * * @param contextPath Context path to which our internal paths are * relative */ - protected InputStream render + protected InputStream renderXml(String contextPath, + ResourceInfo resourceInfo, + InputStream xsltInputStream) { + + StringBuffer sb = new StringBuffer(); + + + + sb.append("<?xml version=\"1.0\"?>"); + sb.append("<listing "); + sb.append(" contextPath='"); + sb.append(contextPath); + sb.append("'"); + sb.append(" directory='"); + sb.append(resourceInfo.path); + sb.append("' "); + sb.append(" hasParent='").append(!resourceInfo.path.equals("/")); + sb.append("'>"); + + sb.append("<entries>"); + + + try { + + // Render the directory entries within this directory + DirContext directory = resourceInfo.directory; + NamingEnumeration enum = + resourceInfo.resources.list(resourceInfo.path); + while (enum.hasMoreElements()) { + + NameClassPair ncPair = (NameClassPair) enum.nextElement(); + String resourceName = ncPair.getName(); + ResourceInfo childResourceInfo = + new ResourceInfo(resourceName, directory); + + String trimmed = resourceName/*.substring(trim)*/; + if (trimmed.equalsIgnoreCase("WEB-INF") || + trimmed.equalsIgnoreCase("META-INF") || + trimmed.equalsIgnoreCase(localXsltFile)) + continue; + + + sb.append("<entry"); + sb.append(" type='") + .append(childResourceInfo.collection?"dir":"file") + .append("'"); + sb.append(" urlPath='") + .append(rewriteUrl(contextPath)) + .append(rewriteUrl(resourceInfo.path + resourceName)) + .append(childResourceInfo.collection?"/":"") + .append("'"); + if (!childResourceInfo.collection) { + sb.append(" size='") + .append(renderSize(childResourceInfo.length)) + .append("'"); + } + sb.append(" date='") + .append(childResourceInfo.httpDate) + .append("'"); + + sb.append(">"); + sb.append(trimmed); + if (childResourceInfo.collection) + sb.append("/"); + sb.append("</entry>"); + + } + + } catch (NamingException e) { + // Something went wrong + e.printStackTrace(); + } + + sb.append("</entries>"); + + if (readmeFile!=null) { + DirContext resources = getResources(); + String readme = resourceInfo.path + readmeFile; + ResourceInfo readmeInfo = new ResourceInfo(readme, + resources); + if (readmeInfo.exists()) { + try { + StringWriter buffer = new StringWriter(); + copyRange(new InputStreamReader(readmeInfo.getStream()), + new PrintWriter(buffer)); + + sb.append("<readme><![CDATA["); + sb.append(buffer.toString()); + sb.append("]]></readme>"); + } catch(IOException e) { + ; /* Change me if this should be verbose */ + } + } + } + + + sb.append("</listing>"); + + + try { + TransformerFactory tFactory = TransformerFactory.newInstance(); + Source xmlSource = new StreamSource(new StringReader(sb.toString())); + Source xslSource = new StreamSource(xsltInputStream); + Transformer transformer = tFactory.newTransformer(xslSource); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); + StreamResult out = new StreamResult(osWriter); + transformer.transform(xmlSource, out); + osWriter.flush(); + return (new ByteArrayInputStream(stream.toByteArray())); + } catch (Exception e) { + e.printStackTrace(); + return renderHtml(contextPath, resourceInfo); + } + } + + /** + * Return an InputStream to an HTML representation of the contents + * of this directory. + * + * @param contextPath Context path to which our internal paths are + * relative + */ + protected InputStream renderHtml (String contextPath, ResourceInfo resourceInfo) { String name = resourceInfo.path; @@ -1460,7 +1657,7 @@ sb.append("<tr"); if (shade) - sb.append(" bgcolor=\"eeeeee\""); + sb.append(" bgcolor=\"#eeeeee\""); sb.append(">\r\n"); shade = !shade; @@ -1500,6 +1697,26 @@ sb.append("</table>\r\n"); sb.append("<HR size=\"1\" noshade>"); + + if (readmeFile!=null) { + DirContext resources = getResources(); + String readme = resourceInfo.path + readmeFile; + ResourceInfo readmeInfo = new ResourceInfo(readme, + resources); + if (readmeInfo.exists()) { + try { + StringWriter buffer = new StringWriter(); + copyRange(new InputStreamReader(readmeInfo.getStream()), + new PrintWriter(buffer)); + + sb.append(buffer.toString()); + sb.append("<HR size=\"1\" noshade>"); + } catch(IOException e) { + ; /* Change me if this should be verbose */ + } + } + } + sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>"); sb.append("</body>\r\n"); sb.append("</html>\r\n"); @@ -1539,7 +1756,7 @@ * @param response The servlet response we are creating * @param resourceInfo File object * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request + * and false if the condition is not satisfied, in which case request * processing is stopped */ private boolean checkIfMatch(HttpServletRequest request, @@ -1584,7 +1801,7 @@ * @param response The servlet response we are creating * @param resourceInfo File object * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request + * and false if the condition is not satisfied, in which case request * processing is stopped */ private boolean checkIfModifiedSince(HttpServletRequest request, @@ -1595,10 +1812,10 @@ long headerValue = request.getDateHeader("If-Modified-Since"); long lastModified = resourceInfo.date; if (headerValue != -1) { - + // If an If-None-Match header has been specified, if modified since // is ignored. - if ((request.getHeader("If-None-Match") == null) + if ((request.getHeader("If-None-Match") == null) && (lastModified <= headerValue + 1000)) { // The entity has not been modified since the date // specified by the client. This is not an error case. @@ -1621,7 +1838,7 @@ * @param response The servlet response we are creating * @param resourceInfo File object * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request + * and false if the condition is not satisfied, in which case request * processing is stopped */ private boolean checkIfNoneMatch(HttpServletRequest request, @@ -1637,7 +1854,7 @@ if (!headerValue.equals("*")) { - StringTokenizer commaTokenizer = + StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ","); while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { @@ -1679,7 +1896,7 @@ * @param response The servlet response we are creating * @param resourceInfo File object * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request + * and false if the condition is not satisfied, in which case request * processing is stopped */ private boolean checkIfUnmodifiedSince(HttpServletRequest request, @@ -2283,7 +2500,7 @@ tempDate = tempAttrs.getLastModifiedDate(); if (tempDate != null) { date = tempDate.getTime(); - httpDate = + httpDate = FastHttpDateFormat.formatDate(date, null); } else { httpDate = FastHttpDateFormat.getCurrentDate();
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]