jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/ 0000775 0001750 0001750 00000000000 12107707214 020260 5 ustar andrew andrew jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/.gitignore 0000664 0001750 0001750 00000000013 11710312010 022223 0 ustar andrew andrew classes
lib jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/.project 0000664 0001750 0001750 00000000563 11710312010 021714 0 ustar andrew andrew
jnlp-servletorg.eclipse.jdt.core.javabuilderorg.eclipse.jdt.core.javanature
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/.classpath 0000664 0001750 0001750 00000000452 11710312010 022225 0 ustar andrew andrew
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/example-web.xml 0000664 0001750 0001750 00000002303 11710312010 023167 0 ustar andrew andrew JnlpDownloadServletjnlp.sample.servlet.JnlpDownloadServletJnlpDownloadServlet*.jnlpJnlpDownloadServlet*.jarjarDiffDisabledtrueWhether jar differencing is disabled or notpackOnTheFlytrueWhether the servlet should attempt to create and save a pack200-gzip file on-the-flypackCommandpack200 -E7 --segment-limit=-1The command and options that should be used for pack200. If using signed jars, the settings need to be identical to the ones used to pack/unpack (normalize) the jar before signing!
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/README 0000664 0001750 0001750 00000006275 11710312010 021133 0 ustar andrew andrew JNLPDownloadServlet
-------------------
Brief Description :
JNLPDownloadServlet can be used to package a JNLP file and its associated
resources in a Web Archive (.war) file. The purpose of the servlet is to
provide a simple and convenient packaging format for JNLP applications, so they
can be easily deployed in a Web Container, such as Tomcat or a J2EE-compliant
Application Server.
The download servlet supports the following features:
* Automatic installation of the codebase URL into JNLP files, thus
eliminating manual management of hard-coded URLs into JNLP files.
* Explicit specification of the timestamp for a JNLP file, independent of
the file-system timestamp.
* Support for download protocols defined in the JNLP specification v1.0.1.
These include basic download protocol, version-based download protocol,
and extension download protocol.
* Version-based information specified per file or per directory in the
Web archive. Thus, no centralized file needs to be managed for the entire
archive.
* Automatic generation of JARDiff files.
* pack200-gzip and gzip compression support. You can now host *.jar.pack.gz
or *.jar.gz files together with you original *.jar files. If the client
supports the pack200-gzip or gzip file formats, the servlet will return
the compressed file if it is available on the server. Java Web Start 1.5
supports both compression formats.
The packaging support consists of one servlet: JnlpDownloadServlet. The servlet
is packaged into the jnlp-servlet.jar file, which can be found in the SDK under
samples/jnlp/servlet/.
Files :
GNUmakefile - the makefile to build the servlet
jnlp-servlet.jar - the JNLPDownloadServlet binary
jardiff.jar - the JarDiff binary
jnlp.jar - the JNLP API binary
src - the directory containing the JNLPDownloadServlet
source code
Building and Deployment of Servlet :
To build jnlp-servlet.jar and jardiff.jar, run gnumake in the current directory
(servlet).
The following environment variables must be set:
# Environment variable CLASS_PATH should contain the path to javaws.jar (under
# the jre/lib directory) and servlet.jar (You can download the latter from
# http://java.sun.com/products/servlet/, or you can find it in the lib
# directory of any servlet container implementing the Java Servlet 2.2
# specification or above; e.g, Tomcat.)
#
# Environment variable FILE_SEPARATOR should be set: ";" on win32 and ":" on
# unix).
#
# Environment variable TMPDIR should point to the tmp directory
#
# Environment variable SDK_HOME should point to the SDK directory
If you are running on the windows platform, it is assumed you have the MKS
Toolkit installed and it is in your path environment variable. (Commands such
as cp, echo, mkdir, and rm are required.)
The generated classes will go to the classes directory, and the resulting jar
files will be in the lib directory by default. You can adjust the output
directory to anything you want by changing the GNUmakefile.
Please refer to the JNLPDownloadServlet guide for more information on the
JNLPDownloadServlet:
http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/downloadservletguide.html
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/GNUmakefile 0000664 0001750 0001750 00000005416 11710312010 022321 0 ustar andrew andrew
# environment variable FILE_SEPARATOR variable for file separator (; on win32 and : on unix)
FILE_SEPARATOR = :
# environment variable CLASS_PATH should contain path to javaws.jar and servlet.jar
CLASS_PATH = $(JAVA_HOME)/lib/javaws.jar$(FILE_SEPARATOR)deplib/servlet-api.jar
# environment variable TMPDIR should point to tmp directory
# environment variable SDK_HOME should point to SDK directory
SDK_HOME = $(JAVA_HOME)
JAVAC = $(SDK_HOME)/bin/javac -source 1.5 -target 1.5
JAR = $(SDK_HOME)/bin/jar
CLASSDESTDIR = classes
MKDIR = mkdir -p
RMDIR = rm -rf
SRCDIR = src/classes
COPY = cp -fr
OUTPUT_DIR = lib
CD = cd
ECHO = echo
FILES_servlet_java = \
jnlp/sample/servlet/JnlpDownloadServlet.java \
jnlp/sample/servlet/JnlpFileHandler.java \
jnlp/sample/servlet/DownloadRequest.java \
jnlp/sample/servlet/DownloadResponse.java \
jnlp/sample/servlet/ErrorResponseException.java \
jnlp/sample/servlet/JnlpResource.java \
jnlp/sample/servlet/ResourceCatalog.java \
jnlp/sample/servlet/JarDiffHandler.java \
jnlp/sample/servlet/XMLParsing.java \
jnlp/sample/servlet/XMLNode.java \
jnlp/sample/servlet/XMLAttribute.java \
jnlp/sample/servlet/Logger.java \
jnlp/sample/util/VersionID.java \
jnlp/sample/util/VersionString.java
FILES_servlet_class = $(FILES_servlet_java:%.java=$(CLASSDESTDIR)/%.class)
FILES_jardiff_java = \
jnlp/sample/jardiff/JarDiffConstants.java \
jnlp/sample/jardiff/JarDiff.java \
jnlp/sample/jardiff/Patcher.java \
jnlp/sample/jardiff/JarDiffPatcher.java
FILES_jardiff_class = $(FILES_jardiff_java:%.java=$(CLASSDESTDIR)/%.class)
$(CLASSDESTDIR)/%.class: $(SRCDIR)/%.java
$(JAVAC) -classpath "$(CLASS_PATH)$(FILE_SEPARATOR)$(SRCDIR)" -d $(CLASSDESTDIR) $?
all: prepare compile-jardiff jardiff-resource jardiff-jar compile-servlet servlet-resource servlet-jar
clean:
$(RMDIR) $(CLASSDESTDIR)
$(RMDIR) $(OUTPUT_DIR)
prepare: clean
$(MKDIR) $(CLASSDESTDIR)
$(MKDIR) $(OUTPUT_DIR)
compile-jardiff: $(FILES_jardiff_class)
compile-servlet: $(FILES_servlet_class)
jardiff-resource:
$(MKDIR) $(CLASSDESTDIR)/jnlp/sample/jardiff/resources/
$(COPY) $(SRCDIR)/jnlp/sample/jardiff/resources/strings.properties $(CLASSDESTDIR)/jnlp/sample/jardiff/resources/strings.properties
servlet-resource:
$(MKDIR) $(CLASSDESTDIR)/jnlp/sample/servlet/resources/
$(COPY) $(SRCDIR)/jnlp/sample/servlet/resources/strings.properties $(CLASSDESTDIR)/jnlp/sample/servlet/resources/strings.properties
jardiff-jar:
$(ECHO) 'Main-Class:' jnlp.sample.jardiff.JarDiff > $(TMPDIR)/jardiff.manifest
$(JAR) cvfm $(OUTPUT_DIR)/jardiff.jar $(TMPDIR)/jardiff.manifest -C $(CLASSDESTDIR) .
$(RM) $(TMPDIR)/jardiff.manifest
servlet-jar:
$(JAR) cvf $(OUTPUT_DIR)/jnlp-servlet.jar -C $(CLASSDESTDIR) .
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/ 0000775 0001750 0001750 00000000000 11710312010 021030 5 ustar andrew andrew jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/ 0000775 0001750 0001750 00000000000 11710312010 022465 5 ustar andrew andrew jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/ 0000775 0001750 0001750 00000000000 11710312010 023430 5 ustar andrew andrew jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/ 0000775 0001750 0001750 00000000000 11710312010 024711 5 ustar andrew andrew jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/ 0000775 0001750 0001750 00000000000 11710312010 026375 5 ustar andrew andrew jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/resources/ 0000775 0001750 0001750 00000000000 11710312010 030407 5 ustar andrew andrew ././@LongLink 0000000 0000000 0000000 00000000163 00000000000 011565 L ustar root root jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/resources/strings.properties jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/resources/stri0000664 0001750 0001750 00000006503 11710312010 031317 0 ustar andrew andrew #
# @(#)strings.properties 1.3 10/01/12
#
# Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# -Redistribution of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# -Redistribution in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of Sun Microsystems, Inc. or the names of contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# This software is provided "AS IS," without a warranty of any kind. ALL
# EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
# ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
# OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
# AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
# AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
# DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
# REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
# INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
# OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
#
# You acknowledge that this software is not designed, licensed or intended
# for use in the design, construction, operation or maintenance of any
# nuclear facility.
#
# Fatals
servlet.log.fatal.internalerror=Internal error:
# Warnings
servlet.log.warning.nolastmodified=Last-modified read as 0 for {0}
servlet.log.warning.notimestamp=Timestamp read as 0 for {0}. Using Last-modified instead
servlet.log.warning.missing-file=Reference to non-existing file ({0}) in {1}
servlet.log.warning.xml.parsing=Error parsing {0} at line {1}: {2}
servlet.log.warning.xml.reading=Unexpected error reading {0}:
servlet.log.warning.xml.missing-jnlp=Missing element in {0}
servlet.log.warning.xml.missing-pattern=Missing element in {0}
servlet.log.warning.xml.missing-elems=Missing or attribute in {0}
servlet.log.warning.xml.missing-elems2=Missing , , or attribute in {0}
servlet.log.warning.jardiff.failed=Failed to generate JarDiff for {0} {1}->{2}
# Informational
servlet.log.info.request=Request: {0}
servlet.log.info.useragent=User-Agent: {0}
servlet.log.info.goodrequest=Resource returned: {0}
servlet.log.info.badrequest=Error code returned for request: {0}
servlet.log.scandir=Rescanning directory: {0}
servlet.log.info.jardiff.response=JarDiff returned for request
servlet.log.info.jardiff.gen=Generating JarDiff for {0} {1}->{2}
# JNLP Error strings
servlet.jnlp.err.10 = Could not locate resource
servlet.jnlp.err.11 = Could not locate requested version
servlet.jnlp.err.20 = Unsupported operating system
servlet.jnlp.err.21 = Unsupported architecture
servlet.jnlp.err.22 = Unsupported locale
servlet.jnlp.err.23 = Unsupported JRE version
servlet.jnlp.err.99 = Unknown error
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/XMLNode.java 0000664 0001750 0001750 00000012512 11710312010 030507 0 ustar andrew andrew /*
* @(#)XMLNode.java 1.7 10/01/12
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package jnlp.sample.servlet;
import java.io.PrintWriter;
import java.io.StringWriter;
/** Class that contains information about an XML Node
*/
public class XMLNode {
private boolean _isElement; // Element/PCTEXT
private String _name;
private XMLAttribute _attr;
private XMLNode _parent; // Parent Node
private XMLNode _nested; // Nested XML tags
private XMLNode _next; // Following XML tag on the same level
/** Creates a PCTEXT node */
public XMLNode(String name) {
this(name, null, null, null);
_isElement = false;
}
/** Creates a ELEMENT node */
public XMLNode(String name, XMLAttribute attr) {
this(name, attr, null, null);
}
/** Creates a ELEMENT node */
public XMLNode(String name, XMLAttribute attr, XMLNode nested, XMLNode next) {
_isElement = true;
_name = name;
_attr = attr;
_nested = nested;
_next = next;
_parent = null;
}
public String getName() { return _name; }
public XMLAttribute getAttributes() { return _attr; }
public XMLNode getNested() { return _nested; }
public XMLNode getNext() { return _next; }
public boolean isElement() { return _isElement; }
public void setParent(XMLNode parent) { _parent = parent; }
public XMLNode getParent() { return _parent; }
public void setNext(XMLNode next) { _next = next; }
public void setNested(XMLNode nested) { _nested = nested; }
public boolean equals(Object o) {
if (o == null || !(o instanceof XMLNode)) return false;
XMLNode other = (XMLNode)o;
boolean result =
match(_name, other._name) &&
match(_attr, other._attr) &&
match(_nested, other._nested) &&
match(_next, other._next);
return result;
}
public String getAttribute(String name) {
XMLAttribute cur = _attr;
while(cur != null) {
if (name.equals(cur.getName())) return cur.getValue();
cur = cur.getNext();
}
return "";
}
private static boolean match(Object o1, Object o2) {
if (o1 == null) return (o2 == null);
return o1.equals(o2);
}
public void printToStream(PrintWriter out) {
printToStream(out, 0);
}
public void printToStream(PrintWriter out, int n) {
if (!isElement()) {
out.print(_name);
} else {
if (_nested == null) {
String attrString = (_attr == null) ? "" : (" " + _attr.toString());
lineln(out, n, "<" + _name + attrString + "/>");
} else {
String attrString = (_attr == null) ? "" : (" " + _attr.toString());
lineln(out, n, "<" + _name + attrString + ">");
_nested.printToStream(out, n + 1);
if (_nested.isElement()) {
lineln(out, n, "" + _name + ">");
} else {
out.print("" + _name + ">");
}
}
}
if (_next != null) {
_next.printToStream(out, n);
}
}
private static void lineln(PrintWriter out, int indent, String s) {
out.println("");
for(int i = 0; i < indent; i++) {
out.print(" ");
}
out.print(s);
}
public String toString() {
StringWriter sw = new StringWriter(1000);
PrintWriter pw = new PrintWriter(sw);
printToStream(pw);
pw.close();
return sw.toString();
}
}
././@LongLink 0000000 0000000 0000000 00000000157 00000000000 011570 L ustar root root jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/JnlpDownloadServlet.java jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/JnlpDownloadSe0000664 0001750 0001750 00000026554 11710312010 031217 0 ustar andrew andrew /*
* @(#)JnlpDownloadServlet.java 1.11 10/01/12
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package jnlp.sample.servlet;
import java.io.IOException;
import java.util.ResourceBundle;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* This Servlet class is an implementation of JNLP Specification's Download
* Protocols.
*
* All requests to this servlet is in the form of HTTP GET commands. The
* parameters that are needed are:
*
*
arch,
*
os,
*
locale,
*
version-id or platform-version-id,
*
current-version-id,
*
known-platforms
*
*
*
* @version 1.8 01/23/03
*/
public class JnlpDownloadServlet extends HttpServlet {
// Localization
private static ResourceBundle _resourceBundle = null;
// Servlet configuration
private static final String PARAM_JNLP_EXTENSION = "jnlp-extension";
private static final String PARAM_JAR_EXTENSION = "jar-extension";
// Servlet configuration
private Logger _log = null;
private JnlpFileHandler _jnlpFileHandler = null;
private JarDiffHandler _jarDiffHandler = null;
private ResourceCatalog _resourceCatalog = null;
/** Initialize servlet */
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// Setup logging
_log = new Logger(config, getResourceBundle());
_log.addDebug("Initializing");
// Get extension from Servlet configuration, or use default
JnlpResource.setDefaultExtensions(config.getInitParameter(PARAM_JNLP_EXTENSION), config
.getInitParameter(PARAM_JAR_EXTENSION));
_jnlpFileHandler = new JnlpFileHandler(config.getServletContext(), _log);
_jarDiffHandler = new JarDiffHandler(config.getServletContext(), _log);
_resourceCatalog = new ResourceCatalog(config.getServletContext(), _log);
}
public static synchronized ResourceBundle getResourceBundle() {
if (_resourceBundle == null) {
_resourceBundle = ResourceBundle.getBundle("jnlp/sample/servlet/resources/strings");
}
return _resourceBundle;
}
@Override
public void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
handleRequest(request, response, true);
}
/**
* We handle get requests too - eventhough the spec. only requeres POST
* requests
*/
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
handleRequest(request, response, false);
}
private void handleRequest(HttpServletRequest request, HttpServletResponse response, boolean isHead)
throws IOException {
String requestStr = request.getRequestURI();
if (request.getQueryString() != null)
requestStr += "?" + request.getQueryString().trim();
// Parse HTTP request
DownloadRequest dreq = new DownloadRequest(getServletContext(), request);
if (_log.isInformationalLevel()) {
_log.addInformational("servlet.log.info.request", requestStr);
_log.addInformational("servlet.log.info.useragent", request.getHeader("User-Agent"));
}
if (_log.isDebugLevel()) {
_log.addDebug(dreq.toString());
}
long ifModifiedSince = request.getDateHeader("If-Modified-Since");
// Check if it is a valid request
try {
// Check if the request is valid
validateRequest(dreq);
// Decide what resource to return
JnlpResource jnlpres = locateResource(dreq);
_log.addDebug("JnlpResource: " + jnlpres);
if (_log.isInformationalLevel()) {
_log.addInformational("servlet.log.info.goodrequest", jnlpres.getPath());
}
DownloadResponse dres = null;
if (isHead) {
int cl = jnlpres.getResource().openConnection().getContentLength();
// head request response
dres = DownloadResponse.getHeadRequestResponse(jnlpres.getMimeType(), jnlpres.getVersionId(), jnlpres
.getLastModified(), cl);
} else
if (ifModifiedSince != -1 && (ifModifiedSince / 1000) >= (jnlpres.getLastModified() / 1000)) {
// We divide the value returned by getLastModified here by
// 1000
// because if protocol is HTTP, last 3 digits will always be
// zero. However, if protocol is JNDI, that's not the case.
// so we divide the value by 1000 to remove the last 3
// digits
// before comparison
// return 304 not modified if possible
_log.addDebug("return 304 Not modified");
dres = DownloadResponse.getNotModifiedResponse();
} else {
// Return selected resource
dres = constructResponse(jnlpres, dreq);
}
dres.sendRespond(response);
} catch (ErrorResponseException ere) {
if (_log.isInformationalLevel()) {
_log.addInformational("servlet.log.info.badrequest", requestStr);
}
if (_log.isDebugLevel()) {
_log.addDebug("Response: " + ere.toString());
}
// Return response from exception
ere.getDownloadResponse().sendRespond(response);
} catch (Throwable e) {
_log.addFatal("servlet.log.fatal.internalerror", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
/**
* Make sure that it is a valid request. This is also the place to implement
* the reverse IP lookup
*/
private void validateRequest(DownloadRequest dreq) throws ErrorResponseException {
String path = dreq.getPath();
if (path.endsWith(ResourceCatalog.VERSION_XML_FILENAME) || path.indexOf("__") != -1) { throw new ErrorResponseException(
DownloadResponse.getNoContentResponse()); }
}
/**
* Interprets the download request and convert it into a resource that is
* part of the Web Archive.
*/
private JnlpResource locateResource(DownloadRequest dreq) throws IOException, ErrorResponseException {
if (dreq.getVersion() == null) {
return handleBasicDownload(dreq);
} else {
return handleVersionRequest(dreq);
}
}
private JnlpResource handleBasicDownload(DownloadRequest dreq) throws ErrorResponseException, IOException {
_log.addDebug("Basic Protocol lookup");
// Do not return directory names for basic protocol
if (dreq.getPath() == null || dreq.getPath().endsWith("/")) { throw new ErrorResponseException(DownloadResponse
.getNoContentResponse()); }
// Lookup resource
JnlpResource jnlpres = new JnlpResource(getServletContext(), dreq.getPath());
if (!jnlpres.exists()) { throw new ErrorResponseException(DownloadResponse.getNoContentResponse()); }
return jnlpres;
}
private JnlpResource handleVersionRequest(DownloadRequest dreq) throws IOException, ErrorResponseException {
_log.addDebug("Version-based/Extension based lookup");
return _resourceCatalog.lookupResource(dreq);
}
/**
* Given a DownloadPath and a DownloadRequest, it constructs the data stream
* to return to the requester
*/
private DownloadResponse constructResponse(JnlpResource jnlpres, DownloadRequest dreq) throws IOException {
String path = jnlpres.getPath();
if (jnlpres.isJnlpFile()) {
// It is a JNLP file. It need to be macro-expanded, so it is handled
// differently
boolean supportQuery = JarDiffHandler.isJavawsVersion(dreq, "1.5+");
_log.addDebug("SupportQuery in Href: " + supportQuery);
// only support query string in href for 1.5 and above
if (supportQuery) {
return _jnlpFileHandler.getJnlpFileEx(jnlpres, dreq);
} else {
return _jnlpFileHandler.getJnlpFile(jnlpres, dreq);
}
}
// Check if a JARDiff can be returned
if (jarDiffEnabled() && dreq.getCurrentVersionId() != null && jnlpres.isJarFile()) {
DownloadResponse response = _jarDiffHandler.getJarDiffEntry(_resourceCatalog, dreq, jnlpres);
if (response != null) {
_log.addInformational("servlet.log.info.jardiff.response");
return response;
}
}
// check and see if we can use pack resource
JnlpResource jr = new JnlpResource(getServletContext(), jnlpres.getName(), jnlpres.getVersionId(), jnlpres
.getOSList(), jnlpres.getArchList(), jnlpres.getLocaleList(), jnlpres.getPath(), jnlpres
.getReturnVersionId(), dreq.getEncoding());
_log.addDebug("Real resource returned: " + jr);
// Return WAR file resource
return DownloadResponse.getFileDownloadResponse(jr.getResource(), jr.getMimeType(), jr.getLastModified(), jr
.getReturnVersionId());
}
private boolean jarDiffEnabled() {
ServletContext context = getServletContext();
if (context == null) { return true; }
return !Boolean.valueOf(context.getInitParameter("jarDiffDisabled"));
}
}
jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/Logger.java 0000664 0001750 0001750 00000017134 11710312010 030465 0 ustar andrew andrew /*
* @(#)Logger.java 1.7 10/01/12
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package jnlp.sample.servlet;
import java.text.MessageFormat;
import java.util.*;
import java.io.*;
import javax.servlet.*;
/* A loging object used by the servlets */
public class Logger {
// Logging levels
public final static int NONE = 0;
public static final String NONE_KEY = "NONE";
public final static int FATAL = 1;
public static final String FATAL_KEY = "FATAL";
public final static int WARNING = 2;
public static final String WARNING_KEY = "WARNING";
public final static int INFORMATIONAL = 3;
public static final String INFORMATIONAL_KEY = "INFORMATIONAL";
public final static int DEBUG = 4;
public static final String DEBUG_KEY = "DEBUG";
// Configuration parameters
private final static String LOG_LEVEL = "logLevel";
private final static String LOG_PATH = "logPath";
private int _loggingLevel = FATAL;
private ServletContext _servletContext = null;
private String _logFile = null;
private String _servletName = null;
// Localization
ResourceBundle _resources = null;
/** Initialize logging object. It reads the logLevel and pathLevel init parameters.
* Default is logging level FATAL, and logging using the ServletContext.log
*/
public Logger(ServletConfig config, ResourceBundle resources) {
_resources = resources;
_servletContext = config.getServletContext();
_servletName = config.getServletName();
_logFile = config.getInitParameter(LOG_PATH);
if (_logFile != null) {
_logFile = _logFile.trim();
if (_logFile.length() == 0) _logFile = null;
}
String level = config.getInitParameter(LOG_LEVEL);
if (level != null) {
level = level.trim().toUpperCase();
if (level.equals(NONE_KEY)) _loggingLevel = NONE;
if (level.equals(FATAL_KEY)) _loggingLevel = FATAL;
if (level.equals(WARNING_KEY)) _loggingLevel = WARNING;
if (level.equals(INFORMATIONAL_KEY)) _loggingLevel = INFORMATIONAL;
if (level.equals(DEBUG_KEY)) _loggingLevel = DEBUG;
}
}
// Logging API. Fatal, Warning, and Informational are localized
public void addFatal(String key, Throwable throwable) {
logEvent(FATAL, getString(key), throwable);
}
public void addWarning(String key, String arg) {
logL10N(WARNING, key, arg, (Throwable)null);
}
public void addWarning(String key, String arg, Throwable t) {
logL10N(WARNING, key, arg, t);
}
public void addWarning(String key, String arg1, String arg2) {
logL10N(WARNING, key, arg1, arg2);
}
public void addWarning(String key, String arg1, String arg2, String arg3) {
logL10N(WARNING, key, arg1, arg2, arg3);
}
public void addInformational(String key) {
logEvent(INFORMATIONAL, getString(key), (Throwable)null);
}
public void addInformational(String key, String arg) {
logL10N(INFORMATIONAL, key, arg, (Throwable)null);
}
public void addInformational(String key, String arg1, String arg2, String arg3) {
logL10N(INFORMATIONAL, key, arg1, arg2, arg3);
}
// Debug messages are not localized
public void addDebug(String msg) { logEvent(DEBUG, msg, null); }
public void addDebug(String msg, Throwable throwable) {
logEvent(DEBUG, msg, throwable);
}
// Query to test for level
boolean isNoneLevel() { return _loggingLevel >= NONE; }
boolean isFatalevel() { return _loggingLevel >= FATAL; }
boolean isWarningLevel() { return _loggingLevel >= WARNING; }
boolean isInformationalLevel() { return _loggingLevel >= INFORMATIONAL; }
boolean isDebugLevel() { return _loggingLevel >= DEBUG; }
// Returns a string from the resources
private String getString(String key) {
try {
return _resources.getString(key);
} catch (MissingResourceException mre) {
return "Missing resource for: " + key;
}
}
private void logL10N(int level, String key, String arg, Throwable e) {
Object[] messageArguments = { arg };
logEvent(level, applyPattern(key, messageArguments), e);
}
private void logL10N(int level, String key, String arg1, String arg2) {
Object[] messageArguments = { arg1, arg2 };
logEvent(level, applyPattern(key, messageArguments), null);
}
private void logL10N(int level, String key, String arg1, String arg2, String arg3) {
Object[] messageArguments = { arg1, arg2, arg3 };
logEvent(level, applyPattern(key, messageArguments), null);
}
/** Helper function that applies the messageArguments to a message from the resource object */
private String applyPattern(String key, Object[] messageArguments) {
String message = getString(key);
MessageFormat formatter = new MessageFormat(message);
String output = formatter.format(message, messageArguments);
return output;
}
// The method that actually does the logging */
private synchronized void logEvent(int level, String string, Throwable throwable) {
// Check if the event should be logged
if (level > _loggingLevel) return;
if (_logFile != null) {
// No logfile specified, log using servlet context
PrintWriter pw = null;
try {
pw = new PrintWriter(new FileWriter(_logFile, true));
pw.println(_servletName + "(" + level + "): " + string);
if (throwable != null) {
throwable.printStackTrace(pw);
}
pw.close();
// Do a return here. An exception will cause a fall through to
// do _servletContex logging API
return;
} catch (IOException ioe) {
/* just ignore */
}
}
// Otherwise, write to servlet context log
if (throwable == null) {
_servletContext.log(string);
} else {
_servletContext.log(string, throwable);
}
}
}
././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011564 L ustar root root jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/JnlpFileHandler.java jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/JnlpFileHandle0000664 0001750 0001750 00000041662 11710312010 031150 0 ustar andrew andrew /*
* @(#)JnlpFileHandler.java 1.13 10/01/12
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package jnlp.sample.servlet;
import java.util.*;
import java.util.regex.*;
import java.net.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
/* The JNLP file handler implements a class that keeps
* track of JNLP files and their specializations
*/
public class JnlpFileHandler {
private static final String JNLP_MIME_TYPE = "application/x-java-jnlp-file";
private static final String HEADER_LASTMOD = "Last-Modified";
private ServletContext _servletContext;
private Logger _log = null;
private HashMap _jnlpFiles = null;
/** Initialize JnlpFileHandler for the specific ServletContext */
public JnlpFileHandler(ServletContext servletContext, Logger log) {
_servletContext = servletContext;
_log = log;
_jnlpFiles = new HashMap();
}
private static class JnlpFileEntry {
// Response
DownloadResponse _response;
// Keeps track of cache is out of date
private long _lastModified;
// Constructor
JnlpFileEntry(DownloadResponse response, long lastmodfied) {
_response = response;
_lastModified = lastmodfied;
}
public DownloadResponse getResponse() { return _response; }
long getLastModified() { return _lastModified; }
}
/* Main method to lookup an entry */
public synchronized DownloadResponse getJnlpFile(JnlpResource jnlpres, DownloadRequest dreq)
throws IOException {
String path = jnlpres.getPath();
URL resource = jnlpres.getResource();
long lastModified = jnlpres.getLastModified();
_log.addDebug("lastModified: " + lastModified + " " + new Date(lastModified));
if (lastModified == 0) {
_log.addWarning("servlet.log.warning.nolastmodified", path);
}
// fix for 4474854: use the request URL as key to look up jnlp file
// in hash map
String reqUrl = HttpUtils.getRequestURL(dreq.getHttpRequest()).toString();
// Check if entry already exist in HashMap
JnlpFileEntry jnlpFile = (JnlpFileEntry)_jnlpFiles.get(reqUrl);
if (jnlpFile != null && jnlpFile.getLastModified() == lastModified) {
// Entry found in cache, so return it
return jnlpFile.getResponse();
}
// Read information from WAR file
long timeStamp = lastModified;
String mimeType = _servletContext.getMimeType(path);
if (mimeType == null) mimeType = JNLP_MIME_TYPE;
StringBuffer jnlpFileTemplate = new StringBuffer();
URLConnection conn = resource.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line = br.readLine();
if (line != null && line.startsWith("TS:")) {
timeStamp = parseTimeStamp(line.substring(3));
_log.addDebug("Timestamp: " + timeStamp + " " + new Date(timeStamp));
if (timeStamp == 0) {
_log.addWarning("servlet.log.warning.notimestamp", path);
timeStamp = lastModified;
}
line = br.readLine();
}
while(line != null) {
jnlpFileTemplate.append(line);
line = br.readLine();
}
String jnlpFileContent = specializeJnlpTemplate(dreq.getHttpRequest(), path, jnlpFileTemplate.toString());
// Convert to bytes as a UTF-8 encoding
byte[] byteContent = jnlpFileContent.getBytes("UTF-8");
// Create entry
DownloadResponse resp = DownloadResponse.getFileDownloadResponse(byteContent,
mimeType,
timeStamp,
jnlpres.getReturnVersionId());
jnlpFile = new JnlpFileEntry(resp, lastModified);
_jnlpFiles.put(reqUrl, jnlpFile);
return resp;
}
/* Main method to lookup an entry (NEW for JavaWebStart 1.5+) */
public synchronized DownloadResponse getJnlpFileEx(JnlpResource jnlpres, DownloadRequest dreq)
throws IOException {
String path = jnlpres.getPath();
URL resource = jnlpres.getResource();
long lastModified = jnlpres.getLastModified();
_log.addDebug("lastModified: " + lastModified + " " + new Date(lastModified));
if (lastModified == 0) {
_log.addWarning("servlet.log.warning.nolastmodified", path);
}
// fix for 4474854: use the request URL as key to look up jnlp file
// in hash map
String reqUrl = HttpUtils.getRequestURL(dreq.getHttpRequest()).toString();
// SQE: To support query string, we changed the hash key from Request URL to (Request URL + query string)
if (dreq.getQuery() != null)
reqUrl += dreq.getQuery();
// Check if entry already exist in HashMap
JnlpFileEntry jnlpFile = (JnlpFileEntry)_jnlpFiles.get(reqUrl);
if (jnlpFile != null && jnlpFile.getLastModified() == lastModified) {
// Entry found in cache, so return it
return jnlpFile.getResponse();
}
// Read information from WAR file
long timeStamp = lastModified;
String mimeType = _servletContext.getMimeType(path);
if (mimeType == null) mimeType = JNLP_MIME_TYPE;
StringBuffer jnlpFileTemplate = new StringBuffer();
URLConnection conn = resource.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line = br.readLine();
if (line != null && line.startsWith("TS:")) {
timeStamp = parseTimeStamp(line.substring(3));
_log.addDebug("Timestamp: " + timeStamp + " " + new Date(timeStamp));
if (timeStamp == 0) {
_log.addWarning("servlet.log.warning.notimestamp", path);
timeStamp = lastModified;
}
line = br.readLine();
}
while(line != null) {
jnlpFileTemplate.append(line);
line = br.readLine();
}
String jnlpFileContent = specializeJnlpTemplate(dreq.getHttpRequest(), path, jnlpFileTemplate.toString());
/* SQE: We need to add query string back to href in jnlp file. We also need to handle JRE requirement for
* the test. We reconstruct the xml DOM object, modify the value, then regenerate the jnlpFileContent.
*/
String query = dreq.getQuery();
String testJRE = dreq.getTestJRE();
_log.addDebug("Double check query string: " + query);
// For backward compatibility: Always check if the href value exists.
// Bug 4939273: We will retain the jnlp template structure and will NOT add href value. Above old
// approach to always check href value caused some test case not run.
if (query != null) {
byte [] cb = jnlpFileContent.getBytes("UTF-8");
ByteArrayInputStream bis = new ByteArrayInputStream(cb);
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(bis);
if (document != null && document.getNodeType() == Node.DOCUMENT_NODE) {
boolean modified = false;
Element root = document.getDocumentElement();
if (root.hasAttribute("href") && query != null) {
String href = root.getAttribute("href");
root.setAttribute("href", href + "?" + query);
modified = true;
}
// Update version value for j2se tag
if (testJRE != null) {
NodeList j2seNL = root.getElementsByTagName("j2se");
if (j2seNL != null) {
Element j2se = (Element) j2seNL.item(0);
String ver = j2se.getAttribute("version");
if (ver.length() > 0) {
j2se.setAttribute("version", testJRE);
modified = true;
}
}
}
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(document);
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
transformer.transform(source, result);
jnlpFileContent = sw.toString();
_log.addDebug("Converted jnlpFileContent: " + jnlpFileContent);
// Since we modified the file on the fly, we always update the timestamp value with current time
if (modified) {
timeStamp = new java.util.Date().getTime();
_log.addDebug("Last modified on the fly: " + timeStamp);
}
}
} catch (Exception e) {
_log.addDebug(e.toString(), e);
}
}
// Convert to bytes as a UTF-8 encoding
byte[] byteContent = jnlpFileContent.getBytes("UTF-8");
// Create entry
DownloadResponse resp = DownloadResponse.getFileDownloadResponse(byteContent,
mimeType,
timeStamp,
jnlpres.getReturnVersionId());
jnlpFile = new JnlpFileEntry(resp, lastModified);
_jnlpFiles.put(reqUrl, jnlpFile);
return resp;
}
/* This method performs the following substituations
* $$name
* $$codebase
* $$context
*/
private String specializeJnlpTemplate(HttpServletRequest request, String respath, String jnlpTemplate) {
String urlprefix = getUrlPrefix(request);
int idx = respath.lastIndexOf('/'); //
String name = respath.substring(idx + 1); // Exclude /
String codebase = respath.substring(0, idx + 1); // Include /
jnlpTemplate = substitute(jnlpTemplate, "$$name", name);
// fix for 5039951: Add $$hostname macro
jnlpTemplate = substitute(jnlpTemplate, "$$hostname",
request.getServerName());
jnlpTemplate = substitute(jnlpTemplate, "$$codebase", urlprefix + request.getContextPath() + codebase);
jnlpTemplate = substitute(jnlpTemplate, "$$context", urlprefix + request.getContextPath());
// fix for 6256326: add $$site macro to sample jnlp servlet
jnlpTemplate = substitute(jnlpTemplate, "$$site", urlprefix);
return jnlpTemplate;
}
// This code is heavily inspired by the stuff in HttpUtils.getRequestURL
private String getUrlPrefix(HttpServletRequest req) {
StringBuffer url = new StringBuffer();
String scheme = req.getScheme();
int port = req.getServerPort();
url.append(scheme); // http, https
url.append("://");
url.append(req.getServerName());
if ((scheme.equals("http") && port != 80)
|| (scheme.equals("https") && port != 443)) {
url.append(':');
url.append(req.getServerPort());
}
return url.toString();
}
private String substitute(String target, String key, String value) {
int start = 0;
do {
int idx = target.indexOf(key, start);
if (idx == -1) return target;
target = target.substring(0, idx) + value + target.substring(idx + key.length());
start = idx + value.length();
} while(true);
}
/** Parses a ISO 8601 Timestamp. The format of the timestamp is:
*
* YYYY-MM-DD hh:mm:ss or YYYYMMDDhhmmss
*
* Hours (hh) is in 24h format. ss are optional. Time are by default relative
* to the current timezone. Timezone information can be specified
* by:
*
* - Appending a 'Z', e.g., 2001-12-19 12:00Z
* - Appending +hh:mm, +hhmm, +hh, -hh:mm -hhmm, -hh to
* indicate that the locale timezone used is either the specified
* amound before or after GMT. For example,
*
* 12:00Z = 13:00+1:00 = 0700-0500
*
* The method returns 0 if it cannot pass the string. Otherwise, it is
* the number of milliseconds size sometime in 1969.
*/
private long parseTimeStamp(String timestamp) {
int YYYY = 0;
int MM = 0;
int DD = 0;
int hh = 0;
int mm = 0;
int ss = 0;
timestamp = timestamp.trim();
try {
// Check what format is used
if (matchPattern("####-##-## ##:##", timestamp)) {
YYYY = getIntValue(timestamp, 0, 4);
MM = getIntValue(timestamp, 5, 7);
DD = getIntValue(timestamp, 8, 10);
hh = getIntValue(timestamp, 11, 13);
mm = getIntValue(timestamp, 14, 16);
timestamp = timestamp.substring(16);
if (matchPattern(":##", timestamp)) {
ss = getIntValue(timestamp, 1, 3);
timestamp = timestamp.substring(3);
}
} else if (matchPattern("############", timestamp)) {
YYYY = getIntValue(timestamp, 0, 4);
MM = getIntValue(timestamp, 4, 6);
DD = getIntValue(timestamp, 6, 8);
hh = getIntValue(timestamp, 8, 10);
mm = getIntValue(timestamp, 10, 12);
timestamp = timestamp.substring(12);
if (matchPattern("##", timestamp)) {
ss = getIntValue(timestamp, 0, 2);
timestamp = timestamp.substring(2);
}
} else {
// Unknown format
return 0;
}
} catch(NumberFormatException e) {
// Bad number
return 0;
}
String timezone = null;
// Remove timezone information
timestamp = timestamp.trim();
if (timestamp.equalsIgnoreCase("Z")) {
timezone ="GMT";
} else if (timestamp.startsWith("+") || timestamp.startsWith("-")) {
timezone = "GMT" + timestamp;
}
if (timezone == null) {
// Date is relative to current locale
Calendar cal = Calendar.getInstance();
cal.set(YYYY, MM - 1, DD, hh, mm, ss);
return cal.getTime().getTime();
} else {
// Date is relative to a timezone
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timezone));
cal.set(YYYY, MM - 1, DD, hh, mm, ss);
return cal.getTime().getTime();
}
}
private int getIntValue(String key, int start, int end) {
return Integer.parseInt(key.substring(start, end));
}
private boolean matchPattern(String pattern, String key) {
// Key must be longer than pattern
if (key.length() < pattern.length()) return false;
for(int i = 0; i < pattern.length(); i++) {
char format = pattern.charAt(i);
char ch = key.charAt(i);
if (!((format == '#' && Character.isDigit(ch)) || (format == ch))) {
return false;
}
}
return true;
}
}
././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011564 L ustar root root jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/DownloadRequest.java jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/DownloadReques0000664 0001750 0001750 00000021536 11710312010 031263 0 ustar andrew andrew /*
* @(#)DownloadRequest.java 1.8 10/01/12
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package jnlp.sample.servlet;
import java.io.File;
import java.util.ArrayList;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* The DownloadRequest incapsulates all the data in a request
* SQE: We need to address query string
*/
public class DownloadRequest {
// Arguments
private static final String ARG_ARCH = "arch";
private static final String ARG_OS = "os";
private static final String ARG_LOCALE = "locale";
private static final String ARG_VERSION_ID = "version-id";
private static final String ARG_CURRENT_VERSION_ID = "current-version-id";
private static final String ARG_PLATFORM_VERSION_ID = "platform-version-id";
private static final String ARG_KNOWN_PLATFORMS = "known-platforms";
private static final String TEST_JRE = "TestJRE";
private String _path = null;
private String _version = null;
private String _currentVersionId = null;
private String[] _os = null;
private String[] _arch = null;
private String[] _locale = null;
private String[] _knownPlatforms = null;
private String _query = null;
private String _testJRE = null;
private boolean _isPlatformRequest = false;
private ServletContext _context = null;
private String _encoding = null;
private HttpServletRequest _httpRequest = null;
// HTTP Compression RFC 2616 : Standard headers
public static final String ACCEPT_ENCODING = "accept-encoding";
// Contruct Request object based on HTTP request
public DownloadRequest(HttpServletRequest request) {
this((ServletContext)null, request);
}
public DownloadRequest(ServletContext context, HttpServletRequest request) {
_context = context;
_httpRequest = request;
_path = request.getRequestURI();
_encoding = request.getHeader(ACCEPT_ENCODING);
String context_path = request.getContextPath();
if (context_path != null) _path = _path.substring(context_path.length());
if (_path == null) _path = request.getServletPath(); // This works for *. invocations
if (_path == null) _path = "/"; // No path given
_path = _path.trim();
if (_context != null && !_path.endsWith("/")) {
String realPath = _context.getRealPath(_path);
// fix for 4474021 - getRealPath might returns NULL
if (realPath != null) {
File f = new File(realPath);
if (f != null && f.exists() && f.isDirectory()) {
_path += "/";
}
}
}
// Append default file for a directory
if (_path.endsWith("/")) _path += "launch.jnlp";
_version = getParameter(request, ARG_VERSION_ID);
_currentVersionId = getParameter(request, ARG_CURRENT_VERSION_ID);
_os = getParameterList(request, ARG_OS);
_arch = getParameterList(request, ARG_ARCH);
_locale = getParameterList(request, ARG_LOCALE);
_knownPlatforms = getParameterList(request, ARG_KNOWN_PLATFORMS);
String platformVersion = getParameter(request, ARG_PLATFORM_VERSION_ID);
_isPlatformRequest = (platformVersion != null);
if (_isPlatformRequest) _version = platformVersion;
_query = request.getQueryString();
_testJRE = getParameter(request, TEST_JRE);
}
/** Returns a DownloadRequest for the currentVersionId, that can be used
* to lookup the existing cached version
*/
private DownloadRequest(DownloadRequest dreq) {
_encoding = dreq._encoding;
_context = dreq._context;
_httpRequest = dreq._httpRequest;
_path = dreq._path;
_version = dreq._currentVersionId;
_currentVersionId = null;
_os = dreq._os;
_arch = dreq._arch;
_locale = dreq._locale;
_knownPlatforms = dreq._knownPlatforms;
_isPlatformRequest = dreq._isPlatformRequest;
_query = dreq._query;
_testJRE = dreq._testJRE;
}
private String getParameter(HttpServletRequest req, String key) {
String res = req.getParameter(key);
return (res == null) ? null : res.trim();
}
/** Converts a space delimitered string to a list of strings */
static private String[] getStringList(String str) {
if (str == null) return null;
ArrayList list = new ArrayList();
int i = 0;
int length = str.length();
StringBuffer sb = null;
while(i < length) {
char ch = str.charAt(i);
if (ch == ' ') {
// A space was hit. Add string to list
if (sb != null) {
list.add(sb.toString());
sb = null;
}
} else if (ch == '\\') {
// It is a delimiter. Add next character
if (i + 1 < length) {
ch = str.charAt(++i);
if (sb == null) sb = new StringBuffer();
sb.append(ch);
}
} else {
if (sb == null) sb = new StringBuffer();
sb.append(ch);
}
i++; // Next character
}
// Make sure to add the last part to the list too
if (sb != null) {
list.add(sb.toString());
}
if (list.size() == 0) return null;
String[] results = new String[list.size()];
return (String[])list.toArray(results);
}
/* Split parameter at spaces. Convert '\ ' insto a space */
private String[] getParameterList(HttpServletRequest req, String key) {
String res = req.getParameter(key);
return (res == null) ? null : getStringList(res.trim());
}
// Query
public String getPath() { return _path; }
public String getVersion() { return _version; }
public String getCurrentVersionId() { return _currentVersionId; }
public String getQuery() { return _query; }
public String getTestJRE() { return _testJRE; }
public String getEncoding() { return _encoding; }
public String[] getOS() { return _os; }
public String[] getArch() { return _arch; }
public String[] getLocale() { return _locale; }
public String[] getKnownPlatforms() { return _knownPlatforms; }
public boolean isPlatformRequest() { return _isPlatformRequest; }
public HttpServletRequest getHttpRequest() { return _httpRequest; }
/** Returns a DownloadRequest for the currentVersionId, that can be used
* to lookup the existing cached version
*/
DownloadRequest getFromDownloadRequest() {
return new DownloadRequest(this);
}
// Debug
public String toString() {
return "DownloadRequest[path=" + _path +
showEntry(" encoding=", _encoding) +
showEntry(" query=", _query) +
showEntry(" TestJRE=", _testJRE) +
showEntry(" version=", _version) +
showEntry(" currentVersionId=", _currentVersionId) +
showEntry(" os=", _os) +
showEntry(" arch=", _arch) +
showEntry(" locale=", _locale) +
showEntry(" knownPlatforms=", _knownPlatforms)
+ " isPlatformRequest=" + _isPlatformRequest + "]";
}
private String showEntry(String msg, String value) {
if (value == null) return "";
return msg + value;
}
private String showEntry(String msg, String[] value) {
if (value == null) return "";
return msg + java.util.Arrays.asList(value).toString();
}
}
././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011564 L ustar root root jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/ResourceCatalog.java jnlp-servlet-527f95ceaf5b0d746348b31c647b93900e72258a/src/classes/jnlp/sample/servlet/ResourceCatalo0000664 0001750 0001750 00000043035 11710312010 031240 0 ustar andrew andrew /*
* @(#)ResourceCatalog.java 1.7 10/01/12
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package jnlp.sample.servlet;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.BufferedInputStream;
import javax.servlet.ServletContext;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import jnlp.sample.util.VersionString;
import jnlp.sample.util.VersionID;
public class ResourceCatalog {
public static final String VERSION_XML_FILENAME = "version.xml";
private Logger _log = null;
private ServletContext _servletContext = null;
private HashMap _entries;
/** Class to contain the information we know
* about a specific directory
*/
static private class PathEntries {
/* Version-based entries at this particular path */
private List _versionXmlList;
private List _directoryList;
private List _platformList;
/* Last time this entry was updated */
private long _lastModified; // Last modified time of entry;
public PathEntries(List versionXmlList, List directoryList, List platformList, long lastModified) {
_versionXmlList = versionXmlList;
_directoryList = directoryList;
_platformList = platformList;
_lastModified = lastModified;
}
public void setDirectoryList(List dirList) {
_directoryList = dirList;
}
public List getVersionXmlList() { return _versionXmlList; }
public List getDirectoryList() { return _directoryList; }
public List getPlatformList() { return _platformList; }
public long getLastModified() { return _lastModified; }
}
public ResourceCatalog(ServletContext servletContext, Logger log) {
_entries = new HashMap();
_servletContext = servletContext;
_log = log;
}
public JnlpResource lookupResource(DownloadRequest dreq) throws ErrorResponseException {
// Split request up into path and name
String path = dreq.getPath();
String name = null;
String dir = null;
int idx = path.lastIndexOf('/');
if (idx == -1) {
name = path;
} else {
name = path.substring(idx + 1); // Exclude '/'
dir = path.substring(0, idx + 1); // Include '/'
}
// Lookup up already parsed entries, and san directory for entries if neccesary
PathEntries pentries = (PathEntries)_entries.get(dir);
JnlpResource xmlVersionResPath = new JnlpResource(_servletContext, dir + VERSION_XML_FILENAME);
if (pentries == null || (xmlVersionResPath.exists() && xmlVersionResPath.getLastModified() > pentries.getLastModified())) {
_log.addInformational("servlet.log.scandir", dir);
List dirList = scanDirectory(dir, dreq);
// Scan XML file
List versionList = new ArrayList();
List platformList = new ArrayList();
parseVersionXML(versionList, platformList, dir, xmlVersionResPath);
pentries = new PathEntries(versionList, dirList, platformList, xmlVersionResPath.getLastModified());
_entries.put(dir, pentries);
}
// Search for a match
JnlpResource[] result = new JnlpResource[1];
if (dreq.isPlatformRequest()) {
int sts = findMatch(pentries.getPlatformList(), name, dreq, result);
if (sts != DownloadResponse.STS_00_OK) {
throw new ErrorResponseException(DownloadResponse.getJnlpErrorResponse(sts));
}
} else {
// First lookup in versions.xml file
int sts1 = findMatch(pentries.getVersionXmlList(), name, dreq, result);
if (sts1 != DownloadResponse.STS_00_OK) {
// Then lookup in directory
int sts2 = findMatch(pentries.getDirectoryList(), name, dreq, result);
if (sts2 != DownloadResponse.STS_00_OK) {
// fix for 4450104
// try rescan and see if it helps
pentries.setDirectoryList(scanDirectory(dir, dreq));
sts2 = findMatch(pentries.getDirectoryList(), name, dreq, result);
// try again after rescanning directory
if (sts2 != DownloadResponse.STS_00_OK) {
// Throw the most specific error code
throw new ErrorResponseException(DownloadResponse.getJnlpErrorResponse(Math.max(sts1, sts2)));
}
}
}
}
return result[0];
}
/** This method finds the best match, or return the best error code. The
* result parameter must be an array with room for one element.
*
* If a match is found, the method returns DownloadResponse.STS_00_OK
* If one or more entries matches on: name, version-id, os, arch, and locale,
* then the one with the highest version-id is set in the result[0] field.
*
* If a match is not found, it returns an error code, either: ERR_10_NO_RESOURCE,
* ERR_11_NO_VERSION, ERR_20_UNSUP_OS, ERR_21_UNSUP_ARCH, ERR_22_UNSUP_LOCALE,
* ERR_23_UNSUP_JRE.
*
*/
public int findMatch(List list, String name, DownloadRequest dreq, JnlpResource[] result) {
if (list == null) return DownloadResponse.ERR_10_NO_RESOURCE;
// Setup return values
VersionID bestVersionId = null;
int error = DownloadResponse.ERR_10_NO_RESOURCE;
VersionString vs = new VersionString(dreq.getVersion());
// Iterate through entries
for(int i = 0; i < list.size(); i++) {
JnlpResource respath = (JnlpResource)list.get(i);
VersionID vid = new VersionID(respath.getVersionId());
int sts = matchEntry(name, vs, dreq, respath, vid);
if (sts == DownloadResponse.STS_00_OK) {
if (result[0] == null || vid.isGreaterThan(bestVersionId)) {
result[0] = respath;
bestVersionId = vid;
}
} else {
error = Math.max(error, sts);
}
}
return (result[0] != null) ? DownloadResponse.STS_00_OK : error;
}
public int matchEntry(String name, VersionString vs, DownloadRequest dreq, JnlpResource jnlpres, VersionID vid) {
if (!name.equals(jnlpres.getName())) {
return DownloadResponse.ERR_10_NO_RESOURCE;
}
if (!vs.contains(vid)) {
return DownloadResponse.ERR_11_NO_VERSION;
}
if (!prefixMatchLists(jnlpres.getOSList(), dreq.getOS())) {
return DownloadResponse.ERR_20_UNSUP_OS;
}
if (!prefixMatchLists(jnlpres.getArchList(), dreq.getArch())) {
return DownloadResponse.ERR_21_UNSUP_ARCH;
}
if (!prefixMatchLists(jnlpres.getLocaleList(), dreq.getLocale())) {
return DownloadResponse.ERR_22_UNSUP_LOCALE;
}
return DownloadResponse.STS_00_OK;
}
private static boolean prefixMatchStringList(String[] prefixList, String target) {
// No prefixes matches everything
if (prefixList == null) return true;
// No target, but a prefix list does not match anything
if (target == null) return false;
for(int i = 0; i < prefixList.length; i++) {
if (target.startsWith(prefixList[i])) return true;
}
return false;
}
/* Return true if at least one of the strings in 'prefixes' are a prefix
* to at least one of the 'keys'.
*/
public boolean prefixMatchLists(String[] prefixes, String[] keys) {
// The prefixes are part of the server resources. If none is given,
// everything matches
if (prefixes == null) return true;
// If no os keyes was given, and the server resource is keyed of this,
// then return false.
if (keys == null) return false;
// Check for a match on a key
for(int i = 0; i < keys.length; i++) {
if (prefixMatchStringList(prefixes, keys[i])) return true;
}
return false;
}
/** This method scans the directory pointed to by the
* given path and creates a list of ResourcePath elements
* that contains information about all the entries
*
* The version-based information is encoded in the file name
* given the following format:
*
* entry ::= __ ( ).
* options ::=