diff --git a/.classpath b/.classpath new file mode 100755 index 0000000..9ab1e23 --- /dev/null +++ b/.classpath @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 9aa16d2..dcf180a --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,6 @@ -1.x/bin/ -.project -.classpath -1.x/lib/ -1.x/*.log -1.x/test/lib/ -1.x/webapps/ -*.class -1.x/src/rogatkin/app/remote/* -1.x/.temp_repo/ -1.x/test/.temp_repo/ -1.x/compatibility/build/ -bin/ -*.obj -.DS_Store \ No newline at end of file +/**/bak +/**/bin +/**/build +/**/.DS_Store +/logs +/**/release-v* diff --git a/.project b/.project new file mode 100644 index 0000000..8bc8786 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + TJWSEclipse + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/1.x/bee.xml b/1.x/bee.xml deleted file mode 100644 index 70c3f4c..0000000 --- a/1.x/bee.xml +++ /dev/null @@ -1,1611 +0,0 @@ - - - - - - ]> - - - - - &env; - - - ================ ATTENTION ================== - Please make sure that below variables obtained correct values - in file env.xml for build correctness: - - SERVLET_LIB - fully qualified path to servlet.jar or other lib/directory containing - JSS 2.3 classes (this one is used for building base TJWS) - = - - - SERVLET_LIB_30 - fully qualified path to javax.servlet.jar or other lib/directory - containing JSS 3.x classes (used for J2EE extension) - = - - - SERVLET_SRC - fully qualified path to sources of JSS classes, used only for packaging - text resources in a launcher (optional) - = - - - SERVLET_BUILD - fully qualified path to binaries of classes of JSS, used only for - packaging JSS in a launcher (correct version of JSS - has to be used for target applications (optional) - = - - - JSP_LIB - fully qualified path to jsp.jar or other lib/directory containing - JSP API classes, unless JASPER library is defined (optional) - = - - - JASPER (optional) - = - - - ANDROID_RT (optional for android compilation) - = - - - WEBSOCKET_CLIENT_LIB, EBSOCKET_SERVER_LIB - websocket (JSR356) API libraries (optional) - = - - - - - WEBSOCKET_API - fully qualified path to websocket spec source api directory (optional) - = - - - CLASS_SCAN_LIB, CLASS_SCAN_CLASSES - fully qualified paths to fast scan library and classes tree (optional) - = - - - - - ============================================= - - - - - - - - - /bin/javac - - - - - - - /bin/idlj - - - - - - - - - - - - - - - - - - - - - - - ./compatibility - - - - - - : - - - - bee - - - bee.bat - - - - - - - - - - - - - jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &build_directory; - - - - - - - - - - &build_directory; - - - - - - - - - - - - - - - - - - - - -//////////////////// TJWS Build Process ///////////////////////// - type: - bee -th - to get help on build targets -///////////////////////////////////////////////////////////////// - - - - - - - - Compiling core... - - - - - - - - - - - - - yes - - - - - 1.7 - - - - - - - - - - - - - - - 1.5 - - - - - -bootclasspath - - - - - - - - - - - - - - - - - - - - - - src/Acme/Utils.java - - - - - - - - 0 - - - Error(s) at compilation - - - - - - - - - - - - IDL compilation... - - - - - - - - - - - - - - - - - - - - - - - - 1.6 - - - - yes - - - - - - - - - - - - .*SysTrayControl\.java - - - - - - - - - - - - - - - - - - - - - Compiling J2EE... - - - - - - - - - - - - - - - 1.6 - - - - yes - - - - - - - - - yes - - - - - - - - - - - .*rogatkin[/|\\]?app.* - - - - - - - -bootclasspath - - - - - - - - - - - - - - - - - - - - - - src/rogatkin/web/WarRoller.java - - - - - - - - 0 - - - Error(s) at compilation - - - - - - - - - - - - - - Compiling checker... - - - 1.5 - - 1.5 - - - - - - - - Jarring war... - - - - - - - - - - - - - - - - - - - Jarring wskt... - - - - - - - - - - - - - - - - - - - - - Jarring app... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Jarring checker.... - - - - - - - - - - - - - - Jarring... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Converting resources - - src/rogatkin/resource/*.asis - - - - - /lib/tools.jar - - - - - - - - - - - src/rogatkin/resource - - - - - .properties - - - - - - - - - - - - - /javax/servlet/LocalStrings*.properties - - - - - - - /javax/servlet/http/LocalStrings*.properties - - - - - - - /javax/servlet/resources/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - src - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Acme/Resource/mime.properties - - - rogatkin/resource/tjws.gif - - - rogatkin/resource/splash.gif - - - - - - - - - - -C - - - - - - - - - - - - - -C - - - - - - - - - - - - - -C - - - - - - - - - - - - /client/lib - - - - - - - - - - /server/lib - - - - - - - - - - - - - - - - JASPER_BUILD - - - - Adding Jasper - - - - - - - - - - - - - - - org/apache/jasper/resources - - - javax/servlet/resources - - - - - Launcher's been built. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - rogatkin/resource/tjws.gif - - - rogatkin/resource/splash.gif - - - Acme/Resource/mime.properties - - - - - - - - - - -C - - - - - - - - - - - - - -C - - - - - - - - - - - - - -C - - - - - - - - - - - - /client/lib - - - - - - - - - - /server/lib - - - - - - - - - - - - - - - - JASPER_BUILD - - - - Adding Jasper - - - - - - - - - - - - - - - org/apache/jasper/resources - - - - No JSP support added in the launcher - - - - App Server Launcher's been built. - - - - - - - - - Enter command line arguments for app [-nohup -p 8080]? - -nohup -p 8080 - - - - - Enter application .war file location? - - - - - - Enter application icon (32x32 gif image file) location[src/rogatkin/resource/tjws.gif]? - src/rogatkin/resource/tjws.gif - - - - - Do you need tools.jar added (Java compiler for JSP) [n]? - n - - - - - - - n - - - - Please precompile your JSP using a command similar to bellow (Jasper): -bee -- -webapp <web app dir> -v -d <target dir> -compile - - - - rundescriptor - - - - - - - - - .war - - - - - rundescriptor - -C - - - - - - - - - - \..* - - - - - - - - - - - - .war - - - - - - - &build_directory;/ - - - - .jar - - - - rundescriptor - - - - - - - - - - - - - - - - Enter command line arguments for app server, use --j org.apache.jasper.servlet.JspServlet -org.apache.jasper.servlet.JspServlet.classpath %classpath% -org.apache.jasper.servlet.JspServlet.scratchdir %deploydir%/WEB-INF -for Jasper enabled application [-nohup -p 80 -dataSource datasource.properties]? - -nohup -p 80 -dataSource datasource.properties - - - - - Enter application .war file location? - - - - - rundescriptor - - - - - - - - - .war - - - - - rundescriptor - -C - - - - - - - - - - \..* - - - - - - - - - - - - .war - - - - - - - &build_directory;/ - - - - .jar - - - - rundescriptor - - - - - - - - - - - - - - y - - - - - - - - - Cleaning... - - - - - - - - - - - - - - - - Generation SSL certificate - - - - - - - /.keystore - - - - - Keystore path[~/.keystore]? - - - - - - Keystore password[changeme]? - changeme - - - - - Keystore provider (use default for BKS/Android, or JKS for standard) [org.bouncycastle.jce.provider.BouncyCastleProvider]? - org.bouncycastle.jce.provider.BouncyCastleProvider - - - - - Key alias name[selfsigned]? - selfsigned - - - - - - - /bin/keytool - - - - - - - - - - -genkeypair - -keyalg - RSA - -validity - 360 - -alias - - -keypass - - -storepass - - -keystore - - - - - - - JKS - - - - - - -storetype - BKS - -provider - - -providerpath - - - - - - - - - - - - - - - /&build_directory;/webserver.jar - - - /&build_directory;/war.jar - - - /&build_directory;/wskt.jar - - - - - /lib/tools.jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /&build_directory;/app.jar - - - - - - - - Runs test.. - - - - - - - - - Scanning and generatiing endpoints list... - - - - - - - - - - - - - - - - - - n - - - - -dataSource - datasource.properties - - -p - - - - - - / - - - - - 8080 - - - 80 - - - - - -z - 50 - -sh - - - - - - - - - - Running... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / - - - - - 8443 - - - - - - - - - - - / - - - - - 8080 - - - 80 - - - - - - - - - - - - - - - - JASPER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -acceptorImpl - - rogatkin.wskt.SSLSelectorAcceptor - -keystorePass - - - - - - - - -acceptorImpl - Acme.Serve.SelectorAcceptor - - - - - - - - - - - - - - - - - -acceptorImpl - rogatkin.web.DualSocketAcceptor - -keystorePass - - -ssl-port - 443 - - - - - - - - - - - \ No newline at end of file diff --git a/1.x/compatibility/src/javax/servlet/HttpConstraintElement.java b/1.x/compatibility/src/javax/servlet/HttpConstraintElement.java deleted file mode 100644 index c988acd..0000000 --- a/1.x/compatibility/src/javax/servlet/HttpConstraintElement.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.servlet; - -import java.util.*; -import javax.servlet.annotation.HttpConstraint; -import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; -import javax.servlet.annotation.ServletSecurity.TransportGuarantee; - -/** - * Java Class representation of an {@link HttpConstraint} annotation value. - * - * @since Servlet 3.0 - */ -public class HttpConstraintElement { - - private EmptyRoleSemantic emptyRoleSemantic; - private TransportGuarantee transportGuarantee; - private String[] rolesAllowed; - - /** - * Constructs a default HTTP constraint element - */ - public HttpConstraintElement() { - this(EmptyRoleSemantic.PERMIT); - } - - /** - * Convenience constructor to establish EmptyRoleSemantic.DENY - * - * @param semantic should be EmptyRoleSemantic.DENY - */ - public HttpConstraintElement(EmptyRoleSemantic semantic) { - this(semantic, TransportGuarantee.NONE, new String[0]); - } - - /** - * Constructor to establish non-empty getRolesAllowed and/or - * TransportGuarantee.CONFIDENTIAL. - * - * @param guarantee TransportGuarantee.NONE or - * TransportGuarantee.CONFIDENTIAL - * @param roleNames the names of the roles that are to be - * allowed access - */ - public HttpConstraintElement(TransportGuarantee guarantee, - String... roleNames) { - this(EmptyRoleSemantic.PERMIT, guarantee, roleNames); - } - - /** - * Constructor to establish all of getEmptyRoleSemantic, - * getRolesAllowed, and getTransportGuarantee. - * - * @param semantic EmptyRoleSemantic.DENY or - * EmptyRoleSemantic.PERMIT - * @param guarantee TransportGuarantee.NONE or - * TransportGuarantee.CONFIDENTIAL - * @param roleNames the names of the roles that are to be allowed - * access, or missing if the semantic is EmptyRoleSemantic.DENY - */ - public HttpConstraintElement(EmptyRoleSemantic semantic, - TransportGuarantee guarantee, String... roleNames) { - if (semantic == EmptyRoleSemantic.DENY && roleNames.length > 0) { - throw new IllegalArgumentException( - "Deny semantic with rolesAllowed"); - } - this.emptyRoleSemantic = semantic; - this.transportGuarantee = guarantee; - this.rolesAllowed = roleNames; - } - - /** - * Gets the default authorization semantic. - * - *

This value is insignificant when getRolesAllowed - * returns a non-empty array, and should not be specified when a - * non-empty array is specified for getRolesAllowed. - * - * @return the {@link EmptyRoleSemantic} to be applied when - * getRolesAllowed returns an empty (that is, zero-length) - * array - */ - public EmptyRoleSemantic getEmptyRoleSemantic() { - return this.emptyRoleSemantic; - } - - /** - * Gets the data protection requirement (i.e., whether or not SSL/TLS is - * required) that must be satisfied by the transport connection. - * - * @return the {@link TransportGuarantee} indicating the data - * protection that must be provided by the connection - */ - public TransportGuarantee getTransportGuarantee() { - return this.transportGuarantee; - } - - /** - * Gets the names of the authorized roles. - * - *

Duplicate role names appearing in getRolesAllowed are insignificant - * and may be discarded. The String "*" has no special meaning - * as a role name (should it occur in getRolesAllowed). - * - * @return a (possibly empty) array of role names. When the - * array is empty, its meaning depends on the value of - * {@link #getEmptyRoleSemantic}. If its value is DENY, - * and getRolesAllowed returns an empty array, - * access is to be denied independent of authentication state and - * identity. Conversely, if its value is PERMIT, it - * indicates that access is to be allowed independent of authentication - * state and identity. When the array contains the names of one or - * more roles, it indicates that access is contingent on membership in at - * least one of the named roles (independent of the value of - * {@link #getEmptyRoleSemantic}). - */ - public String[] getRolesAllowed() { - return this.rolesAllowed; - } -} diff --git a/1.x/compatibility/src/javax/servlet/MultipartConfigElement.java b/1.x/compatibility/src/javax/servlet/MultipartConfigElement.java deleted file mode 100644 index a525e7e..0000000 --- a/1.x/compatibility/src/javax/servlet/MultipartConfigElement.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.servlet; - -import javax.servlet.annotation.MultipartConfig; - -/** - * Java Class represntation of an {@link MultipartConfig} annotation value. - * - * @since Servlet 3.0 - */ -public class MultipartConfigElement { - - private String location; - private long maxFileSize; - private long maxRequestSize; - private int fileSizeThreshold; - - /** - * Constructs an instance with defaults for all but location. - * - * @param location defualts to "" if values is null. - */ - public MultipartConfigElement(String location) { - if (location == null) { - this.location = ""; - } else { - this.location = location; - } - this.maxFileSize = -1L; - this.maxRequestSize = -1L; - this.fileSizeThreshold = 0; - } - - /** - * Constructs an instance with all values specified. - * - * @param location the directory location where files will be stored - * @param maxFileSize the maximum size allowed for uploaded files - * @param maxRequestSize the maximum size allowed for - * multipart/form-data requests - * @param fileSizeThreshold the size threshold after which files will - * be written to disk - */ - public MultipartConfigElement(String location, long maxFileSize, - long maxRequestSize, int fileSizeThreshold) { - if (location == null) { - this.location = ""; - } else { - this.location = location; - } - this.maxFileSize = maxFileSize; - this.maxRequestSize = maxRequestSize; - this.fileSizeThreshold = fileSizeThreshold; - } - - /** - * Constructs an instance from a {@link MultipartConfig} annotation value. - * - * @param annotation the annotation value - */ - public MultipartConfigElement(MultipartConfig annotation) { - this.location = annotation.location(); - this.fileSizeThreshold = annotation.fileSizeThreshold(); - this.maxFileSize = annotation.maxFileSize(); - this.maxRequestSize = annotation.maxRequestSize(); - } - - /** - * Gets the directory location where files will be stored. - * - * @return the directory location where files will be stored - */ - public String getLocation() { - return this.location; - } - - /** - * Gets the maximum size allowed for uploaded files. - * - * @return the maximum size allowed for uploaded files - */ - public long getMaxFileSize() { - return this.maxFileSize; - } - - /** - * Gets the maximum size allowed for multipart/form-data requests. - * - * @return the maximum size allowed for multipart/form-data requests - */ - public long getMaxRequestSize() { - return this.maxRequestSize; - } - - /** - * Gets the size threshold after which files will be written to disk. - * - * @return the size threshold after which files will be written to disk - */ - public int getFileSizeThreshold() { - return this.fileSizeThreshold; - } -} diff --git a/1.x/compatibility/src/javax/servlet/Registration.java b/1.x/compatibility/src/javax/servlet/Registration.java deleted file mode 100644 index 663544f..0000000 --- a/1.x/compatibility/src/javax/servlet/Registration.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.servlet; - -import java.util.Map; -import java.util.Set; - -/** - * Interface through which a {@link Servlet} or {@link Filter} may be - * further configured. - * - *

A Registration object whose {@link #getClassName} method returns null - * is considered preliminary. Servlets and Filters whose implementation - * class is container implementation specific may be declared without - * any servlet-class or filter-class elements, respectively, - * and will be represented as preliminary Registration objects. - * Preliminary registrations must be completed by calling one of the - * addServlet or addFilter methods on - * {@link ServletContext}, and passing in the Servlet or Filter name - * (obtained via {@link #getName}) along with the supporting Servlet or Filter - * implementation class name, Class object, or instance, respectively. - * In most cases, preliminary registrations will be completed by an - * appropriate, container-provided {@link ServletContainerInitializer}. - * - * @since Servlet 3.0 - */ -public interface Registration { - - /** - * Gets the name of the Servlet or Filter that is represented by this - * Registration. - * - * @return the name of the Servlet or Filter that is represented by this - * Registration - */ - public String getName(); - - /** - * Gets the fully qualified class name of the Servlet or Filter that - * is represented by this Registration. - * - * @return the fully qualified class name of the Servlet or Filter - * that is represented by this Registration, or null if this - * Registration is preliminary - */ - public String getClassName(); - - /** - * Sets the initialization parameter with the given name and value - * on the Servlet or Filter that is represented by this Registration. - * - * @param name the initialization parameter name - * @param value the initialization parameter value - * - * @return true if the update was successful, i.e., an initialization - * parameter with the given name did not already exist for the Servlet - * or Filter represented by this Registration, and false otherwise - * - * @throws IllegalStateException if the ServletContext from which this - * Registration was obtained has already been initialized - * @throws IllegalArgumentException if the given name or value is - * null - */ - public boolean setInitParameter(String name, String value); - - /** - * Gets the value of the initialization parameter with the given name - * that will be used to initialize the Servlet or Filter represented - * by this Registration object. - * - * @param name the name of the initialization parameter whose value is - * requested - * - * @return the value of the initialization parameter with the given - * name, or null if no initialization parameter with the given - * name exists - */ - public String getInitParameter(String name); - - /** - * Sets the given initialization parameters on the Servlet or Filter - * that is represented by this Registration. - * - *

The given map of initialization parameters is processed - * by-value, i.e., for each initialization parameter contained - * in the map, this method calls {@link #setInitParameter(String,String)}. - * If that method would return false for any of the - * initialization parameters in the given map, no updates will be - * performed, and false will be returned. Likewise, if the map contains - * an initialization parameter with a null name or value, no - * updates will be performed, and an IllegalArgumentException will be - * thrown. - * - * @param initParameters the initialization parameters - * - * @return the (possibly empty) Set of initialization parameter names - * that are in conflict - * - * @throws IllegalStateException if the ServletContext from which this - * Registration was obtained has already been initialized - * @throws IllegalArgumentException if the given map contains an - * initialization parameter with a null name or value - */ - public Set setInitParameters(Map initParameters); - - /** - * Gets an immutable (and possibly empty) Map containing the - * currently available initialization parameters that will be used to - * initialize the Servlet or Filter represented by this Registration - * object. - * - * @return Map containing the currently available initialization - * parameters that will be used to initialize the Servlet or Filter - * represented by this Registration object - */ - public Map getInitParameters(); - - /** - * Interface through which a {@link Servlet} or {@link Filter} registered - * via one of the addServlet or addFilter methods, - * respectively, on {@link ServletContext} may be further configured. - */ - interface Dynamic extends Registration { - - /** - * Configures the Servlet or Filter represented by this dynamic - * Registration as supporting asynchronous operations or not. - * - *

By default, servlet and filters do not support asynchronous - * operations. - * - *

A call to this method overrides any previous setting. - * - * @param isAsyncSupported true if the Servlet or Filter represented - * by this dynamic Registration supports asynchronous operations, - * false otherwise - * - * @throws IllegalStateException if the ServletContext from which - * this dynamic Registration was obtained has already been - * initialized - */ - public void setAsyncSupported(boolean isAsyncSupported); - } -} - diff --git a/1.x/compatibility/src/javax/servlet/ServletRegistration.java b/1.x/compatibility/src/javax/servlet/ServletRegistration.java deleted file mode 100644 index b65b3ab..0000000 --- a/1.x/compatibility/src/javax/servlet/ServletRegistration.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.servlet; - -import java.util.*; - -/** - * Interface through which a {@link Servlet} may be further configured. - * - * @since Servlet 3.0 - */ -public interface ServletRegistration extends Registration { - - /** - * Adds a servlet mapping with the given URL patterns for the Servlet - * represented by this ServletRegistration. - * - *

If any of the specified URL patterns are already mapped to a - * different Servlet, no updates will be performed. - * - *

If this method is called multiple times, each successive call - * adds to the effects of the former. - * - * @param urlPatterns the URL patterns of the servlet mapping - * - * @return the (possibly empty) Set of URL patterns that are already - * mapped to a different Servlet - * - * @throws IllegalArgumentException if urlPatterns is null - * or empty - * @throws IllegalStateException if the ServletContext from which this - * ServletRegistration was obtained has already been initialized - */ - public Set addMapping(String... urlPatterns); - - /** - * Gets the currently available mappings of the - * Servlet represented by this ServletRegistration. - * - *

If permitted, any changes to the returned Collection must not - * affect this ServletRegistration. - * - * @return a (possibly empty) Collection of the currently - * available mappings of the Servlet represented by this - * ServletRegistration - */ - public Collection getMappings(); - - /** - * Gets the name of the runAs role of the Servlet represented by this - * ServletRegistration. - * - * @return the name of the runAs role, or null if the Servlet is - * configured to run as its caller - */ - public String getRunAsRole(); - - /** - * Interface through which a {@link Servlet} registered via one of the - * addServlet methods on {@link ServletContext} may be further - * configured. - */ - interface Dynamic extends ServletRegistration, Registration.Dynamic { - - /** - * Sets the loadOnStartup priority on the Servlet - * represented by this dynamic ServletRegistration. - * - *

A loadOnStartup value of greater than or equal to - * zero indicates to the container the initialization priority of - * the Servlet. In this case, the container must instantiate and - * initialize the Servlet during the initialization phase of the - * ServletContext, that is, after it has invoked all of the - * ServletContextListener objects configured for the ServletContext - * at their {@link ServletContextListener#contextInitialized} - * method. - * - *

If loadOnStartup is a negative integer, the container - * is free to instantiate and initialize the Servlet lazily. - * - *

The default value for loadOnStartup is -1. - * - *

A call to this method overrides any previous setting. - * - * @param loadOnStartup the initialization priority of the Servlet - * - * @throws IllegalStateException if the ServletContext from which - * this ServletRegistration was obtained has already been initialized - */ - public void setLoadOnStartup(int loadOnStartup); - - /** - * Sets the {@link ServletSecurityElement} to be applied to the - * mappings defined for this ServletRegistration. - * - *

This method applies to all mappings added to this - * ServletRegistration up until the point that the - * ServletContext from which it was obtained has been - * initialized. - * - *

If a URL pattern of this ServletRegistration is an exact target - * of a security-constraint that was established via - * the portable deployment descriptor, then this method does not - * change the security-constraint for that pattern, - * and the pattern will be included in the return value. - * - *

If a URL pattern of this ServletRegistration is an exact - * target of a security constraint that was established via the - * {@link javax.servlet.annotation.ServletSecurity} annotation - * or a previous call to this method, then this method replaces - * the security constraint for that pattern. - * - *

If a URL pattern of this ServletRegistration is neither the - * exact target of a security constraint that was established via - * the {@link javax.servlet.annotation.ServletSecurity} annotation - * or a previous call to this method, nor the exact target of a - * security-constraint in the portable deployment - * descriptor, then this method establishes the security constraint - * for that pattern from the argument - * ServletSecurityElement. - * - * @param constraint the {@link ServletSecurityElement} to be applied - * to the patterns mapped to this ServletRegistration - * - * @return the (possibly empty) Set of URL patterns that were already - * the exact target of a security-constraint that was - * established via the portable deployment descriptor. This method - * has no effect on the patterns included in the returned set - * - * @throws IllegalArgumentException if constraint is null - * - * @throws IllegalStateException if the {@link ServletContext} from - * which this ServletRegistration was obtained has - * already been initialized - */ - public Set setServletSecurity(ServletSecurityElement constraint); - - /** - * Sets the {@link MultipartConfigElement} to be applied to the - * mappings defined for this ServletRegistration. If this - * method is called multiple times, each successive call overrides the - * effects of the former. - * - * @param multipartConfig the {@link MultipartConfigElement} to be - * applied to the patterns mapped to the registration - * - * @throws IllegalArgumentException if multipartConfig is - * null - * - * @throws IllegalStateException if the {@link ServletContext} from - * which this ServletRegistration was obtained has already been - * initialized - */ - public void setMultipartConfig( - MultipartConfigElement multipartConfig); - - /** - * Sets the name of the runAs role for this - * ServletRegistration. - * - * @param roleName the name of the runAs role - * - * @throws IllegalArgumentException if roleName is null - * - * @throws IllegalStateException if the {@link ServletContext} from - * which this ServletRegistration was obtained has already been - * initialized - */ - public void setRunAsRole(String roleName); - - } - -} - diff --git a/1.x/compatibility/src/javax/servlet/ServletSecurityElement.java b/1.x/compatibility/src/javax/servlet/ServletSecurityElement.java deleted file mode 100644 index 5947174..0000000 --- a/1.x/compatibility/src/javax/servlet/ServletSecurityElement.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.servlet; - -import java.util.*; -import javax.servlet.annotation.HttpMethodConstraint; -import javax.servlet.annotation.ServletSecurity; - -/** - * Java Class represntation of a {@link ServletSecurity} annotation value. - * - * @since Servlet 3.0 - */ -public class ServletSecurityElement extends HttpConstraintElement { - - private Collection methodNames; - private Collection methodConstraints; - - /** - * Constructs an instance using the default - * HttpConstraintElement value as the default Constraint - * element and with no HTTP Method specific constraint elements. - */ - public ServletSecurityElement() { - methodConstraints = new HashSet(); - methodNames = Collections.emptySet(); - } - - /** - * Constructs an instance with a default Constraint element - * and with no HTTP Method specific constraint elements. - * - * @param constraint the HttpConstraintElement to be - * applied to all HTTP methods other than those represented in the - * methodConstraints - */ - public ServletSecurityElement(HttpConstraintElement constraint) { - super(constraint.getEmptyRoleSemantic(), - constraint.getTransportGuarantee(), - constraint.getRolesAllowed()); - methodConstraints = new HashSet(); - methodNames = Collections.emptySet(); - } - - /** - * Constructs an instance using the default - * HttpConstraintElement value as the default Constraint - * element and with a collection of HTTP Method specific constraint - * elements. - * - * @param methodConstraints the collection of HTTP method specific - * constraint elements - * - * @throws IllegalArgumentException if duplicate method names are - * detected - */ - public ServletSecurityElement( - Collection methodConstraints) { - this.methodConstraints = (methodConstraints == null ? - new HashSet() : methodConstraints); - methodNames = checkMethodNames(this.methodConstraints); - } - - /** - * Constructs an instance with a default Constraint element - * and with a collection of HTTP Method specific constraint elements. - * - * @param constraint the HttpConstraintElement to be - * applied to all HTTP methods other than those represented in the - * methodConstraints - * @param methodConstraints the collection of HTTP method specific - * constraint elements. - * - * @throws IllegalArgumentException if duplicate method names are - * detected - */ - public ServletSecurityElement(HttpConstraintElement constraint, - Collection methodConstraints) { - super(constraint.getEmptyRoleSemantic(), - constraint.getTransportGuarantee(), - constraint.getRolesAllowed()); - this.methodConstraints = (methodConstraints == null ? - new HashSet() : methodConstraints); - methodNames = checkMethodNames(this.methodConstraints); - } - - /** - * Constructs an instance from a {@link ServletSecurity} annotation value. - * - * @param annotation the annotation value - * - * @throws IllegalArgumentException if duplicate method names are - * detected - */ - public ServletSecurityElement(ServletSecurity annotation) { - super(annotation.value().value(), - annotation.value().transportGuarantee(), - annotation.value().rolesAllowed()); - this.methodConstraints = new HashSet(); - for (HttpMethodConstraint constraint : - annotation.httpMethodConstraints()) { - this.methodConstraints.add( - new HttpMethodConstraintElement( - constraint.value(), - new HttpConstraintElement(constraint.emptyRoleSemantic(), - constraint.transportGuarantee(), - constraint.rolesAllowed()))); - } - methodNames = checkMethodNames(this.methodConstraints); - } - - /** - * Gets the (possibly empty) collection of HTTP Method specific - * constraint elements. - * - *

If permitted, any changes to the returned Collection must not - * affect this ServletSecurityElement. - * - * - * @return the (possibly empty) collection of HttpMethodConstraintElement - * objects - */ - public Collection getHttpMethodConstraints() { - return Collections.unmodifiableCollection(methodConstraints); - } - - /** - * Gets the set of HTTP method names named by the HttpMethodConstraints. - * - *

If permitted, any changes to the returned Collection must not - * affect this ServletSecurityElement. - * - - * - * @return the collection String method names - */ - public Collection getMethodNames() { - return Collections.unmodifiableCollection(methodNames); - } - - /** - * Checks for duplicate method names in methodConstraints. - * - * @param methodConstraints - * - * @retrun Set of method names - * - * @throws IllegalArgumentException if duplicate method names are - * detected - */ - private Collection checkMethodNames( - Collection methodConstraints) { - Collection methodNames = new HashSet(); - for (HttpMethodConstraintElement methodConstraint : - methodConstraints) { - String methodName = methodConstraint.getMethodName(); - if (!methodNames.add(methodName)) { - throw new IllegalArgumentException( - "Duplicate HTTP method name: " + methodName); - } - } - return methodNames; - } -} diff --git a/1.x/compatibility/src/javax/servlet/annotation/HttpMethodConstraint.java b/1.x/compatibility/src/javax/servlet/annotation/HttpMethodConstraint.java deleted file mode 100644 index 1a5e813..0000000 --- a/1.x/compatibility/src/javax/servlet/annotation/HttpMethodConstraint.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package javax.servlet.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; -import javax.servlet.annotation.ServletSecurity.TransportGuarantee; - -/** - * This annotation is used within the {@link ServletSecurity} annotation to - * represent security constraints on specific HTTP protocol messages. - * - * @since Servlet 3.0 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface HttpMethodConstraint { - - /** - * Http protocol method name - * - * @return the name of an HTTP protocol method. value - * may not be null, or the empty string, and must be a - * legitimate HTTP Method name as defined by RFC 2616. - */ - String value(); - - /** - * The default authorization semantic. - * This value is insignificant when rolesAllowed returns a - * non-empty array, and should not be specified when a non-empty - * array is specified for rolesAllowed. - * - * @return the {@link EmptyRoleSemantic} to be applied when - * rolesAllowed returns an empty (that is, zero-length) array. - */ - EmptyRoleSemantic emptyRoleSemantic() default EmptyRoleSemantic.PERMIT; - - /** - * The data protection requirements (i.e., whether or not SSL/TLS is - * required) that must be satisfied by the connections on which requests - * arrive. - * - * @return the {@link TransportGuarantee} - * indicating the data protection that must be provided by the connection. - */ - TransportGuarantee transportGuarantee() default TransportGuarantee.NONE; - - /** - * The names of the authorized roles. - * - * Duplicate role names appearing in rolesAllowed are insignificant and - * may be discarded during runtime processing of the annotation. The String - * "*" has no special meaning as a role name (should it occur in - * rolesAllowed). - * - * @return an array of zero or more role names. When the array contains - * zero elements, its meaning depends on the value returned by - * emptyRoleSemantic. If emptyRoleSemantic returns - * DENY, and rolesAllowed returns a zero length array, - * access is to be denied independent of authentication state and identity. - * Conversely, if emptyRoleSemantic returns - * PERMIT, it indicates that access is to be allowed - * independent of authentication state and identity. When the array - * contains the names of one or more roles, it indicates that access is - * contingent on membership in at least one of the named roles (independent - * of the value returned by emptyRoleSemantic). - */ - String[] rolesAllowed() default {}; -} diff --git a/1.x/env.xml b/1.x/env.xml deleted file mode 100644 index 5eb9ca5..0000000 --- a/1.x/env.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - : - - - - - - - - - /jre - - - - - - - - - - . - - changeme - - - 1.6 - - - 1.7 - - - no - - - maven:javax.servlet:servlet-api:2.3 - - - maven:javax.servlet:javax.servlet-api:3.1.0 - - compatibility/build/compat-jsr315+.jar - - - ..\..\servlet\jsr154\src\share - - - ..\..\servlet\jsr315\lib - - - - - maven:javax.websocket:javax.websocket-api:1.1 - - - C:\tools\libs\websocket-spec~source-code-repository\trunk\api - - - - - - - - - - - ../..\jasper7\build\jasper.jar - - - ../..\jasper7\build - ../..\jasper7\java - - - - C:\tools\adt-bundle-windows-x86_64-20140702\sdk\platforms\android-10\android.jar - - - C:\tools\libs\bouncy castle\lib\bcprov-jdk15on-146.jar - - - - - - - - - C:\tools\libs\java\ - - /lib/rt.jar - - C:\tools\libs\java/ - - /lib/jsse.jar - - C:\tools\libs\java/ - - /lib/jce.jar - - - - - - ..\java_runtime\ - - /lib/rt.jar - - ..\java_runtime\ - - /lib/jsse.jar - - - - - - ../../fast-classpath-scanner/lib/class-scanner.jar - ../../fast-classpath-scanner/lib \ No newline at end of file diff --git a/1.x/html/readme.html b/1.x/html/readme.html deleted file mode 100644 index 3a7b367..0000000 --- a/1.x/html/readme.html +++ /dev/null @@ -1,1082 +0,0 @@ - - - - - - -Tiny Java Web Server aka Miniature JWS - - - - - -

Tiny Java Web Server and Servlet Container

- -

aka Miniature JWS

-

European quality software made in USA

-

(with Android SSL support)

-

Truth is ever to be found in simplicity, and not in the multiplicity and confusion of things.

- - - - - - -
Download7Bee
-
    -
  1. Introduction
  2. -
  3. Features
  4. -
  5. History
  6. -
  7. Competitors
  8. -
  9. Design
  10. -
  11. Configuration - -
  12. -
  13. J2EE deployment
  14. -
  15. App server services (JNDI, DataSource)
  16. -
  17. Embedded usage
  18. -
  19. Embeddable application
  20. -
  21. Mobile and appliance usage
  22. -
  23. Virtual hosting configuration
  24. -
  25. Proxied usage
  26. -
  27. Download
  28. -
  29. Build
  30. -
  31. Applications
  32. -
  33. VM
  34. -
  35. Support
  36. -
  37. Versions
  38. -
  39. Copyright
  40. -
  41. Contact
  42. -
-
- Construction zone -
-

- Introduction

-

- The Miniature Java Web Server is built as a servlet container with HTTPD servlet providing - standard Web server functionality. The server is a small as in Java code -as in a result byte code. General purpose of the Web server is running and -debugging servlets. However, it can be used as a regular web server for sites -with low to medium load. I found also -very convenient shipping a servlet based product packaging with the server, so a user -can start a product just after unwrapping. You can try a web -site hosted on this server on a private Cloud. This web server also works on PDA and smart phones as Android and Blackberry based, or on Windows CE based when JVM installed. - It gives additional flexibility for your phone, since using WebFolder (WebBee web app) - - can simplify file synchronization and provide control of your phone from web.

- - - - - -
-

Testimonies

-

Using tjws with WebServices as a "RMI"/RPC protocol, and with - HTTPS on
- top, this is gold! Thanks!

-

I've downloaded - TJWS and it looks like - exactly what I"e;ve been looking for to use as a local web server to - generate a web application. -

I'm using the miniature java webserver on
- my zaurus.
- I wrote a few servlets for it and I'm very happy with how it performs. -

- TJWS was the only thing out there I found I could use -as a library, programmatically within unit tests. Thanks for a great -library. -

-

Features and Benefits

-
    -
  • About 100Kb footprint (TJWS is the smallest one, like - 5 times less than competitors LWS - and Jetty, - more than twice less than Winstone)
  • -
  • Very fast and reliable, it performs better than some C/C++ based web servers, 10% - faster than Apache 2.x
  • Can scale to thousands connections, clustering configuration is about of - development
  • -
  • A perfect solution for web interfaced applications
  • -
  • Standard J2EE servlet deployment for .war packaged applications
  • -
  • Simple configuration, no hundreds of config parameters
  • -
  • Flexible JSP support
  • -
  • Limited JSS 3.0 support (JSR 315)
  • -
  • JSR 356 support (websocket). See release notes
  • -
  • Built for Java 7 with intelligent downgraded support for Java 2 -
  • -
  • Runs on Android and Blackberry platforms out of the box
  • -
-

History

-

I was looking for a web server with sources to debug some servlets at the end of 1998. One of my findings - -was ACME Java Web Server. It was pretty good, but supported only JSS 1.x and JDK 1.02. Since my servlets required a bit more, I have added -support for contemporary versions of JDK and JSDK. I just continued adding -more features and providing bug fixes after. The current version is mostly -compatible with the latest servlet container specification (3.1) and offers also websocket support.

-
-

- Competitors

-

- Main competitors for TJWS are Winstone, LWS, and Jetty. TJWS can successfully compete - with more established and reputable servers as Tomcat, Glassfish, and JBOSS. Main benefits of TJWS are - simplicity and tiny footprint.

-

- Design -

-

- Modular design is used for TJWS. It gives a flexibility of creation different configurations - with exactly required features. A heart of TJWS is a light weight servlet container. - A set of predefined servlets extends functionality of the container transferring - it to a web server or/and an application server. Predefined servlets can be eliminated - or redefined for extra flexibility.

-

-

-

- Selecting or not J2EE deployment gives an extra flexibility in a final -size of a deployed application. Like for an embeddable or a mobile application is possible -to use Java Personal Profile 1.x compatible servlet container module. For -less critical in size deployment is possible to use J2EE deployment module and -JSP module. Originally provided GNU JSP providers have been withdrawn from latest TJWS version for keeping pure -BSD license, however GNU JSP providers can be reached in previous versions. I do not support them anyway. -Only Jasper is currently supported as JSP provider. However I separate it to avoid any licensing issues. -Base module, and J2EE deployment modules have sizes 110K, and 80K -correspondingly. Jasper's size is about 930K. (I am still looking for help to separate Jasper on runtime and JSP parsing and compilation parts, -it could be beneficial for Android deployment.) App server services module adds 46Kb. And finally websocket module adds 65Kb

-

- Configuration

-

- Most of server configuration is based on command line arguments. The arguments can - be processed from a file as well. Additional configuration values can be provided - over files. J2EE deployed application are configured based on standard web.xml deployment - descriptor.

-
- Command line parameters
-

All command line parameters start with '-' (dash) and most of them have a following value -part. Here they are:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pspecifies port number served by TJWS, default value is 80 for non secure -and 443 for secure configuration, for example -p 8080
tspecifies name of throttles definition file. It allows to reduce -speed accessing to particular files and improve overall performance of a server. -An example of this file can look like: - - -
-

-# throttle file for tjws.sourceforge.net
-*               100000  # limit total web usage to 2/3 of our T1
-*.jpg|*.gif     50000   # limit images to 1/3 of our T1
-*.mpg           20000   # and movies to even less
-mediachest/*    20000   # MediaChest's pages are too popular
-
-
sspecifies servlet properties file in old Sun's legacy form. An example of -this file can look like: - - -
-
servlet./app-bin/tree/*.code=rogatkin.servlet.Dispatcher
-servlet./app-bin/tree/*.initArgs=properties=src\javaarchitect\servlet\treeview.properties
-servlet./app-bin/chat/*.code=rogatkin.chatservlet.ChatServlet
-servlet./app-bin/chat/*.initArgs=properties=C:\\Projects\\ChatServlet\\chatservlet.properties
-servlet./app-bin/lunch.code=javaarchitect.servlet.mishka.Friday
-servlet./app-bin/lunch.initArgs=properties=src\javaarchitect\servlet\mishka.properties
-
-
-Here servlet. is just keyword. Next part is servlet URL mapping and -servlet name at the same time. Mapping notation was changed since 1.93 to match servlet specification, -so /* should be added to old notation. Next part is dot (.) separator of servlet class name, when code used, -or init arguments comma separated name=value pairs when initArgs is used.
rspecifies realm file. A format of this file looks like: - - -
-
realmname=path,user:password
-
Path has similar notation as servlet mapping URL.
aspecifies aliases definition file. Every line of the file -specifies one alias entry starting from keyword from=webpath;dir=directory_in_filesysten_to_map, for example: - - -
-
from=/;dir=src\javaarchitect\servlet\tree\resource
-from=/pool;dir=data
-
bbind address, if your machine has several IP addresses, then you can -specify which one to use
kbacklog size, by default 50, but can't be less than 2
nohupserver doesn't expect any terminal window, can be only killed to -stop
cspecifies a web path of CGI scripts directory
eprovides session timeout in minutes and can be negative. Negative value -won't start session cleaning thread and will use a persistent session cookie
mlimits max number of active sessions by a specified value, - can't be less than 10. Default value is no limitation
l[ar][f format_string]specifies to log accesses with optionally logged user-agent and -referer HTTP headers. When f modifier specified a format string - has to follow which is a valid format string for java.text.MessageFormat class. - Positions of parameters are: - - -
    -
  1. IP
  2. -
  3. RFC 1413 identity
  4. -
  5. Remote user
  6. -
  7. Timestamp
  8. -
  9. Request method
  10. -
  11. Request Resource
  12. -
  13. Request Protocol
  14. -
  15. Result code
  16. -
  17. Bytes transferred to client
  18. -
  19. Local port
  20. -
  21. Referer (if requested)
  22. -
  23. User agent (if requested)
  24. -
-
grequests rolling log file after reaching parameter specified line numbers. Can't be made less than 1000, and no rolling used if not specified or parameter is 0. Since 1.102
wprovides web app deployer class name, by default used rogatkin.web.WarRoller
jJSP servlet class, org.gjt.jsp.JSPServlet is default; extra init parameters can be specified -for JSP servlet; -syntax of parameters is -class_name_perfix.param_name param_value; note that value -can contain variables like %context% and %deploydir% substituted by actual -values respectfully. Another substitution happens for %classloader% by -a -name of a servlet context attribute keeping an instance of a class loader used for a web -application deployment (available from version 1.15). Version 1.22 and above -introduced another variable %classpath% which substituted by class path used for -loading servlet
nkano keep alive (server uses keep-alive by default)
katkeep alive timeout interval in seconds, default is 30
mkamax number of a connection use in keep-alive
shHTTP only attribute for session cookie. Can improve a security. A session - cookie doesn't carry this attribute by default. Since 1.90
ssSecure only attribute for session cookie. Can improve a security. A session - cookie doesn't carry this attribute by default. Since 1.99
sppersistence for sessions, TJWS is capable storing sessions data -in a portable format and reload them between restarts or nodes of a cluster. Do -not use this option if sessions contain -sensitive, not serializable, or bulky data
errallows to use own or standard error print stream. If there is no -following parameter class name then used System.err as error print -stream. If a parameter specified, then it's considered as a class name -compatible for assignment to PrintStream. Such class will be instantiated -and used for error redirection
outallows to define own class which will handle log needs. This -class has to be assignment compatible with PrintStream. An attempt of -instantiation of the class with default constructor happens at TJWS startup, so -the class has to be available in startup class path. This class will handle err -stream too unless -err option is specified. TJWS includes class -Acme.Utils$DummyPrintStream for disabling any log printing. (since 1.26)
dLog file directory for default logging, System.getProperty("user.dir") is used by default (since 1.30)
zdefines max number of created threads in a thread pool used for -servicing requests. 20 used when the parameter not defined. 0 or negative - do -not use thread pool
socketFactoryspecifies class name of socket factory and used for setting -a secure connection. (deprecated since 1.30) -

It accepts also any freely specified options in form -option_name option_value. -Such options passed without checking to a custom server socket factory -implementation and other modules of the server

acceptorImplspecifies a class name of a concerete Acceptor - implementation. Default is Acme.Serve.SimpleAcceptor (since 1.31). See note above about processing - additional connection parameters. Since 1.30
dataSourcespecifies a data source properties file location. Supported by rogatkin.app.Main - run module. Since 1.30
- - This option is valid only for app server runner (class rogatkin.app.Main)
- TJWS .war deployer can process also context.xml file - supplied in META-INF directory of application .war for same purpose. Since 1.98. - A property file can contain the following properties: -
    -
  • jndi-name (required) - under this name the data source will be registered in JNDI - if name starts with jdbc, then prefix java:comp/env/ will be added when registered in JNDI. -
  • driver-class - class name of JDBC driver -
  • url - JDBC connection URL -
  • user - connection user -
  • password - connection password -
  • pool-size - max number of allocated connections, 0 = no size limitation, -1 = no pool used -
  • access-timeout - timeout in ms before getting an exception on connection request when no connections - are available, 0 means wait forever -
  • driver-class-path - defines class path to a driver archive and/or a - connection validator class, unless they are already defined  in a boot classpath -
  • prob-query - a query to run against a given connection to verify a - validity, There are two predefined values IsValid and isClosed - used for calling corresponding methods of JDBC connection - instead of a query. Note that isValid() method is available in JDBC 3. -
  • exception-handler- a class with static public boolean method validate and two parameters of type SQLException, and Connection - returning false when the connection has to be discarded after the SQLException -
- Here is a quick map between properties names and context.xml Resource tag attributes: - - - - - - - - - -
jndi-namename
driver-classdriverClassName
urlurl
userusername
passwordpassword
pool-sizemaxActive
driver-class-pathdriverClassPath
prob-queryvalidationQuery
-
-

- TJWS processes several Java System level definitions in addition to command line arguments - specified as JVM's -D arguments:

-

- tjws.serve.log.encoding - this definition specifies encoding - used for log messages, it can be very convenient to debug multi lingual web - applications.

-

- tjws.proxy.ssl - this definition specifies that server should process - X-Forwarded-xxxx headers for calculation remote and server addresses. If value of the property 'y', - then SSL is considered to be handled by a proxy server. (Since 1.71)

-

- java.protocol.handler.pkgs - this definition is used by SSL - socket factories implementations to define a different protocol handler - packages, than standard com.sun.net.ssl.internal.www.protocol

- -

The following definitions are used by J2EE servlet/deployer module:

-

- tjws.webappdir - specifies path to web application war files location - for automatic deployment. By default TJWS_ROOT/webapps directory is used.

-

- tjws.webclassloader - specifies custom class loader class name used for loading classes - from war file. The class loader must to have constructor accepting parameters as URL[] and - ClassLoader. Since 1.83

-

- tjws.wardeploy.warname-as-context - see details below.

-

- tjws.wardeploy.as-root[.virtual_host_name] - defines context name/war name used for deploying - in root, e.g. -Dtjws.wardeploy.as-root=<app_context/war_name> If virtual host name part is presented, then it defines a fully qualified - host name for which the root context is set. (Since 1.71)

-

- tjws.virtual - defines deployment of web applications in virtual hosting environment.
-
- When the definition is specified, TJWS J2EE web applications deployer looks in all subdirectories - under automatic web application deployment directory and considers directory name as virtual - host name and directory content as automatic web application deployment directory for - corresponding virtual host.

- For example: -

-           TJWS_ROOT/webapps
-               www.travelspal.com
-                   travelspal.war
-                   webfolder.war
-               www.7bee.org
-                   sqlfair.war
-                   webchat.war
-               xumster.war
-               jaddressbook.war
- -

(Since 1.71) -

-

- class_name.debug - this definition is passed to JSP provider - for allowing debug specified class name.

-

- tjws.fileservlet.usecompression - this definition advises to compress text - content response when a client can accept it. To make this suggestion per application, - use tjws.webapp.<context_name>.compressresponse Since 1.31

-

- tjws.fileservlet.suppressindex this definition advises the file servlet - to do not show content of a directory when an index file can't be found. Since 1.96

-

- tjws.wardeploy.dynamically - this definition advises J2EE deployer for - monitoring .war files updates and redeploy corresponding applications without the server - restart. Optional value of this definition specifies time interval in seconds between checks. Since 1.50

-

- tjws.wardeploy.noincremental - instructs TJWS redeploy entire web application when newer version of - .war detected. Default is incremental deployment overriding only older files and not touching added. Since 1.93

-

- tjws.webapp.context name.init.timeout - specifies init timeout in seconds of - corresponding web application by context name, use * if you need to define it for all contexts

-

- tjws.webapp.context name.threadpoolsets - specifies core, max threads, - and queue size a thread pool of corresponding web application by context name, use * if you need to define it for all contexts. Since 1.80

-

- tjws.webapp.debug - value yes turns on additional debug print outs for J2EE deployed apps

-

- tjws.app.orb.arguments - this definition can provide comma - separated parameters used for ORB initialization. Since 1.50

-

tjws.app.main - name of main class started with offering app server services. TJWS supports not - only web applications, any desktop Java application can get benefits of app server services - as JNDI and container managed JDBC connections. Since 1.50 -

-

tjws.app.main.classpath - class path for main application class specified - as definition tjws.app.main, unless the main class can be resolved from boot class path. Since 1.50 -

-

tjws.app.main.striprightparam - specifies a position in command line arguments which have to be not - passed to a main class defined in tjws.app.main. It gives flexibility of separate - command line arguments used by launched application and app server services itself. Since 1.50 -

-

tjws.app.main.stripleftparam specifies a position to cut from left. See description of - tjws.app.main.striprightparam. Since 1.50 -

-

tjws.websocket.container "true" value specifies that websocket end points can be deployed in scope of TJWS itself (not in scanning from a .war packaged web application) - - TJWS class path is used for such deployment. The option is useful for embedded usage of TJWS. Since 1.111 -

-

- Since TJWS has a long history it supports as a legacy way of deployment and configuration - of servlets as a new .war (web.xml) based. The legacy deployment uses property -files, like servlets.properties and aliases.properties. J2EE way is based -on web.xml and config.xml files. When a legacy way used, the server can keep a minimal -configuration and run on JDK version started from 1.2 (Actually the current version has 9 JDK - 1.4 dependencies which can be easily corrected if JDK 1.2 is a real requirement). Websocket - extension deployment uses the modern annotated classes mechanism. -

-

- Security

-

Security becomes more important nowadays, so I decided to add SSL support to -TJWS. Thanks JSSE for making that fairly easy. Here some tips how to install SSL -support to the server.

-
    -
  • Download JSSE from Oracle's website or use JDK1.4.2 or later already including this extension.
  • -
  • Generate certificate using command like: keytool -genkey -keypass 123456 -storepass 123456 -keyalg RSA
    - Read more details in keytool documentation when you need a certificate signed - by CA. Tomcat's how-to for SSL can be useful also.
  • -
  • Add command line parameter -socketFactory socket_factory_class_name - and enjoy the show.
  • -
-

There are three SSL supporting socket factories packaged with TJWS - Acme.Serve.SSLServerSocketFactory -, rogatkin.web.DoubleHeadSocketFactory (available from v 1.17), and -rogatkin.wskt.SSLSelectorAcceptor (available from v 1.110). First is recommended to use -with core TJWS, when second with J2EE deployment module since it provides -supporting http and https at the same time and requires Java 5+. Third is required for websocket configuration. 7Bee script -contains examples of usage two factories. Command bee -Dsecure=true runs TJWS using SSLSelectorAcceptor, and bee -Ddoublehead=true runs DoubleHeadSocketFactory. -Additional command line parameters can be specified with each factory like :

-
    -
  1. algorithm - encryption algorithm, SUNX509 when not specified
  2. -
  3. clientAuth - requires client authentication, false when not - specified
  4. -
  5. keystoreFile - key store file path, user_home/.keystore by - default
  6. -
  7. keystorePass - key store password, empty string when not - specified
  8. -
  9. keystoreType - type of key store, Oracle's JKS when not specified
  10. -
  11. protocol - secure protocol, TLS when not specified
  12. -
  13. backlog - backlog value, 1000 by default
  14. -
  15. ifAddress - bind to specified address
  16. -
  17. port - bind to specified port
  18. -
  19. ssl-port  SSL port (only for DoubleHeadSocketFactory and rogatkin.web.DualSocketAcceptor - )
  20. -
  21. ssl-backlog backlog size (only for DoubleHeadSocketFactory and rogatkin.web.DualSocketAcceptor)
  22. -
-

- Note that some secure socket options will override options specified in a -regular way.

-

You may also adding your own socket factory implementations. See the -packaged socket factories as a reference implementation.

-

- Starting from 1.30 Socket Factory concept was replaced by Acceptor. It allowed to - use Selector based processing requests with 10% improved performance and required for websocket. - Five concrete Acceptor implementations are available:

-
    -
  • Acme.Serve.SelectorAcceptor - non secure, channel based implementation (use with websocket in non blocking IO mode).
  • -
  • rogatkin.wskt.SSLSelectorAcceptor - secure, channel based implementation (use with websocket in non blocking IO mode).
  • -
  • Acme.Serve.SimpleAcceptor - non secure, server socket based implementation, is used by - default.(since 1.31)
  • -
  • Acme.Serve.SSLAcceptor - secure, SSL socket based implementation.
  • -
  • rogatkin.web.DualSocketAcceptor - combined secure and non secure sockets implementation.
  • -
-

- The author appreciates if you can share own implementations of Acceptor.

-
- J2EE deployment -
-

- For J2EE deployment you need to make sure that war.jar is specified in classpath - when you start the server. It will create webapps directory (configured location) where you can put your - .war files for auto deployment. Deployment gets updated at startup absorbing any changes from source .war file, - however all changes done in target deployment directory are preserved. TJWS can monitor also source .war changes - during runtime when tjws.wardeploy.dynamically is specified, and redeploy - application if changes were detected. server.xml - isn't supported and most of server specific parameters have to be specified as command - line arguments, or stored in a flat file as cmdparams. All examples of startup - scripts are presented in directory bin of a distributive archive. Most of examples - contain both ways of server configuration and application deployment. Note that - deployment descriptor (web.xml) parameter display-name defines a context - path of a deployed web application. If you want to have context path matching to - .war name then add system property tjws.wardeploy.warname-as-context set to yes. - For command line it will look like -Dtjws.wardeploy.warname-as-context=yes . (Since - 1.24) To prevent application update at startup time you need to remove corresponding - .war from deployment directory. It gives also a way to deploy web applications without - .war just manually create web app directory structure. Check section 'Embeddable - application' for more options of deployment and distribution of applications.

-

- Supported web.xml deployment tags are:

-
    -
  • context-param - yes
  • -
  • filter - yes
  • -
  • filter-mapping - yes
  • -
  • listener - yes
  • -
  • servlet - yes
  • -
  • servlet-mapping - yes
  • -
  • session-config - yes
  • -
  • mime-mapping - yes
  • -
  • welcome-file-list - yes
  • -
  • error-page - yes
  • -
  • taglib - by JSP provider
  • -
  • resource-env-ref - yes
  • -
  • resource-ref - yes
  • -
  • security-constraint - in work
  • -
  • login-config - in work
  • -
  • security-role - in work
  • -
  • env-entry - yes
  • -
  • ejb-ref - no
  • -
  • ejb-local-ref - no
  • -
  • new JSR315 - yes
  • -
  • new JSR356 - yes
  • -
  • multipart-form - this is non standard tag carries a function of a casual multipart request processing similar to Resin. Since 1.112
  • -
- -

App server services

-

-TJWS includes app server services module. It takes some usable shape from version 1.50. There are two services offered:

-
    -
  • Data source with connection pooling -
  • JNDI -
-

For using these services app.jar has to be in class path, or/and used for starting the server. The bin directory includes an example of starting TJWS with app server services on. Data sources get configured from properties files specified as �dataSource command line option. JNDI properties as context factory and JNDI URL get pre-populated as - rogatkin.app.SimpleJndi and http://localhost:1221 - correspondingly, unless they are defined as system properties. JNDI is capable to register local and CORBA objects. First running JNDI takes care of JNDI master repository, and all following JNDI starts will be registered in the master repository. If the master repository's gone, then all clients won�t be capable to register own CORBA objects or access them, until the repository is back. There is no persistence for stored references, so you should - do a defended programming and reregister references in case of crashing the master repository.

-
context.xml
-

Data source definition can be specified in context.xml placed under META-INF directory of .war structure. (since 1.98)

-
- 3.0 Deployment descriptor
-

Multiple URL patterns can be defined anywhere. Some other features are under -consideration. Work on -processing annotations in a servlet code started. Async and multi part features are supported.

-
- Jasper JSP provider integration
-

You can use Jasper JSP provider for servicing JSP pages inside an - application. Since the original Jasper is a bit bulky for TJWS taste, it's - recommended to strip it to a manageable size. TJWS distribution - includes instructions how to modify, build, and connect Jasper in - jasper.html of webroot directory Jasper of respectful Tomcat versions 5.x, 6.x (since 1.28), and 7.x (since 1.83) is supported. -

-

- Running it as a service on all Windows platforms

-

You can run the server of the version (>1.42/1.7) as Windows service. File -servservice.exe added to the distribution. I wrote this service for JDK -1.4. It works without a change for Java 5 and 6. C source code of service implementation is included. A service starter considers that all TJWS files reside in the same -directory specified at installation of the service. .jar files can be in sub -directory lib. Command line parameters have to be specified in cmdparams -file. Use -nohup switch to avoid a console read attempt. To get help line, run servservice.exe --help. Parameterless version of servservice.exe is considered as a -service.

-

Note that arg[0] which supposes to give a fully qualified name of a service -executable on some versions Windows ((like XP) doesn't do that. For this reason -you have to specify a fully qualified path as the last parameter of an -installation command. -There is no requirements to have servservice.exe in the same -directory where TJWS is. Here is an example of an installation command:
-servservice.exe -install "C:\Project Files\tjws" "C:\Project Files\gnujsp\lib\jspengine.jar" TinyJavaWebServer TinyJavaWebServer "C:\Project Files\tjws\servservice\Debug\servservice.exe" -Dtjws.wardeploy.warname-as-context=yes

-

Running it as a service on all Linux platforms

-

A Linux service script example tjwserv is provided in bin directory of the distribution archive. -It has to be edited to reflect particular TJWS installation directory structure. The script has to be stored in -/etc/init.d/ location. Use command update-rc.d tjwserv defaults to enable the service. -You can control it using command service tjwserv <start|stop|restart>. Look in Raspberry PI -setup section for enabling service on Arch Linux and other systems using systemd.

- - -

- Embeddable application

-

Recently, a new type of application appeared on the market. After starting an -application is launching a browser which represents its UI. This approach has many advantages and becomes more -popular and wider used. The -Miniature Java Web Server is a right tool for creation such kind of application. -Download -and double click JAR in Explorer or launch it from a terminal typing java -jar - -finesearch.jar, -then point browser to http://localhost:8080/finesearch -and enjoy the web interfaced application. Starting from version -1.21 TJWS includes a launcher of a .war packaged application from command line or a -start script. The feature is very similar to used by Winstone.  Use:
-java -jar webapplauncher.jar war_file_name [optional standard TJWS CLI -parameters]
-for example:
-java -jar webapplauncher.jar "C:\Project Files\finesearch\finesearch_app\finesearch.war"
-Note if extra command line arguments are not specified, then TJWS will try to -discover them from cmdparams located in a working directory.
-Version 1.22 and above makes launching Web UI application even more simpler. Web -application .war can be packaged inside of TJWS .jar file allowing one click -launch. To package web application .war with TJWS use target 'embedded' of -7Bee -build tool and answer on few simple questions. For example:

- - - - - -
- C:\Project Files\tjws>bee - embedded
- Launcher's been built.
- Enter command line arguments for app [-nohup -p 80]? -p 80
- Enter application .war file location? C:\Project Files\finesearch\finesearch_app\finesearch.war
- As result finesearch.jar is created in lib directory which is launchable - using java -jar finesearch.jar
When JDK 6 is used you can get -it running in system tray, use javaw for JAR launching.
-
- System tray menu will contain an item for going directly to an application - with web UI (since 1.24).
- Use 7Bee target asembedded, when web application needs container provided - JNDI and data sources. (since 1.50). - -
J2EE without application server
-

TJWS gives a good possibility to create enterprise class J2EE applications -without an expensive and heavy weight application server. -WebBee library will -take care of SOA registry, MVC servlet framework with template based -presentation layer, data persistence and -much more. Check out a demo -of a real application based on this approach. New generation of web application building blocks WebBee -with annotated JDO and forms makes creation of rich application possible even for Android platform.

-

- Embedded usage

-

- TJWS can be successfully used as a part of another Java application. Acme.Serve.Serve - can be instantiated as a Java bean with following setting parameters in its public member - arguments and log print stream in its public member logStream. - Use method addServlet(..) for adding servlets. Note that - server will do nothing without servlets. Default file (HTTPD) and cgi servlets can be added - calling addDefaultServlets(...). Server can be started calling - method serve() and stopped calling notifyStop(). - Note that serve() doesn't exit until a server runs, so stopping should be called - from a separate thread, or serve() is ran in a separate thread.
- A minimal application with embedded TJWS looks like:

-
public class Test {
-	public static void main(String... args) {
-		class MyServ extends Acme.Serve.Serve {
-			// Overriding method for public access
-                        public void setMappingTable(PathTreeDictionary mappingtable) { 
-                              super.setMappingTable(mappingtable);
-                        }
-                        // add the method below when .war deployment is needed
-                        public void addWarDeployer(String deployerFactory, String throttles) {
-                              super.addWarDeployer(deployerFactory, throttles);
-                        }
-                        public void addWebsocketProvider() { // add if plan to deploy websocket endpoints
-                            addWebsocketProvider(null); // list of class path file components can be provided here
-                        }
-
-                };
-
-		final MyServ srv = new MyServ();
- 		// setting aliases, for an optional file servlet
-                Acme.Serve.Serve.PathTreeDictionary aliases = new Acme.Serve.Serve.PathTreeDictionary();
-                aliases.put("/*", new java.io.File("C:\\temp"));
-		//  note cast name will depend on the class name, since it is anonymous class
-                srv.setMappingTable(aliases);
-		// setting properties for the server, and exchangeable Acceptors
-		java.util.Properties properties = new java.util.Properties();
-		properties.put("port", 80);
-		properties.setProperty(Acme.Serve.Serve.ARG_NOHUP, "nohup");
-		properties.setProperty("acceptorImpl", "Acme.Serve.SelectorAcceptor"); // this acceptor is requireed for websocket support
-		srv.arguments = properties;
-		srv.addDefaultServlets(null); // optional file servlet
-		srv.addWebsocketProvider();  // enable websocket
-		srv.addServlet("/myservlet", new MyServlet()); // optional
-		// the pattern above is exact match, use /myservlet/* for mapping any path startting with /myservlet (Since 1.93)
-		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
-			public void run() {
-				srv.notifyStop();
-				srv.destroyAllServlets();
-			}
-		}));
-		srv.serve();
-	}
-}
- 
-

The File servlet without aliases definitions maps your file system directly to a web accessable one, so setting up aliases is recommended.

- -

J2EE servlet deployment is possible in an embedded usage. You need to assure -that JDK 1.5 or above is used and war.jar is in a class path of an -application.
- -Add a line as below: -

-
-      ((Test$1)srv).addWarDeployer(null, null);
-
-

-The default war deployer will look in directory "user.dir/webapps" and -deploy all wars there. You can redefine a deploy repository by setting -

- -System.setProperty("tjws.webappdir", newDeployDirectory); - -

-prior of calling addWarDeployer()

-

TJWS works perfectly on Android platform as embedded server enriching your Android application by - a capability to receive uploads, check - Kamerton application using TJWS for uploading music to Android device.

- -

- Mobile and appliance usage

- TJWS provenly runs on wide specter mobile devices as Sharp Zaurus, Windows CE/Mobile, all Android, and Blackberry platforms. Java - gives great portability of TJWS between different mobile devices. -
- Run it on Zaurus
-

Zaurus version is currently retired, since Zaurus has been replaced by Android.

-
Run it on Windows Mobile
-

Since Microsoft dropped Java and allow to install only products from mobile store on Windows surface tablets, here is -no good possibility to run TJWS. So here is a plan to create Objective C and C++ library supporting core -functionality of TJWS to be able to run it on iOS and Windows Mobile platforms.

-
Run it on Raspberry Pi
-

TJWS is naturally created for running web applications on Raspbery Pi. It will outperform most of other application -servers on the platfrom including Jetty, JBOSS and Tomcat. Start time for it is just around 11 seconds, when you can - observe times close to 1 minute with -other application servers. Here are few notes helping to start using it:

-
    -
  • Debian "wheezy" is preferred as OS for Raspberry Pi and TJWS
  • -
  • Download Oracle JRE marked as Linux ARM v6/v7 Hard Float ABI
  • -
  • If you use Linux "dd" utility on Ubuntu to transfer Debian image to SD card, then keep it mounted and - use device name as /dev/sdc (last letter can be "b" for some systems)
  • -
  • There is a good resource for beatifying JRE installation
  • -
-

If you plan to use Raspberry Pi mostly as server operating 24/7, then I recommend to install Arch Linux especially if your network connection is wireless. -Since Arch Linux specific is less covered on net, I prepared my own guide which can help you start using -TJWS faster.
-Raspberry Pi development is certainly addicting, so if you are on same boat feel free to drop me a note. -

-
Run it on Android devices
-

TJWS provides Android packaging for run the server on Android devices. This packaging got name -Atjeews and provided as a separate download. Atjeews is also available at Google Play under same name. Atjeews is just a small server launcher -Java program. The server runs FileServlet against Android root directory "/". You can deploy -any web application on it just loading war files. Atjeews can be mapped to any port and supports SSL. -

 
- Since Android devices use Dalvik JVM, you need to -convert all content of WEB-INF/lib and class directories of your web application to DEX format - supported by Dalvik. Use DX tool for that.
-The following command will work:
-dx --dex --output=<original_jar_file> <dalvik(dex) jar>
-Please note that your web -application has to be JDK 1.5 compatible since Android OS below version 3.0 supports only Java 1.5. - -7Bee script (7Bee version of 1.1.1 or above required) is availble for converting war files to format supported by Android platfrom. -The script is highly recommended to use when your web application includes JSP pages, since -the script take care of precompilation of JSP files and DEX converting. Atjeews is -bundled with Jasper to run JSP. See more about Atjeews here. - Since 1.83
- Blackberry BAR Atjeews packaging added to version 1.95. It supposes also appearing in RIM AppWorld as a free application. -

-

Run it on iPhone?

-

There are several options to run Java applications on iPhone and iPad. You will need to jail break your iPhone though. - Since Steeve isn't with Apple anymore, there is a good chance for porting Davlik to iOS platfrom. I heard that iOS 9.0 (current is 8.0) will have Java included

- - -

Use TJWS as proxied

-

TJWS can be used with proxy servers. Definition tjws.proxy.ssl -can be specified to correctly determinate remote host and access protocol. -

-To use Apache as a proxy server you can: -

    -
  1. make sure that mod_proxy enabled in httpd.conf
  2. -
  3. add below directives in httpd.conf -
    -   ProxyRequests On
    -   ProxyVia On
    -   ProxyPass /context_path/ http://tjws_host:<TJWS port>/web_app_context/
    -   ProxyPassReverse /context_path/ http://tjws_host:<TJWS port>/web_app_context/
    -# for pushing authentication
    -   RewriteEngine on
    -   RewriteBase /
    -
    -   RewriteCond %{REMOTE_USER} !=""
    -   RewriteRule .* - [E=E_USER:%{REMOTE_USER}]
    -
    -   RequestHeader set my_new_header %{E_USER}e
    -
    -
-
Another example of Apache configuration to use proxied TJWS as virtual host: -
-<VirtualHost *:*>
-ProxyPreserveHost On
-ProxyPass / http://localhost:8080/
-ProxyPassReverse / http://localhost:8080/
-ServerName www.tjws.com
-</VirtualHost>
-
-To use Nginx as a proxy server : -
-    server {
-        listen       80;
-        server_name  localhost;
-...
-        location / {
-            proxy_pass        http://localhost:8080;
-            proxy_set_header  x-Forwarded-for  $remote_addr;
-            proxy_set_header  X-Forwarded-Host $host;
-        }
-...        
-
-Please note that Nginx doesn't support keep alive for proxy requests yet, so you can observe some performance degradation. -

-

Download

-

Please -download -(version 1.114) -

- -

Visit Atjeews at GitHub for Android version of the server and download APK at - Google Play. -

-

Sources of TJWS are available on GitHub

-

Note: Base TJWS is Java 2 (JDK 1.2) compatible, SSL -module requires extra classes introduced in JDK 1.3-1.4. Base TJWS runs also on servlet specification 2.3, when -the rest of server is 3.1 version compatible. It makes building of TJWS a bit tricky. Some methods originally introduced in -TJWS are conflicting with JSR 315, so the author is looking how to eliminate this conflict with a minimal impact -of backward compatibility. J2EE war deployment -requires Java 5 (JDK 1.5, 1.6, 1.7, or 1.8). If you would like to make own build, then you will need to download 7Bee Java -based build tool. The env.xml assumes target 1.4 for TJWS and -1.7 for the -rest. It may need being edited to provide SDK paths and targets. Modify variable 'j2ee -target version' in env.xml to 1.5 to avoid using System tray feature -of JDK 1.6 and up. Specify env.xml variable 'android' as yes to compile the server to run on Android devices (since 1.83). App servers features are not supported for Android though. -Since a build tool is a matter of personal taste, you can -use any other favorite build tools.

-

- Attention POSIX systems users, the distributive archive has access attribute - not set, so execute chmod -R +rwx WebServer after unpackaging WebServer-nnn.zip

-

Zaurus version get here and .ipk -version (use kill to stop)

-
Last changes history
- -
    -
  • nohup option
  • -
  • getSession() never null fix pointed by Warren E. Downs
  • -
  • messed sessions fix when - browser sends more than one session cookies
  • -
  • session persistence between server re-runs (here are some - issues when classes loaded under WEB-INF/..)
  • -
  • fixes realm not got applied to servlets, hanging when - accessed reserved device, like con:, prt: pointed by users (Niel Markwick, - and others)
  • -
  • added J2EE web app deployment and JSP - support (JASPER) as a separate module
  • -
  • support of filters and listeners, requested by Argan
  • -
  • keep-alive support, requested by Torben Bruun
  • -
  • err option to keep System.err unchanged or customize it, - requested by Xavier
  • -
  • many keep-alive fixes came from - Martin Egholm Nielsen
  • -
  • fixes in web app servlet most reported by Nicolas Prochazka
  • -
  • supporting HTTP and HTTPS transports in the same instance
  • -
  • exit out of serve() by Andr� Kischkel
  • -
  • thread pooling for servicing requests
  • -
  • unavailable, and path pattern related fixes
  • -
  • web app launcher including embedded .war
  • -
  • JSP engine with spec 2.0/2.1 support as Japser
  • -
  • filter for include, forward, and error. Multiple URL patterns
  • -
  • HTTP Range request support for file servlet
  • -
  • added Response Buffer and Request Dispatcher support in base server
  • -
  • flexible support of server sockets including Selector based
  • -
  • default log directory by Italia Roberto
  • -
  • compression of text content by file servlet
  • -
  • stronger security for session id
  • -
  • fix: not eating unconsumed part of input stream for keep-alive connection (reported by Bill Burke@redhat)
  • -
  • dynamic redeploy advised by poll results
  • -
  • data sources and connection pooling advised by poll results
  • -
  • missed processing of charset in POST request pointed by Jack
  • -
  • virtual host by ganesan
  • -
  • closing all connections at stop requestedd by Weinan Li@redhat
  • -
  • JSR 315 Comet support requested by Ivan Voronov
  • -
  • Base server vulnerability related directory transversal using '..' pointed by Jo�o Sampaio
  • -
  • Android compatibility of war deployment requested by Alex Xin
  • -
  • Adjustung behavior matching to servlet specification done by Andreas
  • -
  • Using servlets mapping URL patterns matching to servlet specification including extensions mapping, by Bruno B
  • -
  • Accurate handling keep allive by Andreas
  • -
  • Proper freeing resources in CGI servlet by Frank
  • -
  • SSL handler default class updated by Jan
  • -
  • Reliable detection of chunked encoding by Darren
  • -
  • JSR 356 (websocket) by Robert -
-
-

Tested web applications

-

I use TJWS primary for my business, however I verified functionality of some -popular web applications. Here are just few of them:

-
    -
  1. Apache Slide (WebDav) and also WebDav servlet from GitHub
  2. -
  3. jCVSWeb/jCVSServlet 1.41/1.01 (CVS web front-end)
  4. -
  5. Pebble 2.2 (Blogger solution)
  6. -
  7. DaveNPort 0.9.10 (Samba web front-end)
  8. -
  9. Apache Axis2 1.0
  10. -
  11. JASIG - single sign on service
  12. -
  13. SimpleCaptcha
  14. -
  15. Quercus® (PHP engine)
  16. -
  17. Apache Myfaces
  18. -
  19. MetricStream EGRCP
  20. -
  21. Google Web Toolkit (GWT)
  22. -
  23. Stripes (JSP framework)
  24. -
  25. Red5 (Streaming media server)
  26. -
  27. OIOSAML.java SAML SSO servlet filter
  28. -
  29. IBM's WeatherServer (Comet)
  30. -
  31. JEExplorer from Denmark
  32. -
  33. VAADIN another flavor of popular GWT
  34. -
  35. Javamelody enterprise application monitoring and profiling tool
  36. -
  37. Music Barrel - a music jukebox for Raspberry PI and PC
  38. -
-

Build Tool

-

- TJWS is proudly built using most sophisticated Java build tool 7Bee. -The tool is available in sources at GitHub. Another build tools can be used as well, although I support 7Bee only. - There is also no way to convert .war files to be deployed on Android, than using 7Bee. The following values needed to be provided in env.xml to build TJWS:

-
    -
  1. SERVLET_LIB - fully qualified path to servlet.jar or other lib/directory containing - JSS 2.3 classes
  2. -
  3. SERVLET_LIB_30 - fully qualified path to servlet.jar or other lib/directory containing - JSS 3.0 classes
  4. -
  5. SERVLET_SRC - fully qualified path to sources of JSS classes, used only for packaging - text resources in launcher packaging and can be omitted, unless launcher has to be built
  6. -
  7. SERVLET_BUILD - fully qualified path to binaries of classes of JSS, used only for packaging JSS - in launcher packaging and can be omitted, unless launcher with JSP has to be built
  8. -
  9. JSP_LIB - fully qualified path to jsp.jar or other lib/directory containing JSP API classes
  10. -
  11. WEBSOCKETS_CLIENT_LIB, and WEBSOCKETS_SERVER_LIB - fully qualified pathes for JSR 356 API client and server - jars respectfully
  12. -
-Note: environment variables for versions prior 1.28 are slightly different. - -

JVMs

-

TJWS was tested with most popular JVMs under Windows, Linux, Mac OS, and Solaris -platforms and also on mobile platforms as Sharp Zaurus, Android, and Windows Mobile. -Oracle, IBM J9, JRocket, Open JDK, Dalvik, - and GNU VMs are capable to run TJWS.

-

Copyrights

-

The Miniature Java Web Server carries all copyrights of the original author -as stated in the license you can find in any source file.

-
License
-

The Tiny Java Web Server inherited BSD like license from the original -code, check any source file for details.

-

Support

-

I provide support of the server on voluntary basis. Feel free to send bug report on enhancement request. I also provide consulting service -related to creation of web 2.0 J2EE scalable applications. See an example ResumeFair

-
Discussion forum
-

Feel free also to share your concerns, questions, and discoveries in -the Discussion forum.

-
Extra Bonus
-

Version of 1.07 and later includes some useful web applications packaged as -.war files and deployed at first server run. To enjoy the applications just -follow a link on a start page. If you do not want to have these applications -deployed, just remove corresponding .war files from webapps directory -before first server run.

-
- Help wanted
-

I'm looking for developers to finish work on pending web.xml, fragment.xml, and common.xml instructions. Another plan is adding SOAP/RPC support for easy SOA. -SSI servlet is also waiting to be developed. There are tons opportunities to develop Android web applications.

-
Check also...
-

MediaChest Comprehensive tools to handle all media files as digital photos and  music

-

xBox - Bean box supporting XML serialization -(do not confuse with proposed -later java.beans.Encoder)

-

jAddressBook is an address -book with a float XML format of addresses and another profile information, web 2 -UI.

-

Music Barrel Conver any computer including Raspberry Pi to -a music jukebox remote controllable from your phone or tablet.

-

Remote file management - the tool every IT professional or advanced user must have, web interfaced file manager with many useful functions.

- -

Contact

-

Bugs, questions, and enhancement requests you can send to -Dmitriy -Rogatkin.Happy web servicing!

-

-

© 2015
- - - \ No newline at end of file diff --git a/1.x/src/Acme/Serve/SSLAcceptor.java b/1.x/src/Acme/Serve/SSLAcceptor.java deleted file mode 100644 index 1fbaa95..0000000 --- a/1.x/src/Acme/Serve/SSLAcceptor.java +++ /dev/null @@ -1,280 +0,0 @@ -/* tjws - SSLAcceptor.java - * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: SSLAcceptor.java,v 1.10 2013/03/02 09:11:56 cvs Exp $ - * Created on Feb 21, 2007 - * @author dmitriy - */ -package Acme.Serve; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.security.KeyStore; -import java.security.Security; -import java.util.Map; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; - -import Acme.Utils; -import Acme.Serve.Serve.Acceptor; - -public class SSLAcceptor implements Acceptor { - public static final String ARG_ALGORITHM = "algorithm"; // SUNX509 - - public static final String ARG_CLIENTAUTH = "clientAuth"; // false - - public static final String ARG_KEYSTOREFILE = "keystoreFile"; // - - public static final String PROP_KEYSTOREFILE = "javax.net.ssl.keyStore"; // - - public static final String ARG_KEYSTOREPASS = "keystorePass"; // KEYSTOREPASS - - public static final String PROP_KEYSTOREPASS = "javax.net.ssl.keyStorePassword"; - - public static final String ARG_KEYSTORETYPE = "keystoreType"; // KEYSTORETYPE - - public static final String PROP_KEYSTORETYPE = "javax.net.ssl.keyStoreType"; // - - public static final String ARG_KEYPASS = "keyPass"; // - - public static final String ARG_PROTOCOL = "protocol"; // TLS - - public static final String ARG_BACKLOG = Serve.ARG_BACKLOG; - - public static final String ARG_SO_HS_TIMEOUT = "socket-handshake-timeout"; - - public static final String ARG_IFADDRESS = "ifAddress"; - - public static final String ARG_PORT = "ssl-port"; - - public static final String PROTOCOL_HANDLER_JSSE10 = "com.sun.net.ssl.internal.www.protocol"; - - public static final String PROTOCOL_HANDLER = "javax.net.ssl.internal.www.protocol"; - - /** - * The name of the system property containing a "|" delimited list of - * protocol handler packages. - */ - public static final String PROTOCOL_PACKAGES = "java.protocol.handler.pkgs"; - - /** - * Certificate encoding algorithm to be used. - */ - public final static String SUNX509 = "SunX509"; - - /** - * default SSL port - */ - public final static int PORT = 8443; - - /** - * default backlog - */ - public final static int BACKLOG = 1000; - - /** - * Storage type of the key store file to be used. - */ - public final static String KEYSTORETYPE = "JKS"; - - /** - * SSL protocol variant to use. - */ - public final static String TLS = "TLS"; - - /** - * SSL protocol variant to use. - */ - public static final String protocol = TLS; - - /** - * Password for accessing the key store file. - */ - private static final String KEYSTOREPASS = "changeme"; - - /** - * default socket SSL handshake timeout preventing DoS attacks - */ - protected static final int SO_HS_TIMEOIUT = 30 * 1000; - - /** - * Pathname to the key store file to be used. - */ - protected String keystoreFile = System.getProperty("user.home") + File.separator + ".keystore"; - - protected ServerSocket socket; - - protected static int so_hs_timeout; - - protected boolean android, jsse10; - - private String getKeystoreFile() { - return (this.keystoreFile); - } - - public Socket accept() throws IOException { - return socket.accept(); - } - - public void destroy() throws IOException { - try { - socket.close(); - } finally { - socket = null; - } - } - - public void init(Map inProperties, Map outProperties) throws IOException { - // Create the proxy and return - javax.net.ssl.SSLServerSocketFactory sslSoc = initSSLContext(inProperties, outProperties) - .getServerSocketFactory(); - int port = Utils.parseInt(inProperties.get(ARG_PORT), Utils.parseInt(inProperties.get(Serve.ARG_PORT), PORT)); - - if (inProperties.get(ARG_BACKLOG) == null) - if (inProperties.get(ARG_IFADDRESS) == null) - socket = sslSoc.createServerSocket(port); - else - socket = sslSoc.createServerSocket(port, BACKLOG, - InetAddress.getByName((String) inProperties.get(ARG_IFADDRESS))); - else if (inProperties.get(ARG_IFADDRESS) == null) - socket = sslSoc.createServerSocket(port, Utils.parseInt(inProperties.get(ARG_BACKLOG), BACKLOG)); - else - socket = sslSoc.createServerSocket(port, Utils.parseInt(inProperties.get(ARG_BACKLOG), BACKLOG), - InetAddress.getByName((String) inProperties.get(ARG_IFADDRESS))); - - initServerSocket(socket, "true".equals(inProperties.get(ARG_CLIENTAUTH))); - if (outProperties != null) - outProperties.put(Serve.ARG_BINDADDRESS, socket.getInetAddress().getHostName()); - // note it isn't use for the implementation since there is no control over handshake - so_hs_timeout = Utils.parseInt(inProperties.get(ARG_SO_HS_TIMEOUT), SO_HS_TIMEOIUT); - } - - protected SSLContext initSSLContext(Map inProperties, Map outProperties) throws IOException { - // init keystore - KeyStore keyStore = null; - FileInputStream istream = null; - String keystorePass = null; - android = System.getProperty("java.vm.name") != null && System.getProperty("java.vm.name").startsWith("Dalvik"); - try { - String keystoreType = getWithDefault(inProperties, ARG_KEYSTORETYPE, KEYSTORETYPE); - keyStore = KeyStore.getInstance(keystoreType); - String keystoreFile = (String) inProperties.get(ARG_KEYSTOREFILE); - if (keystoreFile == null) - keystoreFile = getKeystoreFile(); - istream = new FileInputStream(keystoreFile); - keystorePass = getWithDefault(inProperties, ARG_KEYSTOREPASS, KEYSTOREPASS); - keyStore.load(istream, keystorePass.toCharArray()); - } catch (Exception e) { - throw (IOException) new IOException(e.toString()).initCause(e); - } finally { - if (istream != null) - istream.close(); - } - - try { - // Register the JSSE security Provider (if it is not already there) - if (android == false) - try { - Security.addProvider((java.security.Provider) Class - .forName("com.sun.net.ssl.internal.ssl.Provider").newInstance()); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - // TODO think to do not propagate absence of the provider, since other can still work - throw (IOException) new IOException(t.toString()).initCause(t); - } - - // Create an SSL context used to create an SSL socket factory - String protocol = getWithDefault(inProperties, ARG_PROTOCOL, TLS); - SSLContext context = SSLContext.getInstance(protocol); - - // Create the key manager factory used to extract the server key - String algorithm = getWithDefault(inProperties, ARG_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm()); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm); - - String keyPass = getWithDefault(inProperties, ARG_KEYPASS, keystorePass); - - keyManagerFactory.init(keyStore, keyPass.toCharArray()); - - // Initialize the context with the key managers - context.init(keyManagerFactory.getKeyManagers(), null, new java.security.SecureRandom()); - return context; - } catch (Exception e) { - System.err.println("SSLsocket creation: " + e); - e.printStackTrace(); - throw (IOException) new IOException(e.toString()).initCause(e); - } - } - - /** - * Register our URLStreamHandler for the "https:" protocol. - */ - protected static void initHandler() { - - String packages = System.getProperty(PROTOCOL_PACKAGES); - if (packages == null) - packages = PROTOCOL_HANDLER; - else if (packages.indexOf(PROTOCOL_HANDLER) < 0) - packages += "|" + PROTOCOL_HANDLER; - System.setProperty(PROTOCOL_PACKAGES, packages); - } - - public String toString() { - return socket != null ? socket.toString() : "SSLAcceptor uninitialized"; - } - - static { - initHandler(); - } - - /** - * Set the requested properties for this server socket. - * - * @param ssocket - * The server socket to be configured - */ - protected void initServerSocket(ServerSocket ssocket, boolean clientAuth) { - - SSLServerSocket socket = (SSLServerSocket) ssocket; - - // Enable all available cipher suites when the socket is connected - String cipherSuites[] = socket.getSupportedCipherSuites(); - socket.setEnabledCipherSuites(cipherSuites); - // Set client authentication if necessary - socket.setNeedClientAuth(clientAuth); - } - - private String getWithDefault(Map args, String name, String defValue) { - String result = (String) args.get(name); - if (result == null) - return defValue; - return result; - } -} diff --git a/1.x/src/Acme/Serve/SelectorAcceptor.java b/1.x/src/Acme/Serve/SelectorAcceptor.java deleted file mode 100644 index d4f79a8..0000000 --- a/1.x/src/Acme/Serve/SelectorAcceptor.java +++ /dev/null @@ -1,130 +0,0 @@ -/* tjws - SelectorAcceptor.java - * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: SelectorAcceptor.java,v 1.8 2008/01/18 10:05:23 dmitriy Exp $ - * Created on Feb 21, 2007 - * @author dmitriy - */ -package Acme.Serve; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.InetAddress; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.ServerSocketChannel; -import java.util.Iterator; -import java.util.Map; - -import Acme.Serve.Serve.Acceptor; - -public class SelectorAcceptor implements Acceptor { - private ServerSocketChannel channel; - - private Selector selector; - - private Iterator readyItor; - - public Socket accept() throws IOException { - do { - if (readyItor == null) { - if (selector.select() > 0) - readyItor = selector.selectedKeys().iterator(); - else - throw new IOException(); - } - - if (readyItor.hasNext()) { - - // Get key from set - SelectionKey key = (SelectionKey) readyItor.next(); - - // Remove current entry - readyItor.remove(); - // TODO add processing CancelledKeyException - if (key.isValid() && key.isAcceptable()) { - // Get channel - ServerSocketChannel keyChannel = (ServerSocketChannel) key.channel(); - - // Get server socket - ServerSocket serverSocket = keyChannel.socket(); - - // Accept request - return serverSocket.accept(); - } - } else - readyItor = null; - } while (true); - } - - public void destroy() throws IOException { - String exceptions = ""; - try { - channel.close(); - } catch (IOException e) { - exceptions += e.toString(); - } - try { - selector.close(); - } catch (IOException e) { - exceptions += e.toString(); - } - if (exceptions.length() > 0) - throw new IOException(exceptions); - } - - public void init(Map inProperties, Map outProperties) throws IOException { - selector = Selector.open(); - - channel = ServerSocketChannel.open(); - channel.configureBlocking(false); - int port = inProperties.get(Serve.ARG_PORT) != null ? ((Integer) inProperties.get(Serve.ARG_PORT)).intValue() - : Serve.DEF_PORT; - InetSocketAddress isa = null; - if (inProperties.get(Serve.ARG_BINDADDRESS) != null) - try { - isa = new InetSocketAddress((String) inProperties.get(Serve.ARG_BINDADDRESS), port); - } catch (Exception e) { - } - if (isa == null) - isa = new InetSocketAddress(port); - // TODO add ARG_BACKLOG - channel.socket().bind(isa); - - // Register interest in when connection - channel.register(selector, SelectionKey.OP_ACCEPT); - if (outProperties != null) { - if (channel.socket().isBound()) - outProperties.put(Serve.ARG_BINDADDRESS, channel.socket().getInetAddress().getHostName()); - else - outProperties.put(Serve.ARG_BINDADDRESS, InetAddress.getLocalHost().getHostName()); - } - } - - public String toString() { - return "SelectorAcceptor - "+(channel == null ?"unset":""+channel.socket()); - } -} diff --git a/1.x/src/Acme/Serve/Serve.java b/1.x/src/Acme/Serve/Serve.java deleted file mode 100644 index c23f042..0000000 --- a/1.x/src/Acme/Serve/Serve.java +++ /dev/null @@ -1,5570 +0,0 @@ -// Serve - minimal Java servlet container class -// -// Copyright (C)1996,1998 by Jef Poskanzer . All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions 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. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// -// Visit the ACME Labs Java page for up-to-date versions of this and other -// fine Java utilities: http://www.acme.com/java/ -// - -// All enhancements Copyright (C)1998-2014 by Dmitriy Rogatkin -// This version is compatible with JSDK 2.5 -// http://tjws.sourceforge.net -// $Id: Serve.java,v 1.269 2013/08/20 04:11:09 cvs Exp $ - -package Acme.Serve; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.io.Writer; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.Socket; -import java.net.URL; -import java.net.SocketTimeoutException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.text.MessageFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.LinkedList; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.TimeZone; -import java.util.TreeSet; -import java.util.Vector; -import java.lang.reflect.Method; - -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.SingleThreadModel; -import javax.servlet.UnavailableException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionActivationListener; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; -import javax.servlet.http.HttpSessionContext; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import Acme.Utils; - -/// Minimal Java servlet container class. -//

-// This class implements a very small embeddable servlet container. -// It runs Servlets compatible with the API used by Sun's -// Java System Application server. -// Servlet API can be found here. -// It comes with default Servlets which provide the usual -// httpd services, returning files and directory listings. -//

-// This is not in any sense a competitor for Java System Application server. -// Java System Application server is a full-fledged HTTP server and more. -// Acme.Serve is tiny, about 5000 lines, and provides only the -// functionality necessary to deliver an Applet's .class files -// and then start up a Servlet talking to the Applet. -// They are both written in Java, they are both web servers, and -// they both implement the Servlet API; other than that they couldn't -// be more different. -//

-// This is actually the second HTTP server I've written. -// The other one is called -// thttpd, -// it's written in C, and is also pretty small although much more -// featureful than this. -//

-// Other Java HTTP servers: -//

-//

-// A June 1997 BYTE -// magazine article mentioning this server.
-// A December 1997 BYTE -// magazine article giving it an Editor's Choice Award of Distinction.
-// Fetch the -// software.
-// Fetch the entire Acme package. -//

-// @see Acme.Serve.servlet.http.HttpServlet -// @see FileServlet -// @see CgiServlet -//

Post notes

-// Currently the server 3 more times complex and can compete with -// most popular app and web servers used for deploying of web -// Java applications. - -// Inheritance can extend usage of this server -public class Serve implements ServletContext, Serializable { - - public static final String ARG_PORT = "port"; - - public static final String ARG_THROTTLES = "throttles"; - - public static final String ARG_SERVLETS = "servlets"; - - public static final String ARG_REALMS = "realms"; - - public static final String ARG_ALIASES = "aliases"; - - public static final String ARG_BINDADDRESS = "bind-address"; - - public static final String ARG_BACKLOG = "backlog"; - - public static final String ARG_CGI_PATH = "cgi-path"; - - public static final String ARG_ERR = "error-stream"; - - public static final String ARG_OUT = "out-stream"; - - public static final String ARG_SESSION_TIMEOUT = "session-timeout"; - - public static final String ARG_LOG_DIR = "log-dir"; - - public static final String ARG_LOG_OPTIONS = "log-options"; - - public static final String ARG_LOGROLLING_LINES = "log-rolling-lines-threshold"; - - public static final String ARG_NOHUP = "nohup"; - - public static final String ARG_JSP = "JSP"; - - public static final String ARG_WAR = "war-deployer"; - - public static final String ARG_WEBSOCKET = "WEBSOCKET-PROVIDER"; - - public static final String ARG_KEEPALIVE = "keep-alive"; - - public static final String ARG_PROXY_CONFIG = "proxy-config"; - - public static final String DEF_LOGENCODING = "tjws.serve.log.encoding"; - - public static final String DEF_PROXY_CONFIG = "tjws.proxy.ssl"; - - public static final String ARG_KEEPALIVE_TIMEOUT = "timeout-keep-alive"; - - public static final String ARG_MAX_CONN_USE = "max-alive-conn-use"; - - public static final String ARG_SESSION_PERSIST = "sssn-persistance"; - - public static final String ARG_MAX_ACTIVE_SESSIONS = "max-active-sessions"; - - public static final String ARG_ACCESS_LOG_FMT = "access-log-format"; - - public static final String ARG_ACCEPTOR_CLASS = "acceptorImpl"; - - public static final String ARG_WORK_DIRECTORY = "workdirectory"; - - public static final String ARG_SESSION_SEED = "SessionSeed"; - - public static final String ARG_SESSION_SEED_ALG = "SecureRandomAlgorithm"; - - public static final String ARG_HTTPONLY_SC = "sessionhttponly"; - - public static final String ARG_SECUREONLY_SC = "sessionsecureonly"; - - public static final String ARG_THREAD_POOL_SIZE = Utils.ThreadPool.MAXNOTHREAD; - - protected static final int DEF_SESSION_TIMEOUT = 30; // in minutes - - protected static final int DEF_MIN_ACT_SESS = 10; - - protected static final int DESTROY_TIME_SEC = 15; - - protected static final int HTTP_MAX_HDR_LEN = 1024 * 1024 * 10; - - public static final int DEF_PORT = 8080; - - public static final String BGCOLOR = "BGCOLOR=\"#D1E9FE\""; - - public final static String LINE_SEP = System.getProperty("line.separator", "\n"); - - /** - * max number of alive connections default value - */ - protected static final int DEF_MAX_CONN_USE = 100; - - protected static final Integer INT_ZERO = new Integer(0); - - public static final String UTF8 = "UTF-8"; // default encoding - - protected String hostName; - - private transient PrintStream logStream; - - private boolean useAccLog; - - private boolean keepAlive; - - private boolean proxyConfig; - - private boolean proxySSL; - - private int timeoutKeepAlive; - - private int maxAliveConnUse; - - private boolean showUserAgent; - - private boolean showReferer; - - protected String keepAliveHdrParams; - - protected transient PathTreeDictionary defaultRegistry; - - protected transient HashMap virtuals; - - protected transient PathTreeDictionary realms; - - protected transient PathTreeDictionary mappingtable; - - private Hashtable attributes; - - protected transient KeepAliveCleaner keepAliveCleaner; - - protected transient ThreadGroup serverThreads; - - protected transient Utils.ThreadPool threadPool; - - protected transient Constructor gzipInStreamConstr; - - private static final ThreadLocal currentRegistry = new ThreadLocal(); - - // for sessions - private byte[] uniqer = new byte[20]; // TODO consider configurable strength - - private SecureRandom srandom; - - protected HttpSessionContextImpl sessions; - - public int expiredIn; - - public boolean httpSessCookie; - - public boolean secureSessCookie; - - public Map arguments; - - public Properties mime; - - public WebsocketProvider websocketProvider; - - // / Constructor. - public Serve(Map arguments, PrintStream logStream) { - this.arguments = arguments; - this.logStream = logStream; - defaultRegistry = new PathTreeDictionary(); - realms = new PathTreeDictionary(); - attributes = new Hashtable(); - serverThreads = new ThreadGroup("TJWS threads"); - Properties props = new Properties(); - props.putAll(arguments); - // TODO do not create thread pool unless requested - threadPool = new Utils.ThreadPool(props, new Utils.ThreadFactory() { - public Thread create(Runnable runnable) { - Thread result = new Thread(serverThreads, runnable); - result.setDaemon(true); - return result; - } - }); - setAccessLogged(); - keepAlive = arguments.get(ARG_KEEPALIVE) == null || ((Boolean) arguments.get(ARG_KEEPALIVE)).booleanValue(); - int timeoutKeepAliveSec = Utils.parseInt(arguments.get(ARG_KEEPALIVE_TIMEOUT), 30); - timeoutKeepAlive = timeoutKeepAliveSec * 1000; - maxAliveConnUse = Utils.parseInt(arguments.get(ARG_MAX_CONN_USE), DEF_MAX_CONN_USE); - keepAliveHdrParams = "timeout=" + timeoutKeepAliveSec + ", max=" + maxAliveConnUse; - - expiredIn = Utils.parseInt(arguments.get(ARG_SESSION_TIMEOUT), DEF_SESSION_TIMEOUT); - String seed = (String) arguments.get(ARG_SESSION_SEED); - String randomProvider = (String) arguments.get(ARG_SESSION_SEED_ALG); //"SHA1PRNG"; - int seedLen = Utils.parseInt(seed, 0); - if (seed != null && seedLen == 0) - srandom = new SecureRandom(seed.getBytes()); - else { - if (randomProvider != null) - try { - srandom = SecureRandom.getInstance(randomProvider); - } catch (NoSuchAlgorithmException e) { - log("TJWS: Unsupported or incorrect secure rndom algorithm: "+randomProvider+"("+e+"), a default is used" ); - } - if (srandom == null) - srandom = new SecureRandom(); - seedLen = seedLen<=0?100:seedLen; - byte bseed[] = null; - srandom.setSeed(bseed = srandom.generateSeed(seedLen)); - srandom.nextBytes(bseed); - srandom.setSeed(bseed); - } - httpSessCookie = arguments.get(ARG_HTTPONLY_SC) != null; - secureSessCookie = arguments.get(ARG_SECUREONLY_SC) != null; - try { - gzipInStreamConstr = Class.forName("java.util.zip.GZIPInputStream").getConstructor( - new Class[] { InputStream.class }); - } catch (ClassNotFoundException cne) { - - } catch (NoSuchMethodException nsm) { - - } - String proxyArg = (String) arguments.get(ARG_PROXY_CONFIG); - if (proxyArg != null) { - proxyConfig = true; - proxySSL = "y".equalsIgnoreCase(proxyArg); - } - initMime(); - } - - /** - * Default constructor to create TJWS as a bean - * - */ - public Serve() { - this(new HashMap(), System.err); - } - - protected void setAccessLogged() { - String logflags = (String) arguments.get(ARG_LOG_OPTIONS); - if (logflags != null) { - useAccLog = true; - showUserAgent = logflags.indexOf('A') >= 0; - showReferer = logflags.indexOf('R') >= 0; - } else - useAccLog = false; - } - - protected boolean isAccessLogged() { - return useAccLog; - } - - protected boolean isShowReferer() { - return showReferer; - } - - protected boolean isShowUserAgent() { - return showUserAgent; - } - - protected boolean isKeepAlive() { - return keepAlive; - } - - protected int getKeepAliveDuration() { - return timeoutKeepAlive; - } - - protected String getKeepAliveParamStr() { - return keepAliveHdrParams; - } - - protected int getMaxTimesConnectionUse() { - return maxAliveConnUse; - } - - protected void initMime() { - mime = new Properties(); - try { - mime.load(getClass().getClassLoader().getResourceAsStream("Acme/Resource/mime.properties")); - } catch (Exception ex) { - log("TJWS: MIME map can't be loaded:" + ex); - } - } - - // / Register a Servlet by class name. Registration consists of a URL - // pattern, which can contain wildcards, and the class name of the Servlet - // to launch when a matching URL comes in. Patterns are checked for - // matches in the order they were added, and only the first match is run. - public javax.servlet.ServletRegistration.Dynamic addServlet(String urlPat, String className) { - addServlet(urlPat, className, (Hashtable) null); - return null; - } - - /** - * Adds a servlet to run - * - * @param urlPat - * servlet invoker URL pattern - * @param className - * servlet class name - * @param initParams - * servlet init parameters - */ - public void addServlet(String urlPat, String className, Hashtable initParams) { - // Check if we're allowed to make one of these. - SecurityManager security = System.getSecurityManager(); - if (security != null) { - int i = className.lastIndexOf('.'); - if (i > 0) { - security.checkPackageAccess(className.substring(0, i)); - security.checkPackageDefinition(className.substring(0, i)); - } - } - - // Make a new one. - try { - addServlet(urlPat, (Servlet) Class.forName(className).newInstance(), initParams, null); - } catch (ClassNotFoundException e) { - log("TJWS: Class not found: " + className); - ClassLoader cl = getClass().getClassLoader(); - log("TJWS: Class loader: " + cl); - if (cl instanceof java.net.URLClassLoader) - log("TJWS: CP: " + java.util.Arrays.asList(((java.net.URLClassLoader) cl).getURLs())); - } catch (ClassCastException e) { - log("TJWS: Servlet class doesn't implement javax.servlet.Servlet: " + e.getMessage()); - } catch (InstantiationException e) { - log("TJWS: Can't instantiate servlet: " + e.getMessage()); - } catch (IllegalAccessException e) { - log("TJWS: Illegal class access: " + e.getMessage()); - } catch (Exception e) { - log("TJWS: Unexpected problem of servlet creation: " + e, e); - } - } - - /** - * Register a Servlet. Registration consists of a URL pattern, which can - * contain wildcards, and the Servlet to launch when a matching URL comes - * in. Patterns are checked for matches in the order they were added, and - * only the first match is run. - * - * @param urlPat - * servlet invoker URL pattern - * @param servlet - * already instantiated servlet but init - * @param host - * name the servlet attached to, when verual hosts are used, use - * null for all hosts - */ - public void addServlet(String urlPat, Servlet servlet, String hostName) { - addServlet(urlPat, servlet, (Hashtable) null, hostName); - } - - /** - * Register a Servlet. Registration consists of a URL pattern, which can - * contain wildcards, and the Servlet to launch when a matching URL comes - * in. Patterns are checked for matches in the order they were added, and - * only the first match is run. - * - * @param urlPat - * servlet invoker URL pattern - * @param servlet - * already instantiated servlet but init - */ - public javax.servlet.ServletRegistration.Dynamic addServlet(String urlPat, Servlet servlet) { - addServlet(urlPat, servlet, (String) null); - return null; - } - - /** - * Register a Servlet - * - * @param urlPat - * @param servlet - * @param initParams - */ - public synchronized void addServlet(String urlPat, Servlet servlet, Hashtable initParams, String virtualHost) { - setHost(virtualHost); - try { - if (getServlet(urlPat) != null) - log("TJWS: Servlet overriden by " + servlet + ", for path:" + urlPat); - servlet.init(new ServeConfig((ServletContext) this, initParams, urlPat)); - if (virtualHost != null) { - if (virtuals == null) - virtuals = new HashMap(); - virtualHost = virtualHost.toLowerCase(); - PathTreeDictionary virtualRegistry = (PathTreeDictionary) virtuals.get(virtualHost); - if (virtualRegistry == null) { - virtualRegistry = new PathTreeDictionary(); - virtuals.put(virtualHost, virtualRegistry); - } - virtualRegistry.put(urlPat, servlet); - } else - defaultRegistry.put(urlPat, servlet); - } catch (ServletException e) { // - // it handles UnavailableException as well without an attempt to - // re-adding - log("TJWS: Problem initializing servlet, it won't be used: " + e); - } - } - - public Servlet unloadServlet(Servlet servlet) { - PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); - if (registry == null) - registry = defaultRegistry; - synchronized (registry) { - return (Servlet) registry.remove(servlet)[0]; - } - } - - public void unloadSessions(ServletContext servletContext) { - if (sessions == null) - return; - File store = getPersistentFile(servletContext); - - Writer w = null; - try { - if (store != null) { - w = new FileWriter(store); - } - // TODO consider moving implementation to HttpSessionContextImpl - // TODO think of concurrency - Enumeration e = sessions.elements(); - int sc = 0; - while (e.hasMoreElements()) { - AcmeSession session = (AcmeSession) e.nextElement(); - if (session.getServletContext() == servletContext) { - if (w != null) - try { - session.save(w); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - log("TJWS: problem in session serialization for " + servletContext + " / " + session, t); - } - session.invalidate(); - sc++; - } - } - if (sc > 0 && ssclThread != null) - ssclThread.interrupt(); - log("TJWS: invalidated " + sc + " sessions for context " + servletContext, null); - } catch (IOException ioe) { - log("TJWS: problem in persisting sessions for " + servletContext, ioe); - } finally { - if (w != null) - try { - w.close(); - } catch (Exception e) { - } - } - } - - public void restoreSessions(ServletContext servletContext) { - File store = sessions == null ? null : getPersistentFile(servletContext); - if (store != null && store.exists()) { - BufferedReader bfr = null; - try { - bfr = new BufferedReader(new FileReader(store)); - - AcmeSession session; - while ((session = AcmeSession.restore(bfr, Math.abs(expiredIn) * 60, servletContext, sessions)) != null) - if (session.checkExpired() == false) - sessions.put(session.getId(), session); - } catch (IOException ioe) { - log("TJWS: problem in sessions deserialization for " + servletContext, ioe); - } finally { - if (bfr != null) - try { - bfr.close(); - } catch (Exception e) { - - } - } - } - } - - // / Register a standard set of Servlets. These will return - // files or directory listings, and run CGI programs, much like a - // standard HTTP server. - //

- // Because of the pattern checking order, this should be called - // after you've added any custom Servlets. - //

- // The current set of default servlet mappings: - //

    - //
  • If enabled, *.cgi goes to CgiServlet, and gets run as a CGI program. - //
  • * goes to FileServlet, and gets served up as a file or directory. - //
- // @param cgi whether to run CGI programs - // TODO: provide user specified CGI directory - public void addDefaultServlets(String cgi) { - try { - addDefaultServlets(cgi, null); - } catch (IOException ioe) { /* ignore, makes sense only for throtles */ - } - } - - /** - * Register a standard set of Servlets, with optional throttles. These will - * return files or directory listings, and run CGI programs, much like a - * standard HTTP server. - *

- * Because of the pattern checking order, this should be called after - * you've added any custom Servlets. - *

- * The current set of default servlet mappings: - *

    - *
  • If enabled, *.cgi goes to CgiServlet, and gets run as a CGI program. - *
  • * goes to FileServlet, and gets served up as a file or directory. - *
- * - * @param cgi - * whether to run CGI programs - * @param throttles - * filename to read FileServlet throttle settings from, can be - * null - * @throws IOException - */ - public void addDefaultServlets(String cgi, String throttles) throws IOException { - // TODO: provide user specified CGI directory - if (cgi != null) { - if (getServlet("/" + cgi +"/*") == null) - addServlet("/" + cgi + "/*", new Acme.Serve.CgiServlet()); - else - log("TJWS: Servlet for path '/" + cgi + "' already defined and no default will be used."); - } - if (getServlet("/*") == null) - if (throttles != null) - addServlet("/*", new Acme.Serve.FileServlet(throttles, null)); - else - addServlet("/*", new Acme.Serve.FileServlet()); - else - log("TJWS: Servlet for path '/' already defined and no default will be used."); - } - - // TODO review this method and figure throttles use - protected void addWarDeployer(String deployerFactory, String throttles) { - if (deployerFactory == null) // try to use def - deployerFactory = "rogatkin.web.WarRoller"; - try { - WarDeployer wd = (WarDeployer) Class.forName(deployerFactory).newInstance(); - wd.deploy(this); - } catch (ClassNotFoundException cnf) { - log("TJWS: Problem initializing war deployer: " + cnf); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - log("TJWS: Problem in war(s) deployment", t); - } - } - - protected void addWebsocketProvider(String provider) { - if (provider == null) - provider = "rogatkin.wskt.SimpleProvider"; - - try { - websocketProvider = (WebsocketProvider) Class.forName(provider).newInstance(); - websocketProvider.init(this); - websocketProvider.deploy(this, null); - } catch (ClassNotFoundException cnf) { - log("TJWS: Problem finding websocket provider: " + cnf); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - log("TJWS: Problem initializing websocket provider", t); - } - } - - protected File getPersistentFile() { - return getPersistentFile(null); - } - - protected File getPersistentFile(ServletContext servletContext) { - if (arguments.get(ARG_SESSION_PERSIST) == null || (Boolean) arguments.get(ARG_SESSION_PERSIST) == Boolean.FALSE) - return null; - String workPath = (String) arguments.get(ARG_WORK_DIRECTORY); - if (workPath == null) - workPath = "."; - if (hostName == null) - hostName="unknown"; - hostName = sanitizeAsFile(hostName); - return new File(workPath, hostName + '-' - + (arguments.get(ARG_PORT) == null ? String.valueOf(DEF_PORT) : arguments.get(ARG_PORT)) - + (servletContext == null ? "" : "-" + servletContext.getServletContextName()) + "-session.obj"); - } - - protected String sanitizeAsFile(String name) { - return name.replaceAll("\\.|:|\\\\|/", "-"); - } - - protected void console(String msg) { - System.out.println(msg); - } - - // Run the server. Returns only on errors. - transient boolean running; - - protected transient Acceptor acceptor; - - protected transient Thread ssclThread; - - /** - * Launches the server It doesn't exist until server runs, so start it in a - * dedicated thread. - * - * @return 0 if the server successfully terminated, 1 or 2 if it can't be - * started
- * and -1 if it was terminated during some errors
- * and -2 if it was ran over running instance
- * and -3 if not terminated correctly from previous run - */ - public int serve() { - if (running) - return -2; // still running - if (acceptor != null) { - return -3; // not finished correctly - } - try { - acceptor = createAcceptor(); - } catch (Throwable /* IllegalArgumentException */e) { - if (e instanceof ThreadDeath) - throw (ThreadDeath) e; - log("TJWS: Acceptor ["+acceptor+": " + e); - acceptor = null; - if (e instanceof java.net.BindException) - return 3; - else if (e instanceof IOException) - return 1; - return 2; - } - running = true; - - if (expiredIn > 0) { - // sessions cleaner thread - ssclThread = new Thread(serverThreads, new Runnable() { - public void run() { - while (running) { - try { - Thread.sleep(expiredIn * 60 * 1000); - } catch (InterruptedException ie) { - if (running == false) - break; - } - Enumeration e = sessions.keys(); - while (e.hasMoreElements()) { - Object sid = e.nextElement(); - if (sid != null) { - AcmeSession as = (AcmeSession) sessions.get(sid); - if (as != null && (as.checkExpired() || !as.isValid())) { // log("sesion - as = (AcmeSession) sessions.remove(sid); - if (as != null && as.isValid()) - try { - as.invalidate(); - } catch (IllegalStateException ise) { - - } - } - } - } - } - } - }, "Session cleaner"); - ssclThread.setPriority(Thread.MIN_PRIORITY); - // ssclThread.setDaemon(true); - ssclThread.start(); - } // else - // expiredIn = -expiredIn; - keepAliveCleaner = new KeepAliveCleaner(); - keepAliveCleaner.start(); - File fsessions = getPersistentFile(); - if (fsessions != null && fsessions.exists()) { - BufferedReader br = null; - try { - br = new BufferedReader(new FileReader(fsessions)); - sessions = HttpSessionContextImpl.restore(br, Math.abs(expiredIn) * 60, this); - } catch (IOException ioe) { - log("TJWS: IO error in restoring sessions.", ioe); - } catch (Exception e) { - log("TJWS: Unexpected problem in restoring sessions.", e); - } finally { - if (br != null) - try { - br.close(); - } catch (IOException ioe) { - } - } - } - if (sessions == null) - sessions = new HttpSessionContextImpl(); - // TODO: display address as name and as ip - console("[" + new Date() + "] TJWS httpd " + hostName + " - " + acceptor + " is listening."); - try { - while (running) { - try { - Socket socket = acceptor.accept(); - // TODO consider to use ServeConnection object pool - // TODO consider req/resp objects pooling - keepAliveCleaner.addConnection(new ServeConnection(socket, this)); - } catch (IOException e) { - log("TJWS: Accept: " + e); - } catch (SecurityException se) { - log("TJWS: Illegal access: " + se); - } catch (IllegalStateException is) { - log("TJWS: Illegal state: " + is); - } - } - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (Error) t; - log("TJWS: Unhandled exception: " + t + ", server is terminating.", t); - return -1; - } finally { - if (acceptor != null) - try { - acceptor.destroy(); - acceptor = null; - } catch (IOException e) { - } - running = false; - if (ssclThread != null) - ssclThread.interrupt(); - ssclThread = null; - keepAliveCleaner.interrupt(); - try { - keepAliveCleaner.join(); - } catch (InterruptedException ie) { - } - keepAliveCleaner.clear(); // clear rest, although should be empty - keepAliveCleaner = null; - if (websocketProvider != null) - try { - websocketProvider.destroy(); - } catch(Exception e) { - // just in case - } - } - return 0; - } - - /** - * Tells the server to stop - * - * @throws IOException - */ - public void notifyStop() { - if (acceptor != null) { - running = false; - try { - acceptor.destroy(); - acceptor = null; - } catch (IOException ioe) { - log("TJWS: IO exception at destroying acceptor: " + acceptor, ioe); - } catch (Exception e) { - acceptor = null; - log("TJWS: An exception at destroying acceptor: " + acceptor, e); - } - } - } - - public static interface Acceptor { - public void init(Map inProperties, Map outProperties) throws IOException; - - public Socket accept() throws IOException; - - public void destroy() throws IOException; - } - - public static interface AsyncCallback { - public void notifyTimeout(); - - public long getTimeout(); - } - - public static interface WebsocketProvider { - public void init(Serve serve); - - public void handshake(Socket socket, String path, Servlet servlet, HttpServletRequest req, HttpServletResponse resp) throws IOException; - - public void upgrade(Socket socket, String path, Servlet servlet, HttpServletRequest req, HttpServletResponse resp) throws IOException; - - public void destroy(); - - public void deploy(ServletContext servletCtx, List classpathFiles); - } - - protected Acceptor createAcceptor() throws IOException { - String acceptorClass = (String) arguments.get(ARG_ACCEPTOR_CLASS); - if (acceptorClass == null) - acceptorClass = "Acme.Serve.SimpleAcceptor"; - // assured defaulting here - try { - acceptor = (Acceptor) Class.forName(acceptorClass).newInstance(); - } catch (InstantiationException e) { - log("TJWS: Couldn't instantiate Acceptor, the Server is inoperable", e); - } catch (IllegalAccessException e) { - Constructor c; - try { - c = Class.forName(acceptorClass).getDeclaredConstructor(Utils.EMPTY_CLASSES); - c.setAccessible(true); - acceptor = (Acceptor) c.newInstance(Utils.EMPTY_OBJECTS); - } catch (Exception e1) { - log("TJWS: Acceptor is not accessable or can't be instantiated, the Server is inoperable", e); - } - } catch (ClassNotFoundException e) { - String fatal; - log(fatal = "TJWS: Acceptor class not found, the Server is inoperable", e); - console(fatal); - System.exit(-2); - } - Map acceptorProperties = new Properties(); - acceptor.init(arguments, acceptorProperties); - hostName = (String) acceptorProperties.get(ARG_BINDADDRESS); - return acceptor; - } - - public void setHost(String hostName) { - if (virtuals == null) - currentRegistry.set(defaultRegistry); - else { - if (hostName == null) - currentRegistry.set(defaultRegistry); - else { - int colInd = hostName.indexOf(':'); // separate port part - if (colInd > 0) - hostName = hostName.substring(0, colInd); - PathTreeDictionary registry = (PathTreeDictionary) virtuals.get(hostName.toLowerCase()); - if (registry != null) - currentRegistry.set(registry); - else - currentRegistry.set(defaultRegistry); - } - } - } - - // ///////////////// Methods from ServletContext ///////////////////// - - // / Gets a servlet by name. - // @param name the servlet name - // @return null if the servlet does not exist - public Servlet getServlet(String name) { - PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); - if (registry == null) - registry = defaultRegistry; - try { - return (Servlet) registry.get(name)[0]; - } catch (NullPointerException npe) { - } - return null; - } - - // / Enumerates the servlets in this context (server). Only servlets that - // are accessible will be returned. This enumeration always includes the - // servlet itself. - public Enumeration getServlets() { - PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); - if (registry == null) - registry = defaultRegistry; - return registry.elements(); - } - - // / Enumerates the names of the servlets in this context (server). Only - // servlets that are accessible will be returned. This enumeration always - // includes the servlet itself. - public Enumeration getServletNames() { - PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); - if (registry == null) - registry = defaultRegistry; - return registry.keys(); - } - - // / Destroys all currently-loaded servlets. - public synchronized void destroyAllServlets() { - // log("Entering destroyAllServlets()", new - // Exception("Entering destroyAllServlets()")); - // serialize sessions - // invalidate all sessions - // TODO consider merging two pieces below, generally if session is - // stored, - // it shouldn't be invalidated - File sf = getPersistentFile(); - if (sf != null && sessions != null) { - Writer w = null; - try { - w = new FileWriter(sf); - sessions.save(w); - log("TJWS: Sessions stored."); - } catch (IOException ioe) { - log("TJWS: IO error in storing sessions " + ioe); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - log("TJWS: Unexpected problem in storing sessions " + t); - } finally { - try { - w.close(); - } catch (Exception e) { - } - } - - Enumeration e = sessions.keys(); - while (e.hasMoreElements()) { - Object sid = e.nextElement(); - if (sid != null) { - AcmeSession as = (AcmeSession) sessions.get(sid); - if (as != null) { - as = (AcmeSession) sessions.remove(sid); - if (as != null && as.isValid()) - try { - as.invalidate(); - } catch (IllegalStateException ise) { - - } - } - } - } - } - // destroy servlets - destroyAll(defaultRegistry); - if (virtuals != null) { - Iterator si = virtuals.values().iterator(); - while (si.hasNext()) - destroyAll((PathTreeDictionary) si.next()); - } - - // clean access tree - defaultRegistry = new PathTreeDictionary(); - virtuals = null; - } - - private void destroyAll(PathTreeDictionary registry) { - final Enumeration en = registry.elements(); - Runnable servletDestroyer = new Runnable() { - public void run() { - ((Servlet) en.nextElement()).destroy(); - } - }; - int dhc = 0; - while (en.hasMoreElements()) { - Thread destroyThread = new Thread(servletDestroyer, "Destroy"); - destroyThread.setDaemon(true); - destroyThread.start(); - try { - destroyThread.join(DESTROY_TIME_SEC * 1000); - } catch (InterruptedException e) { - } - if (destroyThread.isAlive()) { - log("TJWS: Destroying thread didn't terminate in " + DESTROY_TIME_SEC); - destroyThread.setName("Destroying took too long " + (dhc++)); - } - } - } - - protected void setMappingTable(PathTreeDictionary mappingtable) { - this.mappingtable = mappingtable; - } - - protected void setRealms(PathTreeDictionary realms) { - this.realms = realms; - } - - AcmeSession getSession(String id) { - return (AcmeSession) sessions.get(id); - } - - HttpSession createSession() { - Integer ms = (Integer) this.arguments.get(ARG_MAX_ACTIVE_SESSIONS); - if (ms != null && ms.intValue() < sessions.size()) - return null; - HttpSession result = new AcmeSession(generateSessionId(), Math.abs(expiredIn) * 60, this, sessions); - synchronized (sessions) { - sessions.put(result.getId(), result); - } - return result; - } - - void removeSession(String id) { - synchronized (sessions) { - sessions.remove(id); - } - } - - // / Write information to the servlet log. - // @param message the message to log - public void log(String message) { - Date date = new Date(); - logStream.println("[" + date.toString() + "] " + message); - } - - public void log(String message, Throwable throwable) { - if (throwable != null) { - StringWriter sw; - PrintWriter pw = new PrintWriter(sw = new StringWriter()); - throwable.printStackTrace(pw); - // printCauses(throwable, pw); - message = message + LINE_SEP + sw; - } - log(message); - } - - // / Write a stack trace to the servlet log. - // @param exception where to get the stack trace - // @param message the message to log - public void log(Exception exception, String message) { - log(message, exception); - } - - // / Applies alias rules to the specified virtual path and returns the - // corresponding real path. It returns null if the translation - // cannot be performed. - // @param path the path to be translated - public String getRealPath(String path) { - //System.err.print("[" + path + "]->["); - path = Utils.canonicalizePath(path); - if (path != null && mappingtable != null) { - // try find first sub-path - Object[] os = mappingtable.get(path); - //System.err.println("Searching for path: "+path+" found: "+os[0]); - if (os[0] == null) - return null; - int slpos = ((Integer) os[1]).intValue(); - int pl = path.length(); - if (slpos > 0) { - if (path.length() > slpos) - path = path.substring(slpos + 1); - else - path = ""; - } else if (pl > 0) { - for (int i = 0; i < pl; i++) { - char s = path.charAt(i); - if (s == '/' || s == '\\') - continue; - else { - if (i > 0) - path = path.substring(i); - break; - } - } - } - // System.err.println("Path after processing :"+path+" slash was at "+slpos); - return new File((File) os[0], path).getPath(); - } - return path; - } - - /** - * - * @return - */ - public String getContextPath() { - return ""; - } - - // / Returns the MIME type of the specified file. - // @param file file name whose MIME type is required - public String getMimeType(String file) { - int dp = file.lastIndexOf('.'); - if (dp > 0) { - return mime.getProperty(file.substring(dp + 1).toUpperCase()); - } - return null; - } - - // / Returns the name and version of the web server under which the servlet - // is running. - // Same as the CGI variable SERVER_SOFTWARE. - public String getServerInfo() { - return Serve.Identification.serverName + " " + Serve.Identification.serverVersion + " (" - + Serve.Identification.serverUrl + ")"; - } - - // / Returns the value of the named attribute of the network service, or - // null if the attribute does not exist. This method allows access to - // additional information about the service, not already provided by - // the other methods in this interface. - public Object getAttribute(String name) { - return attributes.get(name); - } - - // ///////////////// JSDK 2.1 extensions ////////////////////////// - public void removeAttribute(String name) { - attributes.remove(name); - } - - public void setAttribute(String name, Object object) { - if (object != null) - attributes.put(name, object); - else - attributes.remove(name); - } - - public Enumeration getAttributeNames() { - return attributes.keys(); - } - - public ServletContext getContext(String uripath) { - // TODO check webapp servlets to find out conexts for uri - return this; // only root context supported - } - - public int getMajorVersion() { - return 2; // support 2.x - } - - public int getMinorVersion() { - return 5; // support 2.5 - } - - // 2.3 - - /** - * Returns a directory-like listing of all the paths to resources within the - * web application whose longest sub-path matches the supplied path - * argument. Paths indicating subdirectory paths end with a '/'. The - * returned paths are all relative to the root of the web application and - * have a leading '/'. For example, for a web application containing - *

- * /welcome.html
- * /catalog/index.html
- * /catalog/products.html
- * /catalog/offers/books.html
- * /catalog/offers/music.html
- * /customer/login.jsp
- * /WEB-INF/web.xml
- * /WEB-INF/classes/com.acme.OrderServlet.class, - *

- * getResourcePaths("/") returns {"/welcome.html", "/catalog/", - * "/customer/", "/WEB-INF/"}
- * getResourcePaths("/catalog/") returns {"/catalog/index.html", - * "/catalog/products.html", "/catalog/offers/"}. - *

- * - * @param the - * - partial path used to match the resources, which must start - * with a / - * @return a Set containing the directory listing, or null if there are no - * resources in the web application whose path begins with the - * supplied path. - * @since Servlet 2.3 - * - */ - public java.util.Set getResourcePaths(java.lang.String path) { - String realPath = getRealPath(path); - if (realPath != null) { - - String[] dir = new File(realPath).list(); - if (dir.length > 0) { - HashSet set = new HashSet(dir.length); - for (int i = 0; i < dir.length; i++) - set.add(dir[i]); - return set; - } - } - return null; - } - - /** - * Returns the name of this web application corresponding to this - * ServletContext as specified in the deployment descriptor for this web - * application by the display-name element. - * - * @return The name of the web application or null if no name has been - * declared in the deployment descriptor. - * - * @since Servlet 2.3 - */ - public String getServletContextName() { - return null; - } - - /** - * Returns a URL to the resource that is mapped to a specified path. The - * path must begin with a "/" and is interpreted as relative to the current - * context root. - * - *

- * This method allows the servlet container to make a resource available to - * servlets from any source. Resources can be located on a local or remote - * file system, in a database, or in a .war file. - * - *

- * The servlet container must implement the URL handlers and - * URLConnection objects that are necessary to access the - * resource. - * - *

- * This method returns null if no resource is mapped to the - * pathname. - * - *

- * Some containers may allow writing to the URL returned by this method - * using the methods of the URL class. - * - *

- * The resource content is returned directly, so be aware that requesting a - * .jsp page returns the JSP source code. Use a - * RequestDispatcher instead to include results of an - * execution. - * - *

- * This method has a different purpose than - * java.lang.Class.getResource, which looks up resources based - * on a class loader. This method does not use class loaders. - * - * @param path - * a String specifying the path to the resource - * - * @return the resource located at the named path, or null if - * there is no resource at that path - * - * @exception MalformedURLException - * if the pathname is not given in the correct form - * - * - */ - public URL getResource(String path) throws MalformedURLException { - if (path == null || path.length() == 0 || path.charAt(0) != '/') - throw new MalformedURLException("Path " + path + " is not in acceptable form."); - File resFile = new File(getRealPath(path)); - if (resFile.exists()) // TODO get canonical path is more robust - return new URL("file", "localhost", resFile.getPath()); - return null; - } - - /** - * Returns the resource located at the named path as an - * InputStream object. - * - *

- * The data in the InputStream can be of any type or length. - * The path must be specified according to the rules given in - * getResource. This method returns null if no - * resource exists at the specified path. - * - *

- * Meta-information such as content length and content type that is - * available via getResource method is lost when using this - * method. - * - *

- * The servlet container must implement the URL handlers and - * URLConnection objects necessary to access the resource. - * - *

- * This method is different from - * java.lang.Class.getResourceAsStream, which uses a class - * loader. This method allows servlet containers to make a resource - * available to a servlet from any location, without using a class loader. - * - * - * @param path - * a String specifying the path to the resource - * - * @return the InputStream returned to the servlet, or - * null if no resource exists at the specified path - * - * - */ - public InputStream getResourceAsStream(String path) { - try { - return getResource(path).openStream(); - } catch (Exception e) { - } - return null; - } - - public RequestDispatcher getRequestDispatcher(String urlpath) { - if (urlpath == null || urlpath.length() == 0 || urlpath.charAt(0) != '/') - return null; - try { - return new SimpleRequestDispatcher(urlpath); - } catch (NullPointerException npe) { - return null; - } - } - - // no way to specify parameters for context - public String getInitParameter(String param) { - return null; - } - - public Enumeration getInitParameterNames() { - return Utils.EMPTY_ENUMERATION; - } - - public RequestDispatcher getNamedDispatcher(String name) { - // named resources are not supported - return null; - } - - public synchronized String generateSessionId() { - srandom.nextBytes(uniqer); - // TODO swap randomly bytes - return Utils.base64Encode(uniqer); - } - - protected class SimpleRequestDispatcher implements RequestDispatcher { - HttpServlet servlet; - - String dispatchPath; - - String dispatchQuery; - - int dispatchLen; - - Map parameters; - - SimpleRequestDispatcher(String path) { - PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); - if (registry == null) - registry = defaultRegistry; - Object[] os = registry.get(path); - servlet = (HttpServlet) os[0]; - // log("Dispatch to: " + path + ", servlet "+servlet); - if (servlet == null) - throw new NullPointerException(); - dispatchLen = ((Integer) os[1]).intValue(); - int qmp = path.indexOf('?'); - if (qmp < 0 || qmp >= path.length() - 1) - dispatchPath = path; - else { - dispatchPath = path.substring(0, qmp); - dispatchQuery = path.substring(qmp + 1); - } - } - - public void forward(ServletRequest _request, ServletResponse _response) throws ServletException, - java.io.IOException { - _request.removeAttribute("javax.servlet.forward.request_uri"); // reset in case of nested - _response.reset(); - servlet.service(new HttpServletRequestWrapper((HttpServletRequest) _request) { - public java.lang.String getPathInfo() { - return dispatchLen >= dispatchPath.length() ? null : dispatchPath.substring(dispatchLen); - } - - public String getRequestURI() { - return dispatchPath; - } - - public String getQueryString() { - return dispatchQuery; - } - - public String getPathTranslated() { - // System.out.println("Path t path i: "+getPathInfo()+", dp: "+dispatchPath); - return getRequest().getRealPath(getPathInfo()); - } - - // TODO implement getPathInfo - - public String getServletPath() { - return dispatchLen <= 0 ? "" : dispatchPath.substring(0, dispatchLen); - } - - public synchronized java.util.Enumeration getAttributeNames() { - if (super.getAttribute("javax.servlet.forward.request_uri") == null) { - setAttribute("javax.servlet.forward.request_uri", super.getRequestURI()); - setAttribute("javax.servlet.forward.context_path", this.getContextPath()); - setAttribute("javax.servlet.forward.servlet_path", super.getServletPath()); - setAttribute("javax.servlet.forward.path_info", super.getPathInfo()); - setAttribute("javax.servlet.forward.query_string", super.getQueryString()); - } - return super.getAttributeNames(); - } - - public Object getAttribute(String name) { - getAttributeNames(); // here is some overhead - return super.getAttribute(name); - } - - public String[] getParameterValues(String name) { - Map params = createParameters(); - String[] result = (String[]) params.get(name); - if (result != null) - return result; - return super.getParameterValues(name); - } - public String getParameter(String name) { - Map params = createParameters(); - String[] result = (String[]) params.get(name); - if (result != null) - return result[0]; - return super.getParameter(name); - } - - public Map getParameterMap() { - HashMap result = new HashMap(); - result.putAll(super.getParameterMap()); - result.putAll(createParameters()); - return result; - } - - public Enumeration getParameterNames() { - Map params = getParameterMap(); - Hashtable result = new Hashtable(); - result.putAll(params); - return result.keys(); - } - synchronized protected Map createParameters() { - if (parameters == null) { - String query = getQueryString(); - if (query != null) - parameters = Acme.Utils.parseQueryString(query, null); - else - parameters = new Hashtable(); - } - return parameters; - } - - }, _response); - // TODO think when response isn't actual response ServeConnection - // ((ServeConnection) _response).closeStreams(); // do not allow to - // continue - } - - public void include(ServletRequest _request, ServletResponse _response) throws ServletException, - java.io.IOException { - _request.removeAttribute("javax.servlet.include.request_uri"); // reset - // in - // case - // of - // nested - ((Serve.ServeConnection) _response).setInInclude(true); - try { - servlet.service(new HttpServletRequestWrapper((HttpServletRequest) _request) { - public synchronized java.util.Enumeration getAttributeNames() { - if (super.getAttribute("javax.servlet.include.request_uri") == null) { - setAttribute("javax.servlet.include.request_uri", dispatchPath); - setAttribute("javax.servlet.include.context_path", this.getContextPath()); - setAttribute("javax.servlet.include.servlet_path", - dispatchLen <= 0 ? "" : dispatchPath.substring(0, dispatchLen)); - setAttribute("javax.servlet.include.path_info", dispatchLen >= dispatchPath.length() ? null - : dispatchPath.substring(dispatchLen)); - setAttribute("javax.servlet.include.query_string", dispatchQuery); - } - return super.getAttributeNames(); - } - - public Object getAttribute(String name) { - getAttributeNames(); // here is some overhead - return super.getAttribute(name); - } - - }, _response); - } finally { - ((Serve.ServeConnection) _response).setInInclude(false); - } - } - - } - - // Keep Alive supporter, JDK 1.4 based for backward compatibility - class KeepAliveCleaner extends Thread { - protected List connections; - - protected List ingoings; - - protected boolean stopped; - - private boolean noCheckClose; - - KeepAliveCleaner() { - super("KeepAlive cleaner"); - connections = new LinkedList(); - ingoings = new LinkedList(); - setDaemon(true); - } - - void addConnection(ServeConnection conn) { - synchronized (ingoings) { - if (stopped == false) - ingoings.add(conn); - } - } - - void clear() { - if (stopped == false) - new IllegalStateException("Can't clear running cleaner"); - clear(ingoings); - clear(connections); - } - - private void clear(List ll) { - Iterator i = ll.iterator(); - while (i.hasNext()) { - ServeConnection conn = (ServeConnection) i.next(); - i.remove(); - conn.close(); - } - } - - public void run() { - //int maxUse = getMaxTimesConnectionUse(); - while (true) { - synchronized (ingoings) { - Iterator i = ingoings.iterator(); - while (i.hasNext()) { - connections.add(i.next()); - i.remove(); - } - } - Iterator i = connections.iterator(); - long ct = System.currentTimeMillis(); - long d = getKeepAliveDuration(); - // System.err.println("===> keep alive time"+d); - while (i.hasNext()) { - ServeConnection conn = (ServeConnection) i.next(); - boolean closed = conn.socket == null; - if (noCheckClose == false) - synchronized (conn) { - if (conn.socket != null) - try { - closed = ((Boolean) conn.socket.getClass() - .getMethod("isClosed", Utils.EMPTY_CLASSES) - .invoke(conn.socket, Utils.EMPTY_OBJECTS)).booleanValue(); - } catch (NoSuchMethodException e) { - noCheckClose = true; - } catch (Exception e) { - } - } - if (conn.lastRun < conn.lastWait && (closed || conn.keepAlive == false || (ct - conn.lastWait > d)) - || stopped - /* || conn.timesRequested > maxUse */) { - i.remove(); - synchronized (conn) { - if (conn.socket != null) - try { - // System.err.println("Closing socket:"+conn.socket.getClass().getName()); - // // !!! - // conn.socket.close(); - conn.socket.getInputStream().close(); - } catch (IOException ioe) { - // ignore - } - // System.err.println("done"); - } - // System.err.println("===> Removing and closing con"+conn+" of "+conn.keepAlive); - } - if (conn.asyncTimeout > 0) { - if (ct >= conn.asyncTimeout) { - if (conn.asyncMode != null) { - conn.asyncMode.notifyTimeout(); - conn.keepAlive = false; - if (conn.websocketUpgrade) - conn.asyncMode = null; - conn.joinAsync(); - } /*else if (conn.websocketUpgrade) { - try { - conn.keepAlive = false; - //conn.socket.getChannel().close(); // TODO perhaps use normal close call - //conn.socket = null; - } catch(Exception e) { - - } - }*/ - } else { - long nd = conn.asyncTimeout - ct; - if (nd < d) - d = nd; - } - } - } - if (stopped && connections.size() == 0) // TODO stopped can be - // enough, since clear - // method - break; - try { - sleep(d); - } catch (InterruptedException ie) { - stopped = true; // not thread safe - } - } - } - } - - public static interface Identification { - public static final String serverName = "D. Rogatkin's TJWS (+Android, JSR340, JSR356) https://github.com/drogatkin/TJWS2.git"; - - public static final String serverVersion = "Version 1.115 (nightly)"; - - public static final String serverUrl = "http://tjws.sourceforge.net"; - - public static final String serverIdHtml = "

" + serverName + " " - + serverVersion + "
"; - } - - // //////////////////////////////////////////////////////////////// - - protected static class ServeConfig implements ServletConfig { - - private ServletContext context; - - private Hashtable init_params; - - private String servletName; - - public ServeConfig(ServletContext context) { - this(context, null, "undefined"); - } - - public ServeConfig(ServletContext context, Hashtable initParams, String servletName) { - this.context = context; - this.init_params = initParams; - this.servletName = servletName; - } - - // Methods from ServletConfig. - - // / Returns the context for the servlet. - public ServletContext getServletContext() { - return context; - } - - // / Gets an initialization parameter of the servlet. - // @param name the parameter name - public String getInitParameter(String name) { - // This server supports servlet init params. :) - if (init_params != null) - return (String) init_params.get(name); - return null; - } - - // / Gets the names of the initialization parameters of the servlet. - // @param name the parameter name - public Enumeration getInitParameterNames() { - // This server does:) support servlet init params. - if (init_params != null) - return init_params.keys(); - return new Vector().elements(); - } - - // 2.2 - public String getServletName() { - return servletName; - } - } - - // ///////////////////////////////////////////////////////////////////// - /** - * provides request/response - */ - public static class ServeConnection implements Runnable, HttpServletRequest, HttpServletResponse { - public final static String WWWFORMURLENCODE = "application/x-www-form-urlencoded"; - - public final static String TRANSFERENCODING = "transfer-encoding".toLowerCase(); - - public final static String KEEPALIVE = "Keep-Alive".toLowerCase(); - - public final static String CONTENT_ENCODING = "Content-Encoding".toLowerCase(); - - public final static String CONNECTION = "Connection".toLowerCase(); - - public final static String CHUNKED = "chunked"; - - public final static String CONTENTLENGTH = "Content-Length".toLowerCase(); - - public final static String CONTENTTYPE = "Content-Type".toLowerCase(); - - public final static String SETCOOKIE = "Set-Cookie".toLowerCase(); - - public final static String HOST = "Host".toLowerCase(); - - public final static String COOKIE = "Cookie".toLowerCase(); - - public final static String UPGRADE = "Upgrade".toLowerCase(); - - public final static String WEBSOCKET = "websocket".toLowerCase(); - - public final static String ACCEPT_LANGUAGE = "Accept-Language".toLowerCase(); - - public final static String SESSION_COOKIE_NAME = "JSESSIONID"; - - public final static String SESSION_URL_NAME = ";$sessionid$"; // ;jsessionid= - - public final static String FORWARDED_FOR = "x-Forwarded-for".toLowerCase(); - - public final static String FORWARDED_HOST = "X-Forwarded-Host".toLowerCase(); - - public final static String FORWARDED_SERVER = "X-Forwarded-Server".toLowerCase(); - - private static final Map EMPTYHASHTABLE = new Hashtable(); - - private Socket socket; - - private Hashtable sslAttributes; - - private Serve serve; - - private ServletInputStream in; - - private ServletOutputStream out; - - private String scheme; - - private AsyncCallback asyncMode; - - private Thread requestThread; - - private long asyncTimeout; - - private String reqMethod; // == null by default - - private String reqUriPath, reqUriPathUn; - - private String reqProtocol; - - private String charEncoding; // req and resp - - private String remoteUser; - - private String authType; - - private boolean oneOne; // HTTP/1.1 or better - - private boolean reqMime; - - private boolean websocketUpgrade; - - private Vector reqHeaderNames = new Vector(); - - private Vector reqHeaderValues = new Vector(); - - private Locale locale; // = java.util.Locale.getDefault(); - - private int uriLen; - - private HttpServlet servlet; - - protected boolean keepAlive = true; - - protected int timesRequested; - - protected long lastRun, lastWait; - - private Vector outCookies; - - private Vector inCookies; - - private String sessionCookieValue, sessionUrlValue, sessionValue, reqSessionValue; - - protected String reqQuery; - - private PrintWriter pw; - - private ServletOutputStream rout; - - private Map formParameters; - - private Hashtable attributes = new Hashtable(); - - private int resCode = -1; - - private String resMessage; - - private Hashtable resHeaderNames = new Hashtable(); - - private String[] postCache; - - private boolean headersWritten; - - private MessageFormat accessFmt; - - private Object[] logPlaceholders; - - // TODO consider creation an instance per thread in a pool, thread - // memory can be used - - private final SimpleDateFormat expdatefmt = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss 'GMT'", Locale.US); // used for - // cookie - - private final SimpleDateFormat rfc850DateFmt = new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss 'GMT'", - Locale.US); // rfc850-date - - private final SimpleDateFormat headerdateformat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", - Locale.US); // rfc1123-date - - private final SimpleDateFormat asciiDateFmt = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", Locale.US); // ASCII date, used in - // headers - - private static final TimeZone tz = TimeZone.getTimeZone("GMT"); - - static { - tz.setID("GMT"); - } - - // protected void finalize() throws Throwable { - // serve.log("-------"+this); - // super.finalize(); - // } - - // / Constructor. - public ServeConnection(Socket socket, Serve serve) { - // serve.log("+++++++"+this); - // Save arguments. - this.socket = socket; - this.serve = serve; - expdatefmt.setTimeZone(tz); - headerdateformat.setTimeZone(tz); - rfc850DateFmt.setTimeZone(tz); - asciiDateFmt.setTimeZone(tz); - if (serve.isAccessLogged()) { - // note format string must be not null - accessFmt = new MessageFormat((String) serve.arguments.get(ARG_ACCESS_LOG_FMT)); - logPlaceholders = new Object[12]; - } - try { - in = new ServeInputStream(socket.getInputStream(), this); - out = new ServeOutputStream(socket.getOutputStream(), this); - } catch (IOException ioe) { - close(); - return; - } - serve.threadPool.executeThread(this); - } - - private void initSSLAttrs() { - if (isSSLSocket() && sslAttributes == null) { - try { - sslAttributes = new Hashtable(); - Object sslSession = socket.getClass().getMethod("getSession", Utils.EMPTY_CLASSES) - .invoke(socket, Utils.EMPTY_OBJECTS); - if (sslSession != null) { - sslAttributes.put("javax.net.ssl.session", sslSession); - Method m = sslSession.getClass().getMethod("getCipherSuite", Utils.EMPTY_CLASSES); - m.setAccessible(true); - sslAttributes.put("javax.net.ssl.cipher_suite", m.invoke(sslSession, Utils.EMPTY_OBJECTS)); - m = sslSession.getClass().getMethod("getPeerCertificates", Utils.EMPTY_CLASSES); - m.setAccessible(true); - sslAttributes.put("javax.net.ssl.peer_certificates", m.invoke(sslSession, Utils.EMPTY_OBJECTS)); - } - } catch (IllegalAccessException iae) { - sslAttributes = null; - // iae.printStackTrace(); - } catch (NoSuchMethodException nsme) { - sslAttributes = null; - // nsme.printStackTrace(); - } catch (InvocationTargetException ite) { - // note we do not clear attributes, because - // SSLPeerUnverifiedException - // happens in the last call, when no client sertificate - // sslAttributes = null; - // ite.printStackTrace(); - } catch (IllegalArgumentException iae) { - // sslAttributes = null; - // iae.printStackTrace(); - } - // System.err.println("Socket SSL attrs: "+sslAttributes); - } // else TODO take attributes from SSLEngine when used - } - - /** - * it closes stream awaring of keep -alive - * - * @throws IOException - */ - private void closeStreams() throws IOException { - // System.err.println("===>CLOSE()"); - IOException ioe = null; - try { - if (pw != null) - pw.flush(); - else - out.flush(); - } catch (IOException io1) { - ioe = io1; - } - try { - out.close(); - } catch (IOException io1) { - if (ioe != null) - ioe = (IOException) ioe.initCause(io1); - else - ioe = io1; - } - try { - in.close(); - } catch (IOException io1) { - if (ioe != null) - ioe = (IOException) ioe.initCause(io1); - else - ioe = io1; - } - if (ioe != null) - throw ioe; - } - - /* open for debug only - protected void finalize() throws Throwable { - System.err.println("Connection object gone"); // !!! - super.finalize(); - } - */ - - private void restart() throws IOException { - // new Exception("RESTART").printStackTrace(); - reqMethod = null; - reqUriPath = reqUriPathUn = null; - reqProtocol = null; - charEncoding = null; - remoteUser = null; - authType = null; - servlet = null; - oneOne = false; - reqMime = false; - // considering that clear() works faster than new - if (reqHeaderNames == null) - reqHeaderNames = new Vector(); - else - reqHeaderNames.clear(); - if (reqHeaderValues == null) - reqHeaderValues = new Vector(); - else - reqHeaderValues.clear(); - locale = null; - uriLen = 0; - outCookies = null; - inCookies = null; - sessionCookieValue = null; // requested - sessionUrlValue = null; // requested - sessionValue = null; // actual used - reqSessionValue = null; // requested and used - reqQuery = null; - pw = null; - rout = null; - formParameters = null; - if (attributes == null) - attributes = new Hashtable(); - else - attributes.clear(); - if (sslAttributes != null) - attributes.putAll(sslAttributes); - resCode = -1; - resMessage = null; - resHeaderNames.clear(); - headersWritten = false; - websocketUpgrade = false; - postCache = null; - if (asyncMode != null) { - serve.log("TJWS: debug", new Exception("Restarting without clean async mode")); - asyncMode = null; - } - requestThread = Thread.currentThread(); - ((ServeInputStream) in).refresh(); - out = new ServeOutputStream(socket.getOutputStream(), this); - // stream can be still used asyncronously, so - // ((ServeOutputStream) out).refresh(); - } - - // Methods from Runnable. - public void run() { - if (socket == null) - return; - try { - do { - restart(); - // Get the streams. - parseRequest(); - //serve.log("A>"+asyncMode); - if (asyncMode != null) { - asyncTimeout = asyncMode.getTimeout(); - if (asyncTimeout > 0) - asyncTimeout += System.currentTimeMillis(); - return; - } - finalizerequest(); - if (websocketUpgrade) { - out.flush(); - try { - serve.websocketProvider.upgrade(socket, reqUriPath, servlet, this, this); - return; - }catch(Exception e) { - serve.log("TJWS: websocket upgrade protocol error: "+e, e); - websocketUpgrade = false; - } - } - } while (keepAlive && serve.isKeepAlive() && timesRequested < serve.getMaxTimesConnectionUse()); - } catch (IOException ioe) { - // System.err.println("Drop "+ioe); - if (ioe instanceof SocketTimeoutException) { - // serve.log("Keepalive timeout, async " + asyncMode, null); - } else { - String errMsg = ioe.getMessage(); - if ((errMsg == null || errMsg.indexOf("ocket closed") < 0) - && ioe instanceof java.nio.channels.AsynchronousCloseException == false) - if (socket != null) - serve.log("TJWS: IO error: " + ioe + " in processing a request " +(reqUriPathUn==null?"(NULL)":reqUriPathUn)+" from " - + socket.getInetAddress() + ":" + socket.getLocalPort() + " / " - + socket.getClass().getName()/* , ioe*/ ); - else - serve.log("TJWS: IO error: " + ioe + "(socket NULL)"); - else - synchronized (this) { - socket = null; - } - } //ioe.printStackTrace(); - } finally { - if (asyncMode == null && !websocketUpgrade) - close(); - } - } - - synchronized final void close() { - if (socket != null) - try { - socket.close(); - socket = null; - } catch (IOException e) { /* ignore */ - } - } - - private void parseRequest() throws IOException { - byte[] lineBytes = new byte[4096]; - int len; - String line; - // / TODO put time mark here for start waiting for receiving - // requests - lastWait = System.currentTimeMillis(); - // Read the first line of the request. - socket.setSoTimeout(serve.timeoutKeepAlive); - len = in.readLine(lineBytes, 0, lineBytes.length); - if (len <= 0) { - if (keepAlive) { - keepAlive = false; - // connection seems be closed - } else { - problem("Status-Code 400: Bad Request(empty)", SC_BAD_REQUEST); - } - return; - } - if (len >= lineBytes.length) { - problem("Status-Code 414: Request-URI Too Long", SC_REQUEST_URI_TOO_LONG); - return; - } - line = new String(lineBytes, 0, len, UTF8); - //serve.log("R>"+line); - StringTokenizer ust = new StringTokenizer(line); - if (ust.hasMoreTokens()) { - reqMethod = ust.nextToken(); - if (ust.hasMoreTokens()) { - reqUriPathUn = ust.nextToken(); - // TODO make it only when URL overwrite enambled - int uop = reqUriPathUn.indexOf(SESSION_URL_NAME); - if (uop > 0) { - sessionUrlValue = reqUriPathUn.substring(uop + SESSION_URL_NAME.length()); - reqUriPathUn = reqUriPathUn.substring(0, uop); - try { - serve.getSession(sessionUrlValue).userTouch(); - } catch (NullPointerException npe) { - } catch (IllegalStateException ise) { - } - } - if (ust.hasMoreTokens()) { - reqProtocol = ust.nextToken(); - oneOne = !reqProtocol.toUpperCase().equals("HTTP/1.0"); - reqMime = true; - // Read the rest of the lines. - String s; - while ((s = ((ServeInputStream) in).readLine(HTTP_MAX_HDR_LEN)) != null) { - //serve.log("H>"+s); - if (s.length() == 0) - break; - int c = s.indexOf(':', 0); - if (c > 0) { - String key = s.substring(0, c).trim().toLowerCase(); - String value = s.substring(c + 1).trim(); - reqHeaderNames.addElement(key); - reqHeaderValues.addElement(value); - } else - serve.log("TJWS: header field '" + s + "' without ':'"); - } - } else { - reqProtocol = "HTTP/0.9"; - oneOne = false; - reqMime = false; - // keep alive supposes to be false already - } - } - } - - if (reqProtocol == null) { - problem("Status-Code 400: Malformed request line:" + line, SC_BAD_REQUEST); - return; - } - // Check Host: header in HTTP/1.1 requests. - if (oneOne) { - String s = getHeader(HOST); - if (s == null) { - problem("Status-Code 400: 'Host' header is missing in HTTP/1.1 request", SC_BAD_REQUEST); - return; - } - s = getHeader(CONNECTION); - if (s != null) - s = s.toLowerCase(); - websocketUpgrade = s != null && s.indexOf(UPGRADE) >= 0 && WEBSOCKET.equalsIgnoreCase(getHeader(UPGRADE)); - keepAlive = "close".equalsIgnoreCase(s) == false; - if (keepAlive) { - s = getHeader(KEEPALIVE); - //serve.log("upgrading protocol "+s); - // FF specific ? - // parse value to extract the connection - // specific timeoutKeepAlive and - // maxAliveConnUse - // todo that introduce the value in req/resp - // and copy defaults from Serve - } - } else - keepAlive = false; - - // Split off query string, if any. - int mark = reqUriPathUn.indexOf('?'); - if (mark > -1) { - if (mark < reqUriPathUn.length() - 1) - reqQuery = reqUriPathUn.substring(mark + 1); - reqUriPathUn = reqUriPathUn.substring(0, mark); - } - reqUriPath = Utils.decode(reqUriPathUn, UTF8); - // TDOD check if reqUriPathUn starts with http://host:port - if (CHUNKED.equalsIgnoreCase(getHeader(TRANSFERENCODING))) { - setHeader(CONTENTLENGTH, null); - ((ServeInputStream) in).chunking(true); - } - String contentEncoding = extractEncodingFromContentType(getHeader(CONTENTTYPE)); - // TODO: encoding in request can be invalid, then do default - setCharacterEncoding(contentEncoding != null ? contentEncoding : UTF8); - String contentLength = getHeader(CONTENTLENGTH); - if (contentLength != null) - try { - ((ServeInputStream) in).setContentLength(Long.parseLong(contentLength)); - } catch (NumberFormatException nfe) { - serve.log("TJWS: Invalid value of input content-length: " + contentLength); - } - // the code was originally in processing headers loop, however hhas - // been moved here - String encoding = getHeader(CONTENT_ENCODING); - if (encoding != null) { - if ((encoding.equalsIgnoreCase("gzip") || encoding.equalsIgnoreCase("compressed")) - && null != serve.gzipInStreamConstr && ((ServeInputStream) in).compressed(true)) { - } else { - problem("Status-Code 415: Unsupported media type:" + encoding, SC_UNSUPPORTED_MEDIA_TYPE); - return; - } - } - if (assureHeaders() && socket.getKeepAlive() == false) - socket.setKeepAlive(true); - socket.setSoTimeout(0); - serve.setHost(getHeader(HOST)); - PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); - lastRun = System.currentTimeMillis(); - try { - // TODO new - // SimpleRequestDispatcher(reqUriPathUn).forward((ServletRequest) - // this, (ServletResponse) this); - Object[] os = registry.get(reqUriPath); - if (websocketUpgrade) { - websocketUpgrade = false; - if (serve.websocketProvider != null) - try { - serve.websocketProvider.handshake(socket, reqUriPath, servlet = (HttpServlet) os[0], this, this); - websocketUpgrade = resCode == SC_SWITCHING_PROTOCOLS; - // System.err.println("hs code:"+resCode); - } catch(Exception wse) { - problem("Can't handshake "+wse, SC_INTERNAL_SERVER_ERROR, wse ); - } - else - problem("Websocket support is not configured", SC_NOT_IMPLEMENTED ); - } else { - if (os[0] != null) { // note, os always not null - // / TODO put time mark here to monitor actual servicing - - // System.err.println("Servlet "+os[0]+" for path "+reqUriPath); - uriLen = ((Integer) os[1]).intValue(); - initSSLAttrs(); - runServlet((HttpServlet) os[0]); - } else { - problem("No any servlet found for serving " + reqUriPath, SC_BAD_REQUEST); - } - } - } finally { - currentRegistry.set(null); // remove - } - } - - private void finalizerequest() throws IOException { - if (reqMethod != null && serve.isAccessLogged()) { - // TODO avoid hardcoded indecies, give them name as LOG_IP = 0, - // LOG_IDENT = 1, LOG_REMOTE_USER = 2 - // consider caching socket stuff for faster logging - // {0} {1} {2} [{3,date,dd/MMM/yyyy:HH:mm:ss Z}] \"{4} {5} {6}\" - // {7,number,#} {8,number} {9} {10} - // ARG_ACCESS_LOG_FMT - logPlaceholders[0] = socket.getInetAddress(); // IP - logPlaceholders[1] = "-"; // the RFC 1413 identity of the - // client, TODO get it from BASIC - // auth - logPlaceholders[2] = remoteUser == null ? "-" : remoteUser; // remote - // user - logPlaceholders[3] = new Date(lastRun); // time stamp - // {3,date,dd/MMM/yyyy:HH:mm:ss - // Z} {3,time,} - logPlaceholders[4] = reqMethod; // method - logPlaceholders[5] = reqUriPathUn; // resource - logPlaceholders[6] = reqProtocol; // protocol - logPlaceholders[7] = new Integer(resCode); // res code - logPlaceholders[8] = new Long(((ServeOutputStream) out).lengthWritten()); - logPlaceholders[9] = new Integer(socket.getLocalPort()); - logPlaceholders[10] = serve.isShowReferer() ? getHeader("Referer") : "-"; - logPlaceholders[11] = serve.isShowUserAgent() ? getHeader("User-Agent") : "-"; - serve.logStream.println(accessFmt.format(logPlaceholders)); - } - if (!websocketUpgrade) { - lastRun = 0; - timesRequested++; - closeStreams(); - } - } - - private boolean assureHeaders() { - if (reqMime) - setHeader("MIME-Version", "1.0"); - setDateHeader("Date", System.currentTimeMillis()); - setHeader("Server", Serve.Identification.serverName + "/" + Serve.Identification.serverVersion); - if (keepAlive && serve.isKeepAlive() && !websocketUpgrade) { - if (reqMime) { - setHeader(CONNECTION, KEEPALIVE); // set for 1.1 too, - // because some client - // do not follow a - // standard - if (oneOne) - setHeader(KEEPALIVE, serve.getKeepAliveParamStr()); - } - return true; - } else if (websocketUpgrade) { - setHeader(CONNECTION, UPGRADE); - return true; - } else - setHeader(CONNECTION, "close"); - return false; - } - - private void runServlet(HttpServlet servlete) throws IOException { - // Set default response fields. - setStatus(SC_OK); - try { - parseCookies(); - if (reqSessionValue == null) // not from cookie - reqSessionValue = sessionUrlValue; - sessionValue = reqSessionValue; - if (authenificate()) { - if (servlete instanceof SingleThreadModel) - synchronized (servlete) { - servlete.service((ServletRequest) this, (ServletResponse) this); - } - else - servlete.service((ServletRequest) this, (ServletResponse) this); - } - // old close - } catch (UnavailableException e) { - if (e.isPermanent()) { - serve.unloadServlet(servlete); - servlete.destroy(); - } else if (e.getUnavailableSeconds() > 0) - serve.log("TJWS: Temporary unavailability feature is not supported " + servlete); - problem(e.getMessage(), SC_SERVICE_UNAVAILABLE); - } catch (ServletException e) { - serve.log("TJWS: Servlet exception", e); - Throwable rootCause = e.getRootCause(); - while (rootCause != null) { - serve.log("Caused by", rootCause); - if (rootCause instanceof ServletException) - rootCause = ((ServletException) rootCause).getRootCause(); - else - rootCause = rootCause.getCause(); /* 1.4 */ - } - problem(e.toString(), SC_INTERNAL_SERVER_ERROR); - } catch (IOException ioe) { - throw ioe; - } catch (Exception e) { - serve.log("TJWS: Unexpected problem running servlet", e); - problem("Unexpected problem running servlet: " + e.toString(), SC_INTERNAL_SERVER_ERROR); - } finally { - // closeStreams(); - // socket will be closed by a caller if no keep-alive - } - } - - private boolean authenificate() throws IOException { - Object[] o = serve.realms.get(reqUriPath); // by Niel Markwick - BasicAuthRealm realm = null; - if (o != null) - realm = (BasicAuthRealm) o[0]; - // System.err.println("looking for realm for path "+getPathInfo()+" - // in - // "+serve.realms+" found "+realm); - if (realm == null) - return true; - - String credentials = getHeader("Authorization"); - - if (credentials != null) { - credentials = Acme.Utils.base64Decode(credentials.substring(credentials.indexOf(' ') + 1), - getCharacterEncoding()); - int i = credentials.indexOf(':'); - String user = credentials.substring(0, i); - String password = credentials.substring(i + 1); - remoteUser = user; - authType = "BASIC"; // support only basic authenification (FORM, - // CLIENT_CERT, DIGEST ) - String realPassword = (String) realm.get(user); - // System.err.println("User "+user+" Password "+password+" real - // "+realPassword); - if (realPassword != null && realPassword.equals(password)) - return true; - } - - setStatus(SC_UNAUTHORIZED); - setHeader("WWW-Authenticate", "basic realm=\"" + realm.name() + '"'); - // writeHeaders(); // because sendError() is used - realSendError(); - return false; - } - - private void problem(String logMessage, int resCode, Throwable t) { - serve.log("TJWS: " + logMessage, t); - try { - sendError(resCode, logMessage); - } catch (IllegalStateException e) { /* ignore */ - } catch (IOException e) { /* ignore */ - } - } - - private void problem(String logMessage, int resCode) { - problem(logMessage, resCode, null); - } - - public void setInInclude(boolean set) { - ((ServeOutputStream) out).setInInclude(set); - } - - public void spawnAsync(AsyncCallback setAsync) { - //System.err.println("SPAWN=="); - asyncMode = setAsync; - } - - public void joinAsync() { - //System.err.println("JOIN=="); - //new Exception("JOIN==").printStackTrace(); - synchronized (this) { - if (asyncMode == null) - return; - asyncMode = null; - } - //System.err.println("Comparing request with current "+ requestThread+" "+ Thread.currentThread()); - if (requestThread == Thread.currentThread()) // detecting if called within request processing thread - return; - try { - finalizerequest(); - if (keepAlive && serve.isKeepAlive() && timesRequested < serve.getMaxTimesConnectionUse()) - serve.threadPool.executeThread(this); - else - close(); - } catch (IOException ioe) { - serve.log("TJWS: " + ioe); - } finally { - } - } - - public void extendAsyncTimeout(long period) { - if (period > 0) - asyncTimeout = System.currentTimeMillis() + period; - else if (period < 0) - asyncTimeout = 0; - } - - private static final int MAYBEVERSION = 1; - - private static final int INVERSION = 2; - - private static final int OLD_INNAME = 3; - - private static final int OLD_INVAL = 4; - - private static final int INVERSIONNUM = 5; - - private static final int RECOVER = 6; - - private static final int NEW_INNAME = 7; - - private static final int NEW_INVAL = 8; - - private static final int INPATH = 9; - - private static final int MAYBEINPATH = 10; - - private static final int INPATHVALUE = 11; - - private static final int MAYBEPORT = 12; - - private static final int INDOMAIN = 13; - - private static final int MAYBEDOMAIN = 14; - - private static final int INPORT = 15; - - private static final int INDOMAINVALUE = 16; - - private static final int INPORTVALUE = 17; - - // TODO see if it can be simplified - // TODO check if HTTPOnly can be transfere back - private void parseCookies() throws IOException { - if (inCookies == null) - inCookies = new Vector(); - String cookies = getHeader(COOKIE); - if (cookies == null) - return; - try { - String cookie_name = null; - String cookie_value = null; - String cookie_path = null; - String cookie_domain = null; - //boolean httpOnly = false; - if (cookies.length() > 300 * 4096) - throw new IOException("Cookie string too long:" + cookies.length()); - // System.err.println("We received:" + cookies); - char[] cookiesChars = cookies.toCharArray(); - int state = MAYBEVERSION; - StringBuffer token = new StringBuffer(256); - boolean quoted = false; - for (int i = 0; i < cookiesChars.length; i++) { - char c = cookiesChars[i]; - - switch (state) { - case MAYBEVERSION: - if (c != ' ') { - token.append(c); - if (c == '$') { - state = INVERSION; // RFC 2965 - } else - // RFC 2109 - state = OLD_INNAME; - } - break; - case OLD_INNAME: - if (c == '=') { - state = OLD_INVAL; - cookie_name = token.toString(); - token.setLength(0); - } else if (c != ' ' || token.length() > 0) - token.append(c); - break; - // TODO introduce val_start. then quoted value and value - case OLD_INVAL: - if (quoted == false) { - if (c == ';') { - state = OLD_INNAME; - cookie_value = token.toString(); - token.setLength(0); - addCookie(cookie_name, cookie_value, null, null); - } else if (c == '"' && token.length() == 0) - quoted = true; - else - token.append(c); - } else { - if (c == '"') - quoted = false; - else - token.append(c); - } - break; - case INVERSION: - if (c == '=') { - if ("$Version".equals(token.toString())) - state = INVERSIONNUM; - else { - state = OLD_INVAL; // consider name starts with - // $ - cookie_name = token.toString(); - } - token.setLength(0); - } else - token.append(c); - break; - case INVERSIONNUM: - if (c == ',' || c == ';') { - token.setLength(0); - state = NEW_INNAME; - } else if (Character.isDigit(c) == false) { - state = RECOVER; - } else - token.append(c); - break; - case NEW_INNAME: - if (c == '=') { - state = NEW_INVAL; - cookie_name = token.toString(); - token.setLength(0); - } else if (c != ' ' || token.length() > 0) - token.append(c); - break; - case NEW_INVAL: - if (c == ';') { - state = MAYBEINPATH; - cookie_value = token.toString(); - token.setLength(0); - cookie_path = null; - } else if (c == ',') { - state = NEW_INNAME; - cookie_value = token.toString(); - token.setLength(0); - addCookie(cookie_name, cookie_value, null, null); - } else - token.append(c); - break; - case MAYBEINPATH: - if (c != ' ') { - token.append(c); - if (c == '$') { - state = INPATH; - } else { - addCookie(cookie_name, cookie_value, null, null); - state = NEW_INNAME; - } - } - break; - case INPATH: - if (c == '=') { - if ("$Path".equals(token.toString())) - state = INPATHVALUE; - else { - addCookie(cookie_name, cookie_value, null, null); - state = NEW_INVAL; // consider name starts with - // $ - cookie_name = token.toString(); - } - token.setLength(0); - } else - token.append(c); - break; - case INPATHVALUE: - if (c == ',') { - cookie_path = token.toString(); - state = NEW_INNAME; - addCookie(cookie_name, cookie_value, cookie_path, null); - token.setLength(0); - } else if (c == ';') { - state = MAYBEDOMAIN; - cookie_path = token.toString(); - token.setLength(0); - } else - token.append(c); - break; - case MAYBEDOMAIN: - if (c != ' ') { - token.append(c); - if (c == '$') { - state = INDOMAIN; - } else { - addCookie(cookie_name, cookie_value, cookie_path, null); - state = NEW_INNAME; - } - } - break; - case INDOMAIN: - if (c == '=') { - if ("$Domain".equals(token.toString())) - state = INDOMAINVALUE; - else { - addCookie(cookie_name, cookie_value, cookie_path, null); - state = NEW_INVAL; // consider name starts with - // $ - cookie_name = token.toString(); - } - token.setLength(0); - } - break; - case INDOMAINVALUE: - if (c == ',') { - state = NEW_INNAME; - addCookie(cookie_name, cookie_value, cookie_path, token.toString()); - token.setLength(0); - } else if (c == ';') { - cookie_domain = token.toString(); - state = MAYBEPORT; - } else - token.append(c); - break; - case MAYBEPORT: - if (c != ' ') { - token.append(c); - if (c == '$') { - state = INPORT; - } else { - addCookie(cookie_name, cookie_value, cookie_path, cookie_domain); - state = NEW_INNAME; - } - } - break; - case INPORT: - if (c == '=') { - if ("$Port".equals(token.toString())) - state = INPORTVALUE; - else { - addCookie(cookie_name, cookie_value, cookie_path, cookie_domain); - state = NEW_INVAL; // consider name starts with - // $ - cookie_name = token.toString(); - } - token.setLength(0); - } - break; - case INPORTVALUE: - if (c == ',' || c == ';') { - int port = Integer.parseInt(token.toString()); - state = NEW_INNAME; - addCookie(cookie_name, cookie_value, cookie_path, cookie_domain); - token.setLength(0); - } else if (Character.isDigit(c) == false) { - state = RECOVER; - } else - token.append(c); - break; - case RECOVER: - serve.log("TJWS: Parsing recover of cookie string " + cookies, null); - if (c == ';' || c == ',') { - token.setLength(0); - state = NEW_INNAME; - } - break; - } - } - if (state == OLD_INVAL || state == NEW_INVAL) { - cookie_value = token.toString(); - addCookie(cookie_name, cookie_value, null, null); - } else if (state == INPATHVALUE) { - addCookie(cookie_name, cookie_value, token.toString(), null); - } else if (state == INDOMAINVALUE) { - addCookie(cookie_name, cookie_value, cookie_path, token.toString()); - } else if (state == INPORTVALUE) - addCookie(cookie_name, cookie_value, cookie_path, cookie_domain); - } catch (Error e) { - serve.log("TJWS: Error in parsing cookies: " + cookies, e); - } catch (Exception e) { - serve.log("TJWS: An exception in parsing cookies: " + cookies, e); - } - } - - private void addCookie(String name, String value, String path, String domain) { - if (SESSION_COOKIE_NAME.equals(name) && sessionCookieValue == null) { - sessionCookieValue = value; - try { - serve.getSession(sessionCookieValue).userTouch(); - reqSessionValue = sessionCookieValue; - } catch (IllegalStateException ise) { - } catch (NullPointerException npe) { - } - } else { - Cookie c; - inCookies.addElement(c = new Cookie(name, value)); - if (path != null) { - c.setPath(path); - if (domain != null) - c.setDomain(domain); - } - } - } - - // Methods from ServletRequest. - - // / Returns the size of the request entity data, or -1 if not known. - // Same as the CGI variable CONTENT_LENGTH. - public int getContentLength() { - try { - return getIntHeader(CONTENTLENGTH); - } catch(NumberFormatException nfe) { - - } - return -1; - } - - // / Returns the MIME type of the request entity data, or null if - // not known. - // Same as the CGI variable CONTENT_TYPE. - public String getContentType() { - return getHeader(CONTENTTYPE); - } - - // / Returns the protocol and version of the request as a string of - // the form /.. - // Same as the CGI variable SERVER_PROTOCOL. - public String getProtocol() { - return reqProtocol; - } - - // / Returns the scheme of the URL used in this request, for example - // "http", "https", or "ftp". Different schemes have different rules - // for constructing URLs, as noted in RFC 1738. The URL used to create - // a request may be reconstructed using this scheme, the server name - // and port, and additional information such as URIs. - public String getScheme() { - if (scheme == null) - // lazy stuf dlc - synchronized (this) { - if (scheme == null) - scheme = isSSLSocket() || (serve.proxySSL) ? "https" - : "http"; - } - return scheme; - } - - boolean isSSLSocket() { - return socket.getClass().getName().indexOf("SSLSocket") > 0 || socket.getClass().getName().indexOf("SSLChannel") > 0; - } - - // / Returns the host name of the server as used in the part of - // the request URI. - // Same as the CGI variable SERVER_NAME. - public String getServerName() { - String serverName = getHeader(HOST); - if (serverName != null && serverName.length() > 0) { - int colon = serverName.lastIndexOf(':'); - if (colon >= 0) { - if (colon < serverName.length()) - serverName = serverName.substring(0, colon); - } - } - if (serverName == null) { - if (serve.proxyConfig) - serverName = getHeader(FORWARDED_SERVER); - if (serverName == null) { - try { - serverName = InetAddress.getLocalHost().getHostName(); - } catch (java.net.UnknownHostException ignore) { - serverName = "localhost"; - } - } - } - int slash = serverName.indexOf("/"); - if (slash >= 0) - serverName = serverName.substring(slash + 1); - return serverName; - } - - // / Returns the port number on which this request was received as used - // in - // the part of the request URI. - // Same as the CGI variable SERVER_PORT. - public int getServerPort() { - String serverName = getHeader(HOST); - if (serverName != null && serverName.length() > 0) { - int colon = serverName.indexOf(':'); - if (colon >= 0) - try { - return Integer.parseInt(serverName.substring(colon + 1).trim()); - } catch (NumberFormatException nfe) { - - } - else { - if ("https".equals(getScheme())) - return 443; - return 80; - } - } - return socket.getLocalPort(); - } - - // / Returns the Internet Protocol (IP) address of the client or last - // proxy that sent the request. - // Same as the CGI variable REMOTE_ADDR. - public String getRemoteAddr() { - if (serve.proxyConfig && getHeader(FORWARDED_FOR) != null) - return getHeader(FORWARDED_FOR); - return socket.getInetAddress().getHostAddress(); - } - - // / Returns the fully qualified name of the client or the last proxy - // that sent the request. - // - // Same as the CGI variable REMOTE_HOST. - public String getRemoteHost() { - if (serve.proxyConfig && getHeader(FORWARDED_FOR) != null) - return getHeader(FORWARDED_FOR); // TODO resolve name by IP address from X-Forwarded-For - String result = socket.getInetAddress().getHostName(); - return result != null ? result : getRemoteAddr(); - } - - // / Applies alias rules to the specified virtual path and returns the - // corresponding real path, or null if the translation can not be - // performed for any reason. For example, an HTTP servlet would - // resolve the path using the virtual docroot, if virtual hosting is - // enabled, and with the default docroot otherwise. Calling this - // method with the string "/" as an argument returns the document root. - public String getRealPath(String path) { - return serve.getRealPath(path); - } - - // / Returns an input stream for reading request data. - // @exception IllegalStateException if getReader has already been called - // @exception IOException on other I/O-related errors - public ServletInputStream getInputStream() throws IOException { - synchronized (in) { - if (((ServeInputStream) in).isReturnedAsReader()) - throw new IllegalStateException("Already returned as a reader."); - ((ServeInputStream) in).setReturnedAsStream(true); - } - return in; - } - - // / Returns a buffered reader for reading request data. - // @exception UnsupportedEncodingException if the character set encoding - // isn't supported - // @exception IllegalStateException if getInputStream has already been - // called - // @exception IOException on other I/O-related errors - public BufferedReader getReader() { - synchronized (in) { - if (((ServeInputStream) in).isReturnedAsStream()) - throw new IllegalStateException("Already returned as a stream."); - ((ServeInputStream) in).setReturnedAsReader(true); - } - if (charEncoding != null) - try { - return new BufferedReader(new InputStreamReader(in, charEncoding)); - } catch (UnsupportedEncodingException uee) { - } - return new BufferedReader(new InputStreamReader(in)); - } - - private Map assureParametersFromRequest() { - synchronized (resHeaderNames) { // supposes to not be null - if (formParameters == null) { - if ("GET".equals(reqMethod) || "HEAD".equals(reqMethod)) { - if (reqQuery != null) - try { - formParameters = Acme.Utils.parseQueryString(reqQuery, charEncoding); - } catch (IllegalArgumentException ex) { - serve.log("TJWS: Exception " + ex + " at parsing 'get|head' data " + reqQuery); - } - } else if ("POST".equals(reqMethod)) { - String contentType = getContentType(); - if (contentType != null - && WWWFORMURLENCODE.regionMatches(true, 0, contentType, 0, WWWFORMURLENCODE.length())) { - if (postCache == null) { - postCache = new String[1]; - InputStream is = null; - try { - formParameters = Acme.Utils.parsePostData(getContentLength(), - is = getInputStream(), charEncoding, postCache); - } catch (Exception ex) { - serve.log("TJWS: Exception " + ex + " at parsing 'POST' data of length " - + getContentLength()); - // TODO propagate the exception ? - formParameters = EMPTYHASHTABLE; - } - } else - formParameters = Acme.Utils.parseQueryString(postCache[0], charEncoding); - if (reqQuery != null && reqQuery.length() > 0) - formParameters.putAll(Acme.Utils.parseQueryString(reqQuery, charEncoding)); - } else if (reqQuery != null) - formParameters = Acme.Utils.parseQueryString(reqQuery, charEncoding); - } else - throw new IllegalArgumentException("Request parameters are not supported for method:"+reqMethod); - } - } - if (formParameters == null) - formParameters = EMPTYHASHTABLE; - return formParameters; - } - - // / Returns the parameter names for this request. - public Enumeration getParameterNames() { - assureParametersFromRequest(); - return ((Hashtable) formParameters).keys(); - } - - // / Returns the value of the specified query string parameter, or null - // if not found. - // @param name the parameter name - public String getParameter(String name) { - String[] params = getParameterValues(name); - if (params == null || params.length == 0) - return null; - - return params[0]; - } - - // / Returns the values of the specified parameter for the request as an - // array of strings, or null if the named parameter does not exist. - public String[] getParameterValues(String name) { - assureParametersFromRequest(); - return (String[]) formParameters.get(name); - } - - // / Returns the value of the named attribute of the request, or null if - // the attribute does not exist. This method allows access to request - // information not already provided by the other methods in this - // interface. - public Object getAttribute(String name) { - // System.err.println("!!!Get att orig:"+name+"="+attributes.get(name)); - return attributes.get(name); - } - - // Methods from HttpServletRequest. - - // / Gets the array of cookies found in this request. - public Cookie[] getCookies() { - Cookie[] cookieArray = new Cookie[inCookies.size()]; - inCookies.copyInto(cookieArray); - return cookieArray; - } - - // / Returns the method with which the request was made. This can be - // "GET", - // "HEAD", "POST", or an extension method. - // Same as the CGI variable REQUEST_METHOD. - public String getMethod() { - return reqMethod; - } - - /******************************************************************************************************************************************************* - * Returns the part of this request's URL from the protocol name up to - * the query string in the first line of the HTTP request. To - * reconstruct an URL with a scheme and host, use - * HttpUtils.getRequestURL(javax.servlet.http.HttpServletRequest). - */ - // / Returns the full request URI. - public String getRequestURI() { - return reqUriPathUn; - } - - /** - * Reconstructs the URL the client used to make the request. The - * returned URL contains a protocol, server name, port number, and - * server path, but it does not include query string parameters.
- * Because this method returns a StringBuffer, not a string, you can - * modify the URL easily, for example, to append query parameters. - *

- * This method is useful for creating redirect messages and for - * reporting errors. - * - * @return a StringBuffer object containing the reconstructed URL - * @since 2.3 - */ - public java.lang.StringBuffer getRequestURL() { - int port = getServerPort(); - return new StringBuffer().append(getScheme()).append("://").append(getServerName()) - .append("https".equals(getScheme()) && port == 443 || port == 80 ? "" : ":" + String.valueOf(port)) - .append(getRequestURI()); - } - - // / Returns the part of the request URI that referred to the servlet - // being - // invoked. - // Analogous to the CGI variable SCRIPT_NAME. - public String getServletPath() { - // In this server, the entire path is regexp-matched against the - // servlet pattern, so there's no good way to distinguish which - // part refers to the servlet. - return uriLen > 0 ? reqUriPath.substring(0, uriLen) : ""; - } - - // / Returns optional extra path information following the servlet path, - // but - // immediately preceding the query string. Returns null if not - // specified. - // Same as the CGI variable PATH_INFO. - public String getPathInfo() { - // In this server, the entire path is regexp-matched against the - // servlet pattern, so there's no good way to distinguish which - // part refers to the servlet. - return uriLen >= reqUriPath.length() ? null : reqUriPath.substring(uriLen); - } - - // / Returns extra path information translated to a real path. Returns - // null if no extra path information was specified. - // Same as the CGI variable PATH_TRANSLATED. - public String getPathTranslated() { - // In this server, the entire path is regexp-matched against the - // servlet pattern, so there's no good way to distinguish which - // part refers to the servlet. - return getRealPath(getPathInfo()); - } - - // / Returns the query string part of the servlet URI, or null if not - // known. - // Same as the CGI variable QUERY_STRING. - public String getQueryString() { - return reqQuery; - } - - // / Returns the name of the user making this request, or null if not - // known. - // Same as the CGI variable REMOTE_USER. - public String getRemoteUser() { - return remoteUser; - } - - // / Returns the authentication scheme of the request, or null if none. - // Same as the CGI variable AUTH_TYPE. - public String getAuthType() { - return authType; - } - - // / Returns the value of a header field, or null if not known. - // Same as the information passed in the CGI variabled HTTP_*. - // @param name the header field name - public String getHeader(String name) { - name = name.toLowerCase(); - int i = -1; - if (serve.proxyConfig && HOST.equals(name)) - i = reqHeaderNames.indexOf(FORWARDED_HOST); - if (i < 0) - i = reqHeaderNames.indexOf(name); - if (i < 0) - return null; - return (String) reqHeaderValues.elementAt(i); - } - - public int getIntHeader(String name) { - String val = getHeader(name); - if (val == null) - return -1; - return Integer.parseInt(val); - } - - public long getDateHeader(String name) { - String val = getHeader(name); - if (val == null) - return -1; - try { - return headerdateformat.parse(val).getTime(); - } catch (ParseException pe) { - try { - return rfc850DateFmt.parse(val).getTime(); - } catch (ParseException pe1) { - try { - return asciiDateFmt.parse(val).getTime(); - } catch (ParseException pe3) { - throw new IllegalArgumentException("Value " + val - + " can't be converted to Date using any of formats: [" + headerdateformat.toPattern() - + "][ " + rfc850DateFmt.toPattern() + "][" + asciiDateFmt.toPattern()); - } - } - } - } - - // / Returns an Enumeration of the header names. - public Enumeration getHeaderNames() { - return reqHeaderNames.elements(); - } - - // / Gets the current valid session associated with this request, if - // create is false or, if necessary, creates a new session for the - // request, if create is true. - //

- // Note: to ensure the session is properly maintained, the servlet - // developer must call this method (at least once) before any output - // is written to the response. - //

- // Additionally, application-writers need to be aware that newly - // created sessions (that is, sessions for which HttpSession.isNew - // returns true) do not have any application-specific state. - public synchronized HttpSession getSession(boolean create) { - HttpSession result = null; - if (sessionValue != null) { - result = serve.getSession(sessionValue); - if (result != null && ((AcmeSession) result).isValid() == false) { - serve.removeSession(sessionValue); - result = null; - } - // System.err.println("^^^^^^^req sess: "+sessionValue+", found:"+result); - } - if (result == null && create) { - result = serve.createSession(); - if (result != null) { - sessionValue = result.getId(); - } else - throw new RuntimeException("A session can't be created"); - // System.err.println("^~~~~~created: "+sessionValue); - } - return result; - } - - // JSDK 2.1 - public HttpSession getSession() { - return getSession(true); - } - - public boolean isRequestedSessionIdFromURL() { - return isRequestedSessionIdFromUrl(); - } - - // from ServletRequest - public Enumeration getAttributeNames() { - return attributes.keys(); - } - - /** - * Stores an attribute in this request. Attributes are reset between - * requests. This method is most often used in conjunction with - * RequestDispatcher. - *

- * Attribute names should follow the same conventions as package names. - * Names beginning with java.*, javax.*, and com.sun.*, are reserved for - * use by Sun Microsystems. If the object passed in is null, the effect - * is the same as calling removeAttribute(java.lang.String). - *

- * It is warned that when the request is dispatched from the servlet - * resides in a different web application by RequestDispatcher, the - * object set by this method may not be correctly retrieved in the - * caller servlet. - * - * @param name - * - a String specifying the name of the attribute - * @param o - * - the Object to be stored - */ - public void setAttribute(String key, Object o) { - // System.err.println("!!!Set att orig:"+key+"="+o); - // if ("javax.servlet.jsp.jspException".equals(key) && o instanceof - // Throwable) - // ((Throwable)o).printStackTrace(); - - if (o != null) - attributes.put(key, o); - else - attributes.remove(key); - } - - // / Gets the session id specified with this request. This may differ - // from the actual session id. For example, if the request specified - // an id for an invalid session, then this will get a new session with - // a new id. - public String getRequestedSessionId() { - return reqSessionValue; - } - - // / Checks whether this request is associated with a session that is - // valid in the current session context. If it is not valid, the - // requested session will never be returned from the getSession - // method. - public boolean isRequestedSessionIdValid() { - if (reqSessionValue != null) { - AcmeSession session = serve.getSession(reqSessionValue); - return (session != null && session.isValid()); - } - return false; - } - - /** - * Checks whether the session id specified by this request came in as a - * cookie. (The requested session may not be one returned by the - * getSession method.) - */ - public boolean isRequestedSessionIdFromCookie() { - return sessionCookieValue != null; - } - - // / Checks whether the session id specified by this request came in as - // part of the URL. (The requested session may not be the one returned - // by the getSession method.) - public boolean isRequestedSessionIdFromUrl() { - return sessionUrlValue != null && sessionCookieValue == null; - } - - // Methods from ServletResponse. - - // / Sets the content length for this response. - // @param length the content length - public void setContentLength(int length) { - if (length >= 0) - setIntHeader(CONTENTLENGTH, length); - else - setHeader(CONTENTLENGTH, null); - } - - // / Sets the content type for this response. - // @param type the content type - public void setContentType(String type) { - setHeader(CONTENTTYPE, type); - } - - // / Returns an output stream for writing response data. - public ServletOutputStream getOutputStream() { - synchronized (out) { - if (rout == null) { - if (pw != null) - throw new IllegalStateException("Already returned as a writer"); - rout = out; - } - } - return rout; - } - - // / Returns a print writer for writing response data. The MIME type of - // the response will be modified, if necessary, to reflect the character - // encoding used, through the charset=... property. This means that the - // content type must be set before calling this method. - // @exception UnsupportedEncodingException if no such encoding can be - // provided - // @exception IllegalStateException if getOutputStream has been called - // @exception IOException on other I/O errors - public PrintWriter getWriter() throws IOException { - synchronized (out) { - if (pw == null) { - if (rout != null) - throw new IllegalStateException("Already was returned as servlet output stream"); - String encoding = getCharacterEncoding(); - if (encoding != null) - pw = new PrintWriter(new OutputStreamWriter(out, encoding)); - else - pw = new PrintWriter(out); - } - } - return pw; - } - - // / Returns the character set encoding used for this MIME body. The - // character encoding is either the one specified in the assigned - // content type, or one which the client understands. If no content - // type has yet been assigned, it is implicitly set to text/plain. - public String getCharacterEncoding() { - String ct = (String) resHeaderNames.get(CONTENTTYPE.toLowerCase()); - if (ct != null) { - String enc = extractEncodingFromContentType(ct); - if (enc != null) - return enc; - } - return charEncoding; - } - - private String extractEncodingFromContentType(String ct) { - if (ct == null) - return null; - int scp = ct.indexOf(';'); - if (scp > 0) { - scp = ct.toLowerCase().indexOf("charset=", scp); - if (scp >= 0) { - ct = ct.substring(scp + "charset=".length()).trim(); - scp = ct.indexOf(';'); - if (scp > 0) - ct = ct.substring(0, scp); - int l = ct.length(); - if (l > 2 && ct.charAt(0) == '"') - return ct.substring(1, l - 1); - return ct; - } - } - return null; - } - - // 2.2 - // do not use buffer - public void flushBuffer() throws java.io.IOException { - ((ServeOutputStream) out).flush(); - } - - /** - * Clears the content of the underlying buffer in the response without - * clearing headers or status code. If the response has been committed, - * this method throws an IllegalStateException. - * - * @since 2.3 - */ - public void resetBuffer() { - ((ServeOutputStream) out).reset(); - synchronized (this) { - headersWritten = false; // TODO check if stream was flushed - } - } - - public int getBufferSize() { - return ((ServeOutputStream) out).getBufferSize(); - } - - public void setBufferSize(int size) { - ((ServeOutputStream) out).setBufferSize(size); - } - - /** - * Returns a boolean indicating if the response has been committed. A - * commited response has already had its status code and headers - * written. - * - * @return a boolean indicating if the response has been committed - * @see setBufferSize(int), getBufferSize(), flushBuffer(), reset() - */ - // a caller should think about syncronization - public boolean isCommitted() { - return headersWritten && ((ServeOutputStream) out).lengthWritten() > 0; - } - - /** - * Clears any data that exists in the buffer as well as the status code - * and headers. If the response has been committed, this method throws - * an IllegalStateException. - * - * @throws java.lang.IllegalStateException - * - if the response has already been committed - * @see setBufferSize(int), getBufferSize(), flushBuffer(), - * isCommitted() - */ - public void reset() throws IllegalStateException { - // new Exception("RESET").printStackTrace(); - if (!isCommitted()) { - if (outCookies != null) - outCookies.clear(); - resHeaderNames.clear(); - pw = null; - rout = null; - ((ServeOutputStream) out).reset(); - assureHeaders(); - } else - throw new IllegalStateException("Header have already been committed."); - } - - /** - * Sets the locale of the response, setting the headers (including the - * Content-Type's charset) as appropriate. This method should be called - * before a call to getWriter(). By default, the response locale is the - * default locale for the server. - * - * @param loc - * - the locale of the response - * @see getLocale() - */ - public void setLocale(java.util.Locale locale) { - this.locale = locale; - } - - /** - * For request: Returns the preferred Locale that the client will accept - * content in, based on the Accept-Language header. If the client - * request doesn't provide an Accept-Language header, this method - * returns the default locale for the server. - * - * For response: Returns the locale specified for this response using - * the setLocale(java.util.Locale) method. Calls made to setLocale after - * the response is committed have no effect. If no locale has been - * specified, the container's default locale is returned. - */ - public java.util.Locale getLocale() { - if (locale != null) - return locale; - Enumeration e = getLocales(); - if (e.hasMoreElements()) - return (Locale) e.nextElement(); - return Locale.getDefault(); - } - - /** - * Returns an Enumeration of Locale objects indicating, in decreasing - * order starting with the preferred locale, the locales that are - * acceptable to the client based on the Accept-Language header. If the - * client request doesn't provide an Accept-Language header, this method - * returns an Enumeration containing one Locale, the default locale for - * the server. - */ - public Enumeration getLocales() { - // TODO: cache result - String al = getHeader(ACCEPT_LANGUAGE); - TreeSet ts = new TreeSet(); - if (al != null) { - // System.err.println("Accept lang:"+al); - StringTokenizer st = new StringTokenizer(al, ";", false); - try { - while (st.hasMoreTokens()) { - String langs = st.nextToken(";"); - // System.err.println("Langs:"+langs); - String q = st.nextToken(";="); - // System.err.println("q:"+q); - q = st.nextToken("=,"); - // System.err.println("q:"+q); - float w = 0; - try { - w = Float.valueOf(q).floatValue(); - } catch (NumberFormatException nfe) { - } - if (w > 0) { - StringTokenizer lst = new StringTokenizer(langs, ", ", false); - while (lst.hasMoreTokens()) { - String lan = lst.nextToken(); - int di = lan.indexOf('-'); - if (di < 0) - ts.add(new LocaleWithWeight(new Locale(lan.trim()) /* 1.4 */, w)); - else - ts.add(new LocaleWithWeight(new Locale(lan.substring(0, di), lan.substring(di + 1) - .trim().toUpperCase()), w)); - } - } - } - } catch (NoSuchElementException ncee) { - // can't parse - } - } - if (ts.size() == 0) - ts.add(new LocaleWithWeight(Locale.getDefault(), 1)); - return new AcceptLocaleEnumeration(ts); - } - - /** - * Overrides the name of the character encoding used in the body of this - * request. This method must be called prior to reading request - * parameters or reading input using getReader(). - * - * @param a - * - String containing the name of the chararacter encoding. - * @throws java.io.UnsupportedEncodingException - * - if this is not a valid encoding - * @since JSDK 2.3 - */ - public void setCharacterEncoding(String _enc) { - // TODO: check if encoding is valid - // TODO separate encoding came from page and set programatically - charEncoding = _enc; - synchronized (this) { - formParameters = null; - } - } - - public void addDateHeader(String header, long date) { - addHeader(header, headerdateformat.format(new Date(date))); - } - - public void addHeader(String header, String value) { - header = header.trim().toLowerCase(); - Object o = resHeaderNames.get(header); - if (o == null) - setHeader(header, value); - else { - if (o instanceof String[]) { - String[] oldVal = (String[]) o; - String[] newVal = new String[oldVal.length + 1]; - System.arraycopy(oldVal, 0, newVal, 0, oldVal.length); - newVal[oldVal.length] = value; - resHeaderNames.put(header, newVal); - } else if (o instanceof String) { - String[] newVal = new String[2]; - newVal[0] = (String) o; - newVal[1] = value; - resHeaderNames.put(header, newVal); - } else - throw new RuntimeException("Invalid content of header hash - " + o.getClass().getName()); - } - } - - public void addIntHeader(String header, int value) { - addHeader(header, Integer.toString(value)); - } - - public RequestDispatcher getRequestDispatcher(String urlpath) { - if (urlpath.length() > 0 && urlpath.charAt(0) != '/') { - String dispatchPath = getContextPath(); - String pathInfo = getPathInfo(); - String servletPath = getServletPath(); - ; - if (pathInfo != null) { - dispatchPath += servletPath; - int slp = pathInfo.indexOf('/', 1); - if (slp > 0) // can it ever happen? - dispatchPath += pathInfo.substring(0, slp - 1); - } else { - int spsp = servletPath.lastIndexOf('/'); - if (spsp >= 0) - dispatchPath += servletPath.substring(0, spsp); - } - // serve.log("Dispatch path:"+dispatchPath); - urlpath = dispatchPath + '/' + urlpath; - } - return serve.getRequestDispatcher(urlpath); - } - - public boolean isSecure() { - return "https".equals(getScheme()); - } - - public void removeAttribute(String name) { - attributes.remove(name); - } - - // only root context supported - public String getContextPath() { - return ""; - } - - public Enumeration getHeaders(String header) { - Vector result = new Vector(); - int i = -1; - while ((i = reqHeaderNames.indexOf(header.toLowerCase(), i + 1)) >= 0) - result.addElement(reqHeaderValues.elementAt(i)); - return result.elements(); - } - - public java.security.Principal getUserPrincipal() { - return null; - } - - public boolean isUserInRole(String user) { - return false; - } - - /** - * Returns a java.util.Map of the parameters of this request. Request - * parameters are extra information sent with the request. For HTTP - * servlets, parameters are contained in the query string or posted form - * data. - * - * @return an immutable java.util.Map containing parameter names as keys - * and parameter values as map values. The keys in the parameter - * map are of type String. The values in the parameter map are - * of type String array. - * @since 2.3 - */ - public Map getParameterMap() { - assureParametersFromRequest(); - return formParameters; - } - - // Methods from HttpServletResponse. - - // / Adds the specified cookie to the response. It can be called - // multiple times to set more than one cookie. - public void addCookie(Cookie cookie) { - if (outCookies == null) - outCookies = new Vector(); - - outCookies.addElement(cookie); - } - - // / Checks whether the response message header has a field with the - // specified name. - public boolean containsHeader(String name) { - return resHeaderNames.contains(name); - } - - // JSDK 2.1 extension - public String encodeURL(String url) { - int uop = url.indexOf(SESSION_URL_NAME); - // TODO not robust enough - if (uop > 0) - url = url.substring(0, uop); - if (sessionValue == null || isRequestedSessionIdFromCookie()) - return url; - try { - new URL(url); // for testing syntac - int ehp = url.indexOf('/'); - if (ehp < 0) - ehp = url.indexOf('?'); - if (ehp < 0) - ehp = url.indexOf('#'); - if (ehp < 0) - ehp = url.length(); - if (url.regionMatches(true, 0, getRequestURL().toString(), 0, ehp) == false) - return url; - } catch (MalformedURLException e) { - } - - return url + SESSION_URL_NAME + sessionValue; - } - - public String encodeRedirectURL(String url) { - return encodeURL(url); - } - - /** - * Returns the Internet Protocol (IP) source port of the client or last - * proxy that sent the request. - * - * @return an integer specifying the port number - * - * @since 2.4 - */ - public int getRemotePort() { - return getServerPort(); // TODO not quite robust - } - - /** - * Returns the host name of the Internet Protocol (IP) interface on - * which the request was received. - * - * @return a String containing the host name of the IP on - * which the request was received. - * - * @since 2.4 - */ - public String getLocalName() { - InetAddress ia = socket/* serve.serverSocket */.getLocalAddress(); - return ia == null ? null : ia.getCanonicalHostName(); /* 1.4 */ - } - - /** - * Returns the Internet Protocol (IP) address of the interface on which - * the request was received. - * - * @return a String containing the IP address on which the - * request was received. - * - * @since 2.4 - * - */ - public String getLocalAddr() { - InetAddress ia = /* serve.serverSocket */socket.getLocalAddress(); - return ia == null ? null : ia.getHostAddress(); - } - - /** - * Returns the Internet Protocol (IP) port number of the interface on - * which the request was received. - * - * @return an integer specifying the port number - * - * @since 2.4 - */ - public int getLocalPort() { - return socket.getLocalPort(); - } - - // / Sets the status code and message for this response. - // @param resCode the status code - // @param resMessage the status message - public void setStatus(int resCode, String resMessage) { - // if (((ServeOutputStream) out).isInInclude()) - // return; - this.resCode = resCode; - this.resMessage = resMessage; - } - - // / Sets the status code and a default message for this response. - // @param resCode the status code - public void setStatus(int resCode) { - switch (resCode) { - case SC_CONTINUE: - setStatus(resCode, "Continue"); - break; - case SC_SWITCHING_PROTOCOLS: - setStatus(resCode, "Switching protocols"); - break; - case SC_OK: - setStatus(resCode, "Ok"); - break; - case SC_CREATED: - setStatus(resCode, "Created"); - break; - case SC_ACCEPTED: - setStatus(resCode, "Accepted"); - break; - case SC_NON_AUTHORITATIVE_INFORMATION: - setStatus(resCode, "Non-authoritative"); - break; - case SC_NO_CONTENT: - setStatus(resCode, "No content"); - break; - case SC_RESET_CONTENT: - setStatus(resCode, "Reset content"); - break; - case SC_PARTIAL_CONTENT: - setStatus(resCode, "Partial content"); - break; - case SC_MULTIPLE_CHOICES: - setStatus(resCode, "Multiple choices"); - break; - case SC_MOVED_PERMANENTLY: - setStatus(resCode, "Moved permanentently"); - break; - case SC_MOVED_TEMPORARILY: - setStatus(resCode, "Moved temporarily"); - break; - case SC_SEE_OTHER: - setStatus(resCode, "See other"); - break; - case SC_NOT_MODIFIED: - setStatus(resCode, "Not modified"); - break; - case SC_USE_PROXY: - setStatus(resCode, "Use proxy"); - break; - case SC_BAD_REQUEST: - setStatus(resCode, "Bad request"); - break; - case SC_UNAUTHORIZED: - setStatus(resCode, "Unauthorized"); - break; - case SC_PAYMENT_REQUIRED: - setStatus(resCode, "Payment required"); - break; - case SC_FORBIDDEN: - setStatus(resCode, "Forbidden"); - break; - case SC_NOT_FOUND: - setStatus(resCode, "Not found"); - break; - case SC_METHOD_NOT_ALLOWED: - setStatus(resCode, "Method not allowed"); - break; - case SC_NOT_ACCEPTABLE: - setStatus(resCode, "Not acceptable"); - break; - case SC_PROXY_AUTHENTICATION_REQUIRED: - setStatus(resCode, "Proxy auth required"); - break; - case SC_REQUEST_TIMEOUT: - setStatus(resCode, "Request timeout"); - break; - case SC_CONFLICT: - setStatus(resCode, "Conflict"); - break; - case SC_GONE: - setStatus(resCode, "Gone"); - break; - case SC_LENGTH_REQUIRED: - setStatus(resCode, "Length required"); - break; - case SC_PRECONDITION_FAILED: - setStatus(resCode, "Precondition failed"); - break; - case SC_REQUEST_ENTITY_TOO_LARGE: - setStatus(resCode, "Request entity too large"); - break; - case SC_REQUEST_URI_TOO_LONG: - setStatus(resCode, "Request URI too long"); - break; - case SC_UNSUPPORTED_MEDIA_TYPE: - setStatus(resCode, "Unsupported media type"); - break; - case SC_INTERNAL_SERVER_ERROR: - setStatus(resCode, "Internal server error"); - break; - case SC_NOT_IMPLEMENTED: - setStatus(resCode, "Not implemented"); - break; - case SC_BAD_GATEWAY: - setStatus(resCode, "Bad gateway"); - break; - case SC_SERVICE_UNAVAILABLE: - setStatus(resCode, "Service unavailable"); - break; - case SC_GATEWAY_TIMEOUT: - setStatus(resCode, "Gateway timeout"); - break; - case SC_HTTP_VERSION_NOT_SUPPORTED: - setStatus(resCode, "HTTP version not supported"); - break; - case 207: - setStatus(resCode, "Multi Status"); - break; - default: - setStatus(resCode, ""); - break; - } - } - - // / Sets the value of a header field. - // @param name the header field name - // @param value the header field value - public void setHeader(String header, String value) { - header = header.trim().toLowerCase(); // normilize header - if (value == null) - resHeaderNames.remove(header); - else { - resHeaderNames.put(header, value); - // if (header.equals(CONTENTTYPE)) { - // String enc = extractEncodingFromContentType(value); - // if (enc != null) - // setCharacterEncoding(enc); - // } - } - } - - // / Sets the value of an integer header field. - // @param name the header field name - // @param value the header field integer value - public void setIntHeader(String header, int value) { - setHeader(header, Integer.toString(value)); - } - - // / Sets the value of a long header field. - // @param name the header field name - // @param value the header field long value - public void setLongHeader(String header, long value) { - setHeader(header, Long.toString(value)); - } - - // / Sets the value of a date header field. - // @param name the header field name - // @param value the header field date value - public void setDateHeader(String header, long value) { - setHeader(header, headerdateformat.format(new Date(value))); - } - - // / Writes the status line and message headers for this response to the - // output stream. - // @exception IOException if an I/O error has occurred - void writeHeaders() throws IOException { - synchronized (this) { - // TODO: possible to write trailer when chunked out, - // so chunked out should be global flag - if (headersWritten) - return; - // new Exception("headers").printStackTrace(); - headersWritten = true; - } - if (reqMime) { - boolean chunked_out = false; - long contentLen = -1; - if (resMessage.length() < 256) - out.println(reqProtocol + " " + resCode + " " + resMessage.replace('\r', '/').replace('\n', '/')); - else - out.println(reqProtocol + " " + resCode + " " - + resMessage.substring(0, 255).replace('\r', '/').replace('\n', '/')); - Enumeration he = resHeaderNames.keys(); - while (he.hasMoreElements()) { - String name = (String) he.nextElement(); - if (CONNECTION.equals(name) || KEEPALIVE.equals(name)) // skip header until make decision - continue; - Object o = resHeaderNames.get(name); - if (o instanceof String) { - String value = (String) o; - if (value != null) {// just in case - if(CONTENTTYPE.equals(name)) { - if (charEncoding != null && value.startsWith("text/")) { - int p = value.indexOf(';'); - if (p > 0) - value = value.substring(0, p); - value += "; charset="+charEncoding; - } - // TODO check locale and can take from it as well based on mapping locale charset - } - // some overhead can be here for checking every header, so possibly do checks after loop - if (CONTENTLENGTH.equals(name)) { - if (contentLen < 0) - try { - contentLen = Long.parseLong(value); - } catch (NumberFormatException nfe) { - } - } else - out.println(name + ": " + value); - if (chunked_out == false) - if (TRANSFERENCODING.equals(name) && CHUNKED.equals(value)) - chunked_out = true; - } - } else if (o instanceof String[]) { - String[] values = (String[]) o; - if ("set-cookie".equals(name)) { - for (int i = 0; i < values.length; i++) { - out.print(name); - out.print(": "); - out.println(values[i]); - } - } else { - out.print(name + ": " + values[0]); - for (int i = 1; i < values.length; i++) - out.print("," + values[i]); - out.println(); - } - } - } - - StringBuffer sb = null; - StringBuffer sb2 = null; - Cookie cc = null; - // add session cookie - if (sessionValue != null) { - HttpSession session = serve.getSession(sessionValue); - if (session != null) { - if (((AcmeSession) session).isValid()) { - if (session.isNew()) { - cc = new AcmeCookie(SESSION_COOKIE_NAME, sessionValue); - if (serve.expiredIn < 0) - cc.setMaxAge(Math.abs(serve.expiredIn) * 60); - ((AcmeCookie) cc).setHttpOnly(serve.httpSessCookie); - if (serve.secureSessCookie) - ((AcmeCookie) cc).setSecure(true); - ServletContext sc = ((AcmeSession) session).getServletContext(); - try { - String cp = (String) sc.getClass().getMethod("getContextPath", Utils.EMPTY_CLASSES) - .invoke(sc, Utils.EMPTY_OBJECTS); - if (cp.length() == 0) - cp = "/"; - cc.setPath(cp); - } catch (Exception e) { - - } - addCookie(cc); - } - } else { - cc = new AcmeCookie(SESSION_COOKIE_NAME, ""); - cc.setMaxAge(0); - ((AcmeCookie) cc).setHttpOnly(serve.httpSessCookie); - addCookie(cc); - } - } - } - - // how to remove a cookie - // cc = new Cookie(cookieName, ""); - // cc.setMaxAge(0); - // - for (int i = 0; outCookies != null && i < outCookies.size(); i++) { - cc = (Cookie) outCookies.elementAt(i); - if (cc.getSecure() && isSecure() == false) - continue; - int version = cc.getVersion(); - boolean httpOnly = false; - try { - httpOnly = Boolean.TRUE.equals(cc.getClass().getMethod("isHttpOnly", Utils.EMPTY_CLASSES) - .invoke(cc, Utils.EMPTY_OBJECTS)); - } catch (Exception e) { - - } - String token; - if (version > 1) { - if (sb2 == null) - sb2 = new StringBuffer(SETCOOKIE + "2: "); - else - sb2.append(','); - sb2.append(cc.getName()); - sb2.append("=\""); - sb2.append(cc.getValue()).append('"'); - token = cc.getComment(); - if (token != null) - sb2.append("; Comment=\"").append(token).append('"'); - token = cc.getDomain(); - if (token != null) - sb2.append("; Domain=\"").append(token).append('"'); - if (cc.getMaxAge() >= 0) - sb2.append("; Max-Age=\"").append(cc.getMaxAge()).append('"'); - token = cc.getPath(); - if (token != null) - sb2.append("; Path=\"").append(token).append('"'); - if (cc.getSecure()) { - sb2.append("; Secure"); - } - if (httpOnly) - sb2.append("; HttpOnly"); - sb2.append("; Version=\"").append(version).append('"'); - } else { - if (sb == null) - sb = new StringBuffer(SETCOOKIE + ": "); - else - // sb.append(','); - sb.append("\r\n" + SETCOOKIE + ": "); // for IE not - sb.append(cc.getName()); - sb.append('='); - sb.append(cc.getValue());// .append('"'); - if (cc.getDomain() != null && cc.getDomain().length() > 0) { - sb.append("; domain=" + cc.getDomain()); - } - if (cc.getMaxAge() >= 0) { - sb.append("; expires="); - sb.append(expdatefmt.format(new Date(new Date().getTime() + 1000l * cc.getMaxAge()))); - } - if (cc.getPath() != null && cc.getPath().length() > 0) { - sb.append("; path=" + cc.getPath()); - } - if (cc.getSecure()) { - sb.append("; secure"); - } - if (httpOnly) - sb.append("; HttpOnly"); - } - } - if (sb != null) { - out.println(sb.toString()); - // System.err.println("We sent cookies: " + sb); - } - if (sb2 != null) { - out.println(sb2.toString()); - // System.err.println("We sent cookies 2: " + sb2); - } - if (!websocketUpgrade) - //setHeader(KEEPALIVE, "timeout=30000"); - if (chunked_out == false) { - if (contentLen < 0 ) - if (serve.isKeepAlive() && oneOne ) { - if ((resCode != HttpServletResponse.SC_NO_CONTENT && !"HEAD".equals(reqMethod)) || resCode != HttpServletResponse.SC_NOT_MODIFIED) { - out.println(TRANSFERENCODING + ": " + CHUNKED); - chunked_out = true; - } - } else { - keepAlive = false; - setHeader(CONNECTION, "close"); - setHeader(KEEPALIVE, null); - } - else { - out.print(CONTENTLENGTH); - out.print(": "); - out.println(String.valueOf(contentLen)); - } - } - // process keep alive headers - Object o = resHeaderNames.get(CONNECTION); - if (o instanceof String) { - out.println(CONNECTION + ": " + o); - } - o = resHeaderNames.get(KEEPALIVE); - if (o instanceof String) { - out.println(KEEPALIVE + ": " + o); - } - out.println(); - out.flush(); - if (resCode == HttpServletResponse.SC_NO_CONTENT || resCode == HttpServletResponse.SC_NOT_MODIFIED || "HEAD".equals(reqMethod)) - out.close(); - else - ((ServeOutputStream) out).setChunked(chunked_out); - } - } - - // / Writes an error response using the specified status code and - // message. - // @param resCode the status code - // @param resMessage the status message - // @exception IOException if an I/O error has occurred - public void sendError(int resCode, String resMessage) throws IOException { - setStatus(resCode, resMessage); - realSendError(); - } - - // / Writes an error response using the specified status code and a - // default - // message. - // @param resCode the status code - // @exception IOException if an I/O error has occurred - public void sendError(int resCode) throws IOException { - setStatus(resCode); - realSendError(); - } - - private void realSendError() throws IOException { - if (isCommitted()) - throw new IllegalStateException("Can not send an error ("+resCode+") - "+resMessage+", headers have been already written"); - // if (((ServeOutputStream) out).isInInclude()) // ignore - // return; - setContentType("text/html"); - StringBuffer sb = new StringBuffer(100); - int lsp = resMessage.indexOf('\n'); - sb.append("") - .append("" + resCode + " " + (lsp < 0 ? resMessage : resMessage.substring(0, lsp)) - + "").append("

" + resCode + " " + (lsp < 0 ? resMessage : resMessage.substring(0, lsp)) + "

"); - if (lsp > 0) - sb.append("
").append(Utils.htmlEncode(resMessage.substring(lsp), false)).append("
"); - sb.append("
"); - sendEnd(sb); - } - - // / Sends a redirect message to the client using the specified redirect - // location URL. - // @param location the redirect location URL - // @exception IOException if an I/O error has occurred - public void sendRedirect(String location) throws IOException { - if (isCommitted()) - throw new IllegalStateException("Can not redirect, headers have been already written"); - if (location.indexOf(":/") < 0) { // relative - String portString = ""; - if ("https".equalsIgnoreCase(getScheme())) { - if (getServerPort() != 443) - portString = ":" + getServerPort(); - } else if (getServerPort() != 80) - portString = ":" + getServerPort(); - - if (location.length() > 0 && location.charAt(0) == '/') { - location = getScheme() + "://" + getServerName() + portString + location; - } else { - int sp = reqUriPathUn.lastIndexOf('/'); - String uri; - if (sp < 0) { - uri = reqUriPathUn + '/'; - sp = uri.length(); - } else { - uri = reqUriPathUn; - sp++; - } - location = getScheme() + "://" + getServerName() + portString + uri.substring(0, sp) + location; - } - } - // serve.log("location:"+location); - setHeader("Location", location); - setStatus(SC_MOVED_TEMPORARILY); - setContentType("text/html"); - StringBuffer sb = new StringBuffer(200); - sb.append("" + "" + SC_MOVED_TEMPORARILY + " Moved" + "

" + SC_MOVED_TEMPORARILY + " Moved

" + "This document has moved here.
"); - sendEnd(sb); - } - - private void sendEnd(StringBuffer sendContent) throws IOException { - sendContent.append(Identification.serverIdHtml); - sendContent.append(""); - setContentLength(sendContent.length()); - // to avoid further out - if (!oneOne) { - keepAlive = false; - setHeader(CONNECTION, "close"); - setHeader(KEEPALIVE, null); - } - out.print(sendContent.toString()); - out.close(); - } - - // URL rewriting - // http://www.myserver.com/catalog/index.html;jsessionid=mysession1928 - // like: - // http://www.sun.com/2001-0227/sunblade/;$sessionid$AD5RQ0IAADJAZAMTA1LU5YQ - - // / Encodes the specified URL by including the session ID in it, or, if - // encoding is not needed, returns the URL unchanged. The - // implementation of this method should include the logic to determine - // whether the session ID needs to be encoded in the URL. For example, - // if the browser supports cookies, or session tracking is turned off, - // URL encoding is unnecessary. - //

- // All URLs emitted by a Servlet should be run through this method. - // Otherwise, URL rewriting cannot be used with browsers which do not - // support cookies. - // @deprecated - public String encodeUrl(String url) { - return encodeURL(url); - } - - // / Encodes the specified URL for use in the sendRedirect method or, if - // encoding is not needed, returns the URL unchanged. The - // implementation of this method should include the logic to determine - // whether the session ID needs to be encoded in the URL. Because the - // rules for making this determination differ from those used to - // decide whether to encode a normal link, this method is seperate - // from the encodeUrl method. - //

- // All URLs sent to the HttpServletResponse.sendRedirect method should - // be - // run through this method. Otherwise, URL rewriting cannot be used with - // browsers which do not support cookies. - public String encodeRedirectUrl(String url) { - return encodeRedirectURL(url); - } - - public Socket getSocket() { - // TODO apply security check - return socket; - } - } - - public static class BasicAuthRealm extends Hashtable { - private String name; - - public BasicAuthRealm(String name) { - this.name = name; - } - - String name() { - return name; - } - } - - public static class ServeInputStream extends ServletInputStream { - private final static boolean STREAM_DEBUG = false; - - /** - * The actual input stream (buffered). - */ - private InputStream in, origIn; - - private ServeConnection conn; - - private int chunksize = 0; - - private boolean chunking = false, compressed; - - private boolean returnedAsReader, returnedAsStream; - - private long contentLength = -1; - - private long readCount; - - private byte[] oneReadBuf = new byte[1]; - - private boolean closed; - - /* ------------------------------------------------------------ */ - /** - * Constructor - */ - public ServeInputStream(InputStream in, ServeConnection conn) { - this.conn = conn; - this.in = in; - } - - void refresh() { - returnedAsReader = false; - returnedAsStream = false; - contentLength = -1; - readCount = 0; - chunksize = 0; - closed = false; - compressed(false); - } - - /* ------------------------------------------------------------ */ - /** - * @param chunking - */ - public void chunking(boolean chunking) { - if (contentLength == -1) - this.chunking = chunking; - } - - boolean compressed(boolean on) { - if (on) { - if (compressed == false) { - origIn = in; - try { - ServeInputStream sis = new ServeInputStream(in, conn); - if (chunking) { - sis.chunking(true); - chunking(false); - } - in = (InputStream) conn.serve.gzipInStreamConstr.newInstance(new Object[] { sis }); - compressed = true; - // conn.serve.log("Compressed stream was created with success", - // null); - } catch (Exception ex) { - if (ex instanceof InvocationTargetException) - conn.serve.log("TJWS: Problem in compressed stream creation", - ((InvocationTargetException) ex).getTargetException()); - else - conn.serve.log("TJWS: Problem in compressed stream obtaining", ex); - } - } - } else if (compressed) { - compressed = false; - in = origIn; - } - return compressed; - } - - /** - * sets max read byte in input - */ - void setContentLength(long contentLength) { - if (this.contentLength == -1 && contentLength >= 0 && chunking == false) { - //if (STREAM_DEBUG) { - //new Exception("Set content length:"+contentLength).printStackTrace(); - //} - this.contentLength = contentLength; - readCount = 0; - } //else if (STREAM_DEBUG || true) { - //new Exception("Igonore Set content length:"+contentLength+" for "+this.contentLength).printStackTrace(); - //} - } - - /* ------------------------------------------------------------ */ - /** - * Read a line ended by CRLF, used internally only for reading headers. - * No char encoding, ASCII only - */ - protected String readLine(int maxLen) throws IOException { - if (maxLen <= 0) - throw new IllegalArgumentException("Max len:" + maxLen); - StringBuffer buf = new StringBuffer(Math.min(8192, maxLen)); - - int c; - boolean cr = false; - int i = 0; - while ((c = in.read()) != -1) { - if (c == 10) { // LF - if (cr) - break; - break; - // throw new IOException ("LF without CR"); - } else if (c == 13) // CR - cr = true; - else { - // if (cr) - // throw new IOException ("CR without LF"); - // see - // http://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/draft-lafon-rfc2616bis-03.html#tolerant.applications - cr = false; - if (i >= maxLen) - throw new IOException("Line lenght exceeds " + maxLen); - buf.append((char) c); - i++; - } - } - if (STREAM_DEBUG) - System.err.println(buf); - if (c == -1 && buf.length() == 0) - return null; - - return buf.toString(); - } - - /* ------------------------------------------------------------ */ - public int read() throws IOException { - int result = read(oneReadBuf, 0, 1); - if (result == 1) - return 255 & oneReadBuf[0]; - return -1; - } - - /* ------------------------------------------------------------ */ - public int read(byte b[]) throws IOException { - return read(b, 0, b.length); - } - - /* ------------------------------------------------------------ */ - public synchronized int read(byte b[], int off, int len) throws IOException { - if (closed) - throw new IOException("The stream is already closed"); - if (chunking) { - if (chunksize <= 0 && getChunkSize() <= 0) - return -1; - if (len > chunksize) - len = chunksize; - len = in.read(b, off, len); - chunksize = (len < 0) ? -1 : (chunksize - len); - } else { - if (contentLength >= 0) { - if (readCount >= contentLength) { - if (STREAM_DEBUG) - System.err.print("EOF at " + contentLength); - return -1; - } - if (contentLength - len < readCount) - len = (int) (contentLength - readCount); - - len = in.read(b, off, len); - if (len > 0) - readCount += len; - } else - // to avoid extra if - len = in.read(b, off, len); - } - if (STREAM_DEBUG && len > 0) - System.err.print(new String(b, off, len)); - - return len; - } - - /* ------------------------------------------------------------ */ - public long skip(long len) throws IOException { - if (STREAM_DEBUG) - System.err.println("instream.skip() :" + len); - if (closed) - throw new IOException("The stream is already closed"); - if (chunking) { - if (chunksize <= 0 && getChunkSize() <= 0) - return -1; - if (len > chunksize) - len = chunksize; - len = in.skip(len); - chunksize = (len < 0) ? -1 : (chunksize - (int) len); - } else { - if (contentLength >= 0) { - len = Math.min(len, contentLength - readCount); - if (len <= 0) - return -1; - len = in.skip(len); - readCount += len; - } else - len = in.skip(len); - } - return len; - } - - /* ------------------------------------------------------------ */ - /** - * Available bytes to read without blocking. If you are unlucky may - * return 0 when there are more - */ - public int available() throws IOException { - if (STREAM_DEBUG) - System.err.println("instream.available()"); - if (closed) - //throw new IOException("The stream is already closed"); - return 0; - if (chunking) { - int len = in.available(); - if (len <= chunksize) - return len; - return chunksize; - } - - if (contentLength >= 0) { - int len = in.available(); - if (contentLength - readCount < Integer.MAX_VALUE) - return Math.min(len, (int) (contentLength - readCount)); - return len; - } else - return in.available(); - } - - /* ------------------------------------------------------------ */ - public void close() throws IOException { - // keep alive, will be closed by socket - // in.close(); - if (STREAM_DEBUG) - System.err.println("instream.close() " + closed); - //new Exception("instream.close()").printStackTrace(); - if (closed) - return; // throw new - // IOException("The stream is already closed"); - // read until end of chunks or content length - if (chunking) - while (read() >= 0) - ; - else if (contentLength < 0) - ; - else { - long skipCount = contentLength - readCount; - while (skipCount > 0) { - long skipped = skip(skipCount); - if (skipped <= 0) - break; - skipCount -= skipped; - } - } - if (conn.keepAlive == false) - in.close(); - closed = true; - } - - /* ------------------------------------------------------------ */ - /** - * Mark is not supported - * - * @return false - */ - public boolean markSupported() { - return false; - } - - /* ------------------------------------------------------------ */ - /** - * - */ - public void reset() throws IOException { - // no buffering, so not possible - if (closed) - throw new IOException("The stream is already closed"); - if (STREAM_DEBUG) - System.err.println("instream.reset()"); - in.reset(); - } - - /* ------------------------------------------------------------ */ - /** - * Not Implemented - * - * @param readlimit - */ - public void mark(int readlimit) { - // not supported - if (STREAM_DEBUG) - System.err.println("instream.mark(" + readlimit + ")"); - } - - /* ------------------------------------------------------------ */ - private int getChunkSize() throws IOException { - if (chunksize < 0) - return -1; - - chunksize = -1; - - // Get next non blank line - chunking = false; - String line = readLine(60); - while (line != null && line.length() == 0) - line = readLine(60); - chunking = true; - - // Handle early EOF or error in format - if (line == null) - return -1; - - // Get chunksize - int i = line.indexOf(';'); - if (i > 0) - line = line.substring(0, i).trim(); - try { - chunksize = Integer.parseInt(line, 16); - } catch (NumberFormatException nfe) { - throw new IOException("Chunked stream is broken, " + line); - } - - // check for EOF - if (chunksize == 0) { - chunksize = -1; - // Look for footers - readLine(60); - chunking = false; - } - return chunksize; - } - - boolean isReturnedAsStream() { - return returnedAsStream; - } - - void setReturnedAsStream(boolean _on) { - returnedAsStream = _on; - } - - boolean isReturnedAsReader() { - return returnedAsReader; - } - - void setReturnedAsReader(boolean _on) { - returnedAsReader = _on; - } - } - - public static class ServeOutputStream extends ServletOutputStream { - - private static final boolean STREAM_DEBUG = false; - - private boolean chunked; - - private boolean closed; - - // TODO: predefine as static byte[] used by chunked - // underneath stream - private OutputStream out; - - // private BufferedWriter writer; // for top speed - private ServeConnection conn; - - private int inInclude; - - private String encoding; - - private/* volatile */long lbytes; - - private Utils.SimpleBuffer buffer; - - public ServeOutputStream(OutputStream out, ServeConnection conn) { - this.out = out; - this.conn = conn; - buffer = new Utils.SimpleBuffer(); - encoding = conn.getCharacterEncoding(); - if (encoding == null) - encoding = Utils.ISO_8859_1; - } - - /* - * void refresh() { chunked = false; closed = false; inInclude = 0; - * lbytes = 0; buffer.reset(); encoding = conn.getCharacterEncoding(); - * if (encoding == null) encoding = Utils.ISO_8859_1; } - */ - - protected void reset() { - if (lbytes == 0) - buffer.reset(); - else - throw new IllegalStateException("Result was already committed"); - } - - protected int getBufferSize() { - return buffer.getSize(); - } - - protected void setBufferSize(int size) { - if (lbytes > 0) - throw new IllegalStateException("Bytes already written in response"); - buffer.setSize(size); - } - - protected void setChunked(boolean set) { - chunked = set; - } - - public void print(String s) throws IOException { - write(s.getBytes(encoding)); - } - - public void write(int b) throws IOException { - write(new byte[] { (byte) b }, 0, 1); - } - - public void write(byte[] b) throws IOException { - write(b, 0, b.length); - } - - public void write(byte[] b, int off, int len) throws IOException { - if (closed) { - if (STREAM_DEBUG) - System.err.println((b == null ? "null" : new String(b, off, len)) - + "\n won't be written, stream closed."); - throw new IOException("An attempt of writing " + len + " bytes to a closed out."); - } - - if (len == 0) - return; - // - conn.writeHeaders(); - b = buffer.put(b, off, len); - len = b.length; - if (len == 0) - return; - off = 0; - if (chunked) { - String hexl = Integer.toHexString(len); - out.write((hexl + "\r\n").getBytes()); // no encoding Ok - lbytes += 2 + hexl.length(); - out.write(b, off, len); - lbytes += len; - out.write("\r\n".getBytes()); - lbytes += 2; - } else { - out.write(b, off, len); - lbytes += len; - } - - if (STREAM_DEBUG) { - if (chunked) - System.err.println(Integer.toHexString(len)); - System.err.print(new String(b, off, len)); - if (chunked) - System.err.println(); - } - } - - public void flush() throws IOException { - //boolean cl = closed; - if (closed) - return; - // throw new IOException("An attempt of flushig closed out."); - conn.writeHeaders(); - if (closed) - return; - byte[] b = buffer.get(); - if (b.length > 0) { - if (chunked) { - String hexl = Integer.toHexString(b.length); - out.write((hexl + "\r\n").getBytes()); // no encoding Ok - lbytes += 2 + hexl.length(); - out.write(b); - lbytes += b.length; - out.write("\r\n".getBytes()); - lbytes += 2; - if (STREAM_DEBUG) { - System.err.println(hexl); - System.err.print(new String(b)); - System.err.println(); - } - } else { - out.write(b); - lbytes += b.length; - if (STREAM_DEBUG) { - System.err.print(new String(b)); - } - } - } - //System.err.println("Was "+cl+" now "+closed); - out.flush(); - } - - public void close() throws IOException { - if (closed) - return; - // throw new IOException("Stream is already closed."); - // new IOException("Stream closing").printStackTrace(); - try { - flush(); - if (inInclude == 0) { - if (chunked) { - out.write("0\r\n\r\n".getBytes()); - lbytes += 5; - if (STREAM_DEBUG) - System.err.print("0\r\n\r\n"); - // TODO: here is possible to write trailer headers - out.flush(); - } - if (conn.keepAlive == false) - out.close(); - else { - out = null; - conn = null; // the stream has to be recreated after closing - } - } - } finally { - closed = true; - } - } - - private long lengthWritten() { - return lbytes; - } - - boolean isInInclude() { - return inInclude == 0; - } - - void setInInclude(boolean _set) { - inInclude = _set ? 1 : 0; - /* - * if (_set) inInclude++; else inInclude--; if (inInclude < 0) throw - * new IllegalStateException("Not matching include set"); - */ - } - } - - /** - * Class PathTreeDictionary - this class allows to put path elements in - * format n1/n2/n2[/*.ext] and get match to a pattern and a unmatched tail - */ - public static class PathTreeDictionary { - Node root_node; - Node ext; - Object ctx; - - public PathTreeDictionary() { - root_node = new Node(); - } - - /** - * Manages a tree of web path entries with the following cases - *

    - *
  • /path1/path2... - exact match entry - *
  • anything ending by /* - *
  • *.ext - extension entry applied only for last part - *
  • - empty entry context root servicing only /contextpath/ - *
  • / - default servlet when nothing else is matching - *
- * - * @param path - * @param value - */ - public synchronized Object[] put(String path, Object value) { - // TODO make returning Object[] for cconsitency - if (path.length() == 0) { // context - if (ctx == null) - ctx = new Node(); - Object result = ctx; - ctx = value; - return new Object[] { result, INT_ZERO }; - } - if (path.charAt(0) == '*') { - String ext_str = null; - if (path.length() > 2 && path.charAt(1) == '.') - ext_str = path.substring(1); - else - throw new IllegalArgumentException("No extension specified for * starting pattern:" + path); - if (ext == null) - ext = new Node(); - return new Object[] { ext.put(ext_str, value), INT_ZERO }; - } - //System.out.println("==>PUT path : "+path); - StringTokenizer st = new StringTokenizer(path, "\\/"); - Node cur_node = root_node; - while (st.hasMoreTokens()) { - String nodename = st.nextToken(); - //System.out.println("PUT curr node : "+nodename); - int wci = nodename.indexOf('*'); - if (wci == 0) { - if (nodename.length() > 1 || st.hasMoreTokens()) - throw new IllegalArgumentException("Using * in other than ending /* for path:" + path); - nodename = ""; - } else if (wci > 0) - throw new IllegalArgumentException("Using * in other than ending /* for path:" + path); - Node node = (Node) cur_node.get(nodename); - if (node == null) { - node = new Node(); - cur_node.put(nodename, node); - } - cur_node = node; - } - Object result = cur_node.object; - cur_node.object = value; - return new Object[] { result, INT_ZERO }; - } - - public synchronized Object[] remove(Object value) { - Object[] result = remove(root_node, value); - if (result[0] == null) - result = remove(null, value); - if (result[0] == null) - return remove(ext, value); - return result; - } - - public synchronized Object[] remove(String path) { - Object[] result = get(path); - if (result[0] != null) - return remove(result[0]); - return result; - } - - public Object[] remove(Node node, Object value) { - // TODO make full path, not only last element - if (node == null) { - if (ctx == value) { - ctx = null; - return new Object[] { value, new Integer(0) }; - } - return new Object[] { null, null }; - } - - if (node == ext) { - // TODO potential bug since look for first entry - Enumeration e = ext.keys(); - while (e.hasMoreElements()) { - Object key = e.nextElement(); - if (ext.get(key) == value) { - return new Object[] { ext.remove(key), new Integer(0) }; - } - } - return new Object[] { null, null }; - } - if (node.object == value) { - node.object = null; - return new Object[] { value, new Integer(0) }; - } - Enumeration e = node.keys(); - while (e.hasMoreElements()) { - Object[] result = remove((Node) node.get((String) e.nextElement()), value); - if (result[0] != null) - return result; - } - return new Object[] { null, null }; - } - - /** - * This function looks up in the directory to find the perfect match and - * remove matching part from path, so if you need to keep original path, - * save it somewhere - */ - public Object[] get(String path) { - // System.out.println("==>GET " + path); - // new Exception("GET " + path).printStackTrace(); - Object[] result = new Object[2]; - if (path == null) - return result; - if ((path.length() == 0 || path.equals("/")) && ctx != null) { - result[0] = ctx; - result[1] = INT_ZERO; - return result; - } - char[] ps = path.toCharArray(); - Node cur_node = root_node; // default servlet - int p0 = 0, lm = 0; // last match - - boolean div_state = true; - for (int i = 0; i < ps.length; i++) { - // System.out.println("GET "+ps[i]); - if (ps[i] == '/' || ps[i] == '\\') { // next divider - if (div_state) - continue; - Node node = (Node) cur_node.get(new String(ps, p0, i - p0)); - // System.out.println("GET Node " + node + " for " + new - //String(ps, p0, i - p0)); - - if (node == null) { // exact - node = (Node) cur_node.get(""); // for * - if (node != null && node.object != null) { - result[0] = node.object; - // System.out.println("GET * for " + node); - } - break; - } - cur_node = node; - div_state = true; - p0 = i + 1; - } else { - if (div_state) { - p0 = i; - div_state = false; - } - } - } - - String last_part = new String(ps, p0, ps.length - p0); - Node last_node = (Node) cur_node.get(last_part); - //System.out.println("GET cur node : " + last_node + " for: " + - //last_part + " root ext:" + ext+" and pos:"+p0); - if (last_node != null) { - if (last_node.object == null) { - last_node = (Node) last_node.get(""); // check for * - } - if (last_node != null && last_node.object != null) { - result[0] = last_node.object; - lm = last_part.length() > 0 ? ps.length : p0 - 1; - } - } else { - last_node = (Node) cur_node.get(""); - if (last_node != null && last_node.object != null) { - result[0] = last_node.object; - lm = p0 > 0 ? p0 - 1 : 0; - } - } - - // try ext - if (result[0] == null) { - lm = ps.length; - if (ext != null) { - int ldi = last_part.lastIndexOf('.'); - if (ldi > 0) { // ignoring cases /.extension - result[0] = ext.get(last_part.substring(ldi)); - //System.out.println("GET ext node: " + last_part.substring(ldi)); - } - } - if (result[0] == null) { // look for default servlet - last_node = (Node) root_node.get(""); - if (last_node != null) - result[0] = last_node.object; - if (result[0] == null) { - result[0] = root_node.object; - } - } - } - //System.out.println("GET pos: "+lm); - result[1] = new Integer(lm); - return result; - } - - public Enumeration keys() { - Vector result = new Vector(); - if (ctx != null) - result.addElement(""); - if (root_node.object != null) - result.addElement("/"); - addSiblingNames(root_node, result, ""); - if (ext != null) { - Enumeration e = ext.keys(); - while (e.hasMoreElements()) - result.addElement("*" + e.nextElement()); - } - return result.elements(); - } - - public void addSiblingNames(Node node, Vector result, String path) { - Enumeration e = node.keys(); - while (e.hasMoreElements()) { - String pc = (String) e.nextElement(); - Node childNode = (Node) node.get(pc); - pc = path + '/' + (pc.length() == 0 ? "*" : pc); - if (childNode.object != null) - result.addElement(pc); - addSiblingNames(childNode, result, pc); - } - } - - public Enumeration elements() { - Vector result = new Vector(); - if (root_node.object != null) - result.add(root_node.object); - addSiblingObjects(root_node, result); - return result.elements(); - } - - public void addSiblingObjects(Node node, Vector result) { - Enumeration e = node.keys(); - while (e.hasMoreElements()) { - Node childNode = (Node) node.get(e.nextElement()); - if (childNode.object != null) - result.addElement(childNode.object); - addSiblingObjects(childNode, result); - } - } - - class Node extends Hashtable { - Object object; - String name; - } - } - - /** - * Http session support - * - * TODO: provide lazy session restoring, it should allow to load classes - * from wars 1st step it read serialization data and store under session - * attribute 2nd when the session requested, it tries to deserialize all - * session attributes considered that all classes available - */ - public static class AcmeSession extends Hashtable implements HttpSession { - private long createTime; - - private long lastAccessTime; - - private String id; - - private int inactiveInterval; // in seconds - - private boolean expired; - - private transient ServletContext servletContext; - - private transient HttpSessionContext sessionContext; - - private transient List listeners; - - // TODO: check in documentation what is default inactive interval and - // what - // means 0 - // and what is mesurement unit - AcmeSession(String id, ServletContext servletContext, HttpSessionContext sessionContext) { - this(id, 0, servletContext, sessionContext); - } - - AcmeSession(String id, int inactiveInterval, ServletContext servletContext, HttpSessionContext sessionContext) { - // new - // Exception("Session created with: "+servletContext).printStackTrace(); - // //!!! - createTime = System.currentTimeMillis(); - this.id = id; - this.inactiveInterval = inactiveInterval; - this.servletContext = servletContext; - this.sessionContext = sessionContext; - } - - public long getCreationTime() { - return createTime; - } - - public String getId() { - return id; - } - - public long getLastAccessedTime() { - return lastAccessTime; - } - - public void setMaxInactiveInterval(int interval) { - inactiveInterval = interval; - } - - public int getMaxInactiveInterval() { - return inactiveInterval; - } - - /** - * @deprecated - */ - public HttpSessionContext getSessionContext() { - return sessionContext; - } - - /** - * Returns the ServletContext to which this session belongs. - * - * @return The ServletContext object for the web application - * @ince 2.3 - */ - public ServletContext getServletContext() { - // System.err.println("ctx from:"+servletContext); //!!! - return servletContext; - } - - public Object getAttribute(String name) throws IllegalStateException { - if (expired) - throw new IllegalStateException(); - return get((Object) name); - } - - public Object getValue(String name) throws IllegalStateException { - return getAttribute(name); - } - - public Enumeration getAttributeNames() throws IllegalStateException { - if (expired) - throw new IllegalStateException(); - return keys(); - } - - public String[] getValueNames() throws IllegalStateException { - Enumeration e = getAttributeNames(); - Vector names = new Vector(); - while (e.hasMoreElements()) - names.addElement(e.nextElement()); - String[] result = new String[names.size()]; - names.copyInto(result); - return result; - } - - public void setAttribute(String name, Object value) throws IllegalStateException { - if (expired) - throw new IllegalStateException(); - Object oldValue = value != null ? put((Object) name, value) : remove(name); - if (oldValue != null) { - if (oldValue instanceof HttpSessionBindingListener) - ((HttpSessionBindingListener) oldValue).valueUnbound(new HttpSessionBindingEvent(this, name)); - } - if (value != null) { - if (value instanceof HttpSessionBindingListener) - ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name)); - notifyListeners(name, oldValue, value); - } else - notifyListeners(name, oldValue); - } - - public void putValue(String name, Object value) throws IllegalStateException { - setAttribute(name, value); - } - - public void removeAttribute(String name) throws IllegalStateException { - if (expired) - throw new IllegalStateException(); - Object value = remove((Object) name); - if (value != null) { - if (value instanceof HttpSessionBindingListener) - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name)); - notifyListeners(name, value); - } - } - - public void removeValue(java.lang.String name) throws IllegalStateException { - removeAttribute(name); - } - - public synchronized void invalidate() throws IllegalStateException { - if (expired) - throw new IllegalStateException(); - notifyListeners(); - Enumeration e = getAttributeNames(); - while (e.hasMoreElements()) { - removeAttribute((String) e.nextElement()); - } - listeners = null; - setExpired(true); - // would be nice remove it from hash table also - } - - public boolean isNew() throws IllegalStateException { - if (expired) - throw new IllegalStateException(); - return lastAccessTime == 0; - } - - public synchronized void setListeners(List l) { - if (listeners == null) { - listeners = l; - if (listeners != null) { - HttpSessionEvent event = new HttpSessionEvent(this); - for (int i = 0; i < listeners.size(); i++) - try { - ((HttpSessionListener) listeners.get(i)).sessionCreated(event); - } catch (ClassCastException cce) { - //servletContext. log("Wrong session listener type."+cce); - } catch (NullPointerException npe) { - //servletContext. log("Null session listener."); - } - } - } - } - - /** - * something hack, to update servlet context since session created out - * of scope - * - * @param sc - */ - public synchronized void setServletContext(ServletContext sc) { - // System.err.println("ctx to:"+servletContext); //!!! - servletContext = sc; - } - - private void notifyListeners() { - if (listeners != null) { - HttpSessionEvent event = new HttpSessionEvent(this); - for (int i = 0; i < listeners.size(); i++) - try { - ((HttpSessionListener) listeners.get(i)).sessionDestroyed(event); - } catch (ClassCastException cce) { - //servletContext.log("Wrong session listener type."+cce); - } catch (NullPointerException npe) { - //servletContext. log("Null session listener."); - } - } - } - - private void notifyListeners(String name, Object value) { - if (listeners != null) { - HttpSessionBindingEvent event = new HttpSessionBindingEvent(this, name, value); - for (int i = 0, n = listeners.size(); i < n; i++) - try { - ((HttpSessionAttributeListener) listeners.get(i)).attributeRemoved(event); - } catch (ClassCastException cce) { - } catch (NullPointerException npe) { - } - } - } - - private void notifyListeners(String name, Object oldValue, Object value) { - if (listeners != null) { - HttpSessionBindingEvent event = new HttpSessionBindingEvent(this, name, value); - HttpSessionBindingEvent oldEvent = oldValue == null ? null : new HttpSessionBindingEvent(this, name, - oldValue); - for (int i = 0, n = listeners.size(); i < n; i++) - try { - HttpSessionAttributeListener l = (HttpSessionAttributeListener) listeners.get(i); - if (oldEvent != null) - l.attributeReplaced(oldEvent); - l.attributeAdded(event); - } catch (ClassCastException cce) { - } catch (NullPointerException npe) { - } - } - } - - private void setExpired(boolean expired) { - this.expired = expired; - } - - boolean isValid() { - return !expired; - } - - boolean checkExpired() { - return inactiveInterval > 0 && (inactiveInterval * 1000 < System.currentTimeMillis() - lastAccessTime); - } - - void userTouch() { - if (isValid()) - lastAccessTime = System.currentTimeMillis(); - else - throw new IllegalStateException(); - } - - // storing session in format - // id:latency:contextname:tttt - // entry:base64 ser data - // entry:base64 ser data - // $$ - void save(Writer w) throws IOException { - if (expired) - return; - // can't use append because old JDK - w.write(id); - w.write(':'); - w.write(Integer.toString(inactiveInterval)); - w.write(':'); - w.write(servletContext == null || servletContext.getServletContextName() == null ? "" : servletContext - .getServletContextName()); - w.write(':'); - w.write(Long.toString(lastAccessTime)); - w.write("\r\n"); - Enumeration e = getAttributeNames(); - ByteArrayOutputStream os = new ByteArrayOutputStream(1024 * 16); - while (e.hasMoreElements()) { - String aname = (String) e.nextElement(); - Object so = get(aname); - if (so instanceof Serializable) { - os.reset(); - ObjectOutputStream oos = new ObjectOutputStream(os); - try { - oos.writeObject(so); - w.write(aname); - w.write(":"); - w.write(Utils.base64Encode(os.toByteArray())); - w.write("\r\n"); - } catch (IOException ioe) { - servletContext.log("TJWS: Can't replicate/store a session value of '" + aname + "' class:" - + so.getClass().getName(), ioe); - } - } else - servletContext.log("TJWS: Non serializable session object has been " + so.getClass().getName() - + " skiped in storing of " + aname, null); - if (so instanceof HttpSessionActivationListener) - ((HttpSessionActivationListener) so).sessionWillPassivate(new HttpSessionEvent(this)); - } - w.write("$$\r\n"); - } - - static AcmeSession restore(BufferedReader r, int inactiveInterval, ServletContext servletContext, - HttpSessionContext sessionContext) throws IOException { - String s = r.readLine(); - if (s == null) // eos - return null; - int cp = s.indexOf(':'); - if (cp < 0) - throw new IOException("Invalid format for a session header, no session id: " + s); - String id = s.substring(0, cp); - int cp2 = s.indexOf(':', cp + 1); - if (cp2 < 0) - throw new IOException("Invalid format for a session header, no latency: " + s); - try { - inactiveInterval = Integer.parseInt(s.substring(cp + 1, cp2)); - } catch (NumberFormatException nfe) { - servletContext.log("TJWS: Session latency is invalid:" + s.substring(cp + 1, cp2) + " " + nfe); - } - cp = s.indexOf(':', cp2 + 1); - if (cp < 0) - throw new IOException("TJWS: Invalid format for a session header, context name: " + s); - String contextName = s.substring(cp2 + 1, cp); - // consider servletContext.getContext("/"+contextName) - AcmeSession result = new AcmeSession(id, inactiveInterval, contextName.length() == 0 ? servletContext - : null, sessionContext); - try { - result.lastAccessTime = Long.parseLong(s.substring(cp + 1)); - } catch (NumberFormatException nfe) { - servletContext.log("TJWS: Last access time is invalid:" + s.substring(cp + 1) + " " + nfe); - } - do { - s = r.readLine(); - if (s == null) - throw new IOException("Unexpected end of a stream."); - if ("$$".equals(s)) - return result; - cp = s.indexOf(':'); - if (cp < 0) - throw new IOException("Invalid format for a session entry: " + s); - String aname = s.substring(0, cp); - // if (lazyRestore) - // result.put(aname, s.substring(cp+1)); - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Utils.decode64(s - .substring(cp + 1)))); - Throwable restoreError; - try { - Object so; - result.put(aname, so = ois.readObject()); - restoreError = null; - if (so instanceof HttpSessionActivationListener) - ((HttpSessionActivationListener) so).sessionDidActivate(new HttpSessionEvent(result)); - - } catch (ClassNotFoundException cnfe) { - restoreError = cnfe; - - } catch (NoClassDefFoundError ncdfe) { - restoreError = ncdfe; - } catch (IOException ioe) { - restoreError = ioe; - } - if (restoreError != null) - servletContext.log("TJWS: Can't restore :" + aname + ", " + restoreError); - } while (true); - } - } - - protected static class AcmeCookie extends Cookie { - private boolean httpOnly; - - public AcmeCookie(String name, String value) { - super(name, value); - } - - public boolean isHttpOnly() { - return httpOnly; - } - - public void setHttpOnly(boolean isHttpOnly) { - httpOnly = isHttpOnly; - } - - } - - protected static class LocaleWithWeight implements Comparable { - protected float weight; // should be int - - protected Locale locale; - - LocaleWithWeight(Locale l, float w) { - locale = l; - weight = w; - // System.err.println("Created "+l+", with:"+w); - } - - public int compareTo(Object o) { - if (o instanceof LocaleWithWeight) - return (int) (((LocaleWithWeight) o).weight - weight) * 100; - throw new IllegalArgumentException(); - } - - public Locale getLocale() { - return locale; - } - } - - protected static class AcceptLocaleEnumeration implements Enumeration { - Iterator i; - - public AcceptLocaleEnumeration(TreeSet/* */ts) { - i = ts.iterator(); - } - - public boolean hasMoreElements() { - return i.hasNext(); - } - - public Object nextElement() { - return ((LocaleWithWeight) i.next()).getLocale(); - /* - * Locale l =((LocaleWithWeight)i.next()).getLocale(); - * System.err.println("Returned l:"+l); return l; - */ - } - } - - // TODO: reconsider implementation by providing - // inner class implementing HttpSessionContext - // and returning it on request - // to avoid casting this class to Hashtable - - protected static class HttpSessionContextImpl extends Hashtable implements HttpSessionContext { - - public java.util.Enumeration getIds() { - return keys(); - } - - public HttpSession getSession(String sessionId) { - return (HttpSession) get(sessionId); - } - - void save(Writer w) throws IOException { - Enumeration e = elements(); - while (e.hasMoreElements()) - ((AcmeSession) e.nextElement()).save(w); - } - - static HttpSessionContextImpl restore(BufferedReader br, int inactiveInterval, ServletContext servletContext) - throws IOException { - HttpSessionContextImpl result = new HttpSessionContextImpl(); - AcmeSession session; - while ((session = AcmeSession.restore(br, inactiveInterval, servletContext, result)) != null) - if (session.checkExpired() == false) - result.put(session.getId(), session); - return result; - } - } -} \ No newline at end of file diff --git a/1.x/src/Acme/Serve/SimpleAcceptor.java b/1.x/src/Acme/Serve/SimpleAcceptor.java deleted file mode 100644 index cc0acb6..0000000 --- a/1.x/src/Acme/Serve/SimpleAcceptor.java +++ /dev/null @@ -1,85 +0,0 @@ -/* tjws - SimpleAcceptor.java - * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: SimpleAcceptor.java,v 1.9 2012/08/16 02:50:15 dmitriy Exp $ - * Created on Jun 12, 2007 - * @author dmitriy - */ -package Acme.Serve; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Map; - -public class SimpleAcceptor implements Serve.Acceptor { - public Socket accept() throws IOException { - return socket.accept(); - } - - public void destroy() throws IOException { - if (socket == null) - throw new IOException("Socket already destroyed"); - try { - socket.close(); - } finally { - socket = null; - } - } - - public void init(Map inProperties, Map outProperties) throws IOException { - int port = inProperties.get(Serve.ARG_PORT) != null ? ((Integer) inProperties.get(Serve.ARG_PORT)).intValue() - : Serve.DEF_PORT; - String bindAddrStr = (String) inProperties.get(Serve.ARG_BINDADDRESS); - InetSocketAddress bindAddr = bindAddrStr != null ? new InetSocketAddress(InetAddress.getByName(bindAddrStr), - port) : null; - String backlogStr = (String) inProperties.get(Serve.ARG_BACKLOG); - int backlog = backlogStr != null ? Integer.parseInt(backlogStr) : -1; - if (bindAddr != null) { - socket = new ServerSocket(); - if (backlog < 0) - socket.bind(bindAddr); - else - socket.bind(bindAddr, backlog); - } else { - if (backlog < 0) - socket = new ServerSocket(port); - else - socket = new ServerSocket(port, backlog); - } - if (outProperties != null) - if (socket.isBound()) - outProperties.put(Serve.ARG_BINDADDRESS, socket.getInetAddress().getHostName()); - else - outProperties.put(Serve.ARG_BINDADDRESS, InetAddress.getLocalHost().getHostName()); - } - - public String toString() { - return "SimpleAcceptor " + socket; - } - - private ServerSocket socket; -} \ No newline at end of file diff --git a/1.x/src/Acme/Serve/WarDeployer.java b/1.x/src/Acme/Serve/WarDeployer.java deleted file mode 100644 index 848161b..0000000 --- a/1.x/src/Acme/Serve/WarDeployer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* tjws - WarDeployer.java - * Copyright (C) 1999-2004 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: WarDeployer.java,v 1.1 2006/05/10 05:45:21 rogatkin Exp $ - * Created on Dec 13, 2004 - */ - -package Acme.Serve; - -/** - * @author dmitriy - * - * - */ -public interface WarDeployer { - void deploy(Serve server); -} diff --git a/1.x/src/Acme/Utils.java b/1.x/src/Acme/Utils.java deleted file mode 100644 index 7e80151..0000000 --- a/1.x/src/Acme/Utils.java +++ /dev/null @@ -1,1374 +0,0 @@ -// Utils - assorted static utility routines -// -// Copyright (C)1996,1998 by Jef Poskanzer . All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions 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. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// -// Visit the ACME Labs Java page for up-to-date versions of this and other -// fine Java utilities: http://www.acme.com/java/ -// -// Base64 code borrowed from public domain supported by Robert Harder -// Please visit
http://iharder.net/base64 -// periodically to check for updates or to contribute improvements. -// -// All enhancements Copyright (C)1998-2010 by Dmitriy Rogatkin -// -// $Id: Utils.java,v 1.39 2013/08/10 02:47:26 cvs Exp $ - -package Acme; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.io.Writer; -import java.net.URL; -import java.net.URLClassLoader; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -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.Properties; -import java.util.StringTokenizer; - -/// Assorted static utility routines. -//

-// Whenever I come up with a static routine that might be of general use, -// I put it here. So far the class includes: -//

    -//
  • some string routines that were left out of java.lang.String -//
  • a general array-to-string routine -//
  • a fixed version of java.io.InputStream's byte-array read routine -//
  • a bunch of URL-hacking routines -//
  • some easy-to-use wrappers for Runtime.exec -//
  • a debugging routine to dump the current call stack -//
  • a URLDecoder to match java.net.URLEncoder -//
-// and lots more. -//

-// Fetch the software.
-// Fetch the entire Acme package. - -public class Utils { - // / Returns a date string formatted in Unix ls style - if it's within - // six months of now, Mmm dd hh:ss, else Mmm dd yyyy. - static final SimpleDateFormat shortfmt = new SimpleDateFormat("MMM dd HH:mm"); - - static final SimpleDateFormat longfmt = new SimpleDateFormat("MMM dd yyyy"); - - public static final int COPY_BUF_SIZE = 4096 * 2; - - public final static String ISO_8859_1 = "ISO-8859-1"; - - public static final Class[] EMPTY_CLASSES = {}; - - public static final Object[] EMPTY_OBJECTS = {}; - - public static final Enumeration EMPTY_ENUMERATION = new Enumeration() { - public boolean hasMoreElements() { - return false; - } - - public Object nextElement() { - return null; - } - }; - - public static String lsDateStr(Date date) { - if (Math.abs(System.currentTimeMillis() - date.getTime()) < 183L * 24L * 60L * 60L * 1000L) - return shortfmt.format(date); - else - return longfmt.format(date); - } - - public static Hashtable parseQueryString(String query, String encoding) { - Hashtable result = new Hashtable(); - if (encoding == null) - encoding = "UTF-8"; - StringTokenizer st = new StringTokenizer(query, "&"); - while (st.hasMoreTokens()) { - String pair = st.nextToken(); - int ep = pair.indexOf('='); - String key = ep > 0 ? pair.substring(0, ep) : pair; - String value = ep > 0 ? pair.substring(ep + 1) : ""; - try { - key = /* URLDecoder. */decode(key, encoding); - if (value != null) - value = /* URLDecoder. */decode(value, encoding); - } catch (UnsupportedEncodingException uee) { - } - String[] values = (String[]) result.get(key); - String[] newValues; - if (values == null) { - newValues = new String[1]; - newValues[0] = value; - } else { - newValues = new String[values.length + 1]; - System.arraycopy(values, 0, newValues, 0, values.length); - newValues[values.length] = value; - } - result.put(key, newValues); - } - return result; - } - - public static Map parsePostData(long len, InputStream is, String encoding, String[] cachedStream) - throws IOException { - // TODO: handle parsing data over 2 GB - if (len > Integer.MAX_VALUE) - throw new RuntimeException("Can't process POST data over " + Integer.MAX_VALUE + ", requested: " + len); - byte[] buf = new byte[(int) len]; - int fp = 0; - while (fp < len) { - int c = is.read(buf, fp, buf.length - fp); - if (c < 0) - break; - fp += c; - } - //System.err.println("====>"+new String( buf)); - if (cachedStream != null && cachedStream.length > 0) - return parseQueryString(cachedStream[0] = new String(buf, 0, fp, ISO_8859_1), encoding); - else - return parseQueryString(new String(buf, 0, fp, ISO_8859_1), encoding); - } - - /** - * Decodes URL encoded string including newly introduced JavaScript encoding with %uxxxx chars - * - * @param s - * encoded string - * @param enc - * source encoding - * @return decoded string or original if no decoding required - * @throws UnsupportedEncodingException - */ - public static String decode(String s, String enc) throws UnsupportedEncodingException { - if (enc == null || enc.length() == 0) { - throw new UnsupportedEncodingException("decode: no source char encoding provided."); - } - if (s == null) - return null; - boolean decoded = false; - int l = s.length(); - StringBuffer sb = new StringBuffer(l > 1024 ? l / 3 : l); - - int state = sText; - int i = 0; - int code = 0; - char c; - int pos = 0; - int ofs = 0; - byte[] buf = null; - boolean processDig = false; - while (i < l) { - c = s.charAt(i); - switch (c) { - case '+': - decoded = true; - if (state == sText) - sb.append(' '); - else if (state == s2Dig) { - sb.append(new String(buf, 0, pos + 1, enc)); - state = sText; - sb.append(' '); - } else - new IllegalArgumentException("decode: unexpected + at pos: " + i + ", of : " + s); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - ofs = '0'; - processDig = true; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - ofs = 'a' - 10; - processDig = true; - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - ofs = 'A' - 10; - processDig = true; - break; - case '%': - decoded = true; - if (state == sText) { - state = sEscape; - if (buf == null) - buf = new byte[(l - i) / 3]; - pos = 0; - } else if (state == s2Dig) { - state = sEscape; - pos++; - } else - new IllegalArgumentException("decode: unexpected escape % at pos: " + i + ", of : " + s); - break; - case 'u': - if (state == sEscape) { - if (pos > 0) { - sb.append(new String(buf, 0, pos, enc)); - pos = 0; - } - state = sU1; - } else if (state == sText) { - sb.append(c); - } else if (state == s2Dig) { - sb.append(new String(buf, 0, pos + 1, enc)); - state = sText; - sb.append(c); - } else - new IllegalArgumentException("decode: unexpected char in hex at pos: " + i + ", of : " + s); - break; - default: - if (state == sText) - sb.append(c); - else if (state == s2Dig) { - sb.append(new String(buf, 0, pos + 1, enc)); - state = sText; - sb.append(c); - } else - new IllegalArgumentException("decode: unexpected char in hex at pos: " + i + ", of : " + s); - - break; - } - i++; - if (processDig) { - if (state == sEscape) { - code = c - ofs; - state = s1Dig; - } else if (state == s1Dig) { - buf[pos] = (byte) (code * 16 + (c - ofs)); - state = s2Dig; - } else if (state == s2Dig) { // escape finished - sb.append(new String(buf, 0, pos + 1, enc)); - state = sText; - sb.append(c); - } else if (state == sU1) { - code = c - ofs; - state = sU2; - } else if (state == sU2) { - code = code * 16 + c - ofs; - state = sU3; - } else if (state == sU3) { - code = code * 16 + c - ofs; - state = sU4; - } else if (state == sU4) { - sb.append((char) (code * 16 + c - ofs)); - state = sText; - } else - sb.append(c); - processDig = false; - } - } - if (state == s2Dig) - sb.append(new String(buf, 0, pos + 1, enc)); - return (decoded ? sb.toString() : s); - } - - private static final int sText = 0; - - private static final int s1Dig = 1; - - private static final int s2Dig = 2; - - private static final int sEscape = 3; - - private static final int sU1 = 4; - - private static final int sU2 = 5; - - private static final int sU3 = 6; - - private static final int sU4 = 7; - - public static String htmlEncode(String s, boolean encodeWS) { - if (s == null) - return null; - char[] ca = s.toCharArray(); - StringBuffer res = new StringBuffer(ca.length); - int ls = 0; - boolean blankMet = true; - for (int i = 0; i < ca.length; i++) { - switch (ca[i]) { - case '<': - res.append(ca, ls, i - ls); - res.append("<"); - ls = i + 1; - break; - case '>': - res.append(ca, ls, i - ls); - res.append(">"); - ls = i + 1; - break; - case '"': - res.append(ca, ls, i - ls); - res.append("""); - ls = i + 1; - break; - case '&': - res.append(ca, ls, i - ls); - res.append("&"); - ls = i + 1; - break; - case ' ': - if (blankMet && encodeWS) { - res.append(ca, ls, i - ls); - res.append(" "); - ls = i + 1; - } else - blankMet = true; - break; - case '\n': - if (encodeWS) { - res.append(ca, ls, i - ls); - res.append("
"); - ls = i + 1; - } - break; - case '\r': - if (encodeWS) { - res.append(ca, ls, i - ls); - ls = i + 1; - } - break; - default: - if (ca[i] > 127) { // no unicode - res.append(ca, ls, i - ls); - res.append("&#").append((int)ca[i]).append(';'); - ls = i + 1; - } - blankMet = false; - } - } - if (ls < ca.length) - res.append(ca, ls, ca.length - ls); - return res.toString(); - } - - public static float isGzipAccepted(String contentEncoding) { - float result = 0f; - if (contentEncoding != null) { - int gzsl = "gzip;".length(); - int zp = contentEncoding.indexOf("gzip"); - if (zp >= 0) { - if (contentEncoding.length() > (zp+gzsl) &&contentEncoding.charAt(zp + gzsl) == ';') { - zp = contentEncoding.indexOf("q=", zp + gzsl); - if (zp > 0) { - int qe = contentEncoding.indexOf(",", zp); - if (qe < 0) - qe = contentEncoding.length(); - try { - result = Float.parseFloat(contentEncoding.substring(zp + 2, qe)); - } catch (NumberFormatException e) { - } - } - } else - result = 1f; - } - } - return result; - } - - // / Checks whether a string matches a given wildcard pattern. - // Only does ? and *, and multiple patterns separated by |. - public static boolean match(String pattern, String string) { - for (int p = 0;; ++p) { - for (int s = 0;; ++p, ++s) { - boolean sEnd = (s >= string.length()); - boolean pEnd = (p >= pattern.length() || pattern.charAt(p) == '|'); - if (sEnd && pEnd) - return true; - if (sEnd || pEnd) - break; - if (pattern.charAt(p) == '?') - continue; - if (pattern.charAt(p) == '*') { - int i; - ++p; - for (i = string.length(); i >= s; --i) - if (match(pattern.substring(p), string.substring(i))) // not quite right - return true; - break; - } - if (pattern.charAt(p) != string.charAt(s)) - break; - } - p = pattern.indexOf('|', p); - if (p == -1) - return false; - } - } - - // / Finds the maximum length of a string that matches a given wildcard - // pattern. Only does ? and *, and multiple patterns separated by |. - public static int matchSpan(String pattern, String string) { - int result = 0; - StringTokenizer st = new StringTokenizer(pattern, "|"); - - while (st.hasMoreTokens()) { - int len = matchSpan1(st.nextToken(), string); - if (len > result) - result = len; - } - return result; - } - - static int matchSpan1(String pattern, String string) { - int p = 0; - for (; p < string.length() && p < pattern.length(); p++) { - if (pattern.charAt(p) == string.charAt(p)) - continue; - if (pattern.charAt(p) == '*') - return p - 1; - return 0; - } - return p < (pattern.length() - 1) ? -1 : p; - } - - // / Turns a String into an array of Strings, by using StringTokenizer - // to split it up at whitespace. - public static String[] splitStr(String str) { - StringTokenizer st = new StringTokenizer(str); - int n = st.countTokens(); - String[] strs = new String[n]; - for (int i = 0; i < n; ++i) - strs[i] = st.nextToken(); - return strs; - } - - // / Turns a String into an array of Strings, by splitting it at - // the specified character. This does not use StringTokenizer, - // and therefore can handle empty fields. - public static String[] splitStr(String str, char delim) { - int n = 1; - int index = -1; - while (true) { - index = str.indexOf(delim, index + 1); - if (index == -1) - break; - ++n; - } - String[] strs = new String[n]; - index = -1; - for (int i = 0; i < n - 1; ++i) { - int nextIndex = str.indexOf(delim, index + 1); - strs[i] = str.substring(index + 1, nextIndex); - index = nextIndex; - } - strs[n - 1] = str.substring(index + 1); - return strs; - } - - public static String[] splitStr(String str, String quotes) { - char[] ca = str.toCharArray(); - // List result = new ArrayList(10); - String[] result = new String[0]; - boolean inArg = false; - boolean quoted = false; - int argStart = -1; - for (int i = 0; i < ca.length; i++) { - char c = ca[i]; - if (inArg) { - if (quoted) { - if (quotes.indexOf(c) >= 0) { - result = copyOf(result, result.length + 1); - result[result.length - 1] = new String(ca, argStart, i - argStart); - argStart = -1; - quoted = false; - inArg = false; - } - } else { - if (c == ' ') { - result = copyOf(result, result.length + 1); - result[result.length - 1] = new String(ca, argStart, i - argStart); - argStart = -1; - inArg = false; - } - } - } else { - if (c != ' ') { - inArg = true; - if (quotes.indexOf(c) >= 0) { - quoted = true; - argStart = i + 1; - } else - argStart = i; - } - } - } - if (argStart > 0) { - result = copyOf(result, result.length + 1); - result[result.length - 1] = new String(ca, argStart, ca.length - argStart); - } - // for(int i=0;i 0) - pathElems.remove(pathElems.size() - 1); - else - lev--; - // else exception ? - } else if (el.equals(".") == false) - if (lev >= 0) - pathElems.add(el); - else - lev++; - if (f) { - s = i; - break; - } - s = -1; - } - } - } - if (s > 0) { - String el = new String(pa, s, n - s); - if (el.equals("..")) { - if (pathElems.size() > 0) - pathElems.remove(pathElems.size() - 1); - // else exception ? - } else if (el.equals(".") == false) - if (lev >= 0) - pathElems.add(el); - } else - pathElems.add(""); - if (pathElems.size() == 0) - return lev>=0?"":null; - StringBuffer result = new StringBuffer(n); - result.append(pathElems.get(0)); - n = pathElems.size(); - for (int i = 1; i < n; i++) - result.append('/').append(pathElems.get(i)); - // System.err.println("Before "+path+" after "+result); - return result.toString(); - } - - // / Copy the input to the output until EOF. - public static long copyStream(InputStream in, OutputStream out, long maxLen) throws IOException { - byte[] buf = new byte[COPY_BUF_SIZE]; - int len; - long tot = 0; - if (maxLen <= 0) - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - tot += len; - } - else - while ((len = in.read(buf)) > 0) - if (len <= maxLen) { - out.write(buf, 0, len); - maxLen -= len; - tot += len; - } else { - out.write(buf, 0, (int) maxLen); - tot += maxLen; - break; - } - return tot; - } - - // / Copy the input to the output until EOF. - public static void copyStream(Reader in, Writer out) throws IOException { - char[] buf = new char[COPY_BUF_SIZE]; - int len; - while ((len = in.read(buf)) != -1) - out.write(buf, 0, len); - } - - // / Copy the input to the output until EOF. - public static void copyStream(Reader in, OutputStream out, String charSet) throws IOException { - char[] buf = new char[4096]; - int len; - if (charSet == null) - while ((len = in.read(buf)) != -1) { - out.write(new String(buf, 0, len).getBytes()); - } - else - while ((len = in.read(buf)) != -1) - out.write(new String(buf, 0, len).getBytes(charSet)); - } - - protected final static char BASE64ARRAY[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', - 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' }; - - /** - * base 64 encoding, string converted to bytes using specified encoding - * - * @param String - * _s original string to encode - * @param String - * encoding, can be null, then iso-8859-1 used - * @return String result of encoding as iso-8859-1 string
- * return null in case of invalid encoding or original string null - * @exception no - * exceptions - */ - public final static String base64Encode(String _s, String _enc) { - if (_s == null) - return null; - if (_enc == null) - _enc = ISO_8859_1; - try { - return base64Encode(_s.getBytes(_enc)); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - /** - * base 64 encoding, array of bytes converted to bytes using specified encoding - * - * @param String - * _s original string to encode - * @param String - * encoding, can be null, then iso-8859-1 used - * @return String result of encoding as iso-8859-1 string
- * - * @exception NullPointerException if input parameter is null - */ - public final static String base64Encode(byte[] _bytes) { - StringBuffer encodedBuffer = new StringBuffer((int) (_bytes.length * 1.5)); - int i = 0; - int pad = 0; - while (i < _bytes.length) { - int b1 = (0xFF & _bytes[i++]); - int b2; - int b3; - if (i >= _bytes.length) { - b2 = 0; - b3 = 0; - pad = 2; - } else { - b2 = 0xFF & _bytes[i++]; - if (i >= _bytes.length) { - b3 = 0; - pad = 1; - } else - b3 = (0xFF & _bytes[i++]); - } - byte c1 = (byte) (b1 >> 2); - byte c2 = (byte) (((b1 & 0x3) << 4) | (b2 >> 4)); - byte c3 = (byte) (((b2 & 0xf) << 2) | (b3 >> 6)); - byte c4 = (byte) (b3 & 0x3f); - encodedBuffer.append(BASE64ARRAY[c1]).append(BASE64ARRAY[c2]); - switch (pad) { - case 0: - encodedBuffer.append(BASE64ARRAY[c3]).append(BASE64ARRAY[c4]); - break; - case 1: - encodedBuffer.append(BASE64ARRAY[c3]).append('='); - break; - case 2: - encodedBuffer.append("=="); - break; - } - } - return encodedBuffer.toString(); - } - - /** - * Translates a Base64 value to either its 6-bit reconstruction value or a negative number indicating some other meaning. - */ - protected final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - - // 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' - // through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' - // through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' - // through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' - // through 'z' - -9, -9, -9, -9 // Decimal 123 - 126 - }; - - protected final static byte WHITE_SPACE_ENC = -5; // Indicates white space - - // in encoding - - protected final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign - - // in encoding - - /** The equals sign (=) as a byte. */ - protected final static byte EQUALS_SIGN = (byte) '='; - - /** - * base 64 decoding - * - * @param encoded - * string - * @param encoding - * used to get string bytes - * @return result of encoding, or null if encoding invalid or string null, or string is invalid base 64 encoding - */ - public final static String base64Decode(String _s, String _enc) { - if (_s == null) - return null; - if (_enc == null) - _enc = ISO_8859_1; - try { - return new String(decode64(_s), _enc); - } catch (UnsupportedEncodingException uee) { - } - return null; - } - - /** - * Decodes four bytes from array source and writes the resulting bytes (up to three of them) to destination. The source and - * destination arrays can be manipulated anywhere along their length by specifying srcOffset and destOffset. This method does not - * check to make sure your arrays are large enough to accomodate srcOffset + 4 for the source array or destOffset + 3 - * for the destination array. This method returns the actual number of bytes that were converted from the Base64 encoding. - * - * - * @param source - * the array to convert - * @param srcOffset - * the index where conversion begins - * @param destination - * the array to hold the conversion - * @param destOffset - * the index where output will be put - * @return the number of decoded bytes converted - * @since 1.3 - */ - private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset) { - // Example: Dk== - if (source[srcOffset + 2] == EQUALS_SIGN) { - // Two ways to do the same thing. Don't know which way I like best. - // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 - // ) - // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); - - destination[destOffset] = (byte) (outBuff >>> 16); - return 1; - } - - // Example: DkL= - else if (source[srcOffset + 3] == EQUALS_SIGN) { - // Two ways to do the same thing. Don't know which way I like best. - // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 - // ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) - | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); - - destination[destOffset] = (byte) (outBuff >>> 16); - destination[destOffset + 1] = (byte) (outBuff >>> 8); - return 2; - } - - // Example: DkLE - else { - try { - // Two ways to do the same thing. Don't know which way I like - // best. - // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) - // >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) - // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) - | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) - | ((DECODABET[source[srcOffset + 3]] & 0xFF)); - - destination[destOffset] = (byte) (outBuff >> 16); - destination[destOffset + 1] = (byte) (outBuff >> 8); - destination[destOffset + 2] = (byte) (outBuff); - - return 3; - } catch (Exception e) { - System.out.println("" + source[srcOffset] + ": " + (DECODABET[source[srcOffset]])); - System.out.println("" + source[srcOffset + 1] + ": " + (DECODABET[source[srcOffset + 1]])); - System.out.println("" + source[srcOffset + 2] + ": " + (DECODABET[source[srcOffset + 2]])); - System.out.println("" + source[srcOffset + 3] + ": " + (DECODABET[source[srcOffset + 3]])); - return -1; - } // e nd catch - } - } // end decodeToBytes - - /** - * Very low-level access to decoding ASCII characters in the form of a byte array. Does not support automatically gunzipping or any other "fancy" features. - * - * @param source - * The Base64 encoded data - * @param off - * The offset of where to begin decoding - * @param len - * The length of characters to decode - * @return decoded data - * @since 1.3 - */ - public static byte[] decode(byte[] source, int off, int len) { - int len34 = len * 3 / 4; - byte[] outBuff = new byte[len34]; // Upper limit on size of output - int outBuffPosn = 0; - - byte[] b4 = new byte[4]; - int b4Posn = 0; - int i = 0; - byte sbiCrop = 0; - byte sbiDecode = 0; - for (i = off; i < off + len; i++) { - sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits - sbiDecode = DECODABET[sbiCrop]; - - if (sbiDecode >= WHITE_SPACE_ENC) // Whitesp ace,Eq ualssi gnor be - // tter - { - if (sbiDecode >= EQUALS_SIGN_ENC) { - b4[b4Posn++] = sbiCrop; - if (b4Posn > 3) { - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); - b4Posn = 0; - - // If that was the equals sign, break out of 'for' loop - if (sbiCrop == EQUALS_SIGN) - break; - } // end if: quartet built - - } // end if: equals sign or better - - } // end if: white space, equals sign or better - else { - System.err.println("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); - return null; - } // end else: - } // each input character - - byte[] out = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, out, 0, outBuffPosn); - return out; - } // end decode - - /** - * Decodes data from Base64 notation, automatically detecting gzip-compressed data and decompressing it. - * - * @param s - * the string to decode - * @return the decoded data - * @since 1.4 - */ - public static byte[] decode64(String s) { - byte[] bytes; - try { - bytes = s.getBytes(ISO_8859_1); - } // end try - catch (java.io.UnsupportedEncodingException uee) { - bytes = s.getBytes(); - } // end catch - // - - // Decode - bytes = decode(bytes, 0, bytes.length); - - // Check to see if it's gzip-compressed - // GZIP Magic Two-Byte Number: 0x8b1f (35615) - if (bytes != null && bytes.length >= 4) { - - int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); - if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) { - java.io.ByteArrayInputStream bais = null; - java.util.zip.GZIPInputStream gzis = null; - java.io.ByteArrayOutputStream baos = null; - byte[] buffer = new byte[2048]; - int length = 0; - - try { - baos = new java.io.ByteArrayOutputStream(); - bais = new java.io.ByteArrayInputStream(bytes); - gzis = new java.util.zip.GZIPInputStream(bais); - - while ((length = gzis.read(buffer)) >= 0) { - baos.write(buffer, 0, length); - } // end while: reading input - - // No error? Get new bytes. - bytes = baos.toByteArray(); - - } // end try - catch (java.io.IOException e) { - // Just return originally-decoded bytes - } // end catch - finally { - try { - baos.close(); - } catch (Exception e) { - } - try { - gzis.close(); - } catch (Exception e) { - } - try { - bais.close(); - } catch (Exception e) { - } - } // end finally - - } // end if: gzipped - } // end if: bytes.length >= 2 - - return bytes; - } // end decode - - /** - * calculate local file based class path for class loader if possible (servlet classes must be located there) - * - * @param cl - * class loader - * @return class path in string - */ - static public String calculateClassPath(ClassLoader cl) { - // scan cl chain to find - StringBuffer classPath = new StringBuffer(); - boolean jspFound = false, servletFound = false; - while (cl != null) { - if (cl instanceof URLClassLoader) { - boolean addClasses = false; - if (jspFound == false) { - jspFound = ((URLClassLoader) cl).findResource("javax/servlet/jsp/JspPage.class") != null; - addClasses |= jspFound; - } - if (servletFound == false) { - servletFound = ((URLClassLoader) cl).findResource("javax/servlet/http/HttpServlet.class") != null; - addClasses |= servletFound; - } - if (addClasses) { - URL[] urls = ((URLClassLoader) cl).getURLs(); - for (int i = 0; i < urls.length; i++) { - String classFile = toFile(urls[i]); - if (classFile == null) - continue; - if (classPath.length() > 0) - classPath.append(File.pathSeparatorChar).append(classFile); - else - classPath.append(classFile); - } - } - if (jspFound && servletFound) - return classPath.toString(); - } - cl = cl.getParent(); - } - return System.getProperty("java.class.path"); - } - - public static int parseInt(Object num, int def) { - if (num instanceof Number) - return ((Number)num).intValue(); - try { - return Integer.parseInt(num.toString()); - } catch (Exception e) { - return def; - } - } - - public static final String toFile(URL url) { - if (url.getProtocol().indexOf("file") < 0) - return null; - String result = url.getPath(); - if (result.charAt(0) == '/' && File.separatorChar == '\\') - result = result.substring(1); - try { - return decode(result, "UTF-8"); - } catch (UnsupportedEncodingException e) { - return result; - } - } - - // public static final int firstOccurrence(String s, String occur) { - // - // } - - public static interface ThreadFactory { - Thread create(Runnable runnable); - } - - public static final class ThreadPool { - static final int DEF_MAX_POOLED_THREAD = 20; - - static final String ID = "Acme.Utils.ThreadPool"; - - public static final String MAXNOTHREAD = ID + ".maxpooledthreads"; - - protected static int counter; - - protected ArrayList freeThreads; - - protected HashMap busyThreads; - - protected int maxThreads; - - protected ThreadFactory threadFactory; - - /** - * Creates a thread pool not queued with max number of threads defined in properties or DEF_MAX_POOLED_THREAD = 20 - * - * @param Properties - * where property THREADSINPOOL gives max threads Note if THREADSINPOOL not integers, or negative then DEF_MAX_POOLED_THREAD used - */ - public ThreadPool(Properties properties, ThreadFactory threadfactory) { - maxThreads = parseInt(properties.getProperty(MAXNOTHREAD), DEF_MAX_POOLED_THREAD); - if (maxThreads < 0) - maxThreads = DEF_MAX_POOLED_THREAD; - freeThreads = new ArrayList(maxThreads); - busyThreads = new HashMap(maxThreads); - this.threadFactory = threadfactory; - } - - /** - * Assigns a new value for max threads - * - * @param int - * new value of max threads, can't be less than 2, but can be 0 If current number threads exceed the value, then extra thread will be - * discarded gracefully - */ - public void setMaxThreads(int newSize) { - if (newSize > 2 || newSize == 0) - maxThreads = newSize; - } - - /** - * Returns setting for max number of threads - * - * @return int setting for max number of threads, doesn't reflect actual number of threads though - */ - public int getMaxThreads() { - return maxThreads; - } - - /** - * Takes a new task for execution by a threads in pool will wait until free threads if number of threads reached max - * - * @param Runnable - * task for execution - */ - public void executeThread(Runnable runnable) { - PooledThread pt = null; - do { - synchronized (freeThreads) { - if (freeThreads.size() > 0) - pt = (PooledThread) freeThreads.remove(0); - } - if (pt != null && pt.isAlive() == false) - pt = null; - if (pt == null) - synchronized (busyThreads) { - if (busyThreads.size() < maxThreads || maxThreads == 0) - pt = new PooledThread(); - } - if (pt == null) - synchronized (freeThreads) { - try { - freeThreads.wait(); - } catch (InterruptedException ie) { - } - } - } while (pt == null); - pt.setName("-PooledThread: " + runnable); - pt.setRunner(runnable); - synchronized (busyThreads) { - busyThreads.put(pt, pt); - } - } - - protected void finalize() throws Throwable { - synchronized (freeThreads) { - Iterator i = freeThreads.iterator(); - while (i.hasNext()) - ((PooledThread) i.next()).interrupt(); - } - synchronized (busyThreads) { - Iterator i = freeThreads.iterator(); - while (i.hasNext()) - ((PooledThread) i.next()).interrupt(); - } - super.finalize(); - } - - public String toString() { - if (freeThreads != null && busyThreads != null) - return ID + ": free threads " + freeThreads.size() + " busy threads " + busyThreads.size(); - else - return ID + ": not initialized yet. " + super.toString(); - } - - class PooledThread implements Runnable { - - Runnable runner; - - boolean quit; - - Thread delegateThread; - - String id = ID + "(" + (counter++) + ")"; - - PooledThread() { - if (threadFactory != null) - delegateThread = threadFactory.create(this); - else - delegateThread = new Thread(this); - setName("-PooledThread: CREATED"); - delegateThread.start(); - } - - public void setName(String name) { - delegateThread.setName(id + name); - } - - public boolean isAlive() { - return delegateThread.isAlive(); - } - - synchronized public void run() { - do { - if (runner == null) - try { - this.wait(); - } catch (InterruptedException ie) { - - } - if (runner != null) { - try { - runner.run(); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - t.printStackTrace(); - } finally { - runner = null; - } - - int activeThreads = 0; - synchronized (busyThreads) { - busyThreads.remove(this); - activeThreads = busyThreads.size(); - } - synchronized (freeThreads) { - if (freeThreads.size() + activeThreads > maxThreads) - break; // discard this thread - freeThreads.add(this); - delegateThread.setName(ID + "-PooledThread: FREE"); - freeThreads.notify(); - } - } - } while (!quit); - } - - synchronized public void interrupt() { - quit = true; - delegateThread.interrupt(); - } - - synchronized void setRunner(Runnable runnable) { - if (runner != null) - throw new RuntimeException("Invalid worker thread state, current runner not null."); - runner = runnable; - this.notifyAll(); - } - } - } - - public static class DummyPrintStream extends PrintStream { - public DummyPrintStream() { - super(new OutputStream() { - public void write(int i) { - } - }); - } - } - - public static class SimpleBuffer { - byte[] buffer; - - int fillPos; - - byte[] emptyBuffer; - - public SimpleBuffer() { - fillPos = 0; - setSize(COPY_BUF_SIZE); - } - - public synchronized void setSize(int size) { - if (size < 0) - throw new IllegalArgumentException("Size can't be negative"); - if (fillPos <= 0) - buffer = new byte[size]; - else - throw new IllegalStateException("Can't resize buffer containing data"); - } - - public synchronized int getSize() { - return buffer.length; - } - - public synchronized byte[] put(byte[] data, int off, int len) { - //System.err.println("put in buff:" + len+", fp:"+fillPos); - if (buffer.length > fillPos + len) { - System.arraycopy(data, off, buffer, fillPos, len); - fillPos += len; - return getEmptyBuffer(); - } - byte[] result = new byte[Math.max(fillPos + len - buffer.length, buffer.length)]; - //System.err.println("fp:" + fillPos + ",bl:" + buffer.length + ",rl:" + result.length + ",l:" + len); - // fill result - int rfilled = 0; - if (fillPos < result.length) { - System.arraycopy(buffer, 0, result, 0, fillPos); - rfilled = result.length - fillPos; - System.arraycopy(data, off, result, fillPos, rfilled); - fillPos = 0; - //System.err.println("1rf:"+rfilled); - } else { - System.arraycopy(buffer, 0, result, 0, result.length); - System.arraycopy(buffer, result.length, buffer, 0, fillPos - result.length); - fillPos -= result.length; - rfilled = 0; - //System.err.println("qrf: 0"); - } - if (rfilled < len) { - System.arraycopy(data, off + rfilled, buffer, fillPos, len - rfilled); - fillPos += len - rfilled; - //System.err.println("added to buf:"+(len - rfilled)); - } - return result; - } - - public synchronized byte[] get() { - //System.err.println("get fp: "+fillPos); - if (fillPos <= 0) { - return getEmptyBuffer(); - } - byte[] result = new byte[fillPos]; - System.arraycopy(buffer, 0, result, 0, fillPos); - fillPos = 0; - return result; - } - - public synchronized void reset() { - //System.err.println("reset buf"); - fillPos = 0; - } - - private synchronized byte[] getEmptyBuffer() { - if (emptyBuffer == null) - emptyBuffer = new byte[0]; - return emptyBuffer; - } - } - - public static void main(String[] args) { - try { - System.out.println(args[0]); - System.out.println(canonicalizePath(args[0])); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/1.x/src/jasper/JspC.java b/1.x/src/jasper/JspC.java deleted file mode 100644 index 43f2146..0000000 --- a/1.x/src/jasper/JspC.java +++ /dev/null @@ -1,1368 +0,0 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.servlet.JspCServletContext; - - -/** - * Shell for the jspc compiler. Handles all options associated with the - * command line and creates compilation contexts which it then compiles - * according to the specified options. - * - * This version can process files from a _single_ webapp at once, i.e. - * a single docbase can be specified. - * - * It can be used as an Ant task using: - *

- *   <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
- *      <classpath>
- *          <pathelement location="${java.home}/../lib/tools.jar"/>
- *          <fileset dir="${ENV.CATALINA_HOME}/server/lib">
- *              <include name="*.jar"/>
- *          </fileset>
- *          <fileset dir="${ENV.CATALINA_HOME}/common/lib">
- *              <include name="*.jar"/>
- *          </fileset>
- *          <path refid="myjars"/>
- *       </classpath>
- *  </taskdef>
- *
- *  <jasper2 verbose="0"
- *           package="my.package"
- *           uriroot="${webapps.dir}/${webapp.name}"
- *           webXmlFragment="${build.dir}/generated_web.xml"
- *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
- * 
- * - * @author Danno Ferrin - * @author Pierre Delisle - * @author Costin Manolache - * @author Yoav Shapira - */ -public class JspC implements Options { - - public static final String DEFAULT_IE_CLASS_ID = - "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - // Logger - private static Log log = LogFactory.getLog(JspC.class); - - private static final String SWITCH_VERBOSE = "-v"; - private static final String SWITCH_HELP = "-help"; - private static final String SWITCH_QUIET = "-q"; - private static final String SWITCH_OUTPUT_DIR = "-d"; - private static final String SWITCH_IE_CLASS_ID = "-ieplugin"; - private static final String SWITCH_PACKAGE_NAME = "-p"; - private static final String SWITCH_CACHE = "-cache"; - private static final String SWITCH_CLASS_NAME = "-c"; - private static final String SWITCH_FULL_STOP = "--"; - private static final String SWITCH_COMPILE = "-compile"; - private static final String SWITCH_SOURCE = "-source"; - private static final String SWITCH_TARGET = "-target"; - private static final String SWITCH_URI_BASE = "-uribase"; - private static final String SWITCH_URI_ROOT = "-uriroot"; - private static final String SWITCH_FILE_WEBAPP = "-webapp"; - private static final String SWITCH_WEBAPP_INC = "-webinc"; - private static final String SWITCH_WEBAPP_XML = "-webxml"; - private static final String SWITCH_MAPPED = "-mapped"; - private static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; - private static final String SWITCH_TRIM_SPACES = "-trimSpaces"; - private static final String SWITCH_CLASSPATH = "-classpath"; - private static final String SWITCH_DIE = "-die"; - private static final String SWITCH_POOLING = "-poolingEnabled"; - private static final String SWITCH_ENCODING = "-javaEncoding"; - private static final String SWITCH_SMAP = "-smap"; - private static final String SWITCH_DUMP_SMAP = "-dumpsmap"; - - private static final String SHOW_SUCCESS ="-s"; - private static final String LIST_ERRORS = "-l"; - private static final int NO_WEBXML = 0; - private static final int INC_WEBXML = 10; - private static final int ALL_WEBXML = 20; - private static final int DEFAULT_DIE_LEVEL = 1; - private static final int NO_DIE_LEVEL = 0; - - private static final String[] insertBefore = - { "", "", "", - "", "", "", "", - "", "", "", - "", "", "", "", - "" }; - - private static int die; - private String classPath = null; - private URLClassLoader loader = null; - private boolean trimSpaces = false; - private boolean genStringAsCharArray = false; - private boolean xpoweredBy; - private boolean mappedFile = false; - private boolean poolingEnabled = true; - private File scratchDir; - private String ieClassId = DEFAULT_IE_CLASS_ID; - private String targetPackage; - private String targetClassName; - private String uriBase; - private String uriRoot; - private int dieLevel; - private boolean helpNeeded = false; - private boolean compile = false; - private boolean smapSuppressed = true; - private boolean smapDumped = false; - private boolean caching = true; - private Map cache = new HashMap(); - - private String compiler = null; - - private String compilerTargetVM = "1.4"; - private String compilerSourceVM = "1.4"; - - private boolean classDebugInfo = true; - - /** - * Throw an exception if there's a compilation error, or swallow it. - * Default is true to preserve old behavior. - */ - private boolean failOnError = true; - - /** - * The file extensions to be handled as JSP files. - * Default list is .jsp and .jspx. - */ - private List extensions; - - /** - * The pages. - */ - private List pages = new Vector(); - - /** - * Needs better documentation, this data member does. - * True by default. - */ - private boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * The java file encoding. Default - * is UTF-8. Added per bugzilla 19622. - */ - private String javaEncoding = "UTF-8"; - - // Generation of web.xml fragments - private String webxmlFile; - private int webxmlLevel; - private boolean addWebXmlMappings = false; - - private Writer mapout; - private CharArrayWriter servletout; - private CharArrayWriter mappingout; - - /** - * The servlet context. - */ - private JspCServletContext context; - - /** - * The runtime context. - * Maintain a dummy JspRuntimeContext for compiling tag files. - */ - private JspRuntimeContext rctxt; - - /** - * Cache for the TLD locations - */ - private TldLocationsCache tldLocationsCache = null; - - private JspConfig jspConfig = null; - private TagPluginManager tagPluginManager = null; - - private boolean verbose = false; - private boolean listErrors = false; - private boolean showSuccess = false; - private int argPos; - private boolean fullstop = false; - private String args[]; - - public static void main(String arg[]) { - if (arg.length == 0) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - try { - JspC jspc = new JspC(); - jspc.setArgs(arg); - if (jspc.helpNeeded) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - jspc.execute(); - } - } catch (JasperException je) { - System.err.println(je); - //System.err.println(je.getMessage()); - if (die != NO_DIE_LEVEL) { - System.exit(die); - } - } - } - } - - public void setArgs(String[] arg) throws JasperException { - args = arg; - String tok; - - dieLevel = NO_DIE_LEVEL; - die = dieLevel; - - while ((tok = nextArg()) != null) { - if (tok.equals(SWITCH_VERBOSE)) { - verbose = true; - showSuccess = true; - listErrors = true; - } else if (tok.equals(SWITCH_OUTPUT_DIR)) { - tok = nextArg(); - setOutputDir( tok ); - } else if (tok.equals(SWITCH_PACKAGE_NAME)) { - targetPackage = nextArg(); - } else if (tok.equals(SWITCH_COMPILE)) { - compile=true; - } else if (tok.equals(SWITCH_CLASS_NAME)) { - targetClassName = nextArg(); - } else if (tok.equals(SWITCH_URI_BASE)) { - uriBase=nextArg(); - } else if (tok.equals(SWITCH_URI_ROOT)) { - setUriroot( nextArg()); - } else if (tok.equals(SWITCH_FILE_WEBAPP)) { - setUriroot( nextArg()); - } else if ( tok.equals( SHOW_SUCCESS ) ) { - showSuccess = true; - } else if ( tok.equals( LIST_ERRORS ) ) { - listErrors = true; - } else if (tok.equals(SWITCH_WEBAPP_INC)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = INC_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = ALL_WEBXML; - } - } else if (tok.equals(SWITCH_MAPPED)) { - mappedFile = true; - } else if (tok.equals(SWITCH_XPOWERED_BY)) { - xpoweredBy = true; - } else if (tok.equals(SWITCH_TRIM_SPACES)) { - setTrimSpaces(true); - } else if (tok.equals(SWITCH_CACHE)) { - tok = nextArg(); - if ("false".equals(tok)) { - caching = false; - } else { - caching = true; - } - } else if (tok.equals(SWITCH_CLASSPATH)) { - setClassPath(nextArg()); - } else if (tok.startsWith(SWITCH_DIE)) { - try { - dieLevel = Integer.parseInt( - tok.substring(SWITCH_DIE.length())); - } catch (NumberFormatException nfe) { - dieLevel = DEFAULT_DIE_LEVEL; - } - die = dieLevel; - } else if (tok.equals(SWITCH_HELP)) { - helpNeeded = true; - } else if (tok.equals(SWITCH_POOLING)) { - tok = nextArg(); - if ("false".equals(tok)) { - poolingEnabled = false; - } else { - poolingEnabled = true; - } - } else if (tok.equals(SWITCH_ENCODING)) { - setJavaEncoding(nextArg()); - } else if (tok.equals(SWITCH_SOURCE)) { - setCompilerSourceVM(nextArg()); - } else if (tok.equals(SWITCH_TARGET)) { - setCompilerTargetVM(nextArg()); - } else if (tok.equals(SWITCH_SMAP)) { - smapSuppressed = false; - } else if (tok.equals(SWITCH_DUMP_SMAP)) { - smapDumped = true; - } else { - if (tok.startsWith("-")) { - throw new JasperException("Unrecognized option: " + tok + - ". Use -help for help."); - } - if (!fullstop) { - argPos--; - } - // Start treating the rest as JSP Pages - break; - } - } - - // Add all extra arguments to the list of files - while( true ) { - String file = nextFile(); - if( file==null ) { - break; - } - pages.add( file ); - } - } - - public boolean getKeepGenerated() { - // isn't this why we are running jspc? - return true; - } - - public boolean getTrimSpaces() { - return trimSpaces; - } - - public void setTrimSpaces(boolean ts) { - this.trimSpaces = ts; - } - - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - public boolean isXpoweredBy() { - return xpoweredBy; - } - - public void setXpoweredBy(boolean xpoweredBy) { - this.xpoweredBy = xpoweredBy; - } - - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - public int getTagPoolSize() { - return Constants.MAX_POOL_SIZE; - } - - /** - * Are we supporting HTML mapped servlets? - */ - public boolean getMappedFile() { - return mappedFile; - } - - // Off-line compiler, no need for security manager - public Object getProtectionDomain() { - return null; - } - - public boolean getSendErrorToClient() { - // implied send to System.err - return true; - } - - public void setClassDebugInfo( boolean b ) { - classDebugInfo=b; - } - - public boolean getClassDebugInfo() { - // compile with debug info - return classDebugInfo; - } - - /** - * @see Options#isCaching() - */ - public boolean isCaching() { - return caching; - } - - /** - * @see Options#isCaching() - */ - public void setCaching(boolean caching) { - this.caching = caching; - } - - /** - * @see Options#getCache() - */ - public Map getCache() { - return cache; - } - - /** - * Background compilation check intervals in seconds - */ - public int getCheckInterval() { - return 0; - } - - /** - * Modification test interval. - */ - public int getModificationTestInterval() { - return 0; - } - - /** - * Is Jasper being used in development mode? - */ - public boolean getDevelopment() { - return false; - } - - /** - * Is the generation of SMAP info for JSR45 debuggin suppressed? - */ - public boolean isSmapSuppressed() { - return smapSuppressed; - } - - /** - * Set smapSuppressed flag. - */ - public void setSmapSuppressed(boolean smapSuppressed) { - this.smapSuppressed = smapSuppressed; - } - - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - public boolean isSmapDumped() { - return smapDumped; - } - - /** - * Set smapSuppressed flag. - */ - public void setSmapDumped(boolean smapDumped) { - this.smapDumped = smapDumped; - } - - - /** - * Determines whether text strings are to be generated as char arrays, - * which improves performance in some cases. - * - * @param genStringAsCharArray true if text strings are to be generated as - * char arrays, false otherwise - */ - public void setGenStringAsCharArray(boolean genStringAsCharArray) { - this.genStringAsCharArray = genStringAsCharArray; - } - - /** - * Indicates whether text strings are to be generated as char arrays. - * - * @return true if text strings are to be generated as char arrays, false - * otherwise - */ - public boolean genStringAsCharArray() { - return genStringAsCharArray; - } - - /** - * Sets the class-id value to be sent to Internet Explorer when using - * tags. - * - * @param ieClassId Class-id value - */ - public void setIeClassId(String ieClassId) { - this.ieClassId = ieClassId; - } - - /** - * Gets the class-id value that is sent to Internet Explorer when using - * tags. - * - * @return Class-id value - */ - public String getIeClassId() { - return ieClassId; - } - - public File getScratchDir() { - return scratchDir; - } - - public Class getJspCompilerPlugin() { - // we don't compile, so this is meanlingless - return null; - } - - public String getJspCompilerPath() { - // we don't compile, so this is meanlingless - return null; - } - - /** - * Compiler to use. - */ - public String getCompiler() { - return compiler; - } - - public void setCompiler(String c) { - compiler=c; - } - - /** - * @see Options#getCompilerTargetVM - */ - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - public void setCompilerTargetVM(String vm) { - compilerTargetVM = vm; - } - - /** - * @see Options#getCompilerSourceVM() - */ - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * @see Options#getCompilerSourceVM() - */ - public void setCompilerSourceVM(String vm) { - compilerSourceVM = vm; - } - - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - /** - * Returns the encoding to use for - * java files. The default is UTF-8. - * - * @return String The encoding - */ - public String getJavaEncoding() { - return javaEncoding; - } - - /** - * Sets the encoding to use for - * java files. - * - * @param encodingName The name, e.g. "UTF-8" - */ - public void setJavaEncoding(String encodingName) { - javaEncoding = encodingName; - } - - public boolean getFork() { - return false; - } - - public String getClassPath() { - if( classPath != null ) - return classPath; - return System.getProperty("java.class.path"); - } - - public void setClassPath(String s) { - classPath=s; - } - - /** - * Returns the list of file extensions - * that are treated as JSP files. - * - * @return The list of extensions - */ - public List getExtensions() { - return extensions; - } - - /** - * Adds the given file extension to the - * list of extensions handled as JSP files. - * - * @param extension The extension to add, e.g. "myjsp" - */ - protected void addExtension(final String extension) { - if(extension != null) { - if(extensions == null) { - extensions = new Vector(); - } - - extensions.add(extension); - } - } - - /** - * Base dir for the webapp. Used to generate class names and resolve - * includes - */ - public void setUriroot( String s ) { - if( s==null ) { - uriRoot = s; - return; - } - try { - uriRoot = resolveFile(s).getCanonicalPath(); - } catch( Exception ex ) { - uriRoot = s; - } - } - - /** - * Parses comma-separated list of JSP files to be processed. If the argument - * is null, nothing is done. - * - *

Each file is interpreted relative to uriroot, unless it is absolute, - * in which case it must start with uriroot.

- * - * @param jspFiles Comma-separated list of JSP files to be processed - */ - public void setJspFiles(final String jspFiles) { - if(jspFiles == null) { - return; - } - - StringTokenizer tok = new StringTokenizer(jspFiles, ","); - while (tok.hasMoreTokens()) { - pages.add(tok.nextToken()); - } - } - - /** - * Sets the compile flag. - * - * @param b Flag value - */ - public void setCompile( final boolean b ) { - compile = b; - } - - /** - * Sets the verbosity level. The actual number doesn't - * matter: if it's greater than zero, the verbose flag will - * be true. - * - * @param level Positive means verbose - */ - public void setVerbose( final int level ) { - if (level > 0) { - verbose = true; - showSuccess = true; - listErrors = true; - } - } - - public void setValidateXml( boolean b ) { - org.apache.jasper.xmlparser.ParserUtils.validating=b; - } - - public void setListErrors( boolean b ) { - listErrors = b; - } - - public void setOutputDir( String s ) { - if( s!= null ) { - scratchDir = resolveFile(s).getAbsoluteFile(); - } else { - scratchDir=null; - } - } - - public void setPackage( String p ) { - targetPackage=p; - } - - /** - * Class name of the generated file ( without package ). - * Can only be used if a single file is converted. - * XXX Do we need this feature ? - */ - public void setClassName( String p ) { - targetClassName=p; - } - - /** - * File where we generate a web.xml fragment with the class definitions. - */ - public void setWebXmlFragment( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=INC_WEBXML; - } - - /** - * File where we generate a complete web.xml with the class definitions. - */ - public void setWebXml( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=ALL_WEBXML; - } - - public void setAddWebXmlMappings(boolean b) { - addWebXmlMappings = b; - } - - /** - * Set the option that throws an exception in case of a compilation error. - */ - public void setFailOnError(final boolean b) { - failOnError = b; - } - - public boolean getFailOnError() { - return failOnError; - } - - /** - * Obtain JSP configuration informantion specified in web.xml. - */ - public JspConfig getJspConfig() { - return jspConfig; - } - - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - public void generateWebMapping( String file, JspCompilationContext clctxt ) - throws IOException - { - String className = clctxt.getServletClassName(); - String packageName = clctxt.getServletPackageName(); - - String thisServletName; - if ("".equals(packageName)) { - thisServletName = className; - } else { - thisServletName = packageName + '.' + className; - } - - if (servletout != null) { - servletout.write("\n \n "); - servletout.write(thisServletName); - servletout.write("\n "); - servletout.write(thisServletName); - servletout.write("\n \n"); - } - if (mappingout != null) { - mappingout.write("\n \n "); - mappingout.write(thisServletName); - mappingout.write("\n "); - mappingout.write(file.replace('\\', '/')); - mappingout.write("\n \n"); - - } - } - - /** - * Include the generated web.xml inside the webapp's web.xml. - */ - protected void mergeIntoWebXml() throws IOException { - - File webappBase = new File(uriRoot); - File webXml = new File(webappBase, "WEB-INF/web.xml"); - File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); - String insertStartMarker = - Localizer.getMessage("jspc.webinc.insertStart"); - String insertEndMarker = - Localizer.getMessage("jspc.webinc.insertEnd"); - - BufferedReader reader = new BufferedReader(new FileReader(webXml)); - BufferedReader fragmentReader = - new BufferedReader(new FileReader(webxmlFile)); - PrintWriter writer = new PrintWriter(new FileWriter(webXml2)); - - // Insert the and declarations - int pos = -1; - String line = null; - while (true) { - line = reader.readLine(); - if (line == null) { - break; - } - // Skip anything previously generated by JSPC - if (line.indexOf(insertStartMarker) >= 0) { - while (true) { - line = reader.readLine(); - if (line == null) { - return; - } - if (line.indexOf(insertEndMarker) >= 0) { - line = reader.readLine(); - line = reader.readLine(); - if (line == null) { - return; - } - break; - } - } - } - for (int i = 0; i < insertBefore.length; i++) { - pos = line.indexOf(insertBefore[i]); - if (pos >= 0) - break; - } - if (pos >= 0) { - writer.print(line.substring(0, pos)); - break; - } else { - writer.println(line); - } - } - - writer.println(insertStartMarker); - while (true) { - String line2 = fragmentReader.readLine(); - if (line2 == null) { - writer.println(); - break; - } - writer.println(line2); - } - writer.println(insertEndMarker); - writer.println(); - - for (int i = 0; i < pos; i++) { - writer.print(" "); - } - writer.println(line.substring(pos)); - - while (true) { - line = reader.readLine(); - if (line == null) { - break; - } - writer.println(line); - } - writer.close(); - - reader.close(); - fragmentReader.close(); - - FileInputStream fis = new FileInputStream(webXml2); - FileOutputStream fos = new FileOutputStream(webXml); - - byte buf[] = new byte[512]; - while (true) { - int n = fis.read(buf); - if (n < 0) { - break; - } - fos.write(buf, 0, n); - } - - fis.close(); - fos.close(); - - webXml2.delete(); - (new File(webxmlFile)).delete(); - - } - - private void processFile(String file) - throws JasperException - { - ClassLoader originalClassLoader = null; - - try { - // set up a scratch/output dir if none is provided - if (scratchDir == null) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = ""; - } - scratchDir = new File(new File(temp).getAbsolutePath()); - } - - String jspUri=file.replace('\\','/'); - JspCompilationContext clctxt = new JspCompilationContext - ( jspUri, false, this, context, null, rctxt ); - - /* Override the defaults */ - if ((targetClassName != null) && (targetClassName.length() > 0)) { - clctxt.setServletClassName(targetClassName); - targetClassName = null; - } - if (targetPackage != null) { - clctxt.setServletPackageName(targetPackage); - } - - originalClassLoader = Thread.currentThread().getContextClassLoader(); - if( loader==null ) { - initClassLoader( clctxt ); - } - Thread.currentThread().setContextClassLoader(loader); - - clctxt.setClassLoader(loader); - clctxt.setClassPath(classPath); - - Compiler clc = clctxt.createCompiler(); - - // If compile is set, generate both .java and .class, if - // .jsp file is newer than .class file; - // Otherwise only generate .java, if .jsp file is newer than - // the .java file - if( clc.isOutDated(compile) ) { - clc.compile(compile, true); - } - - // Generate mapping - generateWebMapping( file, clctxt ); - if ( showSuccess ) { - log.info( "Built File: " + file ); - } - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - log.error(Localizer.getMessage("jspc.error.generalException", - file), - rootCause); - } - - // Bugzilla 35114. - if(getFailOnError()) { - throw je; - } else { - log.error(je.getMessage()); - } - - } catch (Exception e) { - if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", - e.getMessage())); - } - throw new JasperException(e); - } finally { - if(originalClassLoader != null) { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - - /** - * Locate all jsp files in the webapp. Used if no explicit - * jsps are specified. - */ - public void scanFiles( File base ) throws JasperException { - Stack dirs = new Stack(); - dirs.push(base); - - // Make sure default extensions are always included - if ((getExtensions() == null) || (getExtensions().size() < 2)) { - addExtension("jsp"); - addExtension("jspx"); - } - - while (!dirs.isEmpty()) { - String s = dirs.pop().toString(); - File f = new File(s); - if (f.exists() && f.isDirectory()) { - String[] files = f.list(); - String ext; - for (int i = 0; (files != null) && i < files.length; i++) { - File f2 = new File(s, files[i]); - if (f2.isDirectory()) { - dirs.push(f2.getPath()); - } else { - String path = f2.getPath(); - String uri = path.substring(uriRoot.length()); - ext = files[i].substring(files[i].lastIndexOf('.') +1); - if (getExtensions().contains(ext) || - jspConfig.isJspPage(uri)) { - pages.add(path); - } - } - } - } - } - } - - /** - * Executes the compilation. - * - * @throws JasperException If an error occurs - */ - public void execute() throws JasperException { - if(log.isDebugEnabled()) { - log.debug("execute() starting for " + pages.size() + " pages."); - } - - try { - if (uriRoot == null) { - if( pages.size() == 0 ) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.missingTarget")); - } - String firstJsp = (String) pages.get( 0 ); - File firstJspF = new File( firstJsp ); - if (!firstJspF.exists()) { - throw new JasperException( - Localizer.getMessage("jspc.error.fileDoesNotExist", - firstJsp)); - } - locateUriRoot( firstJspF ); - } - - if (uriRoot == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.no_uriroot")); - } - - if( context==null ) { - initServletContext(); - } - - // No explicit pages, we'll process all .jsp in the webapp - if (pages.size() == 0) { - scanFiles( new File( uriRoot )); - } - - File uriRootF = new File(uriRoot); - if (!uriRootF.exists() || !uriRootF.isDirectory()) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); - } - - initWebXml(); - - Iterator iter = pages.iterator(); - while (iter.hasNext()) { - String nextjsp = iter.next().toString(); - File fjsp = new File(nextjsp); - if (!fjsp.isAbsolute()) { - fjsp = new File(uriRootF, nextjsp); - } - if (!fjsp.exists()) { - if (log.isWarnEnabled()) { - log.warn - (Localizer.getMessage - ("jspc.error.fileDoesNotExist", fjsp.toString())); - } - continue; - } - String s = fjsp.getAbsolutePath(); - if (s.startsWith(uriRoot)) { - nextjsp = s.substring(uriRoot.length()); - } - if (nextjsp.startsWith("." + File.separatorChar)) { - nextjsp = nextjsp.substring(2); - } - processFile(nextjsp); - } - - completeWebXml(); - - if (addWebXmlMappings) { - mergeIntoWebXml(); - } - - } catch (IOException ioe) { - throw new JasperException(ioe); - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - rootCause.printStackTrace(); - } - throw je; - } finally { - if (loader != null) { - LogFactory.release(loader); - } - } - } - - // ==================== Private utility methods ==================== - - private String nextArg() { - if ((argPos >= args.length) - || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { - return null; - } else { - return args[argPos++]; - } - } - - private String nextFile() { - if (fullstop) argPos++; - if (argPos >= args.length) { - return null; - } else { - return args[argPos++]; - } - } - - private void initWebXml() { - try { - if (webxmlLevel >= INC_WEBXML) { - File fmapings = new File(webxmlFile); - mapout = new FileWriter(fmapings); - servletout = new CharArrayWriter(); - mappingout = new CharArrayWriter(); - } else { - mapout = null; - servletout = null; - mappingout = null; - } - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.header")); - mapout.flush(); - } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.header")); - mapout.flush(); - } - } catch (IOException ioe) { - mapout = null; - servletout = null; - mappingout = null; - } - } - - private void completeWebXml() { - if (mapout != null) { - try { - servletout.writeTo(mapout); - mappingout.writeTo(mapout); - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.footer")); - } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.footer")); - } - mapout.close(); - } catch (IOException ioe) { - // noting to do if it fails since we are done with it - } - } - } - - private void initServletContext() { - try { - context =new JspCServletContext - (new PrintWriter(System.out), - new URL("file:" + uriRoot.replace('\\','/') + '/')); - tldLocationsCache = new TldLocationsCache(context, true); - } catch (MalformedURLException me) { - System.out.println("**" + me); - } - rctxt = new JspRuntimeContext(context, this); - jspConfig = new JspConfig(context); - tagPluginManager = new TagPluginManager(context); - } - - /** - * Initializes the classloader as/if needed for the given - * compilation context. - * - * @param clctxt The compilation context - * @throws IOException If an error occurs - */ - private void initClassLoader(JspCompilationContext clctxt) - throws IOException { - - classPath = getClassPath(); - - ClassLoader jspcLoader = getClass().getClassLoader(); - - // Turn the classPath into URLs - ArrayList urls = new ArrayList(); - StringTokenizer tokenizer = new StringTokenizer(classPath, - File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - String path = tokenizer.nextToken(); - try { - File libFile = new File(path); - urls.add(libFile.toURL()); - } catch (IOException ioe) { - // Failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak uot - throw new RuntimeException(ioe.toString()); - } - } - - File webappBase = new File(uriRoot); - if (webappBase.exists()) { - File classes = new File(webappBase, "/WEB-INF/classes"); - try { - if (classes.exists()) { - classPath = classPath + File.pathSeparator - + classes.getCanonicalPath(); - urls.add(classes.getCanonicalFile().toURL()); - } - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - File lib = new File(webappBase, "/WEB-INF/lib"); - if (lib.exists() && lib.isDirectory()) { - String[] libs = lib.list(); - for (int i = 0; i < libs.length; i++) { - if( libs[i].length() <5 ) continue; - String ext=libs[i].substring( libs[i].length() - 4 ); - if (! ".jar".equalsIgnoreCase(ext)) { - if (".tld".equalsIgnoreCase(ext)) { - log.warn("TLD files should not be placed in " - + "/WEB-INF/lib"); - } - continue; - } - try { - File libFile = new File(lib, libs[i]); - classPath = classPath + File.pathSeparator - + libFile.getAbsolutePath(); - urls.add(libFile.getAbsoluteFile().toURL()); - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - } - } - } - - // What is this ?? - urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL()); - - URL urlsA[]=new URL[urls.size()]; - urls.toArray(urlsA); - loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); - - } - - /** - * Find the WEB-INF dir by looking up in the directory tree. - * This is used if no explicit docbase is set, but only files. - * XXX Maybe we should require the docbase. - */ - private void locateUriRoot( File f ) { - String tUriBase = uriBase; - if (tUriBase == null) { - tUriBase = "/"; - } - try { - if (f.exists()) { - f = new File(f.getAbsolutePath()); - while (f != null) { - File g = new File(f, "WEB-INF"); - if (g.exists() && g.isDirectory()) { - uriRoot = f.getCanonicalPath(); - uriBase = tUriBase; - if (log.isInfoEnabled()) { - log.info(Localizer.getMessage( - "jspc.implicit.uriRoot", - uriRoot)); - } - break; - } - if (f.exists() && f.isDirectory()) { - tUriBase = "/" + f.getName() + "/" + tUriBase; - } - - String fParent = f.getParent(); - if (fParent == null) { - break; - } else { - f = new File(fParent); - } - - // If there is no acceptible candidate, uriRoot will - // remain null to indicate to the CompilerContext to - // use the current working/user dir. - } - - if (uriRoot != null) { - File froot = new File(uriRoot); - uriRoot = froot.getCanonicalPath(); - } - } - } catch (IOException ioe) { - // since this is an optional default and a null value - // for uriRoot has a non-error meaning, we can just - // pass straight through - } - } - - /** - * Resolves the relative or absolute pathname correctly - * in both Ant and command-line situations. If Ant launched - * us, we should use the basedir of the current project - * to resolve relative paths. - * - * See Bugzilla 35571. - * - * @param s The file - * @return The file resolved - */ - protected File resolveFile(final String s) { - return new File(s); - } -} diff --git a/1.x/src/jasper/JspCompilationContext.java b/1.x/src/jasper/JspCompilationContext.java deleted file mode 100644 index 183b6cf..0000000 --- a/1.x/src/jasper/JspCompilationContext.java +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Hashtable; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.JspUtil; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.ServletWriter; -import org.apache.jasper.servlet.JasperLoader; -import org.apache.jasper.servlet.JspServletWrapper; - -/** - * A place holder for various things that are used through out the JSP - * engine. This is a per-request/per-context data structure. Some of - * the instance variables are set at different points. - * - * Most of the path-related stuff is here - mangling names, versions, dirs, - * loading resources and dealing with uris. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Pierre Delisle - * @author Costin Manolache - * @author Kin-man Chung - */ -public class JspCompilationContext { - - protected org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class); - - private Hashtable tagFileJarUrls; - private boolean isPackagedTagFile; - - private String className; - private String jspUri; - private boolean isErrPage; - private String basePackageName; - private String derivedPackageName; - private String servletJavaFileName; - private String javaPath; - private String classFileName; - private String contentType; - private ServletWriter writer; - private Options options; - private JspServletWrapper jsw; - private Compiler jspCompiler; - private String classPath; - - private String baseURI; - private String baseOutputDir; - private String outputDir; - private ServletContext context; - private URLClassLoader loader; - - private JspRuntimeContext rctxt; - - private int removed = 0; - - private URLClassLoader jspLoader; - private URL baseUrl; - private Class servletClass; - - private boolean isTagFile; - private boolean protoTypeMode; - private TagInfo tagInfo; - private URL tagFileJarUrl; - - // jspURI _must_ be relative to the context - public JspCompilationContext(String jspUri, - boolean isErrPage, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt) { - - this.jspUri = canonicalURI(jspUri); - this.isErrPage = isErrPage; - this.options = options; - this.jsw = jsw; - this.context = context; - - this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); - // hack fix for resolveRelativeURI - if (baseURI == null) { - baseURI = "/"; - } else if (baseURI.charAt(0) != '/') { - // strip the basde slash since it will be combined with the - // uriBase to generate a file - baseURI = "/" + baseURI; - } - if (baseURI.charAt(baseURI.length() - 1) != '/') { - baseURI += '/'; - } - - this.rctxt = rctxt; - this.tagFileJarUrls = new Hashtable(); - this.basePackageName = Constants.JSP_PACKAGE_NAME; - } - - public JspCompilationContext(String tagfile, - TagInfo tagInfo, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt, - URL tagFileJarUrl) { - this(tagfile, false, options, context, jsw, rctxt); - this.isTagFile = true; - this.tagInfo = tagInfo; - this.tagFileJarUrl = tagFileJarUrl; - if (tagFileJarUrl != null) { - isPackagedTagFile = true; - } - } - - /* ==================== Methods to override ==================== */ - - /** ---------- Class path and loader ---------- */ - - /** - * The classpath that is passed off to the Java compiler. - */ - public String getClassPath() { - if( classPath != null ) - return classPath; - return rctxt.getClassPath(); - } - - /** - * The classpath that is passed off to the Java compiler. - */ - public void setClassPath(String classPath) { - this.classPath = classPath; - } - - /** - * What class loader to use for loading classes while compiling - * this JSP? - */ - public ClassLoader getClassLoader() { - if( loader != null ) - return loader; - return rctxt.getParentClassLoader(); - } - - public void setClassLoader(URLClassLoader loader) { - this.loader = loader; - } - - public ClassLoader getJspLoader() { - if( jspLoader == null ) { - jspLoader = new JasperLoader - (new URL[] {baseUrl}, - getClassLoader(), - rctxt.getPermissionCollection(), - rctxt.getCodeSource()); - } - return jspLoader; - } - - /** ---------- Input/Output ---------- */ - - /** - * The output directory to generate code into. The output directory - * is make up of the scratch directory, which is provide in Options, - * plus the directory derived from the package name. - */ - public String getOutputDir() { - if (outputDir == null) { - createOutputDir(); - } - - return outputDir; - } - - /** - * Create a "Compiler" object based on some init param data. This - * is not done yet. Right now we're just hardcoding the actual - * compilers that are created. - */ - public Compiler createCompiler() throws JasperException { - if (jspCompiler != null ) { - return jspCompiler; - } - jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); - if (jspCompiler == null) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); - } - jspCompiler.init(this, jsw); - return jspCompiler; - } - - private Compiler createCompiler(String className) { - Compiler compiler = null; - try { - compiler = (Compiler) Class.forName(className).newInstance(); - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), t); - } - } - return compiler; - } - - public Compiler getCompiler() { - return jspCompiler; - } - - /** ---------- Access resources in the webapp ---------- */ - - /** - * Get the full value of a URI relative to this compilations context - * uses current file as the base. - */ - public String resolveRelativeUri(String uri) { - // sometimes we get uri's massaged from File(String), so check for - // a root directory deperator char - if (uri.startsWith("/") || uri.startsWith(File.separator)) { - return uri; - } else { - return baseURI + uri; - } - } - - /** - * Gets a resource as a stream, relative to the meanings of this - * context's implementation. - * @return a null if the resource cannot be found or represented - * as an InputStream. - */ - public java.io.InputStream getResourceAsStream(String res) { - return context.getResourceAsStream(canonicalURI(res)); - } - - - public URL getResource(String res) throws MalformedURLException { - return context.getResource(canonicalURI(res)); - } - - public Set getResourcePaths(String path) { - return context.getResourcePaths(canonicalURI(path)); - } - - /** - * Gets the actual path of a URI relative to the context of - * the compilation. - */ - public String getRealPath(String path) { - if (context != null) { - return context.getRealPath(path); - } - return path; - } - - /** - * Returns the tag-file-name-to-JAR-file map of this compilation unit, - * which maps tag file names to the JAR files in which the tag files are - * packaged. - * - * The map is populated when parsing the tag-file elements of the TLDs - * of any imported taglibs. - */ - public Hashtable getTagFileJarUrls() { - return this.tagFileJarUrls; - } - - /** - * Returns the JAR file in which the tag file for which this - * JspCompilationContext was created is packaged, or null if this - * JspCompilationContext does not correspond to a tag file, or if the - * corresponding tag file is not packaged in a JAR. - */ - public URL getTagFileJarUrl() { - return this.tagFileJarUrl; - } - - /* ==================== Common implementation ==================== */ - - /** - * Just the class name (does not include package name) of the - * generated class. - */ - public String getServletClassName() { - - if (className != null) { - return className; - } - - if (isTagFile) { - className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - if (lastIndex != -1) { - className = className.substring(lastIndex + 1); - } - } else { - int iSep = jspUri.lastIndexOf('/') + 1; - className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); - } - return className; - } - - public void setServletClassName(String className) { - this.className = className; - } - - /** - * Path of the JSP URI. Note that this is not a file name. This is - * the context rooted URI of the JSP file. - */ - public String getJspFile() { - return jspUri; - } - - /** - * Are we processing something that has been declared as an - * errorpage? - */ - public boolean isErrorPage() { - return isErrPage; - } - - public void setErrorPage(boolean isErrPage) { - this.isErrPage = isErrPage; - } - - public boolean isTagFile() { - return isTagFile; - } - - public TagInfo getTagInfo() { - return tagInfo; - } - - public void setTagInfo(TagInfo tagi) { - tagInfo = tagi; - } - - /** - * True if we are compiling a tag file in prototype mode. - * ie we only generate codes with class for the tag handler with empty - * method bodies. - */ - public boolean isPrototypeMode() { - return protoTypeMode; - } - - public void setPrototypeMode(boolean pm) { - protoTypeMode = pm; - } - - /** - * Package name for the generated class is make up of the base package - * name, which is user settable, and the derived package name. The - * derived package name directly mirrors the file heirachy of the JSP page. - */ - public String getServletPackageName() { - if (isTagFile()) { - String className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - String pkgName = ""; - if (lastIndex != -1) { - pkgName = className.substring(0, lastIndex); - } - return pkgName; - } else { - String dPackageName = getDerivedPackageName(); - if (dPackageName.length() == 0) { - return basePackageName; - } - return basePackageName + '.' + getDerivedPackageName(); - } - } - - private String getDerivedPackageName() { - if (derivedPackageName == null) { - int iSep = jspUri.lastIndexOf('/'); - derivedPackageName = (iSep > 0) ? - JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : ""; - } - return derivedPackageName; - } - - /** - * The package name into which the servlet class is generated. - */ - public void setServletPackageName(String servletPackageName) { - this.basePackageName = servletPackageName; - } - - /** - * Full path name of the Java file into which the servlet is being - * generated. - */ - public String getServletJavaFileName() { - - if (servletJavaFileName == null) { - servletJavaFileName = - getOutputDir() + getServletClassName() + ".java"; - } else { - // Make sure output dir exists - makeOutputDir(); - } - return servletJavaFileName; - } - - public void setServletJavaFileName(String servletJavaFileName) { - this.servletJavaFileName = servletJavaFileName; - } - - /** - * Get hold of the Options object for this context. - */ - public Options getOptions() { - return options; - } - - public ServletContext getServletContext() { - return context; - } - - public JspRuntimeContext getRuntimeContext() { - return rctxt; - } - - /** - * Path of the Java file relative to the work directory. - */ - public String getJavaPath() { - - if (javaPath != null) { - return javaPath; - } - - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - javaPath = tagName.replace('.', '/') + ".java"; - } else { - javaPath = getServletPackageName().replace('.', '/') + '/' + - getServletClassName() + ".java"; - } - return javaPath; - } - - public String getClassFileName() { - - if (classFileName == null) { - classFileName = getOutputDir() + getServletClassName() + ".class"; - } else { - // Make sure output dir exists - makeOutputDir(); - } - return classFileName; - } - - /** - * Get the content type of this JSP. - * - * Content type includes content type and encoding. - */ - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - /** - * Where is the servlet being generated? - */ - public ServletWriter getWriter() { - return writer; - } - - public void setWriter(ServletWriter writer) { - this.writer = writer; - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the given uri is not associated with any tag library - * 'exposed' in the web application. - */ - public String[] getTldLocation(String uri) throws JasperException { - String[] location = - getOptions().getTldLocationsCache().getLocation(uri); - return location; - } - - /** - * Are we keeping generated code around? - */ - public boolean keepGenerated() { - return getOptions().getKeepGenerated(); - } - - // ==================== Removal ==================== - - public void incrementRemoved() { - if (removed > 1) { - jspCompiler.removeGeneratedFiles(); - if( rctxt != null ) - rctxt.removeWrapper(jspUri); - } - removed++; - } - - public boolean isRemoved() { - if (removed > 1 ) { - return true; - } - return false; - } - - // ==================== Compile and reload ==================== - - public void compile() throws JasperException, FileNotFoundException { - createCompiler(); - if (isPackagedTagFile || jspCompiler.isOutDated()) { - try { - jspLoader = null; - jspCompiler.compile(); - jsw.setReload(true); - jsw.setCompilationException(null); - } catch (JasperException ex) { - // Cache compilation exception - jsw.setCompilationException(ex); - throw ex; - } catch (Exception ex) { - ex.printStackTrace(); - JasperException je = new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), - ex); - // Cache compilation exception - jsw.setCompilationException(je); - throw je; - } - } - } - - // ==================== Manipulating the class ==================== - - public Class load() - throws JasperException, FileNotFoundException - { - try { - getJspLoader(); - - String name; - if (isTagFile()) { - name = tagInfo.getTagClassName(); - } else { - name = getServletPackageName() + "." + getServletClassName(); - } - servletClass = jspLoader.loadClass(name); - } catch (ClassNotFoundException cex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), - cex); - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), - ex); - } - removed = 0; - return servletClass; - } - - // ==================== Private methods ==================== - - static Object outputDirLock = new Object(); - - private void makeOutputDir() { - synchronized(outputDirLock) { - File outDirFile = new File(outputDir); - outDirFile.mkdirs(); - } - } - - private void createOutputDir() { - String path = null; - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - path = tagName.replace('.', '/'); - path = path.substring(0, path.lastIndexOf('/')); - } else { - path = getServletPackageName().replace('.', '/'); - } - - try { - // Append servlet or tag handler path to scratch dir - baseUrl = options.getScratchDir().toURL(); - String outUrlString = baseUrl.toString() + '/' + path; - URL outUrl = new URL(outUrlString); - outputDir = outUrl.getFile() + File.separator; - makeOutputDir(); - } catch (Exception e) { - throw new IllegalStateException("No output directory: " + - e.getMessage()); - } - } - - private static final boolean isPathSeparator(char c) { - return (c == '/' || c == '\\'); - } - - private static final String canonicalURI(String s) { - if (s == null) return null; - StringBuffer result = new StringBuffer(); - final int len = s.length(); - int pos = 0; - while (pos < len) { - char c = s.charAt(pos); - if ( isPathSeparator(c) ) { - /* - * multiple path separators. - * 'foo///bar' -> 'foo/bar' - */ - while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) { - ++pos; - } - - if (pos+1 < len && s.charAt(pos+1) == '.') { - /* - * a single dot at the end of the path - we are done. - */ - if (pos+2 >= len) break; - - switch (s.charAt(pos+2)) { - /* - * self directory in path - * foo/./bar -> foo/bar - */ - case '/': - case '\\': - pos += 2; - continue; - - /* - * two dots in a path: go back one hierarchy. - * foo/bar/../baz -> foo/baz - */ - case '.': - // only if we have exactly _two_ dots. - if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) { - pos += 3; - int separatorPos = result.length()-1; - while (separatorPos >= 0 && - ! isPathSeparator(result - .charAt(separatorPos))) { - --separatorPos; - } - if (separatorPos >= 0) - result.setLength(separatorPos); - continue; - } - } - } - } - result.append(c); - ++pos; - } - return result.toString(); - } -} - diff --git a/1.x/src/jasper/TldLocationsCache.java b/1.x/src/jasper/TldLocationsCache.java deleted file mode 100644 index 5c7b30e..0000000 --- a/1.x/src/jasper/TldLocationsCache.java +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.InputStream; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLConnection; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import org.xml.sax.InputSource; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.xmlparser.ParserUtils; -import org.apache.jasper.xmlparser.TreeNode; - -/** - * A container for all tag libraries that are defined "globally" - * for the web application. - * - * Tag Libraries can be defined globally in one of two ways: - * 1. Via elements in web.xml: - * the uri and location of the tag-library are specified in - * the element. - * 2. Via packaged jar files that contain .tld files - * within the META-INF directory, or some subdirectory - * of it. The taglib is 'global' if it has the - * element defined. - * - * A mapping between the taglib URI and its associated TaglibraryInfoImpl - * is maintained in this container. - * Actually, that's what we'd like to do. However, because of the - * way the classes TagLibraryInfo and TagInfo have been defined, - * it is not currently possible to share an instance of TagLibraryInfo - * across page invocations. A bug has been submitted to the spec lead. - * In the mean time, all we do is save the 'location' where the - * TLD associated with a taglib URI can be found. - * - * When a JSP page has a taglib directive, the mappings in this container - * are first searched (see method getLocation()). - * If a mapping is found, then the location of the TLD is returned. - * If no mapping is found, then the uri specified - * in the taglib directive is to be interpreted as the location for - * the TLD of this tag library. - * - * @author Pierre Delisle - * @author Jan Luehe - */ - -public class TldLocationsCache { - - // Logger - private Log log = LogFactory.getLog(TldLocationsCache.class); - - /** - * The types of URI one may specify for a tag library - */ - public static final int ABS_URI = 0; - public static final int ROOT_REL_URI = 1; - public static final int NOROOT_REL_URI = 2; - - private static final String WEB_XML = "/WEB-INF/web.xml"; - private static final String FILE_PROTOCOL = "file:"; - private static final String JAR_FILE_SUFFIX = ".jar"; - - // Names of JARs that are known not to contain any TLDs - private static HashSet noTldJars; - - /** - * The mapping of the 'global' tag library URI to the location (resource - * path) of the TLD associated with that tag library. The location is - * returned as a String array: - * [0] The location - * [1] If the location is a jar file, this is the location of the tld. - */ - private Hashtable mappings; - - private boolean initialized; - private ServletContext ctxt; - private boolean redeployMode; - - //********************************************************************* - // Constructor and Initilizations - - /* - * Initializes the set of JARs that are known not to contain any TLDs - */ - static { - noTldJars = new HashSet(); - noTldJars.add("ant.jar"); - noTldJars.add("catalina.jar"); - noTldJars.add("catalina-ant.jar"); - noTldJars.add("catalina-cluster.jar"); - noTldJars.add("catalina-optional.jar"); - noTldJars.add("catalina-i18n-fr.jar"); - noTldJars.add("catalina-i18n-ja.jar"); - noTldJars.add("catalina-i18n-es.jar"); - noTldJars.add("commons-dbcp.jar"); - noTldJars.add("commons-modeler.jar"); - noTldJars.add("commons-logging-api.jar"); - noTldJars.add("commons-beanutils.jar"); - noTldJars.add("commons-fileupload-1.0.jar"); - noTldJars.add("commons-pool.jar"); - noTldJars.add("commons-digester.jar"); - noTldJars.add("commons-logging.jar"); - noTldJars.add("commons-collections.jar"); - noTldJars.add("commons-el.jar"); - noTldJars.add("jakarta-regexp-1.2.jar"); - noTldJars.add("jasper-compiler.jar"); - noTldJars.add("jasper-runtime.jar"); - noTldJars.add("jmx.jar"); - noTldJars.add("jmx-tools.jar"); - noTldJars.add("jsp-api.jar"); - noTldJars.add("jkshm.jar"); - noTldJars.add("jkconfig.jar"); - noTldJars.add("naming-common.jar"); - noTldJars.add("naming-resources.jar"); - noTldJars.add("naming-factory.jar"); - noTldJars.add("naming-java.jar"); - noTldJars.add("servlet-api.jar"); - noTldJars.add("servlets-default.jar"); - noTldJars.add("servlets-invoker.jar"); - noTldJars.add("servlets-common.jar"); - noTldJars.add("servlets-webdav.jar"); - noTldJars.add("tomcat-util.jar"); - noTldJars.add("tomcat-http11.jar"); - noTldJars.add("tomcat-jni.jar"); - noTldJars.add("tomcat-jk.jar"); - noTldJars.add("tomcat-jk2.jar"); - noTldJars.add("tomcat-coyote.jar"); - noTldJars.add("xercesImpl.jar"); - noTldJars.add("xmlParserAPIs.jar"); - noTldJars.add("xml-apis.jar"); - // JARs from J2SE runtime - noTldJars.add("sunjce_provider.jar"); - noTldJars.add("ldapsec.jar"); - noTldJars.add("localedata.jar"); - noTldJars.add("dnsns.jar"); - } - - public TldLocationsCache(ServletContext ctxt) { - this(ctxt, true); - } - - /** Constructor. - * - * @param ctxt the servlet context of the web application in which Jasper - * is running - * @param redeployMode if true, then the compiler will allow redeploying - * a tag library from the same jar, at the expense of slowing down the - * server a bit. Note that this may only work on JDK 1.3.1_01a and later, - * because of JDK bug 4211817 fixed in this release. - * If redeployMode is false, a faster but less capable mode will be used. - */ - public TldLocationsCache(ServletContext ctxt, boolean redeployMode) { - this.ctxt = ctxt; - this.redeployMode = redeployMode; - mappings = new Hashtable(); - initialized = false; - } - - /** - * Sets the list of JARs that are known not to contain any TLDs. - * - * @param jarNames List of comma-separated names of JAR files that are - * known not to contain any TLDs - */ - public static void setNoTldJars(String jarNames) { - if (jarNames != null) { - noTldJars.clear(); - StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); - while (tokenizer.hasMoreElements()) { - noTldJars.add(tokenizer.nextToken()); - } - } - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * Returns null if the uri is not associated with any tag library 'exposed' - * in the web application. A tag library is 'exposed' either explicitly in - * web.xml or implicitly via the uri tag in the TLD of a taglib deployed - * in a jar file (WEB-INF/lib). - * - * @param uri The taglib uri - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the uri is not associated with any tag library 'exposed' - * in the web application. - */ - public String[] getLocation(String uri) throws JasperException { - if (!initialized) { - init(); - } - return (String[]) mappings.get(uri); - } - - /** - * Returns the type of a URI: - * ABS_URI - * ROOT_REL_URI - * NOROOT_REL_URI - */ - public static int uriType(String uri) { - if (uri.indexOf(':') != -1) { - return ABS_URI; - } else if (uri.startsWith("/")) { - return ROOT_REL_URI; - } else { - return NOROOT_REL_URI; - } - } - - private void init() throws JasperException { - if (initialized) return; - try { - processWebDotXml(); - scanJars(); - processTldsInFileSystem("/WEB-INF/"); - initialized = true; - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage( - "jsp.error.internal.tldinit", ex.getMessage()), ex); - } - } - - /* - * Populates taglib map described in web.xml. - */ - private void processWebDotXml() throws Exception { - - InputStream is = null; - - try { - // Acquire input stream to web application deployment descriptor - String altDDName = (String)ctxt.getAttribute( - Constants.ALT_DD_ATTR); - URL uri = null; - if (altDDName != null) { - try { - uri = new URL(FILE_PROTOCOL+altDDName.replace('\\', '/')); - } catch (MalformedURLException e) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.error.internal.filenotfound", - altDDName)); - } - } - } else { - uri = ctxt.getResource(WEB_XML); - if (uri == null && log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.error.internal.filenotfound", - WEB_XML)); - } - } - - if (uri == null) { - return; - } - is = uri.openStream(); - InputSource ip = new InputSource(is); - ip.setSystemId(uri.toExternalForm()); - - // Parse the web application deployment descriptor - TreeNode webtld = null; - // altDDName is the absolute path of the DD - if (altDDName != null) { - webtld = new ParserUtils().parseXMLDocument(altDDName, ip); - } else { - webtld = new ParserUtils().parseXMLDocument(WEB_XML, ip); - } - - // Allow taglib to be an element of the root or jsp-config (JSP2.0) - TreeNode jspConfig = webtld.findChild("jsp-config"); - if (jspConfig != null) { - webtld = jspConfig; - } - Iterator taglibs = webtld.findChildren("taglib"); - while (taglibs.hasNext()) { - - // Parse the next element - TreeNode taglib = (TreeNode) taglibs.next(); - String tagUri = null; - String tagLoc = null; - TreeNode child = taglib.findChild("taglib-uri"); - if (child != null) - tagUri = child.getBody(); - child = taglib.findChild("taglib-location"); - if (child != null) - tagLoc = child.getBody(); - - // Save this location if appropriate - if (tagLoc == null) - continue; - if (uriType(tagLoc) == NOROOT_REL_URI) - tagLoc = "/WEB-INF/" + tagLoc; - String tagLoc2 = null; - if (tagLoc.endsWith(JAR_FILE_SUFFIX)) { - tagLoc = ctxt.getResource(tagLoc).toString(); - tagLoc2 = "META-INF/taglib.tld"; - } - mappings.put(tagUri, new String[] { tagLoc, tagLoc2 }); - } - } finally { - if (is != null) { - try { - is.close(); - } catch (Throwable t) {} - } - } - } - - /** - * Scans the given JarURLConnection for TLD files located in META-INF - * (or a subdirectory of it), adding an implicit map entry to the taglib - * map for any TLD that has a element. - * - * @param conn The JarURLConnection to the JAR file to scan - * @param ignore true if any exceptions raised when processing the given - * JAR should be ignored, false otherwise - */ - private void scanJar(JarURLConnection conn, boolean ignore) - throws JasperException { - - JarFile jarFile = null; - String resourcePath = conn.getJarFileURL().toString(); - try { - if (redeployMode) { - conn.setUseCaches(false); - } - jarFile = conn.getJarFile(); - Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = (JarEntry) entries.nextElement(); - String name = entry.getName(); - if (!name.startsWith("META-INF/")) continue; - if (!name.endsWith(".tld")) continue; - InputStream stream = jarFile.getInputStream(entry); - try { - String uri = getUriFromTld(resourcePath, stream); - // Add implicit map entry only if its uri is not already - // present in the map - if (uri != null && mappings.get(uri) == null) { - mappings.put(uri, new String[]{ resourcePath, name }); - } - } finally { - if (stream != null) { - try { - stream.close(); - } catch (Throwable t) { - // do nothing - } - } - } - } - } catch (Exception ex) { - if (!redeployMode) { - // if not in redeploy mode, close the jar in case of an error - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - // ignore - } - } - } - if (!ignore) { - throw new JasperException(ex); - } - } finally { - if (redeployMode) { - // if in redeploy mode, always close the jar - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - // ignore - } - } - } - } - } - - /* - * Searches the filesystem under /WEB-INF for any TLD files, and adds - * an implicit map entry to the taglib map for any TLD that has a - * element. - */ - private void processTldsInFileSystem(String startPath) - throws Exception { - - Set dirList = ctxt.getResourcePaths(startPath); - if (dirList != null) { - Iterator it = dirList.iterator(); - while (it.hasNext()) { - String path = (String) it.next(); - if (path.endsWith("/")) { - processTldsInFileSystem(path); - } - if (!path.endsWith(".tld")) { - continue; - } - InputStream stream = ctxt.getResourceAsStream(path); - String uri = null; - try { - uri = getUriFromTld(path, stream); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (Throwable t) { - // do nothing - } - } - } - // Add implicit map entry only if its uri is not already - // present in the map - if (uri != null && mappings.get(uri) == null) { - mappings.put(uri, new String[] { path, null }); - } - } - } - } - - /* - * Returns the value of the uri element of the given TLD, or null if the - * given TLD does not contain any such element. - */ - private String getUriFromTld(String resourcePath, InputStream in) - throws JasperException - { - // Parse the tag library descriptor at the specified resource path - TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in); - TreeNode uri = tld.findChild("uri"); - if (uri != null) { - String body = uri.getBody(); - if (body != null) - return body; - } - - return null; - } - - /* - * Scans all JARs accessible to the webapp's classloader and its - * parent classloaders for TLDs. - * - * The list of JARs always includes the JARs under WEB-INF/lib, as well as - * all shared JARs in the classloader delegation chain of the webapp's - * classloader. - * - * Considering JARs in the classloader delegation chain constitutes a - * Tomcat-specific extension to the TLD search - * order defined in the JSP spec. It allows tag libraries packaged as JAR - * files to be shared by web applications by simply dropping them in a - * location that all web applications have access to (e.g., - * /common/lib). - * - * The set of shared JARs to be scanned for TLDs is narrowed down by - * the noTldJars class variable, which contains the names of JARs - * that are known not to contain any TLDs. - */ - private void scanJars() throws Exception { - - ClassLoader webappLoader - = Thread.currentThread().getContextClassLoader(); - ClassLoader loader = webappLoader; - - while (loader != null) { - if (loader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) loader).getURLs(); - for (int i=0; ijarPath
needs to be - * scanned for TLDs. - * - * @param loader The current classloader in the parent chain - * @param webappLoader The webapp classloader - * @param jarPath The JAR file path - * - * @return TRUE if the JAR file identified by jarPath needs to be - * scanned for TLDs, FALSE otherwise - */ - private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader, - String jarPath) { - if (loader == webappLoader) { - // JARs under WEB-INF/lib must be scanned unconditionally according - // to the spec. - return true; - } else { - String jarName = jarPath; - int slash = jarPath.lastIndexOf('/'); - if (slash >= 0) { - jarName = jarPath.substring(slash + 1); - } - return (!noTldJars.contains(jarName)); - } - } -} diff --git a/1.x/src/jasper/bee-jasper.xml b/1.x/src/jasper/bee-jasper.xml deleted file mode 100644 index 5314734..0000000 --- a/1.x/src/jasper/bee-jasper.xml +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - - - - - - ]> - - - - &env; - - - - - /bin/javac - - - - - - - /bin/javadoc - - - - - - ******** &project; Build Process ******** -********* Available targets: ************************************* -* compile - do Java compilation * -* jar - build &build_file; file * -* run - run application &main_class; * -******************************************************************* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /&build_directory; - - - - - - - - - - - - - - - - - - Compiling javax... - - - - - - - - - - > - - - - 0 - - - Error(s) at compilation of javax - - - - - - - - - Exception at compilation of javax - - - - - - - - - - - - - - - - - - - - - - Compiling... &project; - - - - - - - - - - > - - - - 0 - - - Error(s) at compilation of &project; - - - - - - - - - Exception at compilation of &project; - - - - - - - - - - &manifestf; - - - - - true - - - - -d - - -sourcepath - - -classpath - - &domain; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &source_directory;/javax/servlet/jsp/resources/jsp*.dtd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/jsp*.xsd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/web-jsp*.dtd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/web-jsp*.xsd - &build_directory;/javax/servlet/jsp/resources - - &source_directory;/javax/servlet/resources/j2ee*.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/j2ee*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/javaee_*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/web-app*.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/web-*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/datatypes.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/xml.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/XMLSchema.dtd - &build_directory;/javax/servlet/resources - - - - - - - - - - - - - Jarring... - - - - - - - - - - - - - - - - - - - - - - - - - - -cf - - - - -cmf - - - - - - - - - - - - - - - java - org/apache/jasper/resources - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - Exception at jarring - - - - - - - - - - - - - y - - - - - - - - - Cleaning... - - - - - - - - - - - /&build_directory;/&build_file; - - - - - /lib/tools.jar - - - - - Running... - - - - -classpath - - - - - - diff --git a/1.x/src/jasper/env.xml b/1.x/src/jasper/env.xml deleted file mode 100644 index 270b948..0000000 --- a/1.x/src/jasper/env.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - . - - - - - - - / - - - - - - - - - /jre - - - - - - - - - - - maven:javax.servlet:javax.servlet-api:3.1.0 - - 1.6 - - - - \\jre - - - - - - - - - diff --git a/1.x/src/jasper6/JspC.java b/1.x/src/jasper6/JspC.java deleted file mode 100644 index 2f6d632..0000000 --- a/1.x/src/jasper6/JspC.java +++ /dev/null @@ -1,1597 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.servlet.JspCServletContext; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - - -/** - * Shell for the jspc compiler. Handles all options associated with the - * command line and creates compilation contexts which it then compiles - * according to the specified options. - * - * This version can process files from a _single_ webapp at once, i.e. - * a single docbase can be specified. - * - * It can be used as an Ant task using: - *
- *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
- *      <classpath>
- *          <pathelement location="${java.home}/../lib/tools.jar"/>
- *          <fileset dir="${ENV.CATALINA_HOME}/lib">
- *              <include name="*.jar"/>
- *          </fileset>
- *          <path refid="myjars"/>
- *       </classpath>
- *  </taskdef>
- *
- *  <jasper verbose="0"
- *           package="my.package"
- *           uriroot="${webapps.dir}/${webapp.name}"
- *           webXmlFragment="${build.dir}/generated_web.xml"
- *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
- * 
- * - * @author Danno Ferrin - * @author Pierre Delisle - * @author Costin Manolache - * @author Yoav Shapira - */ -public class JspC implements Options { - - public static final String DEFAULT_IE_CLASS_ID = - "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - // Logger - protected static Log log = LogFactory.getLog(JspC.class); - - protected static final String SWITCH_VERBOSE = "-v"; - protected static final String SWITCH_HELP = "-help"; - protected static final String SWITCH_OUTPUT_DIR = "-d"; - protected static final String SWITCH_PACKAGE_NAME = "-p"; - protected static final String SWITCH_CACHE = "-cache"; - protected static final String SWITCH_CLASS_NAME = "-c"; - protected static final String SWITCH_FULL_STOP = "--"; - protected static final String SWITCH_COMPILE = "-compile"; - protected static final String SWITCH_SOURCE = "-source"; - protected static final String SWITCH_TARGET = "-target"; - protected static final String SWITCH_URI_BASE = "-uribase"; - protected static final String SWITCH_URI_ROOT = "-uriroot"; - protected static final String SWITCH_FILE_WEBAPP = "-webapp"; - protected static final String SWITCH_WEBAPP_INC = "-webinc"; - protected static final String SWITCH_WEBAPP_XML = "-webxml"; - protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; - protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; - protected static final String SWITCH_MAPPED = "-mapped"; - protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; - protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; - protected static final String SWITCH_CLASSPATH = "-classpath"; - protected static final String SWITCH_DIE = "-die"; - protected static final String SWITCH_POOLING = "-poolingEnabled"; - protected static final String SWITCH_ENCODING = "-javaEncoding"; - protected static final String SWITCH_SMAP = "-smap"; - protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; - - protected static final String SHOW_SUCCESS ="-s"; - protected static final String LIST_ERRORS = "-l"; - protected static final int INC_WEBXML = 10; - protected static final int ALL_WEBXML = 20; - protected static final int DEFAULT_DIE_LEVEL = 1; - protected static final int NO_DIE_LEVEL = 0; - - protected static final String[] insertBefore = - { "", "", "", - "", "", "", "", - "", "", "", - "", "", "", "", - "" }; - - protected static int die; - protected String classPath = null; - protected URLClassLoader loader = null; - protected boolean trimSpaces = false; - protected boolean genStringAsCharArray = false; - protected boolean xpoweredBy; - protected boolean mappedFile = false; - protected boolean poolingEnabled = true; - protected File scratchDir; - protected String ieClassId = DEFAULT_IE_CLASS_ID; - protected String targetPackage; - protected String targetClassName; - protected String uriBase; - protected String uriRoot; - protected int dieLevel; - protected boolean helpNeeded = false; - protected boolean compile = false; - protected boolean smapSuppressed = true; - protected boolean smapDumped = false; - protected boolean caching = true; - protected Map cache = new HashMap(); - - protected String compiler = null; - - protected String compilerTargetVM = "1.5"; - protected String compilerSourceVM = "1.5"; - - protected boolean classDebugInfo = true; - - /** - * Throw an exception if there's a compilation error, or swallow it. - * Default is true to preserve old behavior. - */ - protected boolean failOnError = true; - - /** - * The file extensions to be handled as JSP files. - * Default list is .jsp and .jspx. - */ - protected List extensions; - - /** - * The pages. - */ - protected List pages = new Vector(); - - /** - * Needs better documentation, this data member does. - * True by default. - */ - protected boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * The java file encoding. Default - * is UTF-8. Added per bugzilla 19622. - */ - protected String javaEncoding = "UTF-8"; - - // Generation of web.xml fragments - protected String webxmlFile; - protected int webxmlLevel; - protected String webxmlEncoding; - protected boolean addWebXmlMappings = false; - - protected Writer mapout; - protected CharArrayWriter servletout; - protected CharArrayWriter mappingout; - - /** - * The servlet context. - */ - protected JspCServletContext context; - - /** - * The runtime context. - * Maintain a dummy JspRuntimeContext for compiling tag files. - */ - protected JspRuntimeContext rctxt; - - /** - * Cache for the TLD locations - */ - protected TldLocationsCache tldLocationsCache = null; - - protected JspConfig jspConfig = null; - protected TagPluginManager tagPluginManager = null; - - protected boolean verbose = false; - protected boolean listErrors = false; - protected boolean showSuccess = false; - protected int argPos; - protected boolean fullstop = false; - protected String args[]; - - public static void main(String arg[]) { - if (arg.length == 0) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - try { - JspC jspc = new JspC(); - jspc.setArgs(arg); - if (jspc.helpNeeded) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - jspc.execute(); - } - } catch (JasperException je) { - System.err.println(je); - if (die != NO_DIE_LEVEL) { - System.exit(die); - } - } - } - } - - /** - * Apply command-line arguments. - * - * @param arg - * The arguments - */ - public void setArgs(String[] arg) throws JasperException { - args = arg; - String tok; - - dieLevel = NO_DIE_LEVEL; - die = dieLevel; - - while ((tok = nextArg()) != null) { - if (tok.equals(SWITCH_VERBOSE)) { - verbose = true; - showSuccess = true; - listErrors = true; - } else if (tok.equals(SWITCH_OUTPUT_DIR)) { - tok = nextArg(); - setOutputDir( tok ); - } else if (tok.equals(SWITCH_PACKAGE_NAME)) { - targetPackage = nextArg(); - } else if (tok.equals(SWITCH_COMPILE)) { - compile=true; - } else if (tok.equals(SWITCH_CLASS_NAME)) { - targetClassName = nextArg(); - } else if (tok.equals(SWITCH_URI_BASE)) { - uriBase=nextArg(); - } else if (tok.equals(SWITCH_URI_ROOT)) { - setUriroot( nextArg()); - } else if (tok.equals(SWITCH_FILE_WEBAPP)) { - setUriroot( nextArg()); - } else if ( tok.equals( SHOW_SUCCESS ) ) { - showSuccess = true; - } else if ( tok.equals( LIST_ERRORS ) ) { - listErrors = true; - } else if (tok.equals(SWITCH_WEBAPP_INC)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = INC_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = ALL_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { - setWebXmlEncoding(nextArg()); - } else if (tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { - setAddWebXmlMappings(true); - } else if (tok.equals(SWITCH_MAPPED)) { - mappedFile = true; - } else if (tok.equals(SWITCH_XPOWERED_BY)) { - xpoweredBy = true; - } else if (tok.equals(SWITCH_TRIM_SPACES)) { - setTrimSpaces(true); - } else if (tok.equals(SWITCH_CACHE)) { - tok = nextArg(); - if ("false".equals(tok)) { - caching = false; - } else { - caching = true; - } - } else if (tok.equals(SWITCH_CLASSPATH)) { - setClassPath(nextArg()); - } else if (tok.startsWith(SWITCH_DIE)) { - try { - dieLevel = Integer.parseInt( - tok.substring(SWITCH_DIE.length())); - } catch (NumberFormatException nfe) { - dieLevel = DEFAULT_DIE_LEVEL; - } - die = dieLevel; - } else if (tok.equals(SWITCH_HELP)) { - helpNeeded = true; - } else if (tok.equals(SWITCH_POOLING)) { - tok = nextArg(); - if ("false".equals(tok)) { - poolingEnabled = false; - } else { - poolingEnabled = true; - } - } else if (tok.equals(SWITCH_ENCODING)) { - setJavaEncoding(nextArg()); - } else if (tok.equals(SWITCH_SOURCE)) { - setCompilerSourceVM(nextArg()); - } else if (tok.equals(SWITCH_TARGET)) { - setCompilerTargetVM(nextArg()); - } else if (tok.equals(SWITCH_SMAP)) { - smapSuppressed = false; - } else if (tok.equals(SWITCH_DUMP_SMAP)) { - smapDumped = true; - } else { - if (tok.startsWith("-")) { - throw new JasperException("Unrecognized option: " + tok + - ". Use -help for help."); - } - if (!fullstop) { - argPos--; - } - // Start treating the rest as JSP Pages - break; - } - } - - // Add all extra arguments to the list of files - while( true ) { - String file = nextFile(); - if( file==null ) { - break; - } - pages.add( file ); - } - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - public boolean getKeepGenerated() { - // isn't this why we are running jspc? - return true; - } - - /** - * {@inheritDoc} - */ - public boolean getTrimSpaces() { - return trimSpaces; - } - - /** - * Sets the option to trim white spaces between directives or actions. - */ - public void setTrimSpaces(boolean ts) { - this.trimSpaces = ts; - } - - /** - * {@inheritDoc} - */ - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - /** - * Sets the option to enable the tag handler pooling. - */ - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - /** - * {@inheritDoc} - */ - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Sets the option to enable generation of X-Powered-By response header. - */ - public void setXpoweredBy(boolean xpoweredBy) { - this.xpoweredBy = xpoweredBy; - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - public boolean getDisplaySourceFragment() { - return true; - } - - /** - * {@inheritDoc} - */ - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - /** - * Sets the option to issue a compilation error if the class attribute - * specified in useBean action is invalid. - */ - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - /** - * @deprecated Removed in Tomcat 7 - */ - @Deprecated - public int getTagPoolSize() { - return Constants.MAX_POOL_SIZE; - } - - /** - * {@inheritDoc} - */ - public boolean getMappedFile() { - return mappedFile; - } - - /** - * @deprecated Removed in Tomcat 7 - */ - @Deprecated - public Object getProtectionDomain() { - // Off-line compiler, no need for security manager - return null; - } - - /** - * @deprecated - */ - @Deprecated - public boolean getSendErrorToClient() { - return true; - } - - /** - * Sets the option to include debug information in compiled class. - */ - public void setClassDebugInfo( boolean b ) { - classDebugInfo=b; - } - - /** - * {@inheritDoc} - */ - public boolean getClassDebugInfo() { - // compile with debug info - return classDebugInfo; - } - - /** - * {@inheritDoc} - */ - public boolean isCaching() { - return caching; - } - - /** - * Sets the option to enable caching. - * - * @see Options#isCaching() - */ - public void setCaching(boolean caching) { - this.caching = caching; - } - - /** - * {@inheritDoc} - */ - public Map getCache() { - return cache; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - public int getCheckInterval() { - return 0; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - public int getModificationTestInterval() { - return 0; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - public boolean getRecompileOnFail() { - return false; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - public boolean getDevelopment() { - return false; - } - - /** - * {@inheritDoc} - */ - public boolean isSmapSuppressed() { - return smapSuppressed; - } - - /** - * Sets smapSuppressed flag. - */ - public void setSmapSuppressed(boolean smapSuppressed) { - this.smapSuppressed = smapSuppressed; - } - - /** - * {@inheritDoc} - */ - public boolean isSmapDumped() { - return smapDumped; - } - - /** - * Sets smapDumped flag. - * - * @see Options#isSmapDumped() - */ - public void setSmapDumped(boolean smapDumped) { - this.smapDumped = smapDumped; - } - - - /** - * Determines whether text strings are to be generated as char arrays, - * which improves performance in some cases. - * - * @param genStringAsCharArray true if text strings are to be generated as - * char arrays, false otherwise - */ - public void setGenStringAsCharArray(boolean genStringAsCharArray) { - this.genStringAsCharArray = genStringAsCharArray; - } - - /** - * {@inheritDoc} - */ - public boolean genStringAsCharArray() { - return genStringAsCharArray; - } - - /** - * Sets the class-id value to be sent to Internet Explorer when using - * <jsp:plugin> tags. - * - * @param ieClassId - * Class-id value - */ - public void setIeClassId(String ieClassId) { - this.ieClassId = ieClassId; - } - - /** - * {@inheritDoc} - */ - public String getIeClassId() { - return ieClassId; - } - - /** - * {@inheritDoc} - */ - public File getScratchDir() { - return scratchDir; - } - - /** - * @deprecated Removed in Tomcat 7 - */ - @Deprecated - public Class getJspCompilerPlugin() { - // we don't compile, so this is meanlingless - return null; - } - - /** - * @deprecated Removed in Tomcat 7 - */ - @Deprecated - public String getJspCompilerPath() { - // we don't compile, so this is meanlingless - return null; - } - - /** - * {@inheritDoc} - */ - public String getCompiler() { - return compiler; - } - - /** - * Sets the option to determine what compiler to use. - * - * @see Options#getCompiler() - */ - public void setCompiler(String c) { - compiler=c; - } - - /** - * {@inheritDoc} - */ - public String getCompilerClassName() { - return null; - } - - /** - * {@inheritDoc} - */ - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * Sets the compiler target VM. - * - * @see Options#getCompilerTargetVM() - */ - public void setCompilerTargetVM(String vm) { - compilerTargetVM = vm; - } - - /** - * {@inheritDoc} - */ - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * Sets the compiler source VM. - * - * @see Options#getCompilerSourceVM() - */ - public void setCompilerSourceVM(String vm) { - compilerSourceVM = vm; - } - - /** - * {@inheritDoc} - */ - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - /** - * Returns the encoding to use for - * java files. The default is UTF-8. - * - * @return String The encoding - */ - public String getJavaEncoding() { - return javaEncoding; - } - - /** - * Sets the encoding to use for - * java files. - * - * @param encodingName The name, e.g. "UTF-8" - */ - public void setJavaEncoding(String encodingName) { - javaEncoding = encodingName; - } - - /** - * {@inheritDoc} - */ - public boolean getFork() { - return false; - } - - /** - * {@inheritDoc} - */ - public String getClassPath() { - if( classPath != null ) - return classPath; - return System.getProperty("java.class.path"); - } - - /** - * Sets the classpath used while compiling the servlets generated from JSP - * files - */ - public void setClassPath(String s) { - classPath=s; - } - - /** - * Returns the list of file extensions - * that are treated as JSP files. - * - * @return The list of extensions - */ - public List getExtensions() { - return extensions; - } - - /** - * Adds the given file extension to the - * list of extensions handled as JSP files. - * - * @param extension The extension to add, e.g. "myjsp" - */ - protected void addExtension(final String extension) { - if(extension != null) { - if(extensions == null) { - extensions = new Vector(); - } - - extensions.add(extension); - } - } - - /** - * Base dir for the webapp. Used to generate class names and resolve - * includes. - */ - public void setUriroot( String s ) { - if( s==null ) { - uriRoot = s; - return; - } - try { - uriRoot = resolveFile(s).getCanonicalPath(); - } catch( Exception ex ) { - uriRoot = s; - } - } - - /** - * Parses comma-separated list of JSP files to be processed. If the argument - * is null, nothing is done. - * - *

Each file is interpreted relative to uriroot, unless it is absolute, - * in which case it must start with uriroot.

- * - * @param jspFiles Comma-separated list of JSP files to be processed - */ - public void setJspFiles(final String jspFiles) { - if(jspFiles == null) { - return; - } - - StringTokenizer tok = new StringTokenizer(jspFiles, ","); - while (tok.hasMoreTokens()) { - pages.add(tok.nextToken()); - } - } - - /** - * Sets the compile flag. - * - * @param b Flag value - */ - public void setCompile( final boolean b ) { - compile = b; - } - - /** - * Sets the verbosity level. The actual number doesn't - * matter: if it's greater than zero, the verbose flag will - * be true. - * - * @param level Positive means verbose - */ - public void setVerbose( final int level ) { - if (level > 0) { - verbose = true; - showSuccess = true; - listErrors = true; - } - } - - public void setValidateXml( boolean b ) { - org.apache.jasper.xmlparser.ParserUtils.validating=b; - } - - public void setListErrors( boolean b ) { - listErrors = b; - } - - public void setOutputDir( String s ) { - if( s!= null ) { - scratchDir = resolveFile(s).getAbsoluteFile(); - } else { - scratchDir=null; - } - } - - /** - * Sets the package name to be used for the generated servlet classes. - */ - public void setPackage( String p ) { - targetPackage=p; - } - - /** - * Class name of the generated file ( without package ). - * Can only be used if a single file is converted. - * XXX Do we need this feature ? - */ - public void setClassName( String p ) { - targetClassName=p; - } - - /** - * File where we generate a web.xml fragment with the class definitions. - */ - public void setWebXmlFragment( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=INC_WEBXML; - } - - /** - * File where we generate a complete web.xml with the class definitions. - */ - public void setWebXml( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=ALL_WEBXML; - } - - /** - * Sets the encoding to be used to read and write web.xml files. - * - *

- * If not specified, defaults to the platform default encoding. - *

- * - * @param encoding - * Encoding, e.g. "UTF-8". - */ - public void setWebXmlEncoding(String encoding) { - webxmlEncoding = encoding; - } - - /** - * Sets the option to merge generated web.xml fragment into the - * WEB-INF/web.xml file of the web application that we were processing. - * - * @param b - * true to merge the fragment into the existing - * web.xml file of the processed web application - * ({uriroot}/WEB-INF/web.xml), false to keep the - * generated web.xml fragment - */ - public void setAddWebXmlMappings(boolean b) { - addWebXmlMappings = b; - } - - /** - * Sets the option that throws an exception in case of a compilation error. - */ - public void setFailOnError(final boolean b) { - failOnError = b; - } - - /** - * Returns true if an exception will be thrown in case of a compilation - * error. - */ - public boolean getFailOnError() { - return failOnError; - } - - /** - * {@inheritDoc} - */ - public JspConfig getJspConfig() { - return jspConfig; - } - - /** - * {@inheritDoc} - */ - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - /** - * Adds servlet declaration and mapping for the JSP page servlet to the - * generated web.xml fragment. - * - * @param file - * Context-relative path to the JSP file, e.g. - * /index.jsp - * @param clctxt - * Compilation context of the servlet - */ - public void generateWebMapping( String file, JspCompilationContext clctxt ) - throws IOException - { - if (log.isDebugEnabled()) { - log.debug("Generating web mapping for file " + file - + " using compilation context " + clctxt); - } - - String className = clctxt.getServletClassName(); - String packageName = clctxt.getServletPackageName(); - - String thisServletName; - if ("".equals(packageName)) { - thisServletName = className; - } else { - thisServletName = packageName + '.' + className; - } - - if (servletout != null) { - servletout.write("\n \n "); - servletout.write(thisServletName); - servletout.write("\n "); - servletout.write(thisServletName); - servletout.write("\n \n"); - } - if (mappingout != null) { - mappingout.write("\n \n "); - mappingout.write(thisServletName); - mappingout.write("\n "); - mappingout.write(file.replace('\\', '/')); - mappingout.write("\n \n"); - - } - } - - /** - * Include the generated web.xml inside the webapp's web.xml. - */ - protected void mergeIntoWebXml() throws IOException { - - File webappBase = new File(uriRoot); - File webXml = new File(webappBase, "WEB-INF/web.xml"); - File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); - String insertStartMarker = - Localizer.getMessage("jspc.webinc.insertStart"); - String insertEndMarker = - Localizer.getMessage("jspc.webinc.insertEnd"); - - BufferedReader reader = new BufferedReader(openWebxmlReader(webXml)); - BufferedReader fragmentReader = new BufferedReader( - openWebxmlReader(new File(webxmlFile))); - PrintWriter writer = new PrintWriter(openWebxmlWriter(webXml2)); - - // Insert the and declarations - boolean inserted = false; - int current = reader.read(); - while (current > -1) { - if (current == '<') { - String element = getElement(reader); - boolean found = false; - if (!inserted) { - for (String before : insertBefore) { - if (element.equals(before)) { - found = true; - break; - } - } - } - if (found) { - // Insert generated content here - writer.println(insertStartMarker); - while (true) { - String line = fragmentReader.readLine(); - if (line == null) { - writer.println(); - break; - } - writer.println(line); - } - writer.println(insertEndMarker); - writer.println(); - writer.write(element); - inserted = true; - } else if (element.equals(insertStartMarker)) { - // Skip the previous auto-generated content - while (true) { - current = reader.read(); - if (current < 0) { - throw new EOFException(); - } - if (current == '<') { - element = getElement(reader); - if (element.equals(insertEndMarker)) { - break; - } - } - } - current = reader.read(); - while (current == '\n' || current == '\r') { - current = reader.read(); - } - continue; - } else { - writer.write(element); - } - } else { - writer.write(current); - } - current = reader.read(); - } - writer.close(); - - reader.close(); - fragmentReader.close(); - - FileInputStream fis = new FileInputStream(webXml2); - FileOutputStream fos = new FileOutputStream(webXml); - - byte buf[] = new byte[512]; - while (true) { - int n = fis.read(buf); - if (n < 0) { - break; - } - fos.write(buf, 0, n); - } - - fis.close(); - fos.close(); - - webXml2.delete(); - (new File(webxmlFile)).delete(); - - } - - - /* - * Assumes valid xml - */ - private String getElement(Reader reader) throws IOException { - StringBuilder result = new StringBuilder(); - result.append('<'); - - boolean done = false; - - while (!done) { - int current = reader.read(); - while (current != '>') { - if (current < 0) { - throw new EOFException(); - } - result.append((char) current); - current = reader.read(); - } - result.append((char) current); - - int len = result.length(); - if (len > 4 && result.substring(0, 4).equals("")) { - done = true; - } - } else { - done = true; - } - } - - - return result.toString(); - } - - - protected void processFile(String file) - throws JasperException - { - if (log.isDebugEnabled()) { - log.debug("Processing file: " + file); - } - - ClassLoader originalClassLoader = null; - - try { - // set up a scratch/output dir if none is provided - if (scratchDir == null) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = ""; - } - scratchDir = new File(new File(temp).getAbsolutePath()); - } - - String jspUri=file.replace('\\','/'); - JspCompilationContext clctxt = new JspCompilationContext - ( jspUri, false, this, context, null, rctxt ); - - /* Override the defaults */ - if ((targetClassName != null) && (targetClassName.length() > 0)) { - clctxt.setServletClassName(targetClassName); - targetClassName = null; - } - if (targetPackage != null) { - clctxt.setServletPackageName(targetPackage); - } - - originalClassLoader = Thread.currentThread().getContextClassLoader(); - if( loader==null ) { - initClassLoader( clctxt ); - } - Thread.currentThread().setContextClassLoader(loader); - - clctxt.setClassLoader(loader); - clctxt.setClassPath(classPath); - - Compiler clc = clctxt.createCompiler(); - - // If compile is set, generate both .java and .class, if - // .jsp file is newer than .class file; - // Otherwise only generate .java, if .jsp file is newer than - // the .java file - if( clc.isOutDated(compile) ) { - if (log.isDebugEnabled()) { - log.debug(jspUri + " is out dated, compiling..."); - } - - clc.compile(compile, true); - } - - // Generate mapping - generateWebMapping( file, clctxt ); - if ( showSuccess ) { - log.info( "Built File: " + file ); - } - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - log.error(Localizer.getMessage("jspc.error.generalException", - file), - rootCause); - } - - // Bugzilla 35114. - if(getFailOnError()) { - throw je; - } else { - log.error(je.getMessage()); - } - - } catch (Exception e) { - if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", - e.getMessage())); - } - throw new JasperException(e); - } finally { - if(originalClassLoader != null) { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - - /** - * Locate all jsp files in the webapp. Used if no explicit - * jsps are specified. - */ - public void scanFiles( File base ) throws JasperException { - Stack dirs = new Stack(); - dirs.push(base.toString()); - - // Make sure default extensions are always included - if ((getExtensions() == null) || (getExtensions().size() < 2)) { - addExtension("jsp"); - addExtension("jspx"); - } - - while (!dirs.isEmpty()) { - String s = dirs.pop(); - File f = new File(s); - if (f.exists() && f.isDirectory()) { - String[] files = f.list(); - String ext; - for (int i = 0; (files != null) && i < files.length; i++) { - File f2 = new File(s, files[i]); - if (f2.isDirectory()) { - dirs.push(f2.getPath()); - } else { - String path = f2.getPath(); - String uri = path.substring(uriRoot.length()); - ext = files[i].substring(files[i].lastIndexOf('.') +1); - if (getExtensions().contains(ext) || - jspConfig.isJspPage(uri)) { - pages.add(path); - } - } - } - } - } - } - - /** - * Executes the compilation. - * - * @throws JasperException If an error occurs - */ - public void execute() throws JasperException { - if(log.isDebugEnabled()) { - log.debug("execute() starting for " + pages.size() + " pages."); - } - - try { - if (uriRoot == null) { - if( pages.size() == 0 ) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.missingTarget")); - } - String firstJsp = (String) pages.get( 0 ); - File firstJspF = new File( firstJsp ); - if (!firstJspF.exists()) { - throw new JasperException( - Localizer.getMessage("jspc.error.fileDoesNotExist", - firstJsp)); - } - locateUriRoot( firstJspF ); - } - - if (uriRoot == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.no_uriroot")); - } - - if( context==null ) { - initServletContext(); - } - - // No explicit pages, we'll process all .jsp in the webapp - if (pages.size() == 0) { - scanFiles( new File( uriRoot )); - } - - File uriRootF = new File(uriRoot); - if (!uriRootF.exists() || !uriRootF.isDirectory()) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); - } - - initWebXml(); - - Iterator iter = pages.iterator(); - while (iter.hasNext()) { - String nextjsp = iter.next().toString(); - File fjsp = new File(nextjsp); - if (!fjsp.isAbsolute()) { - fjsp = new File(uriRootF, nextjsp); - } - if (!fjsp.exists()) { - if (log.isWarnEnabled()) { - log.warn - (Localizer.getMessage - ("jspc.error.fileDoesNotExist", fjsp.toString())); - } - continue; - } - String s = fjsp.getAbsolutePath(); - if (s.startsWith(uriRoot)) { - nextjsp = s.substring(uriRoot.length()); - } - if (nextjsp.startsWith("." + File.separatorChar)) { - nextjsp = nextjsp.substring(2); - } - processFile(nextjsp); - } - - completeWebXml(); - - if (addWebXmlMappings) { - mergeIntoWebXml(); - } - - } catch (IOException ioe) { - throw new JasperException(ioe); - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - rootCause.printStackTrace(); - } - throw je; - } finally { - if (loader != null) { - LogFactory.release(loader); - } - } - } - - // ==================== protected utility methods ==================== - - protected String nextArg() { - if ((argPos >= args.length) - || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { - return null; - } else { - return args[argPos++]; - } - } - - protected String nextFile() { - if (fullstop) argPos++; - if (argPos >= args.length) { - return null; - } else { - return args[argPos++]; - } - } - - protected void initWebXml() { - try { - if (webxmlLevel >= INC_WEBXML) { - mapout = openWebxmlWriter(new File(webxmlFile)); - servletout = new CharArrayWriter(); - mappingout = new CharArrayWriter(); - } else { - mapout = null; - servletout = null; - mappingout = null; - } - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.header")); - mapout.flush(); - } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.header")); - mapout.flush(); - } - } catch (IOException ioe) { - mapout = null; - servletout = null; - mappingout = null; - } - } - - protected void completeWebXml() { - if (mapout != null) { - try { - servletout.writeTo(mapout); - mappingout.writeTo(mapout); - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.footer")); - } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.footer")); - } - mapout.close(); - } catch (IOException ioe) { - // noting to do if it fails since we are done with it - } - } - } - - protected void initServletContext() { - try { - context =new JspCServletContext - (new PrintWriter(System.out), - new URL("file:" + uriRoot.replace('\\','/') + '/')); - tldLocationsCache = new TldLocationsCache(context, true); - } catch (MalformedURLException me) { - System.out.println("**" + me); - } - rctxt = new JspRuntimeContext(context, this); - jspConfig = new JspConfig(context); - tagPluginManager = new TagPluginManager(context); - } - - /** - * Initializes the classloader as/if needed for the given - * compilation context. - * - * @param clctxt The compilation context - * @throws IOException If an error occurs - */ - protected void initClassLoader(JspCompilationContext clctxt) - throws IOException { - - classPath = getClassPath(); - - ClassLoader jspcLoader = getClass().getClassLoader(); - - // TODO add 7Bee class loader - - // Turn the classPath into URLs - ArrayList urls = new ArrayList(); - StringTokenizer tokenizer = new StringTokenizer(classPath, - File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - String path = tokenizer.nextToken(); - try { - File libFile = new File(path); - urls.add(libFile.toURL()); - } catch (IOException ioe) { - // Failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak uot - throw new RuntimeException(ioe.toString()); - } - } - - File webappBase = new File(uriRoot); - if (webappBase.exists()) { - File classes = new File(webappBase, "/WEB-INF/classes"); - try { - if (classes.exists()) { - classPath = classPath + File.pathSeparator - + classes.getCanonicalPath(); - urls.add(classes.getCanonicalFile().toURL()); - } - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - File lib = new File(webappBase, "/WEB-INF/lib"); - if (lib.exists() && lib.isDirectory()) { - String[] libs = lib.list(); - for (int i = 0; i < libs.length; i++) { - if( libs[i].length() <5 ) continue; - String ext=libs[i].substring( libs[i].length() - 4 ); - if (! ".jar".equalsIgnoreCase(ext)) { - if (".tld".equalsIgnoreCase(ext)) { - log.warn("TLD files should not be placed in " - + "/WEB-INF/lib"); - } - continue; - } - try { - File libFile = new File(lib, libs[i]); - classPath = classPath + File.pathSeparator - + libFile.getAbsolutePath(); - urls.add(libFile.getAbsoluteFile().toURL()); - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - } - } - } - - // What is this ?? - urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL()); - - URL urlsA[]=new URL[urls.size()]; - urls.toArray(urlsA); - loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); - - } - - /** - * Find the WEB-INF dir by looking up in the directory tree. - * This is used if no explicit docbase is set, but only files. - * XXX Maybe we should require the docbase. - */ - protected void locateUriRoot( File f ) { - String tUriBase = uriBase; - if (tUriBase == null) { - tUriBase = "/"; - } - try { - if (f.exists()) { - f = new File(f.getAbsolutePath()); - while (f != null) { - File g = new File(f, "WEB-INF"); - if (g.exists() && g.isDirectory()) { - uriRoot = f.getCanonicalPath(); - uriBase = tUriBase; - if (log.isInfoEnabled()) { - log.info(Localizer.getMessage( - "jspc.implicit.uriRoot", - uriRoot)); - } - break; - } - if (f.exists() && f.isDirectory()) { - tUriBase = "/" + f.getName() + "/" + tUriBase; - } - - String fParent = f.getParent(); - if (fParent == null) { - break; - } else { - f = new File(fParent); - } - - // If there is no acceptible candidate, uriRoot will - // remain null to indicate to the CompilerContext to - // use the current working/user dir. - } - - if (uriRoot != null) { - File froot = new File(uriRoot); - uriRoot = froot.getCanonicalPath(); - } - } - } catch (IOException ioe) { - // since this is an optional default and a null value - // for uriRoot has a non-error meaning, we can just - // pass straight through - } - } - - /** - * Resolves the relative or absolute pathname correctly - * in both Ant and command-line situations. If Ant launched - * us, we should use the basedir of the current project - * to resolve relative paths. - * - * See Bugzilla 35571. - * - * @param s The file - * @return The file resolved - */ - protected File resolveFile(final String s) { - return new File(s); - } - - private Reader openWebxmlReader(File file) throws IOException { - FileInputStream fis = new FileInputStream(file); - try { - return webxmlEncoding != null ? new InputStreamReader(fis, - webxmlEncoding) : new InputStreamReader(fis); - } catch (IOException ex) { - fis.close(); - throw ex; - } - } - - private Writer openWebxmlWriter(File file) throws IOException { - FileOutputStream fos = new FileOutputStream(file); - try { - return webxmlEncoding != null ? new OutputStreamWriter(fos, - webxmlEncoding) : new OutputStreamWriter(fos); - } catch (IOException ex) { - fos.close(); - throw ex; - } - } -} diff --git a/1.x/src/jasper6/JspCompilationContext.java b/1.x/src/jasper6/JspCompilationContext.java deleted file mode 100644 index 1d78239..0000000 --- a/1.x/src/jasper6/JspCompilationContext.java +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.JspUtil; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.ServletWriter; -import org.apache.jasper.servlet.JasperLoader; -import org.apache.jasper.servlet.JspServletWrapper; - -/** - * A place holder for various things that are used through out the JSP - * engine. This is a per-request/per-context data structure. Some of - * the instance variables are set at different points. - * - * Most of the path-related stuff is here - mangling names, versions, dirs, - * loading resources and dealing with uris. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Pierre Delisle - * @author Costin Manolache - * @author Kin-man Chung - */ -public class JspCompilationContext { - - protected org.apache.juli.logging.Log log = - org.apache.juli.logging.LogFactory.getLog(JspCompilationContext.class); - - protected Map tagFileJarUrls; - protected boolean isPackagedTagFile; - - protected String className; - protected String jspUri; - protected boolean isErrPage; - protected String basePackageName; - protected String derivedPackageName; - protected String servletJavaFileName; - protected String javaPath; - protected String classFileName; - protected String contentType; - protected ServletWriter writer; - protected Options options; - protected JspServletWrapper jsw; - protected Compiler jspCompiler; - protected String classPath; - - protected String baseURI; - protected String outputDir; - protected ServletContext context; - protected URLClassLoader loader; - - protected JspRuntimeContext rctxt; - - protected int removed = 0; - - protected URLClassLoader jspLoader; - protected URL baseUrl; - protected Class servletClass; - - protected boolean isTagFile; - protected boolean protoTypeMode; - protected TagInfo tagInfo; - protected URL tagFileJarUrl; - - // jspURI _must_ be relative to the context - public JspCompilationContext(String jspUri, - boolean isErrPage, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt) { - - this.jspUri = canonicalURI(jspUri); - this.isErrPage = isErrPage; - this.options = options; - this.jsw = jsw; - this.context = context; - - this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); - // hack fix for resolveRelativeURI - if (baseURI == null) { - baseURI = "/"; - } else if (baseURI.charAt(0) != '/') { - // strip the basde slash since it will be combined with the - // uriBase to generate a file - baseURI = "/" + baseURI; - } - if (baseURI.charAt(baseURI.length() - 1) != '/') { - baseURI += '/'; - } - - this.rctxt = rctxt; - this.tagFileJarUrls = new HashMap(); - this.basePackageName = Constants.JSP_PACKAGE_NAME; - } - - public JspCompilationContext(String tagfile, - TagInfo tagInfo, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt, - URL tagFileJarUrl) { - this(tagfile, false, options, context, jsw, rctxt); - this.isTagFile = true; - this.tagInfo = tagInfo; - this.tagFileJarUrl = tagFileJarUrl; - if (tagFileJarUrl != null) { - isPackagedTagFile = true; - } - } - - /* ==================== Methods to override ==================== */ - - /** ---------- Class path and loader ---------- */ - - /** - * The classpath that is passed off to the Java compiler. - */ - public String getClassPath() { - if( classPath != null ) - return classPath; - return rctxt.getClassPath(); - } - - /** - * The classpath that is passed off to the Java compiler. - */ - public void setClassPath(String classPath) { - this.classPath = classPath; - } - - /** - * What class loader to use for loading classes while compiling - * this JSP? - */ - public ClassLoader getClassLoader() { - if( loader != null ) - return loader; - return rctxt.getParentClassLoader(); - } - - public void setClassLoader(URLClassLoader loader) { - this.loader = loader; - } - - public ClassLoader getJspLoader() { - if( jspLoader == null ) { - jspLoader = new JasperLoader - (new URL[] {baseUrl}, - getClassLoader(), - rctxt.getPermissionCollection(), - rctxt.getCodeSource()); - } - return jspLoader; - } - - /** ---------- Input/Output ---------- */ - - /** - * The output directory to generate code into. The output directory - * is make up of the scratch directory, which is provide in Options, - * plus the directory derived from the package name. - */ - public String getOutputDir() { - if (outputDir == null) { - createOutputDir(); - } - - return outputDir; - } - - /** - * Create a "Compiler" object based on some init param data. This - * is not done yet. Right now we're just hardcoding the actual - * compilers that are created. - */ - public Compiler createCompiler() throws JasperException { - if (jspCompiler != null ) { - return jspCompiler; - } - jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); - if (jspCompiler == null) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); - } - jspCompiler.init(this, jsw); - return jspCompiler; - } - - protected Compiler createCompiler(String className) { - Compiler compiler = null; - try { - compiler = (Compiler) Class.forName(className).newInstance(); - } catch (InstantiationException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (IllegalAccessException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (NoClassDefFoundError e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } catch (ClassNotFoundException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } - return compiler; - } - - public Compiler getCompiler() { - return jspCompiler; - } - - /** ---------- Access resources in the webapp ---------- */ - - /** - * Get the full value of a URI relative to this compilations context - * uses current file as the base. - */ - public String resolveRelativeUri(String uri) { - // sometimes we get uri's massaged from File(String), so check for - // a root directory deperator char - if (uri.startsWith("/") || uri.startsWith(File.separator)) { - return uri; - } else { - return baseURI + uri; - } - } - - /** - * Gets a resource as a stream, relative to the meanings of this - * context's implementation. - * @return a null if the resource cannot be found or represented - * as an InputStream. - */ - public java.io.InputStream getResourceAsStream(String res) { - return context.getResourceAsStream(canonicalURI(res)); - } - - - public URL getResource(String res) throws MalformedURLException { - return context.getResource(canonicalURI(res)); - } - - public Set getResourcePaths(String path) { - return context.getResourcePaths(canonicalURI(path)); - } - - /** - * Gets the actual path of a URI relative to the context of - * the compilation. - */ - public String getRealPath(String path) { - if (context != null) { - return context.getRealPath(path); - } - return path; - } - - /** - * Returns the tag-file-name-to-JAR-file map of this compilation unit, - * which maps tag file names to the JAR files in which the tag files are - * packaged. - * - * The map is populated when parsing the tag-file elements of the TLDs - * of any imported taglibs. - */ - public URL getTagFileJarUrl(String tagFile) { - return this.tagFileJarUrls.get(tagFile); - } - - public void setTagFileJarUrl(String tagFile, URL tagFileURL) { - this.tagFileJarUrls.put(tagFile, tagFileURL); - } - - /** - * Returns the JAR file in which the tag file for which this - * JspCompilationContext was created is packaged, or null if this - * JspCompilationContext does not correspond to a tag file, or if the - * corresponding tag file is not packaged in a JAR. - */ - public URL getTagFileJarUrl() { - return this.tagFileJarUrl; - } - - /* ==================== Common implementation ==================== */ - - /** - * Just the class name (does not include package name) of the - * generated class. - */ - public String getServletClassName() { - - if (className != null) { - return className; - } - - if (isTagFile) { - className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - if (lastIndex != -1) { - className = className.substring(lastIndex + 1); - } - } else { - int iSep = jspUri.lastIndexOf('/') + 1; - className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); - } - return className; - } - - public void setServletClassName(String className) { - this.className = className; - } - - /** - * Path of the JSP URI. Note that this is not a file name. This is - * the context rooted URI of the JSP file. - */ - public String getJspFile() { - return jspUri; - } - - /** - * Are we processing something that has been declared as an - * errorpage? - */ - public boolean isErrorPage() { - return isErrPage; - } - - public void setErrorPage(boolean isErrPage) { - this.isErrPage = isErrPage; - } - - public boolean isTagFile() { - return isTagFile; - } - - public TagInfo getTagInfo() { - return tagInfo; - } - - public void setTagInfo(TagInfo tagi) { - tagInfo = tagi; - } - - /** - * True if we are compiling a tag file in prototype mode. - * ie we only generate codes with class for the tag handler with empty - * method bodies. - */ - public boolean isPrototypeMode() { - return protoTypeMode; - } - - public void setPrototypeMode(boolean pm) { - protoTypeMode = pm; - } - - /** - * Package name for the generated class is make up of the base package - * name, which is user settable, and the derived package name. The - * derived package name directly mirrors the file heirachy of the JSP page. - */ - public String getServletPackageName() { - if (isTagFile()) { - String className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - String pkgName = ""; - if (lastIndex != -1) { - pkgName = className.substring(0, lastIndex); - } - return pkgName; - } else { - String dPackageName = getDerivedPackageName(); - if (dPackageName.length() == 0) { - return basePackageName; - } - return basePackageName + '.' + getDerivedPackageName(); - } - } - - protected String getDerivedPackageName() { - if (derivedPackageName == null) { - int iSep = jspUri.lastIndexOf('/'); - derivedPackageName = (iSep > 0) ? - JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : ""; - } - return derivedPackageName; - } - - /** - * The package name into which the servlet class is generated. - */ - public void setServletPackageName(String servletPackageName) { - this.basePackageName = servletPackageName; - } - - /** - * Full path name of the Java file into which the servlet is being - * generated. - */ - public String getServletJavaFileName() { - if (servletJavaFileName == null) { - servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; - } - return servletJavaFileName; - } - - /** - * Get hold of the Options object for this context. - */ - public Options getOptions() { - return options; - } - - public ServletContext getServletContext() { - return context; - } - - public JspRuntimeContext getRuntimeContext() { - return rctxt; - } - - /** - * Path of the Java file relative to the work directory. - */ - public String getJavaPath() { - - if (javaPath != null) { - return javaPath; - } - - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - javaPath = tagName.replace('.', '/') + ".java"; - } else { - javaPath = getServletPackageName().replace('.', '/') + '/' + - getServletClassName() + ".java"; - } - return javaPath; - } - - public String getClassFileName() { - if (classFileName == null) { - classFileName = getOutputDir() + getServletClassName() + ".class"; - } - return classFileName; - } - - /** - * Get the content type of this JSP. - * - * Content type includes content type and encoding. - */ - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - /** - * Where is the servlet being generated? - */ - public ServletWriter getWriter() { - return writer; - } - - public void setWriter(ServletWriter writer) { - this.writer = writer; - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the given uri is not associated with any tag library - * 'exposed' in the web application. - */ - public String[] getTldLocation(String uri) throws JasperException { - String[] location = - getOptions().getTldLocationsCache().getLocation(uri); - return location; - } - - /** - * Are we keeping generated code around? - */ - public boolean keepGenerated() { - return getOptions().getKeepGenerated(); - } - - // ==================== Removal ==================== - - public void incrementRemoved() { - if (removed == 0 && rctxt != null) { - rctxt.removeWrapper(jspUri); - } - removed++; - } - - public boolean isRemoved() { - if (removed > 1 ) { - return true; - } - return false; - } - - // ==================== Compile and reload ==================== - - public void compile() throws JasperException, FileNotFoundException { - createCompiler(); - if (isPackagedTagFile || jspCompiler.isOutDated()) { - try { - jspCompiler.removeGeneratedFiles(); - jspLoader = null; - jspCompiler.compile(); - jsw.setReload(true); - jsw.setCompilationException(null); - } catch (JasperException ex) { - // Cache compilation exception - jsw.setCompilationException(ex); - throw ex; - } catch (Exception ex) { - JasperException je = new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), - ex); - // Cache compilation exception - jsw.setCompilationException(je); - throw je; - } - } - } - - // ==================== Manipulating the class ==================== - - public Class load() - throws JasperException, FileNotFoundException - { - try { - getJspLoader(); - - String name; - if (isTagFile()) { - name = tagInfo.getTagClassName(); - } else { - name = getServletPackageName() + "." + getServletClassName(); - } - servletClass = jspLoader.loadClass(name); - } catch (ClassNotFoundException cex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), - cex); - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), - ex); - } - removed = 0; - return servletClass; - } - - // ==================== protected methods ==================== - - static Object outputDirLock = new Object(); - - public void checkOutputDir() { - if (outputDir != null) { - if (!(new File(outputDir)).exists()) { - makeOutputDir(); - } - } else { - createOutputDir(); - } - } - - protected boolean makeOutputDir() { - synchronized(outputDirLock) { - File outDirFile = new File(outputDir); - return (outDirFile.exists() || outDirFile.mkdirs()); - } - } - - protected void createOutputDir() { - String path = null; - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - path = tagName.replace('.', '/'); - path = path.substring(0, path.lastIndexOf('/')); - } else { - path = getServletPackageName().replace('.', '/'); - } - - // Append servlet or tag handler path to scratch dir - try { - baseUrl = options.getScratchDir().toURL(); - String outUrlString = baseUrl.toString() + '/' + path; - URL outUrl = new URL(outUrlString); - outputDir = outUrl.getFile() + File.separator; - if (!makeOutputDir()) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); - } - } catch (MalformedURLException e) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); - } - } - - protected static final boolean isPathSeparator(char c) { - return (c == '/' || c == '\\'); - } - - protected static final String canonicalURI(String s) { - if (s == null) return null; - StringBuffer result = new StringBuffer(); - final int len = s.length(); - int pos = 0; - while (pos < len) { - char c = s.charAt(pos); - if ( isPathSeparator(c) ) { - /* - * multiple path separators. - * 'foo///bar' -> 'foo/bar' - */ - while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) { - ++pos; - } - - if (pos+1 < len && s.charAt(pos+1) == '.') { - /* - * a single dot at the end of the path - we are done. - */ - if (pos+2 >= len) break; - - switch (s.charAt(pos+2)) { - /* - * self directory in path - * foo/./bar -> foo/bar - */ - case '/': - case '\\': - pos += 2; - continue; - - /* - * two dots in a path: go back one hierarchy. - * foo/bar/../baz -> foo/baz - */ - case '.': - // only if we have exactly _two_ dots. - if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) { - pos += 3; - int separatorPos = result.length()-1; - while (separatorPos >= 0 && - ! isPathSeparator(result - .charAt(separatorPos))) { - --separatorPos; - } - if (separatorPos >= 0) - result.setLength(separatorPos); - continue; - } - } - } - } - result.append(c); - ++pos; - } - return result.toString(); - } -} - diff --git a/1.x/src/jasper6/bee-jasper.xml b/1.x/src/jasper6/bee-jasper.xml deleted file mode 100644 index 86f0bbd..0000000 --- a/1.x/src/jasper6/bee-jasper.xml +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - - - - ]> - - - - &env; - - - - - /bin/javac - - - - - - - /bin/javadoc - - - - - - ******** &project; Build Process ******** -********* Available targets: ************************************* -* compile - do Java compilation * -* jar - build &build_file; file * -* run - run application &main_class; * -******************************************************************* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /&build_directory; - - - - - - - - - - - - - - - - - - Compiling javax... - - - - - - - - - - > - - - - 0 - - - Error(s) at compilation of javax - - - - - - - - - Exception at compilation of javax - - - - - - - - - - - - - - - - - - - - - - Compiling... &project; - - - - - - - - - - > - - - - 0 - - - Error(s) at compilation of &project; - - - - - - - - - Exception at compilation of &project; - - - - - - - - - - &manifestf; - - - - - true - - - - -d - - -sourcepath - - -classpath - - &domain; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &source_directory;/javax/servlet/jsp/resources/jsp*.dtd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/jsp*.xsd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/web-jsp*.dtd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/web-jsp*.xsd - &build_directory;/javax/servlet/jsp/resources - - &source_directory;/javax/servlet/resources/j2ee*.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/j2ee*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/web-app*.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/web-app*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/datatypes.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/xml.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/XMLSchema.dtd - &build_directory;/javax/servlet/resources - - - - - - - - - - - - - Jarring... - - - - - - - - - - - - - - - - - - - - - - - - - - -cf - - - - -cmf - - - - - - - - - - - - - - - java - org/apache/jasper/resources - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - Exception at jarring - - - - - - - - - - - - - y - - - - - - - - - Cleaning... - - - - - - - - - - - /&build_directory;/&build_file; - - - - - /lib/tools.jar - - - - - Running... - - - - -classpath - - - - - - diff --git a/1.x/src/jasper6/env.xml b/1.x/src/jasper6/env.xml deleted file mode 100644 index f3eef26..0000000 --- a/1.x/src/jasper6/env.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - . - - - - - - - / - - - - - - - - - /jre - - - - - - - - - - - /home/dmitriy/libs/javax. - - 1.5 - - - - \\jre - - - - - - - - servlet.jar - - diff --git a/1.x/src/jasper7-6x/EmbeddedServletOptions.java b/1.x/src/jasper7-6x/EmbeddedServletOptions.java deleted file mode 100644 index f381c80..0000000 --- a/1.x/src/jasper7-6x/EmbeddedServletOptions.java +++ /dev/null @@ -1,758 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.util.Enumeration; -import java.util.Map; -import java.util.Properties; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagLibraryInfo; - -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * A class to hold all init parameters specific to the JSP engine. - * - * @author Anil K. Vijendran - * @author Hans Bergsten - * @author Pierre Delisle - */ -public final class EmbeddedServletOptions implements Options { - - // Logger - private final Log log = LogFactory.getLog(EmbeddedServletOptions.class); - - private Properties settings = new Properties(); - - /** - * Is Jasper being used in development mode? - */ - private boolean development = true; - - /** - * Should Ant fork its java compiles of JSP pages. - */ - public boolean fork = true; - - /** - * Do you want to keep the generated Java files around? - */ - private boolean keepGenerated = true; - - /** - * Should white spaces between directives or actions be trimmed? - */ - private boolean trimSpaces = false; - - /** - * Determines whether tag handler pooling is enabled. - */ - private boolean isPoolingEnabled = true; - - /** - * Do you want support for "mapped" files? This will generate - * servlet that has a print statement per line of the JSP file. - * This seems like a really nice feature to have for debugging. - */ - private boolean mappedFile = true; - - /** - * Do we want to include debugging information in the class file? - */ - private boolean classDebugInfo = true; - - /** - * Background compile thread check interval in seconds. - */ - private int checkInterval = 0; - - /** - * Is the generation of SMAP info for JSR45 debugging suppressed? - */ - private boolean isSmapSuppressed = false; - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - private boolean isSmapDumped = false; - - /** - * Are Text strings to be generated as char arrays? - */ - private boolean genStringAsCharArray = false; - - private boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * I want to see my generated servlets. Which directory are they - * in? - */ - private File scratchDir; - - /** - * Need to have this as is for versions 4 and 5 of IE. Can be set from - * the initParams so if it changes in the future all that is needed is - * to have a jsp initParam of type ieClassId="" - */ - private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - /** - * What classpath should I use while compiling generated servlets? - */ - private String classpath = null; - - /** - * Compiler to use. - */ - private String compiler = null; - - /** - * Compiler target VM. - */ - private String compilerTargetVM = "1.6"; - - /** - * The compiler source VM. - */ - private String compilerSourceVM = "1.6"; - - /** - * The compiler class name. - */ - private String compilerClassName = null; - - /** - * Cache for the TLD locations - */ - private TldLocationsCache tldLocationsCache = null; - - /** - * Jsp config information - */ - private JspConfig jspConfig = null; - - /** - * TagPluginManager - */ - private TagPluginManager tagPluginManager = null; - - /** - * Java platform encoding to generate the JSP - * page servlet. - */ - private String javaEncoding = "UTF8"; - - /** - * Modification test interval. - */ - private int modificationTestInterval = 4; - - /** - * Is re-compilation attempted immediately after a failure? - */ - private boolean recompileOnFail = false; - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - private boolean xpoweredBy; - - /** - * Should we include a source fragment in exception messages, which could be displayed - * to the developer ? - */ - private boolean displaySourceFragment = true; - - - /** - * The maximum number of loaded jsps per web-application. If there are more - * jsps loaded, they will be unloaded. - */ - private int maxLoadedJsps = -1; - - /** - * The idle time in seconds after which a JSP is unloaded. - * If unset or less or equal than 0, no jsps are unloaded. - */ - private int jspIdleTimeout = -1; - - public String getProperty(String name ) { - return settings.getProperty( name ); - } - - public void setProperty(String name, String value ) { - if (name != null && value != null){ - settings.setProperty( name, value ); - } - } - - /** - * Are we keeping generated code around? - */ - @Override - public boolean getKeepGenerated() { - return keepGenerated; - } - - /** - * Should white spaces between directives or actions be trimmed? - */ - @Override - public boolean getTrimSpaces() { - return trimSpaces; - } - - @Override - public boolean isPoolingEnabled() { - return isPoolingEnabled; - } - - /** - * Are we supporting HTML mapped servlets? - */ - @Override - public boolean getMappedFile() { - return mappedFile; - } - - /** - * Should class files be compiled with debug information? - */ - @Override - public boolean getClassDebugInfo() { - return classDebugInfo; - } - - /** - * Background JSP compile thread check interval - */ - @Override - public int getCheckInterval() { - return checkInterval; - } - - /** - * Modification test interval. - */ - @Override - public int getModificationTestInterval() { - return modificationTestInterval; - } - - /** - * Re-compile on failure. - */ - @Override - public boolean getRecompileOnFail() { - return recompileOnFail; - } - - /** - * Is Jasper being used in development mode? - */ - @Override - public boolean getDevelopment() { - return development; - } - - /** - * Is the generation of SMAP info for JSR45 debugging suppressed? - */ - @Override - public boolean isSmapSuppressed() { - return isSmapSuppressed; - } - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - @Override - public boolean isSmapDumped() { - return isSmapDumped; - } - - /** - * Are Text strings to be generated as char arrays? - */ - @Override - public boolean genStringAsCharArray() { - return this.genStringAsCharArray; - } - - /** - * Class ID for use in the plugin tag when the browser is IE. - */ - @Override - public String getIeClassId() { - return ieClassId; - } - - /** - * What is my scratch dir? - */ - @Override - public File getScratchDir() { - return scratchDir; - } - - /** - * What classpath should I use while compiling the servlets - * generated from JSP files? - */ - @Override - public String getClassPath() { - return classpath; - } - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - @Override - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Compiler to use. - */ - @Override - public String getCompiler() { - return compiler; - } - - /** - * @see Options#getCompilerTargetVM - */ - @Override - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * @see Options#getCompilerSourceVM - */ - @Override - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * Java compiler class to use. - */ - @Override - public String getCompilerClassName() { - return compilerClassName; - } - - @Override - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - @Override - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - public void setTldLocationsCache( TldLocationsCache tldC ) { - tldLocationsCache = tldC; - } - - @Override - public String getJavaEncoding() { - return javaEncoding; - } - - @Override - public boolean getFork() { - return fork; - } - - @Override - public JspConfig getJspConfig() { - return jspConfig; - } - - @Override - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - @Override - public boolean isCaching() { - return false; - } - - @Override - public Map getCache() { - return null; - } - - /** - * Should we include a source fragment in exception messages, which could be displayed - * to the developer ? - */ - @Override - public boolean getDisplaySourceFragment() { - return displaySourceFragment; - } - - /** - * Should jsps be unloaded if to many are loaded? - * If set to a value greater than 0 eviction of jsps is started. Default: -1 - */ - @Override - public int getMaxLoadedJsps() { - return maxLoadedJsps; - } - - /** - * Should any jsps be unloaded when being idle for this time in seconds? - * If set to a value greater than 0 eviction of jsps is started. Default: -1 - */ - @Override - public int getJspIdleTimeout() { - return jspIdleTimeout; - } - - /** - * Create an EmbeddedServletOptions object using data available from - * ServletConfig and ServletContext. - */ - public EmbeddedServletOptions(ServletConfig config, - ServletContext context) { - - Enumeration enumeration=config.getInitParameterNames(); - while( enumeration.hasMoreElements() ) { - String k=enumeration.nextElement(); - String v=config.getInitParameter( k ); - setProperty( k, v); - } - - String keepgen = config.getInitParameter("keepgenerated"); - if (keepgen != null) { - if (keepgen.equalsIgnoreCase("true")) { - this.keepGenerated = true; - } else if (keepgen.equalsIgnoreCase("false")) { - this.keepGenerated = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.keepgen")); - } - } - } - - - String trimsp = config.getInitParameter("trimSpaces"); - if (trimsp != null) { - if (trimsp.equalsIgnoreCase("true")) { - trimSpaces = true; - } else if (trimsp.equalsIgnoreCase("false")) { - trimSpaces = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.trimspaces")); - } - } - } - - this.isPoolingEnabled = true; - String poolingEnabledParam - = config.getInitParameter("enablePooling"); - if (poolingEnabledParam != null - && !poolingEnabledParam.equalsIgnoreCase("true")) { - if (poolingEnabledParam.equalsIgnoreCase("false")) { - this.isPoolingEnabled = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.enablePooling")); - } - } - } - - String mapFile = config.getInitParameter("mappedfile"); - if (mapFile != null) { - if (mapFile.equalsIgnoreCase("true")) { - this.mappedFile = true; - } else if (mapFile.equalsIgnoreCase("false")) { - this.mappedFile = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.mappedFile")); - } - } - } - - String debugInfo = config.getInitParameter("classdebuginfo"); - if (debugInfo != null) { - if (debugInfo.equalsIgnoreCase("true")) { - this.classDebugInfo = true; - } else if (debugInfo.equalsIgnoreCase("false")) { - this.classDebugInfo = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.classDebugInfo")); - } - } - } - - String checkInterval = config.getInitParameter("checkInterval"); - if (checkInterval != null) { - try { - this.checkInterval = Integer.parseInt(checkInterval); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.checkInterval")); - } - } - } - - String modificationTestInterval = config.getInitParameter("modificationTestInterval"); - if (modificationTestInterval != null) { - try { - this.modificationTestInterval = Integer.parseInt(modificationTestInterval); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval")); - } - } - } - - String recompileOnFail = config.getInitParameter("recompileOnFail"); - if (recompileOnFail != null) { - if (recompileOnFail.equalsIgnoreCase("true")) { - this.recompileOnFail = true; - } else if (recompileOnFail.equalsIgnoreCase("false")) { - this.recompileOnFail = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.recompileOnFail")); - } - } - } - String development = config.getInitParameter("development"); - if (development != null) { - if (development.equalsIgnoreCase("true")) { - this.development = true; - } else if (development.equalsIgnoreCase("false")) { - this.development = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.development")); - } - } - } - - String suppressSmap = config.getInitParameter("suppressSmap"); - if (suppressSmap != null) { - if (suppressSmap.equalsIgnoreCase("true")) { - isSmapSuppressed = true; - } else if (suppressSmap.equalsIgnoreCase("false")) { - isSmapSuppressed = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.suppressSmap")); - } - } - } - - String dumpSmap = config.getInitParameter("dumpSmap"); - if (dumpSmap != null) { - if (dumpSmap.equalsIgnoreCase("true")) { - isSmapDumped = true; - } else if (dumpSmap.equalsIgnoreCase("false")) { - isSmapDumped = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.dumpSmap")); - } - } - } - - String genCharArray = config.getInitParameter("genStringAsCharArray"); - if (genCharArray != null) { - if (genCharArray.equalsIgnoreCase("true")) { - genStringAsCharArray = true; - } else if (genCharArray.equalsIgnoreCase("false")) { - genStringAsCharArray = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.genchararray")); - } - } - } - - String errBeanClass = - config.getInitParameter("errorOnUseBeanInvalidClassAttribute"); - if (errBeanClass != null) { - if (errBeanClass.equalsIgnoreCase("true")) { - errorOnUseBeanInvalidClassAttribute = true; - } else if (errBeanClass.equalsIgnoreCase("false")) { - errorOnUseBeanInvalidClassAttribute = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.errBean")); - } - } - } - - String ieClassId = config.getInitParameter("ieClassId"); - if (ieClassId != null) - this.ieClassId = ieClassId; - - String classpath = config.getInitParameter("classpath"); - if (classpath != null) - this.classpath = classpath; - - /* - * scratchdir - */ - String dir = config.getInitParameter("scratchdir"); - if (dir != null) { - scratchDir = new File(dir); - } else { - // First try the Servlet 2.2 javax.servlet.context.tempdir property - scratchDir = (File) context.getAttribute(ServletContext.TEMPDIR); - if (scratchDir == null) { - // Not running in a Servlet 2.2 container. - // Try to get the JDK 1.2 java.io.tmpdir property - dir = System.getProperty("java.io.tmpdir"); - if (dir != null) - scratchDir = new File(dir); - } - } - if (this.scratchDir == null) { - log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir")); - return; - } - - if (!scratchDir.exists()) - scratchDir.mkdirs(); - if (!(scratchDir.exists() && scratchDir.canRead() && - scratchDir.canWrite() && scratchDir.isDirectory())) - log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir", - scratchDir.getAbsolutePath())); - - this.compiler = config.getInitParameter("compiler"); - - String compilerTargetVM = config.getInitParameter("compilerTargetVM"); - if(compilerTargetVM != null) { - this.compilerTargetVM = compilerTargetVM; - } - - String compilerSourceVM = config.getInitParameter("compilerSourceVM"); - if(compilerSourceVM != null) { - this.compilerSourceVM = compilerSourceVM; - } - - String javaEncoding = config.getInitParameter("javaEncoding"); - if (javaEncoding != null) { - this.javaEncoding = javaEncoding; - } - - String compilerClassName = config.getInitParameter("compilerClassName"); - if (compilerClassName != null) { - this.compilerClassName = compilerClassName; - } - - String fork = config.getInitParameter("fork"); - if (fork != null) { - if (fork.equalsIgnoreCase("true")) { - this.fork = true; - } else if (fork.equalsIgnoreCase("false")) { - this.fork = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.fork")); - } - } - } - - String xpoweredBy = config.getInitParameter("xpoweredBy"); - if (xpoweredBy != null) { - if (xpoweredBy.equalsIgnoreCase("true")) { - this.xpoweredBy = true; - } else if (xpoweredBy.equalsIgnoreCase("false")) { - this.xpoweredBy = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.xpoweredBy")); - } - } - } - - String displaySourceFragment = config.getInitParameter("displaySourceFragment"); - if (displaySourceFragment != null) { - if (displaySourceFragment.equalsIgnoreCase("true")) { - this.displaySourceFragment = true; - } else if (displaySourceFragment.equalsIgnoreCase("false")) { - this.displaySourceFragment = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.displaySourceFragment")); - } - } - } - - String maxLoadedJsps = config.getInitParameter("maxLoadedJsps"); - if (maxLoadedJsps != null) { - try { - this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps", ""+this.maxLoadedJsps)); - } - } - } - - String jspIdleTimeout = config.getInitParameter("jspIdleTimeout"); - if (jspIdleTimeout != null) { - try { - this.jspIdleTimeout = Integer.parseInt(jspIdleTimeout); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.jspIdleTimeout", ""+this.jspIdleTimeout)); - } - } - } - - // Setup the global Tag Libraries location cache for this - // web-application. - tldLocationsCache = TldLocationsCache.getInstance(context); - - // Setup the jsp config info for this web app. - jspConfig = new JspConfig(context); - - // Create a Tag plugin instance - tagPluginManager = new TagPluginManager(context); - } - -} - diff --git a/1.x/src/jasper7-6x/JspC.java b/1.x/src/jasper7-6x/JspC.java deleted file mode 100644 index 3f520a7..0000000 --- a/1.x/src/jasper7-6x/JspC.java +++ /dev/null @@ -1,1640 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.servlet.jsp.tagext.TagLibraryInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.servlet.JspCServletContext; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * Shell for the jspc compiler. Handles all options associated with the - * command line and creates compilation contexts which it then compiles - * according to the specified options. - * - * This version can process files from a _single_ webapp at once, i.e. - * a single docbase can be specified. - * - * It can be used as an Ant task using: - *
- *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
- *      <classpath>
- *          <pathelement location="${java.home}/../lib/tools.jar"/>
- *          <fileset dir="${ENV.CATALINA_HOME}/lib">
- *              <include name="*.jar"/>
- *          </fileset>
- *          <path refid="myjars"/>
- *       </classpath>
- *  </taskdef>
- *
- *  <jasper verbose="0"
- *           package="my.package"
- *           uriroot="${webapps.dir}/${webapp.name}"
- *           webXmlFragment="${build.dir}/generated_web.xml"
- *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
- * 
- * - * @author Danno Ferrin - * @author Pierre Delisle - * @author Costin Manolache - * @author Yoav Shapira - */ -public class JspC implements Options { - - public static final String DEFAULT_IE_CLASS_ID = - "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - // Logger - private static final Log log = LogFactory.getLog(JspC.class); - - protected static final String SWITCH_VERBOSE = "-v"; - protected static final String SWITCH_HELP = "-help"; - protected static final String SWITCH_OUTPUT_DIR = "-d"; - protected static final String SWITCH_PACKAGE_NAME = "-p"; - protected static final String SWITCH_CACHE = "-cache"; - protected static final String SWITCH_CLASS_NAME = "-c"; - protected static final String SWITCH_FULL_STOP = "--"; - protected static final String SWITCH_COMPILE = "-compile"; - protected static final String SWITCH_SOURCE = "-source"; - protected static final String SWITCH_TARGET = "-target"; - protected static final String SWITCH_URI_BASE = "-uribase"; - protected static final String SWITCH_URI_ROOT = "-uriroot"; - protected static final String SWITCH_FILE_WEBAPP = "-webapp"; - protected static final String SWITCH_WEBAPP_INC = "-webinc"; - protected static final String SWITCH_WEBAPP_XML = "-webxml"; - protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; - protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; - protected static final String SWITCH_MAPPED = "-mapped"; - protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; - protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; - protected static final String SWITCH_CLASSPATH = "-classpath"; - protected static final String SWITCH_DIE = "-die"; - protected static final String SWITCH_POOLING = "-poolingEnabled"; - protected static final String SWITCH_ENCODING = "-javaEncoding"; - protected static final String SWITCH_SMAP = "-smap"; - protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; - protected static final String SWITCH_VALIDATE_TLD = "-validateTld"; - protected static final String SWITCH_VALIDATE_XML = "-validateXml"; - protected static final String SWITCH_BLOCK_EXTERNAL = "-blockExternal"; - protected static final String SWITCH_NO_BLOCK_EXTERNAL = "-no-blockExternal"; - protected static final String SHOW_SUCCESS ="-s"; - protected static final String LIST_ERRORS = "-l"; - protected static final int INC_WEBXML = 10; - protected static final int ALL_WEBXML = 20; - protected static final int DEFAULT_DIE_LEVEL = 1; - protected static final int NO_DIE_LEVEL = 0; - protected static final Set insertBefore = new HashSet(); - - static { - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - } - - protected String classPath = null; - protected ClassLoader loader = null; - protected boolean trimSpaces = false; - protected boolean genStringAsCharArray = false; - protected boolean validateTld; - protected boolean validateXml; - protected boolean blockExternal = true; - protected boolean xpoweredBy; - protected boolean mappedFile = false; - protected boolean poolingEnabled = true; - protected File scratchDir; - protected String ieClassId = DEFAULT_IE_CLASS_ID; - protected String targetPackage; - protected String targetClassName; - protected String uriBase; - protected String uriRoot; - protected int dieLevel; - protected boolean helpNeeded = false; - protected boolean compile = false; - protected boolean smapSuppressed = true; - protected boolean smapDumped = false; - protected boolean caching = true; - protected final Map cache = - new HashMap(); - - protected String compiler = null; - - protected String compilerTargetVM = "1.6"; - protected String compilerSourceVM = "1.6"; - - protected boolean classDebugInfo = true; - - /** - * Throw an exception if there's a compilation error, or swallow it. - * Default is true to preserve old behavior. - */ - protected boolean failOnError = true; - - /** - * The file extensions to be handled as JSP files. - * Default list is .jsp and .jspx. - */ - protected List extensions; - - /** - * The pages. - */ - protected final List pages = new Vector(); - - /** - * Needs better documentation, this data member does. - * True by default. - */ - protected boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * The java file encoding. Default - * is UTF-8. Added per bugzilla 19622. - */ - protected String javaEncoding = "UTF-8"; - - // Generation of web.xml fragments - protected String webxmlFile; - protected int webxmlLevel; - protected String webxmlEncoding; - protected boolean addWebXmlMappings = false; - - protected Writer mapout; - protected CharArrayWriter servletout; - protected CharArrayWriter mappingout; - - /** - * The servlet context. - */ - protected JspCServletContext context; - - /** - * The runtime context. - * Maintain a dummy JspRuntimeContext for compiling tag files. - */ - protected JspRuntimeContext rctxt; - - /** - * Cache for the TLD locations - */ - protected TldLocationsCache tldLocationsCache = null; - - protected JspConfig jspConfig = null; - protected TagPluginManager tagPluginManager = null; - - protected boolean verbose = false; - protected boolean listErrors = false; - protected boolean showSuccess = false; - protected int argPos; - protected boolean fullstop = false; - protected String args[]; - - public static void main(String arg[]) { - if (arg.length == 0) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - JspC jspc = new JspC(); - try { - jspc.setArgs(arg); - if (jspc.helpNeeded) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - jspc.execute(); - } - } catch (JasperException je) { - System.err.println(je); - if (jspc.dieLevel != NO_DIE_LEVEL) { - System.exit(jspc.dieLevel); - } - } catch (RuntimeException je) { - System.err.println(je); - if (jspc.dieLevel != NO_DIE_LEVEL) { - System.exit(jspc.dieLevel); - } - } - } - } - - /** - * Apply command-line arguments. - * - * @param arg - * The arguments - */ - public void setArgs(String[] arg) throws JasperException { - args = arg; - String tok; - - dieLevel = NO_DIE_LEVEL; - - while ((tok = nextArg()) != null) { - if (tok.equals(SWITCH_VERBOSE)) { - verbose = true; - showSuccess = true; - listErrors = true; - } else if (tok.equals(SWITCH_OUTPUT_DIR)) { - tok = nextArg(); - setOutputDir( tok ); - } else if (tok.equals(SWITCH_PACKAGE_NAME)) { - targetPackage = nextArg(); - } else if (tok.equals(SWITCH_COMPILE)) { - compile=true; - } else if (tok.equals(SWITCH_CLASS_NAME)) { - targetClassName = nextArg(); - } else if (tok.equals(SWITCH_URI_BASE)) { - uriBase=nextArg(); - } else if (tok.equals(SWITCH_URI_ROOT)) { - setUriroot( nextArg()); - } else if (tok.equals(SWITCH_FILE_WEBAPP)) { - setUriroot( nextArg()); - } else if ( tok.equals( SHOW_SUCCESS ) ) { - showSuccess = true; - } else if ( tok.equals( LIST_ERRORS ) ) { - listErrors = true; - } else if (tok.equals(SWITCH_WEBAPP_INC)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = INC_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = ALL_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { - setWebXmlEncoding(nextArg()); - } else if (tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { - setAddWebXmlMappings(true); - } else if (tok.equals(SWITCH_MAPPED)) { - mappedFile = true; - } else if (tok.equals(SWITCH_XPOWERED_BY)) { - xpoweredBy = true; - } else if (tok.equals(SWITCH_TRIM_SPACES)) { - setTrimSpaces(true); - } else if (tok.equals(SWITCH_CACHE)) { - tok = nextArg(); - if ("false".equals(tok)) { - caching = false; - } else { - caching = true; - } - } else if (tok.equals(SWITCH_CLASSPATH)) { - setClassPath(nextArg()); - } else if (tok.startsWith(SWITCH_DIE)) { - try { - dieLevel = Integer.parseInt( - tok.substring(SWITCH_DIE.length())); - } catch (NumberFormatException nfe) { - dieLevel = DEFAULT_DIE_LEVEL; - } - } else if (tok.equals(SWITCH_HELP)) { - helpNeeded = true; - } else if (tok.equals(SWITCH_POOLING)) { - tok = nextArg(); - if ("false".equals(tok)) { - poolingEnabled = false; - } else { - poolingEnabled = true; - } - } else if (tok.equals(SWITCH_ENCODING)) { - setJavaEncoding(nextArg()); - } else if (tok.equals(SWITCH_SOURCE)) { - setCompilerSourceVM(nextArg()); - } else if (tok.equals(SWITCH_TARGET)) { - setCompilerTargetVM(nextArg()); - } else if (tok.equals(SWITCH_SMAP)) { - smapSuppressed = false; - } else if (tok.equals(SWITCH_DUMP_SMAP)) { - smapDumped = true; - } else if (tok.equals(SWITCH_VALIDATE_TLD)) { - setValidateTld(true); - } else if (tok.equals(SWITCH_VALIDATE_XML)) { - setValidateXml(true); - } else if (tok.equals(SWITCH_BLOCK_EXTERNAL)) { - setBlockExternal(true); - } else if (tok.equals(SWITCH_NO_BLOCK_EXTERNAL)) { - setBlockExternal(false); - } else { - if (tok.startsWith("-")) { - throw new JasperException("Unrecognized option: " + tok + - ". Use -help for help."); - } - if (!fullstop) { - argPos--; - } - // Start treating the rest as JSP Pages - break; - } - } - - // Add all extra arguments to the list of files - while( true ) { - String file = nextFile(); - if( file==null ) { - break; - } - pages.add( file ); - } - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - @Override - public boolean getKeepGenerated() { - // isn't this why we are running jspc? - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getTrimSpaces() { - return trimSpaces; - } - - /** - * Sets the option to trim white spaces between directives or actions. - */ - public void setTrimSpaces(boolean ts) { - this.trimSpaces = ts; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - /** - * Sets the option to enable the tag handler pooling. - */ - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Sets the option to enable generation of X-Powered-By response header. - */ - public void setXpoweredBy(boolean xpoweredBy) { - this.xpoweredBy = xpoweredBy; - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - @Override - public boolean getDisplaySourceFragment() { - return true; - } - - @Override - public int getMaxLoadedJsps() { - return -1; - } - - @Override - public int getJspIdleTimeout() { - return -1; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - /** - * Sets the option to issue a compilation error if the class attribute - * specified in useBean action is invalid. - */ - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getMappedFile() { - return mappedFile; - } - - public void setMappedFile(boolean b) { - mappedFile = b; - } - - /** - * Sets the option to include debug information in compiled class. - */ - public void setClassDebugInfo( boolean b ) { - classDebugInfo=b; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getClassDebugInfo() { - // compile with debug info - return classDebugInfo; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isCaching() { - return caching; - } - - /** - * Sets the option to enable caching. - * - * @see Options#isCaching() - */ - public void setCaching(boolean caching) { - this.caching = caching; - } - - /** - * {@inheritDoc} - */ - @Override - public Map getCache() { - return cache; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - @Override - public int getCheckInterval() { - return 0; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - @Override - public int getModificationTestInterval() { - return 0; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - @Override - public boolean getRecompileOnFail() { - return false; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - @Override - public boolean getDevelopment() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSmapSuppressed() { - return smapSuppressed; - } - - /** - * Sets smapSuppressed flag. - */ - public void setSmapSuppressed(boolean smapSuppressed) { - this.smapSuppressed = smapSuppressed; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSmapDumped() { - return smapDumped; - } - - /** - * Sets smapDumped flag. - * - * @see Options#isSmapDumped() - */ - public void setSmapDumped(boolean smapDumped) { - this.smapDumped = smapDumped; - } - - - /** - * Determines whether text strings are to be generated as char arrays, - * which improves performance in some cases. - * - * @param genStringAsCharArray true if text strings are to be generated as - * char arrays, false otherwise - */ - public void setGenStringAsCharArray(boolean genStringAsCharArray) { - this.genStringAsCharArray = genStringAsCharArray; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean genStringAsCharArray() { - return genStringAsCharArray; - } - - /** - * Sets the class-id value to be sent to Internet Explorer when using - * <jsp:plugin> tags. - * - * @param ieClassId - * Class-id value - */ - public void setIeClassId(String ieClassId) { - this.ieClassId = ieClassId; - } - - /** - * {@inheritDoc} - */ - @Override - public String getIeClassId() { - return ieClassId; - } - - /** - * {@inheritDoc} - */ - @Override - public File getScratchDir() { - return scratchDir; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompiler() { - return compiler; - } - - /** - * Sets the option to determine what compiler to use. - * - * @see Options#getCompiler() - */ - public void setCompiler(String c) { - compiler=c; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerClassName() { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * Sets the compiler target VM. - * - * @see Options#getCompilerTargetVM() - */ - public void setCompilerTargetVM(String vm) { - compilerTargetVM = vm; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * Sets the compiler source VM. - * - * @see Options#getCompilerSourceVM() - */ - public void setCompilerSourceVM(String vm) { - compilerSourceVM = vm; - } - - /** - * {@inheritDoc} - */ - @Override - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - /** - * Returns the encoding to use for - * java files. The default is UTF-8. - * - * @return String The encoding - */ - @Override - public String getJavaEncoding() { - return javaEncoding; - } - - /** - * Sets the encoding to use for - * java files. - * - * @param encodingName The name, e.g. "UTF-8" - */ - public void setJavaEncoding(String encodingName) { - javaEncoding = encodingName; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getFork() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public String getClassPath() { - if( classPath != null ) - return classPath; - return System.getProperty("java.class.path"); - } - - /** - * Sets the classpath used while compiling the servlets generated from JSP - * files - */ - public void setClassPath(String s) { - classPath=s; - } - - /** - * Returns the list of file extensions - * that are treated as JSP files. - * - * @return The list of extensions - */ - public List getExtensions() { - return extensions; - } - - /** - * Adds the given file extension to the - * list of extensions handled as JSP files. - * - * @param extension The extension to add, e.g. "myjsp" - */ - protected void addExtension(final String extension) { - if(extension != null) { - if(extensions == null) { - extensions = new Vector(); - } - - extensions.add(extension); - } - } - - /** - * Base dir for the webapp. Used to generate class names and resolve - * includes. - */ - public void setUriroot( String s ) { - if (s == null) { - uriRoot = null; - return; - } - try { - uriRoot = resolveFile(s).getCanonicalPath(); - } catch( Exception ex ) { - uriRoot = s; - } - } - - /** - * Parses comma-separated list of JSP files to be processed. If the argument - * is null, nothing is done. - * - *

Each file is interpreted relative to uriroot, unless it is absolute, - * in which case it must start with uriroot.

- * - * @param jspFiles Comma-separated list of JSP files to be processed - */ - public void setJspFiles(final String jspFiles) { - if(jspFiles == null) { - return; - } - - StringTokenizer tok = new StringTokenizer(jspFiles, ","); - while (tok.hasMoreTokens()) { - pages.add(tok.nextToken()); - } - } - - /** - * Sets the compile flag. - * - * @param b Flag value - */ - public void setCompile( final boolean b ) { - compile = b; - } - - /** - * Sets the verbosity level. The actual number doesn't - * matter: if it's greater than zero, the verbose flag will - * be true. - * - * @param level Positive means verbose - */ - public void setVerbose( final int level ) { - if (level > 0) { - verbose = true; - showSuccess = true; - listErrors = true; - } - } - - public void setValidateTld( boolean b ) { - this.validateTld = b; - } - - public boolean isValidateTld() { - return validateTld; - } - - public void setValidateXml( boolean b ) { - this.validateXml = b; - } - - public boolean isValidateXml() { - return validateXml; - } - - public void setBlockExternal( boolean b ) { - this.blockExternal = b; - } - - public boolean isBlockExternal() { - return blockExternal; - } - - public void setListErrors( boolean b ) { - listErrors = b; - } - - public void setOutputDir( String s ) { - if( s!= null ) { - scratchDir = resolveFile(s).getAbsoluteFile(); - } else { - scratchDir=null; - } - } - - /** - * Sets the package name to be used for the generated servlet classes. - */ - public void setPackage( String p ) { - targetPackage=p; - } - - /** - * Class name of the generated file ( without package ). - * Can only be used if a single file is converted. - * XXX Do we need this feature ? - */ - public void setClassName( String p ) { - targetClassName=p; - } - - /** - * File where we generate a web.xml fragment with the class definitions. - */ - public void setWebXmlFragment( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=INC_WEBXML; - } - - /** - * File where we generate a complete web.xml with the class definitions. - */ - public void setWebXml( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=ALL_WEBXML; - } - - /** - * Sets the encoding to be used to read and write web.xml files. - * - *

- * If not specified, defaults to the platform default encoding. - *

- * - * @param encoding - * Encoding, e.g. "UTF-8". - */ - public void setWebXmlEncoding(String encoding) { - webxmlEncoding = encoding; - } - - /** - * Sets the option to merge generated web.xml fragment into the - * WEB-INF/web.xml file of the web application that we were processing. - * - * @param b - * true to merge the fragment into the existing - * web.xml file of the processed web application - * ({uriroot}/WEB-INF/web.xml), false to keep the - * generated web.xml fragment - */ - public void setAddWebXmlMappings(boolean b) { - addWebXmlMappings = b; - } - - /** - * Sets the option that throws an exception in case of a compilation error. - */ - public void setFailOnError(final boolean b) { - failOnError = b; - } - - /** - * Returns true if an exception will be thrown in case of a compilation - * error. - */ - public boolean getFailOnError() { - return failOnError; - } - - /** - * {@inheritDoc} - */ - @Override - public JspConfig getJspConfig() { - return jspConfig; - } - - /** - * {@inheritDoc} - */ - @Override - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - /** - * Adds servlet declaration and mapping for the JSP page servlet to the - * generated web.xml fragment. - * - * @param file - * Context-relative path to the JSP file, e.g. - * /index.jsp - * @param clctxt - * Compilation context of the servlet - */ - public void generateWebMapping( String file, JspCompilationContext clctxt ) - throws IOException - { - if (log.isDebugEnabled()) { - log.debug("Generating web mapping for file " + file - + " using compilation context " + clctxt); - } - - String className = clctxt.getServletClassName(); - String packageName = clctxt.getServletPackageName(); - - String thisServletName; - if ("".equals(packageName)) { - thisServletName = className; - } else { - thisServletName = packageName + '.' + className; - } - - if (servletout != null) { - servletout.write("\n \n "); - servletout.write(thisServletName); - servletout.write("\n "); - servletout.write(thisServletName); - servletout.write("\n \n"); - } - if (mappingout != null) { - mappingout.write("\n \n "); - mappingout.write(thisServletName); - mappingout.write("\n "); - mappingout.write(file.replace('\\', '/')); - mappingout.write("\n \n"); - - } - } - - /** - * Include the generated web.xml inside the webapp's web.xml. - */ - protected void mergeIntoWebXml() throws IOException { - - File webappBase = new File(uriRoot); - File webXml = new File(webappBase, "WEB-INF/web.xml"); - File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); - String insertStartMarker = - Localizer.getMessage("jspc.webinc.insertStart"); - String insertEndMarker = - Localizer.getMessage("jspc.webinc.insertEnd"); - - BufferedReader reader = new BufferedReader(openWebxmlReader(webXml)); - BufferedReader fragmentReader = new BufferedReader( - openWebxmlReader(new File(webxmlFile))); - PrintWriter writer = new PrintWriter(openWebxmlWriter(webXml2)); - - // Insert the and declarations - boolean inserted = false; - int current = reader.read(); - while (current > -1) { - if (current == '<') { - String element = getElement(reader); - if (!inserted && insertBefore.contains(element)) { - // Insert generated content here - writer.println(insertStartMarker); - while (true) { - String line = fragmentReader.readLine(); - if (line == null) { - writer.println(); - break; - } - writer.println(line); - } - writer.println(insertEndMarker); - writer.println(); - writer.write(element); - inserted = true; - } else if (element.equals(insertStartMarker)) { - // Skip the previous auto-generated content - while (true) { - current = reader.read(); - if (current < 0) { - throw new EOFException(); - } - if (current == '<') { - element = getElement(reader); - if (element.equals(insertEndMarker)) { - break; - } - } - } - current = reader.read(); - while (current == '\n' || current == '\r') { - current = reader.read(); - } - continue; - } else { - writer.write(element); - } - } else { - writer.write(current); - } - current = reader.read(); - } - writer.close(); - - reader.close(); - fragmentReader.close(); - - FileInputStream fis = new FileInputStream(webXml2); - FileOutputStream fos = new FileOutputStream(webXml); - - byte buf[] = new byte[512]; - while (true) { - int n = fis.read(buf); - if (n < 0) { - break; - } - fos.write(buf, 0, n); - } - - fis.close(); - fos.close(); - - if(!webXml2.delete() && log.isDebugEnabled()) - log.debug(Localizer.getMessage("jspc.delete.fail", - webXml2.toString())); - - if (!(new File(webxmlFile)).delete() && log.isDebugEnabled()) - log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile)); - - } - - /* - * Assumes valid xml - */ - private String getElement(Reader reader) throws IOException { - StringBuilder result = new StringBuilder(); - result.append('<'); - - boolean done = false; - - while (!done) { - int current = reader.read(); - while (current != '>') { - if (current < 0) { - throw new EOFException(); - } - result.append((char) current); - current = reader.read(); - } - result.append((char) current); - - int len = result.length(); - if (len > 4 && result.substring(0, 4).equals("")) { - done = true; - } - } else { - done = true; - } - } - - - return result.toString(); - } - - protected void processFile(String file) - throws JasperException - { - if (log.isDebugEnabled()) { - log.debug("Processing file: " + file); - } - - ClassLoader originalClassLoader = null; - - try { - // set up a scratch/output dir if none is provided - if (scratchDir == null) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = ""; - } - scratchDir = new File(new File(temp).getAbsolutePath()); - } - - String jspUri=file.replace('\\','/'); - JspCompilationContext clctxt = new JspCompilationContext - ( jspUri, this, context, null, rctxt ); - - /* Override the defaults */ - if ((targetClassName != null) && (targetClassName.length() > 0)) { - clctxt.setServletClassName(targetClassName); - targetClassName = null; - } - if (targetPackage != null) { - clctxt.setServletPackageName(targetPackage); - } - - originalClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(loader); - - clctxt.setClassLoader(loader); - clctxt.setClassPath(classPath); - - Compiler clc = clctxt.createCompiler(); - - // If compile is set, generate both .java and .class, if - // .jsp file is newer than .class file; - // Otherwise only generate .java, if .jsp file is newer than - // the .java file - if( clc.isOutDated(compile) ) { - if (log.isDebugEnabled()) { - log.debug(jspUri + " is out dated, compiling..."); - } - - clc.compile(compile, true); - } - - // Generate mapping - generateWebMapping( file, clctxt ); - if ( showSuccess ) { - log.info( "Built File: " + file ); - } - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - log.error(Localizer.getMessage("jspc.error.generalException", - file), - rootCause); - } - - // Bugzilla 35114. - if(getFailOnError()) { - throw je; - } else { - log.error(je.getMessage()); - } - - } catch (Exception e) { - if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", - e.getMessage())); - } - throw new JasperException(e); - } finally { - if(originalClassLoader != null) { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - - /** - * Locate all jsp files in the webapp. Used if no explicit - * jsps are specified. - */ - public void scanFiles( File base ) throws JasperException { - Stack dirs = new Stack(); - dirs.push(base.toString()); - - // Make sure default extensions are always included - if ((getExtensions() == null) || (getExtensions().size() < 2)) { - addExtension("jsp"); - addExtension("jspx"); - } - - while (!dirs.isEmpty()) { - String s = dirs.pop(); - File f = new File(s); - if (f.exists() && f.isDirectory()) { - String[] files = f.list(); - String ext; - for (int i = 0; (files != null) && i < files.length; i++) { - File f2 = new File(s, files[i]); - if (f2.isDirectory()) { - dirs.push(f2.getPath()); - } else { - String path = f2.getPath(); - String uri = path.substring(uriRoot.length()); - ext = files[i].substring(files[i].lastIndexOf('.') +1); - if (getExtensions().contains(ext) || - jspConfig.isJspPage(uri)) { - pages.add(path); - } - } - } - } - } - } - - /** - * Executes the compilation. - */ - public void execute() { - if(log.isDebugEnabled()) { - log.debug("execute() starting for " + pages.size() + " pages."); - } - - try { - if (uriRoot == null) { - if( pages.size() == 0 ) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.missingTarget")); - } - String firstJsp = pages.get( 0 ); - File firstJspF = new File( firstJsp ); - if (!firstJspF.exists()) { - throw new JasperException( - Localizer.getMessage("jspc.error.fileDoesNotExist", - firstJsp)); - } - locateUriRoot( firstJspF ); - } - - if (uriRoot == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.no_uriroot")); - } - - File uriRootF = new File(uriRoot); - if (!uriRootF.isDirectory()) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); - } - - if (loader == null) { - loader = initClassLoader(); - } - if (context == null) { - initServletContext(loader); - } - - // No explicit pages, we'll process all .jsp in the webapp - if (pages.size() == 0) { - scanFiles(uriRootF); - } - - initWebXml(); - - Iterator iter = pages.iterator(); - while (iter.hasNext()) { - String nextjsp = iter.next().toString(); - File fjsp = new File(nextjsp); - if (!fjsp.isAbsolute()) { - fjsp = new File(uriRootF, nextjsp); - } - if (!fjsp.exists()) { - if (log.isWarnEnabled()) { - log.warn - (Localizer.getMessage - ("jspc.error.fileDoesNotExist", fjsp.toString())); - } - continue; - } - String s = fjsp.getAbsolutePath(); - if (s.startsWith(uriRoot)) { - nextjsp = s.substring(uriRoot.length()); - } - if (nextjsp.startsWith("." + File.separatorChar)) { - nextjsp = nextjsp.substring(2); - } - processFile(nextjsp); - } - - completeWebXml(); - - if (addWebXmlMappings) { - mergeIntoWebXml(); - } - - } catch (IOException ioe) { - throw new RuntimeException(ioe); // TODO make it our own - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - rootCause.printStackTrace(); - } - throw new RuntimeException(je); // TODO make it our own - } finally { - if (loader != null) { - LogFactory.release(loader); - } - } - } - - // ==================== protected utility methods ==================== - - protected String nextArg() { - if ((argPos >= args.length) - || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { - return null; - } else { - return args[argPos++]; - } - } - - protected String nextFile() { - if (fullstop) argPos++; - if (argPos >= args.length) { - return null; - } else { - return args[argPos++]; - } - } - - protected void initWebXml() { - try { - if (webxmlLevel >= INC_WEBXML) { - mapout = openWebxmlWriter(new File(webxmlFile)); - servletout = new CharArrayWriter(); - mappingout = new CharArrayWriter(); - } else { - mapout = null; - servletout = null; - mappingout = null; - } - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.header")); - mapout.flush(); - } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.header")); - mapout.flush(); - } - } catch (IOException ioe) { - mapout = null; - servletout = null; - mappingout = null; - } - } - - protected void completeWebXml() { - if (mapout != null) { - try { - servletout.writeTo(mapout); - mappingout.writeTo(mapout); - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.footer")); - } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.footer")); - } - mapout.close(); - } catch (IOException ioe) { - // noting to do if it fails since we are done with it - } - } - } - - protected void initServletContext(ClassLoader classLoader) - throws IOException, JasperException { - // TODO: should we use the Ant Project's log? - PrintWriter log = new PrintWriter(System.out); - URL resourceBase = new File(uriRoot).getCanonicalFile().toURI().toURL(); - context = new JspCServletContext(log, resourceBase, classLoader); - if (isValidateTld()) { - context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true"); - } - if (isValidateXml()) { - context.setInitParameter(Constants.XML_VALIDATION_INIT_PARAM, "true"); - } - context.setInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM, - String.valueOf(isBlockExternal())); - - tldLocationsCache = TldLocationsCache.getInstance(context); - rctxt = new JspRuntimeContext(context, this); - jspConfig = new JspConfig(context); - tagPluginManager = new TagPluginManager(context); - } - - /** - * Initializes the classloader as/if needed for the given - * compilation context. - * - * @throws IOException If an error occurs - */ - protected ClassLoader initClassLoader() throws IOException { - - classPath = getClassPath(); - - ClassLoader jspcLoader = getClass().getClassLoader(); - // TODO add check for 7Bee/TJWS class loader and extend CP as needed - - // Turn the classPath into URLs - ArrayList urls = new ArrayList(); - StringTokenizer tokenizer = new StringTokenizer(classPath, - File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - String path = tokenizer.nextToken(); - try { - File libFile = new File(path); - urls.add(libFile.toURI().toURL()); - } catch (IOException ioe) { - // Failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak uot - throw new RuntimeException(ioe.toString()); - } - } - - File webappBase = new File(uriRoot); - if (webappBase.exists()) { - File classes = new File(webappBase, "/WEB-INF/classes"); - try { - if (classes.exists()) { - classPath = classPath + File.pathSeparator - + classes.getCanonicalPath(); - urls.add(classes.getCanonicalFile().toURI().toURL()); - } - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - File lib = new File(webappBase, "/WEB-INF/lib"); - if (lib.exists() && lib.isDirectory()) { - String[] libs = lib.list(); - for (int i = 0; i < libs.length; i++) { - if( libs[i].length() <5 ) continue; - String ext=libs[i].substring( libs[i].length() - 4 ); - if (! ".jar".equalsIgnoreCase(ext)) { - if (".tld".equalsIgnoreCase(ext)) { - log.warn("TLD files should not be placed in " - + "/WEB-INF/lib"); - } - continue; - } - try { - File libFile = new File(lib, libs[i]); - classPath = classPath + File.pathSeparator - + libFile.getAbsolutePath(); - urls.add(libFile.getAbsoluteFile().toURI().toURL()); - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - } - } - } - - URL urlsA[]=new URL[urls.size()]; - urls.toArray(urlsA); - loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); - return loader; - } - - /** - * Find the WEB-INF dir by looking up in the directory tree. - * This is used if no explicit docbase is set, but only files. - * XXX Maybe we should require the docbase. - */ - protected void locateUriRoot( File f ) { - String tUriBase = uriBase; - if (tUriBase == null) { - tUriBase = "/"; - } - try { - if (f.exists()) { - f = new File(f.getAbsolutePath()); - while (true) { - File g = new File(f, "WEB-INF"); - if (g.exists() && g.isDirectory()) { - uriRoot = f.getCanonicalPath(); - uriBase = tUriBase; - if (log.isInfoEnabled()) { - log.info(Localizer.getMessage( - "jspc.implicit.uriRoot", - uriRoot)); - } - break; - } - if (f.exists() && f.isDirectory()) { - tUriBase = "/" + f.getName() + "/" + tUriBase; - } - - String fParent = f.getParent(); - if (fParent == null) { - break; - } else { - f = new File(fParent); - } - - // If there is no acceptable candidate, uriRoot will - // remain null to indicate to the CompilerContext to - // use the current working/user dir. - } - - if (uriRoot != null) { - File froot = new File(uriRoot); - uriRoot = froot.getCanonicalPath(); - } - } - } catch (IOException ioe) { - // since this is an optional default and a null value - // for uriRoot has a non-error meaning, we can just - // pass straight through - } - } - - /** - * Resolves the relative or absolute pathname correctly - * in both Ant and command-line situations. If Ant launched - * us, we should use the basedir of the current project - * to resolve relative paths. - * - * See Bugzilla 35571. - * - * @param s The file - * @return The file resolved - */ - protected File resolveFile(final String s) { - // TODO consider some massaging of s as relative path to project home - return new File(s); - } - - private Reader openWebxmlReader(File file) throws IOException { - FileInputStream fis = new FileInputStream(file); - try { - return webxmlEncoding != null ? new InputStreamReader(fis, - webxmlEncoding) : new InputStreamReader(fis); - } catch (IOException ex) { - fis.close(); - throw ex; - } - } - - private Writer openWebxmlWriter(File file) throws IOException { - FileOutputStream fos = new FileOutputStream(file); - try { - return webxmlEncoding != null ? new OutputStreamWriter(fos, - webxmlEncoding) : new OutputStreamWriter(fos); - } catch (IOException ex) { - fos.close(); - throw ex; - } - } -} diff --git a/1.x/src/jasper7-6x/JspCServletContext.java b/1.x/src/jasper7-6x/JspCServletContext.java deleted file mode 100644 index 282d73b..0000000 --- a/1.x/src/jasper7-6x/JspCServletContext.java +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.servlet; - - -import java.io.File; -import java.io.InputStream; -import java.io.PrintWriter; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.EnumSet; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Map; -import java.util.Set; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; - -import javax.servlet.Filter; -import javax.servlet.FilterRegistration; -import javax.servlet.FilterRegistration.Dynamic; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.descriptor.JspConfigDescriptor; - -import org.apache.jasper.JasperException; -import org.apache.jasper.util.ExceptionUtils; - - -/** - * Simple ServletContext implementation without - * HTTP-specific methods. - * - * @author Peter Rossbach (pr@webapp.de) - */ - -public class JspCServletContext implements ServletContext { - - - // ----------------------------------------------------- Instance Variables - - - /** - * Servlet context attributes. - */ - protected Hashtable myAttributes; - - - /** - * Servlet context initialization parameters. - */ - private final ConcurrentHashMap myParameters; - - - /** - * The log writer we will write log messages to. - */ - protected PrintWriter myLogWriter; - - - /** - * The base URL (document root) for this context. - */ - protected URL myResourceBaseURL; - - - /** - * Web application class loader. - */ - private final ClassLoader loader; - - - // ----------------------------------------------------------- Constructors - - /** - * Create a new instance of this ServletContext implementation. - * - * @param aLogWriter PrintWriter which is used for log() calls - * @param aResourceBaseURL Resource base URL - */ - public JspCServletContext(PrintWriter aLogWriter, URL aResourceBaseURL, ClassLoader classLoader) - throws JasperException { - - myAttributes = new Hashtable(); - myParameters = new ConcurrentHashMap(); - myLogWriter = aLogWriter; - myResourceBaseURL = aResourceBaseURL; - this.loader = classLoader; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the specified context attribute, if any. - * - * @param name Name of the requested attribute - */ - @Override - public Object getAttribute(String name) { - - return (myAttributes.get(name)); - - } - - - /** - * Return an enumeration of context attribute names. - */ - @Override - public Enumeration getAttributeNames() { - - return (myAttributes.keys()); - - } - - - /** - * Return the servlet context for the specified path. - * - * @param uripath Server-relative path starting with '/' - */ - @Override - public ServletContext getContext(String uripath) { - - return (null); - - } - - - /** - * Return the context path. - */ - @Override - public String getContextPath() { - - return (null); - - } - - - /** - * Return the specified context initialization parameter. - * - * @param name Name of the requested parameter - */ - @Override - public String getInitParameter(String name) { - return myParameters.get(name); - } - - - /** - * Return an enumeration of the names of context initialization - * parameters. - */ - @Override - public Enumeration getInitParameterNames() { - return myParameters.keys(); - } - - - /** - * Return the Servlet API major version number. - */ - @Override - public int getMajorVersion() { - - return (3); - - } - - - /** - * Return the MIME type for the specified filename. - * - * @param file Filename whose MIME type is requested - */ - @Override - public String getMimeType(String file) { - - return (null); - - } - - - /** - * Return the Servlet API minor version number. - */ - @Override - public int getMinorVersion() { - - return (0); - - } - - - /** - * Return a request dispatcher for the specified servlet name. - * - * @param name Name of the requested servlet - */ - @Override - public RequestDispatcher getNamedDispatcher(String name) { - - return (null); - - } - - - /** - * Return the real path for the specified context-relative - * virtual path. - * - * @param path The context-relative virtual path to resolve - */ - @Override - public String getRealPath(String path) { - - if (!myResourceBaseURL.getProtocol().equals("file")) - return null; - if (!path.startsWith("/")) - return null; - try { - File f = new File(getResource(path).toURI()); - return f.getAbsolutePath(); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - return null; - } - } - - - /** - * Return a request dispatcher for the specified context-relative path. - * - * @param path Context-relative path for which to acquire a dispatcher - */ - @Override - public RequestDispatcher getRequestDispatcher(String path) { - - return (null); - - } - - - /** - * Return a URL object of a resource that is mapped to the - * specified context-relative path. - * - * @param path Context-relative path of the desired resource - * - * @exception MalformedURLException if the resource path is - * not properly formed - */ - @Override - public URL getResource(String path) throws MalformedURLException { - - if (!path.startsWith("/")) - throw new MalformedURLException("Path '" + path + - "' does not start with '/'"); - URL url = new URL(myResourceBaseURL, path.substring(1)); - InputStream is = null; - try { - is = url.openStream(); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - url = null; - } finally { - if (is != null) { - try { - is.close(); - } catch (Throwable t2) { - ExceptionUtils.handleThrowable(t2); - } - } - } - return url; - - } - - - /** - * Return an InputStream allowing access to the resource at the - * specified context-relative path. - * - * @param path Context-relative path of the desired resource - */ - @Override - public InputStream getResourceAsStream(String path) { - - try { - return (getResource(path).openStream()); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - return (null); - } - - } - - - /** - * Return the set of resource paths for the "directory" at the - * specified context path. - * - * @param path Context-relative base path - */ - @Override - public Set getResourcePaths(String path) { - - Set thePaths = new HashSet(); - if (!path.endsWith("/")) - path += "/"; - String basePath = getRealPath(path); - if (basePath == null) - return (thePaths); - File theBaseDir = new File(basePath); - if (!theBaseDir.exists() || !theBaseDir.isDirectory()) - return (thePaths); - String theFiles[] = theBaseDir.list(); - for (int i = 0; i < theFiles.length; i++) { - File testFile = new File(basePath + File.separator + theFiles[i]); - if (testFile.isFile()) - thePaths.add(path + theFiles[i]); - else if (testFile.isDirectory()) - thePaths.add(path + theFiles[i] + "/"); - } - return (thePaths); - - } - - - /** - * Return descriptive information about this server. - */ - @Override - public String getServerInfo() { - - return ("JspCServletContext/1.0"); - - } - - - /** - * Return a null reference for the specified servlet name. - * - * @param name Name of the requested servlet - * - * @deprecated This method has been deprecated with no replacement - */ - @Override - @Deprecated - public Servlet getServlet(String name) throws ServletException { - - return (null); - - } - - - /** - * Return the name of this servlet context. - */ - @Override - public String getServletContextName() { - - return (getServerInfo()); - - } - - - /** - * Return an empty enumeration of servlet names. - * - * @deprecated This method has been deprecated with no replacement - */ - @Override - @Deprecated - public Enumeration getServletNames() { - - return (new Vector().elements()); - - } - - - /** - * Return an empty enumeration of servlets. - * - * @deprecated This method has been deprecated with no replacement - */ - @Override - @Deprecated - public Enumeration getServlets() { - - return (new Vector().elements()); - - } - - - /** - * Log the specified message. - * - * @param message The message to be logged - */ - @Override - public void log(String message) { - - myLogWriter.println(message); - - } - - - /** - * Log the specified message and exception. - * - * @param exception The exception to be logged - * @param message The message to be logged - * - * @deprecated Use log(String,Throwable) instead - */ - @Override - @Deprecated - public void log(Exception exception, String message) { - - log(message, exception); - - } - - - /** - * Log the specified message and exception. - * - * @param message The message to be logged - * @param exception The exception to be logged - */ - @Override - public void log(String message, Throwable exception) { - - myLogWriter.println(message); - exception.printStackTrace(myLogWriter); - - } - - - /** - * Remove the specified context attribute. - * - * @param name Name of the attribute to remove - */ - @Override - public void removeAttribute(String name) { - - myAttributes.remove(name); - - } - - - /** - * Set or replace the specified context attribute. - * - * @param name Name of the context attribute to set - * @param value Corresponding attribute value - */ - @Override - public void setAttribute(String name, Object value) { - - myAttributes.put(name, value); - - } - - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, - String className) { - return null; - } - - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, - String className) { - return null; - } - - - @Override - public Set getDefaultSessionTrackingModes() { - return EnumSet.noneOf(SessionTrackingMode.class); - } - - - @Override - public Set getEffectiveSessionTrackingModes() { - return EnumSet.noneOf(SessionTrackingMode.class); - } - - - @Override - public SessionCookieConfig getSessionCookieConfig() { - return null; - } - - - @Override - public void setSessionTrackingModes( - Set sessionTrackingModes) { - // Do nothing - } - - - @Override - public Dynamic addFilter(String filterName, Filter filter) { - return null; - } - - - @Override - public Dynamic addFilter(String filterName, - Class filterClass) { - return null; - } - - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, - Servlet servlet) { - return null; - } - - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, - Class servletClass) { - return null; - } - - - @Override - public T createFilter(Class c) - throws ServletException { - return null; - } - - - @Override - public T createServlet(Class c) - throws ServletException { - return null; - } - - - @Override - public FilterRegistration getFilterRegistration(String filterName) { - return null; - } - - - @Override - public ServletRegistration getServletRegistration(String servletName) { - return null; - } - - - @Override - public boolean setInitParameter(String name, String value) { - return myParameters.putIfAbsent(name, value) == null; - } - - - @Override - public void addListener(Class listenerClass) { - // NOOP - } - - - @Override - public void addListener(String className) { - // NOOP - } - - - @Override - public void addListener(T t) { - // NOOP - } - - - @Override - public T createListener(Class c) - throws ServletException { - return null; - } - - - @Override - public void declareRoles(String... roleNames) { - // NOOP - } - - - @Override - public ClassLoader getClassLoader() { - return loader; - } - - - @Override - public int getEffectiveMajorVersion() { - return 3; - } - - - @Override - public int getEffectiveMinorVersion() { - return 0; - } - - - @Override - public Map getFilterRegistrations() { - return null; - } - - - @Override - public JspConfigDescriptor getJspConfigDescriptor() { - return null; - } - - - @Override - public Map getServletRegistrations() { - return null; - } - - //@Override - public String getVirtualServerName() { - throw new UnsupportedOperationException("TJWS will do it"); - } - -} diff --git a/1.x/src/jasper7-6x/JspCompilationContext.java b/1.x/src/jasper7-6x/JspCompilationContext.java deleted file mode 100644 index a4bfbe7..0000000 --- a/1.x/src/jasper7-6x/JspCompilationContext.java +++ /dev/null @@ -1,821 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JarResource; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.JspUtil; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.ServletWriter; -import org.apache.jasper.compiler.TldLocation; -import org.apache.jasper.servlet.JasperLoader; -import org.apache.jasper.servlet.JspServletWrapper; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * A place holder for various things that are used through out the JSP - * engine. This is a per-request/per-context data structure. Some of - * the instance variables are set at different points. - * - * Most of the path-related stuff is here - mangling names, versions, dirs, - * loading resources and dealing with uris. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Pierre Delisle - * @author Costin Manolache - * @author Kin-man Chung - */ -public class JspCompilationContext { - - private final Log log = LogFactory.getLog(JspCompilationContext.class); // must not be static - - protected Map tagFileJarUrls; - - protected String className; - protected String jspUri; - protected String basePackageName; - protected String derivedPackageName; - protected String servletJavaFileName; - protected String javaPath; - protected String classFileName; - protected ServletWriter writer; - protected Options options; - protected JspServletWrapper jsw; - protected Compiler jspCompiler; - protected String classPath; - - protected String baseURI; - protected String outputDir; - protected ServletContext context; - protected ClassLoader loader; - - protected JspRuntimeContext rctxt; - - protected volatile int removed = 0; - - protected URLClassLoader jspLoader; - protected URL baseUrl; - protected Class servletClass; - - protected boolean isTagFile; - protected boolean protoTypeMode; - protected TagInfo tagInfo; - protected JarResource tagJarResource; - - // jspURI _must_ be relative to the context - public JspCompilationContext(String jspUri, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt) { - - this.jspUri = canonicalURI(jspUri); - this.options = options; - this.jsw = jsw; - this.context = context; - - this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); - // hack fix for resolveRelativeURI - if (baseURI == null) { - baseURI = "/"; - } else if (baseURI.charAt(0) != '/') { - // strip the base slash since it will be combined with the - // uriBase to generate a file - baseURI = "/" + baseURI; - } - if (baseURI.charAt(baseURI.length() - 1) != '/') { - baseURI += '/'; - } - - this.rctxt = rctxt; - this.tagFileJarUrls = new HashMap(); - this.basePackageName = Constants.JSP_PACKAGE_NAME; - } - - public JspCompilationContext(String tagfile, - TagInfo tagInfo, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt, - JarResource tagJarResource) { - this(tagfile, options, context, jsw, rctxt); - this.isTagFile = true; - this.tagInfo = tagInfo; - this.tagJarResource = tagJarResource; - } - - /* ==================== Methods to override ==================== */ - - /** ---------- Class path and loader ---------- */ - - /** - * The classpath that is passed off to the Java compiler. - */ - public String getClassPath() { - if( classPath != null ) { - return classPath; - } - return rctxt.getClassPath(); - } - - /** - * The classpath that is passed off to the Java compiler. - */ - public void setClassPath(String classPath) { - this.classPath = classPath; - } - - /** - * What class loader to use for loading classes while compiling - * this JSP? - */ - public ClassLoader getClassLoader() { - if( loader != null ) { - return loader; - } - return rctxt.getParentClassLoader(); - } - - public void setClassLoader(ClassLoader loader) { - this.loader = loader; - } - - public ClassLoader getJspLoader() { - if( jspLoader == null ) { - jspLoader = new JasperLoader - (new URL[] {baseUrl}, - getClassLoader(), - rctxt.getPermissionCollection()); - } - return jspLoader; - } - - public void clearJspLoader() { - jspLoader = null; - } - - /** ---------- Input/Output ---------- */ - - /** - * The output directory to generate code into. The output directory - * is make up of the scratch directory, which is provide in Options, - * plus the directory derived from the package name. - */ - public String getOutputDir() { - if (outputDir == null) { - createOutputDir(); - } - - return outputDir; - } - - /** - * Create a "Compiler" object based on some init param data. This - * is not done yet. Right now we're just hardcoding the actual - * compilers that are created. - */ - public Compiler createCompiler() { - if (jspCompiler != null ) { - return jspCompiler; - } - jspCompiler = null; - jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); - if (jspCompiler == null) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); - } - jspCompiler.init(this, jsw); - return jspCompiler; - } - - protected Compiler createCompiler(String className) { - Compiler compiler = null; - try { - compiler = (Compiler) Class.forName(className).newInstance(); - } catch (InstantiationException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (IllegalAccessException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (NoClassDefFoundError e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } catch (ClassNotFoundException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } - return compiler; - } - - public Compiler getCompiler() { - return jspCompiler; - } - - /** ---------- Access resources in the webapp ---------- */ - - /** - * Get the full value of a URI relative to this compilations context - * uses current file as the base. - */ - public String resolveRelativeUri(String uri) { - // sometimes we get uri's massaged from File(String), so check for - // a root directory separator char - if (uri.startsWith("/") || uri.startsWith(File.separator)) { - return uri; - } else { - return baseURI + uri; - } - } - - /** - * Gets a resource as a stream, relative to the meanings of this - * context's implementation. - * @return a null if the resource cannot be found or represented - * as an InputStream. - */ - public java.io.InputStream getResourceAsStream(String res) { - return context.getResourceAsStream(canonicalURI(res)); - } - - - public URL getResource(String res) throws MalformedURLException { - URL result = null; - - if (res.startsWith("/META-INF/")) { - // This is a tag file packaged in a jar that is being compiled - JarResource jarResource = tagFileJarUrls.get(res); - if (jarResource == null) { - jarResource = tagJarResource; - } - if (jarResource != null) { - result = jarResource.getEntry(res.substring(1)); - } else { - // May not be in a JAR in some IDE environments - result = context.getResource(canonicalURI(res)); - } - } else if (res.startsWith("jar:jndi:")) { - // This is a tag file packaged in a jar that is being checked - // for a dependency - result = new URL(res); - - } else { - result = context.getResource(canonicalURI(res)); - } - return result; - } - - - public Set getResourcePaths(String path) { - return context.getResourcePaths(canonicalURI(path)); - } - - /** - * Gets the actual path of a URI relative to the context of - * the compilation. - */ - public String getRealPath(String path) { - if (context != null) { - return context.getRealPath(path); - } - return path; - } - - /** - * Returns the tag-file-name-to-JAR-file map of this compilation unit, - * which maps tag file names to the JAR files in which the tag files are - * packaged. - * - * The map is populated when parsing the tag-file elements of the TLDs - * of any imported taglibs. - */ - public JarResource getTagFileJarResource(String tagFile) { - return this.tagFileJarUrls.get(tagFile); - } - - public void setTagFileJarResource(String tagFile, JarResource jarResource) { - this.tagFileJarUrls.put(tagFile, jarResource); - } - - /** - * Returns the JAR file in which the tag file for which this - * JspCompilationContext was created is packaged, or null if this - * JspCompilationContext does not correspond to a tag file, or if the - * corresponding tag file is not packaged in a JAR. - */ - public JarResource getTagFileJarResource() { - return this.tagJarResource; - } - - /* ==================== Common implementation ==================== */ - - /** - * Just the class name (does not include package name) of the - * generated class. - */ - public String getServletClassName() { - - if (className != null) { - return className; - } - - if (isTagFile) { - className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - if (lastIndex != -1) { - className = className.substring(lastIndex + 1); - } - } else { - int iSep = jspUri.lastIndexOf('/') + 1; - className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); - } - return className; - } - - public void setServletClassName(String className) { - this.className = className; - } - - /** - * Path of the JSP URI. Note that this is not a file name. This is - * the context rooted URI of the JSP file. - */ - public String getJspFile() { - return jspUri; - } - - /** - * @deprecated Will be removed in Tomcat 8.0.x. Use - * {@link #getLastModified(String)} instead. - */ - @Deprecated - public long getJspLastModified() { - long result = -1; - URLConnection uc = null; - try { - URL jspUrl = getResource(getJspFile()); - if (jspUrl == null) { - incrementRemoved(); - return result; - } - uc = jspUrl.openConnection(); - if (uc instanceof JarURLConnection) { - result = ((JarURLConnection) uc).getJarEntry().getTime(); - } else { - result = uc.getLastModified(); - } - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } finally { - if (uc != null) { - try { - uc.getInputStream().close(); - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } - } - } - return result; - } - - - public Long getLastModified(String resource) { - long result = -1; - if (resource.startsWith("file:/")) { - File f; - try { - f = new File(new URI(resource)); - } catch (URISyntaxException e) { - return Long.valueOf(-1); - } - return Long.valueOf(f.lastModified()); - } - - URLConnection uc = null; - try { - URL jspUrl = getResource(resource); - if (jspUrl == null) { - incrementRemoved(); - return Long.valueOf(result); - } - File resFile = new File(jspUrl.getFile()); // TJWS on Android - if (resFile.exists()) { - result = resFile.lastModified(); - //System.err.printf("Android for %s is %d%n", jspUrl, result); - } else { - uc = jspUrl.openConnection(); - if (uc instanceof JarURLConnection) { - result = ((JarURLConnection) uc).getJarEntry().getTime(); - } else { - result = uc.getLastModified(); - } - } - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } finally { - if (uc != null) { - try { - uc.getInputStream().close(); - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } - } - } - return Long.valueOf(result); - } - - public boolean isTagFile() { - return isTagFile; - } - - public TagInfo getTagInfo() { - return tagInfo; - } - - public void setTagInfo(TagInfo tagi) { - tagInfo = tagi; - } - - /** - * True if we are compiling a tag file in prototype mode. - * ie we only generate codes with class for the tag handler with empty - * method bodies. - */ - public boolean isPrototypeMode() { - return protoTypeMode; - } - - public void setPrototypeMode(boolean pm) { - protoTypeMode = pm; - } - - /** - * Package name for the generated class is make up of the base package - * name, which is user settable, and the derived package name. The - * derived package name directly mirrors the file hierarchy of the JSP page. - */ - public String getServletPackageName() { - if (isTagFile()) { - String className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - String pkgName = ""; - if (lastIndex != -1) { - pkgName = className.substring(0, lastIndex); - } - return pkgName; - } else { - String dPackageName = getDerivedPackageName(); - if (dPackageName.length() == 0) { - return basePackageName; - } - return basePackageName + '.' + getDerivedPackageName(); - } - } - - protected String getDerivedPackageName() { - if (derivedPackageName == null) { - int iSep = jspUri.lastIndexOf('/'); - derivedPackageName = (iSep > 0) ? - JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : ""; - } - return derivedPackageName; - } - - /** - * The package name into which the servlet class is generated. - */ - public void setServletPackageName(String servletPackageName) { - this.basePackageName = servletPackageName; - } - - /** - * Full path name of the Java file into which the servlet is being - * generated. - */ - public String getServletJavaFileName() { - if (servletJavaFileName == null) { - servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; - } - return servletJavaFileName; - } - - /** - * Get hold of the Options object for this context. - */ - public Options getOptions() { - return options; - } - - public ServletContext getServletContext() { - return context; - } - - public JspRuntimeContext getRuntimeContext() { - return rctxt; - } - - /** - * Path of the Java file relative to the work directory. - */ - public String getJavaPath() { - - if (javaPath != null) { - return javaPath; - } - - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - javaPath = tagName.replace('.', '/') + ".java"; - } else { - javaPath = getServletPackageName().replace('.', '/') + '/' + - getServletClassName() + ".java"; - } - return javaPath; - } - - public String getClassFileName() { - if (classFileName == null) { - classFileName = getOutputDir() + getServletClassName() + ".class"; - } - return classFileName; - } - - /** - * Where is the servlet being generated? - */ - public ServletWriter getWriter() { - return writer; - } - - public void setWriter(ServletWriter writer) { - this.writer = writer; - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the given uri is not associated with any tag library - * 'exposed' in the web application. - */ - public TldLocation getTldLocation(String uri) throws JasperException { - TldLocation location = - getOptions().getTldLocationsCache().getLocation(uri); - return location; - } - - /** - * Are we keeping generated code around? - */ - public boolean keepGenerated() { - return getOptions().getKeepGenerated(); - } - - // ==================== Removal ==================== - - public void incrementRemoved() { - if (removed == 0 && rctxt != null) { - rctxt.removeWrapper(jspUri); - } - removed++; - } - - public boolean isRemoved() { - if (removed > 0 ) { - return true; - } - return false; - } - - // ==================== Compile and reload ==================== - - public void compile() throws JasperException, FileNotFoundException { - createCompiler(); - if (jspCompiler.isOutDated()) { - if (isRemoved()) { - throw new FileNotFoundException(jspUri); - } - try { - jspCompiler.removeGeneratedFiles(); - jspLoader = null; - jspCompiler.compile(); - jsw.setReload(true); - jsw.setCompilationException(null); - } catch (JasperException ex) { - // Cache compilation exception - jsw.setCompilationException(ex); - if (options.getDevelopment() && options.getRecompileOnFail()) { - // Force a recompilation attempt on next access - jsw.setLastModificationTest(-1); - } - throw ex; - } catch (FileNotFoundException fnfe) { - // Re-throw to let caller handle this - will result in a 404 - throw fnfe; - } catch (Exception ex) { - JasperException je = new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), - ex); - // Cache compilation exception - jsw.setCompilationException(je); - throw je; - } - } - } - - // ==================== Manipulating the class ==================== - - public Class load() throws JasperException { - try { - getJspLoader(); - - String name = getFQCN(); - servletClass = jspLoader.loadClass(name); - } catch (ClassNotFoundException cex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), - cex); - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), - ex); - } - removed = 0; - return servletClass; - } - - public String getFQCN() { - String name; - if (isTagFile()) { - name = tagInfo.getTagClassName(); - } else { - name = getServletPackageName() + "." + getServletClassName(); - } - return name; - } - - // ==================== protected methods ==================== - - static Object outputDirLock = new Object(); - - public void checkOutputDir() { - if (outputDir != null) { - if (!(new File(outputDir)).exists()) { - makeOutputDir(); - } - } else { - createOutputDir(); - } - } - - protected boolean makeOutputDir() { - synchronized(outputDirLock) { - File outDirFile = new File(outputDir); - return (outDirFile.mkdirs() || outDirFile.isDirectory()); - } - } - - protected void createOutputDir() { - String path = null; - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - path = tagName.replace('.', File.separatorChar); - path = path.substring(0, path.lastIndexOf(File.separatorChar)); - } else { - path = getServletPackageName().replace('.',File.separatorChar); - } - - // Append servlet or tag handler path to scratch dir - try { - File base = options.getScratchDir(); - baseUrl = base.toURI().toURL(); - outputDir = base.getAbsolutePath() + File.separator + path + - File.separator; - if (!makeOutputDir()) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); - } - } catch (MalformedURLException e) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); - } - } - - protected static final boolean isPathSeparator(char c) { - return (c == '/' || c == '\\'); - } - - protected static final String canonicalURI(String s) { - if (s == null) { - return null; - } - StringBuilder result = new StringBuilder(); - final int len = s.length(); - int pos = 0; - while (pos < len) { - char c = s.charAt(pos); - if ( isPathSeparator(c) ) { - /* - * multiple path separators. - * 'foo///bar' -> 'foo/bar' - */ - while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) { - ++pos; - } - - if (pos+1 < len && s.charAt(pos+1) == '.') { - /* - * a single dot at the end of the path - we are done. - */ - if (pos+2 >= len) { - break; - } - - switch (s.charAt(pos+2)) { - /* - * self directory in path - * foo/./bar -> foo/bar - */ - case '/': - case '\\': - pos += 2; - continue; - - /* - * two dots in a path: go back one hierarchy. - * foo/bar/../baz -> foo/baz - */ - case '.': - // only if we have exactly _two_ dots. - if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) { - pos += 3; - int separatorPos = result.length()-1; - while (separatorPos >= 0 && - ! isPathSeparator(result - .charAt(separatorPos))) { - --separatorPos; - } - if (separatorPos >= 0) { - result.setLength(separatorPos); - } - continue; - } - } - } - } - result.append(c); - ++pos; - } - return result.toString(); - } -} - diff --git a/1.x/src/jasper7-6x/SimpleInstanceManager.java b/1.x/src/jasper7-6x/SimpleInstanceManager.java deleted file mode 100644 index e6f64ad..0000000 --- a/1.x/src/jasper7-6x/SimpleInstanceManager.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.apache.jasper.tjws; - -import java.lang.reflect.InvocationTargetException; -import javax.naming.NamingException; -import org.apache.tomcat.InstanceManager; - -public class SimpleInstanceManager implements InstanceManager { - - public Object newInstance(Class clazz) - throws IllegalAccessException, InvocationTargetException, NamingException, - InstantiationException { - return clazz.newInstance(); - } - - - public Object newInstance(String className) throws IllegalAccessException, - InvocationTargetException, NamingException, InstantiationException, - ClassNotFoundException { - return Class.forName(className).newInstance(); - } - - public Object newInstance(String fqcn, ClassLoader classLoader) - throws IllegalAccessException, InvocationTargetException, - NamingException, InstantiationException, ClassNotFoundException { - //System.err.printf("Requested new instance as %s with loader %s and parent %s%n", fqcn, classLoader, classLoader.getParent()); - try { - return Class.forName(fqcn, true, classLoader).newInstance(); - } catch (ClassNotFoundException cnfe) { - //System.err.printf("Exceprion %s%n", cnfe); - // trying parent loader for Android - } - return Class.forName(fqcn, true, classLoader.getParent()).newInstance(); - } - - public void newInstance(Object o) throws IllegalAccessException, - InvocationTargetException, NamingException { - //System.err.printf("New instance for object %s", o); - } - - public void destroyInstance(Object o) throws IllegalAccessException, - InvocationTargetException { - //System.err.printf("Destroying object %s", o); - } - -} \ No newline at end of file diff --git a/1.x/src/jasper7-6x/Util.java b/1.x/src/jasper7-6x/Util.java deleted file mode 100644 index 742f0fb..0000000 --- a/1.x/src/jasper7-6x/Util.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.util.Locale; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.JspTagException; -import javax.servlet.jsp.PageContext; - -import org.apache.jasper.Constants; - -/** - * Util contains some often used consts, static methods and embedded class - * to support the JSTL tag plugin. - */ - -public class Util { - - public static final String VALID_SCHEME_CHAR = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-"; - - public static final String DEFAULT_ENCODING = - "ISO-8859-1"; - - public static final int HIGHEST_SPECIAL = '>'; - - private static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][]; - - static { - specialCharactersRepresentation['&'] = "&".toCharArray(); - specialCharactersRepresentation['<'] = "<".toCharArray(); - specialCharactersRepresentation['>'] = ">".toCharArray(); - specialCharactersRepresentation['"'] = """.toCharArray(); - specialCharactersRepresentation['\''] = "'".toCharArray(); - } - - /** - * Converts the given string description of a scope to the corresponding - * PageContext constant. - * - * The validity of the given scope has already been checked by the - * appropriate TLV. - * - * @param scope String description of scope - * - * @return PageContext constant corresponding to given scope description - * - * taken from org.apache.taglibs.standard.tag.common.core.Util - */ - public static int getScope(String scope){ - int ret = PageContext.PAGE_SCOPE; - - if("request".equalsIgnoreCase(scope)){ - ret = PageContext.REQUEST_SCOPE; - }else if("session".equalsIgnoreCase(scope)){ - ret = PageContext.SESSION_SCOPE; - }else if("application".equalsIgnoreCase(scope)){ - ret = PageContext.APPLICATION_SCOPE; - } - - return ret; - } - - /** - * Returns true if our current URL is absolute, - * false otherwise. - * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport - */ - public static boolean isAbsoluteUrl(String url){ - if(url == null){ - return false; - } - - int colonPos = url.indexOf(":"); - if(colonPos == -1){ - return false; - } - - for(int i=0;iurl
. The session ID - * is encoded as a URL "path parameter" beginning with "jsessionid=". - * We thus remove anything we find between ";jsessionid=" (inclusive) - * and either EOS or a subsequent ';' (exclusive). - * - * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport - */ - public static String stripSession(String url) { - StringBuilder u = new StringBuilder(url); - int sessionStart; - while ((sessionStart = u.toString().indexOf(";" + Constants.SESSION_PARAMETER_NAME + "=")) != -1) { - int sessionEnd = u.toString().indexOf(";", sessionStart + 1); - if (sessionEnd == -1) - sessionEnd = u.toString().indexOf("?", sessionStart + 1); - if (sessionEnd == -1) // still - sessionEnd = u.length(); - u.delete(sessionStart, sessionEnd); - } - return u.toString(); - } - - - /** - * Performs the following substring replacements - * (to facilitate output to XML/HTML pages): - * - * & -> & - * < -> < - * > -> > - * " -> " - * ' -> ' - * - * See also OutSupport.writeEscapedXml(). - * - * taken from org.apache.taglibs.standard.tag.common.core.Util - */ - public static String escapeXml(String buffer) { - String result = escapeXml(buffer.toCharArray(), buffer.length()); - if (result == null) { - return buffer; - } else { - return result; - } - } - - @SuppressWarnings("null") // escapedBuffer cannot be null - public static String escapeXml(char[] arrayBuffer, int length) { - int start = 0; - StringBuilder escapedBuffer = null; - - for (int i = 0; i < length; i++) { - char c = arrayBuffer[i]; - if (c <= HIGHEST_SPECIAL) { - char[] escaped = specialCharactersRepresentation[c]; - if (escaped != null) { - // create StringBuilder to hold escaped xml string - if (start == 0) { - escapedBuffer = new StringBuilder(length + 5); - } - // add unescaped portion - if (start < i) { - escapedBuffer.append(arrayBuffer,start,i-start); - } - start = i + 1; - // add escaped xml - escapedBuffer.append(escaped); - } - } - } - // no xml escaping was necessary - if (start == 0) { - return null; - } - // add rest of unescaped portion - if (start < length) { - escapedBuffer.append(arrayBuffer,start,length-start); - } - return escapedBuffer.toString(); - } - - /** Utility methods - * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport - */ - public static String resolveUrl( - String url, String context, PageContext pageContext) - throws JspException { - // don't touch absolute URLs - if (isAbsoluteUrl(url)) - return url; - - // normalize relative URLs against a context root - HttpServletRequest request = - (HttpServletRequest) pageContext.getRequest(); - if (context == null) { - if (url.startsWith("/")) - return (request.getContextPath() + url); - else - return url; - } else { - if (!context.startsWith("/") || !url.startsWith("/")) { - throw new JspTagException( - "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\"."); - } - if (context.equals("/")) { - // Don't produce string starting with '//', many - // browsers interpret this as host name, not as - // path on same host. - return url; - } else { - return (context + url); - } - } - } - - /** Wraps responses to allow us to retrieve results as Strings. - * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport - */ - public static class ImportResponseWrapper extends HttpServletResponseWrapper{ - - private StringWriter sw = new StringWriter(); - private ByteArrayOutputStream bos = new ByteArrayOutputStream(); - private ServletOutputStream sos = new ServletOutputStream() { - @Override - public void write(int b) throws IOException { - bos.write(b); - } - // @Override - public void setWriteListener(javax.servlet.WriteListener writeListener) { - // TODO implement it, or borrow from Tomcat 8 - } - // @Override - public boolean isReady() { - return true; - } - - }; - private boolean isWriterUsed; - private boolean isStreamUsed; - private int status = 200; - private String charEncoding; - - public ImportResponseWrapper(HttpServletResponse arg0) { - super(arg0); - // TODO Auto-generated constructor stub - } - - @Override - public PrintWriter getWriter() { - if (isStreamUsed) - throw new IllegalStateException("Unexpected internal error during <import>: " + - "Target servlet called getWriter(), then getOutputStream()"); - isWriterUsed = true; - return new PrintWriter(sw); - } - - @Override - public ServletOutputStream getOutputStream() { - if (isWriterUsed) - throw new IllegalStateException("Unexpected internal error during <import>: " + - "Target servlet called getOutputStream(), then getWriter()"); - isStreamUsed = true; - return sos; - } - - /** Has no effect. */ - @Override - public void setContentType(String x) { - // ignore - } - - /** Has no effect. */ - @Override - public void setLocale(Locale x) { - // ignore - } - - @Override - public void setStatus(int status) { - this.status = status; - } - - @Override - public int getStatus() { - return status; - } - - public String getCharEncoding(){ - return this.charEncoding; - } - - public void setCharEncoding(String ce){ - this.charEncoding = ce; - } - - public String getString() throws UnsupportedEncodingException { - if (isWriterUsed) - return sw.toString(); - else if (isStreamUsed) { - if (this.charEncoding != null && !this.charEncoding.equals("")) - return bos.toString(charEncoding); - else - return bos.toString("ISO-8859-1"); - } else - return ""; // target didn't write anything - } - - } - -} diff --git a/1.x/src/jasper7-6x/bee-jasper.xml b/1.x/src/jasper7-6x/bee-jasper.xml deleted file mode 100644 index 5314734..0000000 --- a/1.x/src/jasper7-6x/bee-jasper.xml +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - - - - - - ]> - - - - &env; - - - - - /bin/javac - - - - - - - /bin/javadoc - - - - - - ******** &project; Build Process ******** -********* Available targets: ************************************* -* compile - do Java compilation * -* jar - build &build_file; file * -* run - run application &main_class; * -******************************************************************* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /&build_directory; - - - - - - - - - - - - - - - - - - Compiling javax... - - - - - - - - - - > - - - - 0 - - - Error(s) at compilation of javax - - - - - - - - - Exception at compilation of javax - - - - - - - - - - - - - - - - - - - - - - Compiling... &project; - - - - - - - - - - > - - - - 0 - - - Error(s) at compilation of &project; - - - - - - - - - Exception at compilation of &project; - - - - - - - - - - &manifestf; - - - - - true - - - - -d - - -sourcepath - - -classpath - - &domain; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &source_directory;/javax/servlet/jsp/resources/jsp*.dtd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/jsp*.xsd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/web-jsp*.dtd - &build_directory;/javax/servlet/jsp/resources - &source_directory;/javax/servlet/jsp/resources/web-jsp*.xsd - &build_directory;/javax/servlet/jsp/resources - - &source_directory;/javax/servlet/resources/j2ee*.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/j2ee*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/javaee_*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/web-app*.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/web-*.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/datatypes.dtd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/xml.xsd - &build_directory;/javax/servlet/resources - &source_directory;/javax/servlet/resources/XMLSchema.dtd - &build_directory;/javax/servlet/resources - - - - - - - - - - - - - Jarring... - - - - - - - - - - - - - - - - - - - - - - - - - - -cf - - - - -cmf - - - - - - - - - - - - - - - java - org/apache/jasper/resources - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - - - -C - &source_directory; - - - - - - - - - - Exception at jarring - - - - - - - - - - - - - y - - - - - - - - - Cleaning... - - - - - - - - - - - /&build_directory;/&build_file; - - - - - /lib/tools.jar - - - - - Running... - - - - -classpath - - - - - - diff --git a/1.x/src/jasper7-6x/env.xml b/1.x/src/jasper7-6x/env.xml deleted file mode 100644 index 270b948..0000000 --- a/1.x/src/jasper7-6x/env.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - . - - - - - - - / - - - - - - - - - /jre - - - - - - - - - - - maven:javax.servlet:javax.servlet-api:3.1.0 - - 1.6 - - - - \\jre - - - - - - - - - diff --git a/1.x/src/jasper7-7x/EmbeddedServletOptions.java b/1.x/src/jasper7-7x/EmbeddedServletOptions.java deleted file mode 100644 index fae23f3..0000000 --- a/1.x/src/jasper7-7x/EmbeddedServletOptions.java +++ /dev/null @@ -1,789 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.util.Enumeration; -import java.util.Map; -import java.util.Properties; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagLibraryInfo; - -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * A class to hold all init parameters specific to the JSP engine. - * - * @author Anil K. Vijendran - * @author Hans Bergsten - * @author Pierre Delisle - */ -public final class EmbeddedServletOptions implements Options { - - // Logger - private final Log log = LogFactory.getLog(EmbeddedServletOptions.class); - - private Properties settings = new Properties(); - - /** - * Is Jasper being used in development mode? - */ - private boolean development = true; - - /** - * Should Ant fork its java compiles of JSP pages. - */ - public boolean fork = true; - - /** - * Do you want to keep the generated Java files around? - */ - private boolean keepGenerated = true; - - /** - * Should white spaces between directives or actions be trimmed? - */ - private boolean trimSpaces = false; - - /** - * Determines whether tag handler pooling is enabled. - */ - private boolean isPoolingEnabled = true; - - /** - * Do you want support for "mapped" files? This will generate - * servlet that has a print statement per line of the JSP file. - * This seems like a really nice feature to have for debugging. - */ - private boolean mappedFile = true; - - /** - * Do we want to include debugging information in the class file? - */ - private boolean classDebugInfo = true; - - /** - * Background compile thread check interval in seconds. - */ - private int checkInterval = 0; - - /** - * Is the generation of SMAP info for JSR45 debugging suppressed? - */ - private boolean isSmapSuppressed = false; - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - private boolean isSmapDumped = false; - - /** - * Are Text strings to be generated as char arrays? - */ - private boolean genStringAsCharArray = false; - - private boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * I want to see my generated servlets. Which directory are they - * in? - */ - private File scratchDir; - - /** - * Need to have this as is for versions 4 and 5 of IE. Can be set from - * the initParams so if it changes in the future all that is needed is - * to have a jsp initParam of type ieClassId="" - */ - private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - /** - * What classpath should I use while compiling generated servlets? - */ - private String classpath = null; - - /** - * Compiler to use. - */ - private String compiler = null; - - /** - * Compiler target VM. - */ - private String compilerTargetVM = "1.6"; - - /** - * The compiler source VM. - */ - private String compilerSourceVM = "1.6"; - - /** - * The compiler class name. - */ - private String compilerClassName = null; - - /** - * Cache for the TLD locations - */ - private TldLocationsCache tldLocationsCache = null; - - /** - * Jsp config information - */ - private JspConfig jspConfig = null; - - /** - * TagPluginManager - */ - private TagPluginManager tagPluginManager = null; - - /** - * Java platform encoding to generate the JSP - * page servlet. - */ - private String javaEncoding = "UTF8"; - - /** - * Modification test interval. - */ - private int modificationTestInterval = 4; - - /** - * Is re-compilation attempted immediately after a failure? - */ - private boolean recompileOnFail = false; - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - private boolean xpoweredBy; - - /** - * Should we include a source fragment in exception messages, which could be displayed - * to the developer ? - */ - private boolean displaySourceFragment = true; - - - /** - * The maximum number of loaded jsps per web-application. If there are more - * jsps loaded, they will be unloaded. - */ - private int maxLoadedJsps = -1; - - /** - * The idle time in seconds after which a JSP is unloaded. - * If unset or less or equal than 0, no jsps are unloaded. - */ - private int jspIdleTimeout = -1; - - /** - * When EL is used in JSP attribute values, should the rules for quoting of - * attributes described in JSP.1.6 be applied to the expression? - */ - private boolean quoteAttributeEL = true; - - public String getProperty(String name ) { - return settings.getProperty( name ); - } - - public void setProperty(String name, String value ) { - if (name != null && value != null){ - settings.setProperty( name, value ); - } - } - - public void setQuoteAttributeEL(boolean b) { - this.quoteAttributeEL = b; - } - - @Override - public boolean getQuoteAttributeEL() { - return quoteAttributeEL; - } - - /** - * Are we keeping generated code around? - */ - @Override - public boolean getKeepGenerated() { - return keepGenerated; - } - - /** - * Should white spaces between directives or actions be trimmed? - */ - @Override - public boolean getTrimSpaces() { - return trimSpaces; - } - - @Override - public boolean isPoolingEnabled() { - return isPoolingEnabled; - } - - /** - * Are we supporting HTML mapped servlets? - */ - @Override - public boolean getMappedFile() { - return mappedFile; - } - - /** - * Should class files be compiled with debug information? - */ - @Override - public boolean getClassDebugInfo() { - return classDebugInfo; - } - - /** - * Background JSP compile thread check interval - */ - @Override - public int getCheckInterval() { - return checkInterval; - } - - /** - * Modification test interval. - */ - @Override - public int getModificationTestInterval() { - return modificationTestInterval; - } - - /** - * Re-compile on failure. - */ - @Override - public boolean getRecompileOnFail() { - return recompileOnFail; - } - - /** - * Is Jasper being used in development mode? - */ - @Override - public boolean getDevelopment() { - return development; - } - - /** - * Is the generation of SMAP info for JSR45 debugging suppressed? - */ - @Override - public boolean isSmapSuppressed() { - return isSmapSuppressed; - } - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - @Override - public boolean isSmapDumped() { - return isSmapDumped; - } - - /** - * Are Text strings to be generated as char arrays? - */ - @Override - public boolean genStringAsCharArray() { - return this.genStringAsCharArray; - } - - /** - * Class ID for use in the plugin tag when the browser is IE. - */ - @Override - public String getIeClassId() { - return ieClassId; - } - - /** - * What is my scratch dir? - */ - @Override - public File getScratchDir() { - return scratchDir; - } - - /** - * What classpath should I use while compiling the servlets - * generated from JSP files? - */ - @Override - public String getClassPath() { - return classpath; - } - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - @Override - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Compiler to use. - */ - @Override - public String getCompiler() { - return compiler; - } - - /** - * @see Options#getCompilerTargetVM - */ - @Override - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * @see Options#getCompilerSourceVM - */ - @Override - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * Java compiler class to use. - */ - @Override - public String getCompilerClassName() { - return compilerClassName; - } - - @Override - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - @Override - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - public void setTldLocationsCache( TldLocationsCache tldC ) { - tldLocationsCache = tldC; - } - - @Override - public String getJavaEncoding() { - return javaEncoding; - } - - @Override - public boolean getFork() { - return fork; - } - - @Override - public JspConfig getJspConfig() { - return jspConfig; - } - - @Override - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - @Override - public boolean isCaching() { - return false; - } - - @Override - public Map getCache() { - return null; - } - - /** - * Should we include a source fragment in exception messages, which could be displayed - * to the developer ? - */ - @Override - public boolean getDisplaySourceFragment() { - return displaySourceFragment; - } - - /** - * Should jsps be unloaded if to many are loaded? - * If set to a value greater than 0 eviction of jsps is started. Default: -1 - */ - @Override - public int getMaxLoadedJsps() { - return maxLoadedJsps; - } - - /** - * Should any jsps be unloaded when being idle for this time in seconds? - * If set to a value greater than 0 eviction of jsps is started. Default: -1 - */ - @Override - public int getJspIdleTimeout() { - return jspIdleTimeout; - } - - /** - * Create an EmbeddedServletOptions object using data available from - * ServletConfig and ServletContext. - */ - public EmbeddedServletOptions(ServletConfig config, - ServletContext context) { - - Enumeration enumeration=config.getInitParameterNames(); - while( enumeration.hasMoreElements() ) { - String k=enumeration.nextElement(); - String v=config.getInitParameter( k ); - setProperty( k, v); - } - - String keepgen = config.getInitParameter("keepgenerated"); - if (keepgen != null) { - if (keepgen.equalsIgnoreCase("true")) { - this.keepGenerated = true; - } else if (keepgen.equalsIgnoreCase("false")) { - this.keepGenerated = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.keepgen")); - } - } - } - - - String trimsp = config.getInitParameter("trimSpaces"); - if (trimsp != null) { - if (trimsp.equalsIgnoreCase("true")) { - trimSpaces = true; - } else if (trimsp.equalsIgnoreCase("false")) { - trimSpaces = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.trimspaces")); - } - } - } - - this.isPoolingEnabled = true; - String poolingEnabledParam - = config.getInitParameter("enablePooling"); - if (poolingEnabledParam != null - && !poolingEnabledParam.equalsIgnoreCase("true")) { - if (poolingEnabledParam.equalsIgnoreCase("false")) { - this.isPoolingEnabled = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.enablePooling")); - } - } - } - - String mapFile = config.getInitParameter("mappedfile"); - if (mapFile != null) { - if (mapFile.equalsIgnoreCase("true")) { - this.mappedFile = true; - } else if (mapFile.equalsIgnoreCase("false")) { - this.mappedFile = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.mappedFile")); - } - } - } - - String debugInfo = config.getInitParameter("classdebuginfo"); - if (debugInfo != null) { - if (debugInfo.equalsIgnoreCase("true")) { - this.classDebugInfo = true; - } else if (debugInfo.equalsIgnoreCase("false")) { - this.classDebugInfo = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.classDebugInfo")); - } - } - } - - String checkInterval = config.getInitParameter("checkInterval"); - if (checkInterval != null) { - try { - this.checkInterval = Integer.parseInt(checkInterval); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.checkInterval")); - } - } - } - - String modificationTestInterval = config.getInitParameter("modificationTestInterval"); - if (modificationTestInterval != null) { - try { - this.modificationTestInterval = Integer.parseInt(modificationTestInterval); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval")); - } - } - } - - String recompileOnFail = config.getInitParameter("recompileOnFail"); - if (recompileOnFail != null) { - if (recompileOnFail.equalsIgnoreCase("true")) { - this.recompileOnFail = true; - } else if (recompileOnFail.equalsIgnoreCase("false")) { - this.recompileOnFail = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.recompileOnFail")); - } - } - } - String development = config.getInitParameter("development"); - if (development != null) { - if (development.equalsIgnoreCase("true")) { - this.development = true; - } else if (development.equalsIgnoreCase("false")) { - this.development = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.development")); - } - } - } - - String suppressSmap = config.getInitParameter("suppressSmap"); - if (suppressSmap != null) { - if (suppressSmap.equalsIgnoreCase("true")) { - isSmapSuppressed = true; - } else if (suppressSmap.equalsIgnoreCase("false")) { - isSmapSuppressed = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.suppressSmap")); - } - } - } - - String dumpSmap = config.getInitParameter("dumpSmap"); - if (dumpSmap != null) { - if (dumpSmap.equalsIgnoreCase("true")) { - isSmapDumped = true; - } else if (dumpSmap.equalsIgnoreCase("false")) { - isSmapDumped = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.dumpSmap")); - } - } - } - - String genCharArray = config.getInitParameter("genStringAsCharArray"); - if (genCharArray != null) { - if (genCharArray.equalsIgnoreCase("true")) { - genStringAsCharArray = true; - } else if (genCharArray.equalsIgnoreCase("false")) { - genStringAsCharArray = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.genchararray")); - } - } - } - - String errBeanClass = - config.getInitParameter("errorOnUseBeanInvalidClassAttribute"); - if (errBeanClass != null) { - if (errBeanClass.equalsIgnoreCase("true")) { - errorOnUseBeanInvalidClassAttribute = true; - } else if (errBeanClass.equalsIgnoreCase("false")) { - errorOnUseBeanInvalidClassAttribute = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.errBean")); - } - } - } - - String ieClassId = config.getInitParameter("ieClassId"); - if (ieClassId != null) - this.ieClassId = ieClassId; - - String classpath = config.getInitParameter("classpath"); - if (classpath != null) - this.classpath = classpath; - - /* - * scratchdir - */ - String dir = config.getInitParameter("scratchdir"); - if (dir != null && Constants.IS_SECURITY_ENABLED) { - log.info(Localizer.getMessage("jsp.info.ignoreSetting", "scratchdir", dir)); - dir = null; - } - if (dir != null) { - scratchDir = new File(dir); - } else { - // First try the Servlet 2.2 javax.servlet.context.tempdir property - scratchDir = (File) context.getAttribute(ServletContext.TEMPDIR); - if (scratchDir == null) { - // Not running in a Servlet 2.2 container. - // Try to get the JDK 1.2 java.io.tmpdir property - dir = System.getProperty("java.io.tmpdir"); - if (dir != null) - scratchDir = new File(dir); - } - } - if (this.scratchDir == null) { - log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir")); - return; - } - if (!scratchDir.exists()) // for TJWS force creation of scratchdir - scratchDir.mkdirs(); - if (!(scratchDir.exists() && scratchDir.canRead() && - scratchDir.canWrite() && scratchDir.isDirectory())) - log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir", - scratchDir.getAbsolutePath())); - - this.compiler = config.getInitParameter("compiler"); - - String compilerTargetVM = config.getInitParameter("compilerTargetVM"); - if(compilerTargetVM != null) { - this.compilerTargetVM = compilerTargetVM; - } - - String compilerSourceVM = config.getInitParameter("compilerSourceVM"); - if(compilerSourceVM != null) { - this.compilerSourceVM = compilerSourceVM; - } - - String javaEncoding = config.getInitParameter("javaEncoding"); - if (javaEncoding != null) { - this.javaEncoding = javaEncoding; - } - - String compilerClassName = config.getInitParameter("compilerClassName"); - if (compilerClassName != null) { - this.compilerClassName = compilerClassName; - } - - String fork = config.getInitParameter("fork"); - if (fork != null) { - if (fork.equalsIgnoreCase("true")) { - this.fork = true; - } else if (fork.equalsIgnoreCase("false")) { - this.fork = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.fork")); - } - } - } - - String xpoweredBy = config.getInitParameter("xpoweredBy"); - if (xpoweredBy != null) { - if (xpoweredBy.equalsIgnoreCase("true")) { - this.xpoweredBy = true; - } else if (xpoweredBy.equalsIgnoreCase("false")) { - this.xpoweredBy = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.xpoweredBy")); - } - } - } - - String displaySourceFragment = config.getInitParameter("displaySourceFragment"); - if (displaySourceFragment != null) { - if (displaySourceFragment.equalsIgnoreCase("true")) { - this.displaySourceFragment = true; - } else if (displaySourceFragment.equalsIgnoreCase("false")) { - this.displaySourceFragment = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.displaySourceFragment")); - } - } - } - - String maxLoadedJsps = config.getInitParameter("maxLoadedJsps"); - if (maxLoadedJsps != null) { - try { - this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps", ""+this.maxLoadedJsps)); - } - } - } - - String jspIdleTimeout = config.getInitParameter("jspIdleTimeout"); - if (jspIdleTimeout != null) { - try { - this.jspIdleTimeout = Integer.parseInt(jspIdleTimeout); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.jspIdleTimeout", ""+this.jspIdleTimeout)); - } - } - } - - String quoteAttributeEL = config.getInitParameter("quoteAttributeEL"); - if (quoteAttributeEL != null) { - if (quoteAttributeEL.equalsIgnoreCase("true")) { - this.quoteAttributeEL = true; - } else if (quoteAttributeEL.equalsIgnoreCase("false")) { - this.quoteAttributeEL = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.quoteAttributeEL")); - } - } - } - - // Setup the global Tag Libraries location cache for this - // web-application. - tldLocationsCache = TldLocationsCache.getInstance(context); - - // Setup the jsp config info for this web app. - jspConfig = new JspConfig(context); - - // Create a Tag plugin instance - tagPluginManager = new TagPluginManager(context); - } - -} - diff --git a/1.x/src/jasper7-7x/JspC.java b/1.x/src/jasper7-7x/JspC.java deleted file mode 100644 index 060de36..0000000 --- a/1.x/src/jasper7-7x/JspC.java +++ /dev/null @@ -1,1689 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.servlet.jsp.tagext.TagLibraryInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.servlet.JspCServletContext; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * Shell for the jspc compiler. Handles all options associated with the - * command line and creates compilation contexts which it then compiles - * according to the specified options. - * - * This version can process files from a _single_ webapp at once, i.e. - * a single docbase can be specified. - * - * It can be used as an Ant task using: - *
- *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
- *      <classpath>
- *          <pathelement location="${java.home}/../lib/tools.jar"/>
- *          <fileset dir="${ENV.CATALINA_HOME}/lib">
- *              <include name="*.jar"/>
- *          </fileset>
- *          <path refid="myjars"/>
- *       </classpath>
- *  </taskdef>
- *
- *  <jasper verbose="0"
- *           package="my.package"
- *           uriroot="${webapps.dir}/${webapp.name}"
- *           webXmlFragment="${build.dir}/generated_web.xml"
- *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
- * 
- * - * @author Danno Ferrin - * @author Pierre Delisle - * @author Costin Manolache - * @author Yoav Shapira - */ -public class JspC implements Options { - - public static final String DEFAULT_IE_CLASS_ID = - "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - // Logger - private static final Log log = LogFactory.getLog(JspC.class); - - protected static final String SWITCH_VERBOSE = "-v"; - protected static final String SWITCH_HELP = "-help"; - protected static final String SWITCH_OUTPUT_DIR = "-d"; - protected static final String SWITCH_PACKAGE_NAME = "-p"; - protected static final String SWITCH_CACHE = "-cache"; - protected static final String SWITCH_CLASS_NAME = "-c"; - protected static final String SWITCH_FULL_STOP = "--"; - protected static final String SWITCH_COMPILE = "-compile"; - protected static final String SWITCH_SOURCE = "-source"; - protected static final String SWITCH_TARGET = "-target"; - protected static final String SWITCH_URI_BASE = "-uribase"; - protected static final String SWITCH_URI_ROOT = "-uriroot"; - protected static final String SWITCH_FILE_WEBAPP = "-webapp"; - protected static final String SWITCH_WEBAPP_INC = "-webinc"; - protected static final String SWITCH_WEBAPP_XML = "-webxml"; - protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; - protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; - protected static final String SWITCH_MAPPED = "-mapped"; - protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; - protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; - protected static final String SWITCH_CLASSPATH = "-classpath"; - protected static final String SWITCH_DIE = "-die"; - protected static final String SWITCH_POOLING = "-poolingEnabled"; - protected static final String SWITCH_ENCODING = "-javaEncoding"; - protected static final String SWITCH_SMAP = "-smap"; - protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; - protected static final String SWITCH_VALIDATE_TLD = "-validateTld"; - protected static final String SWITCH_VALIDATE_XML = "-validateXml"; - protected static final String SWITCH_BLOCK_EXTERNAL = "-blockExternal"; - protected static final String SWITCH_NO_BLOCK_EXTERNAL = "-no-blockExternal"; - protected static final String SWITCH_QUOTE_ATTRIBUTE_EL = "-quoteAttributeEL"; - protected static final String SWITCH_NO_QUOTE_ATTRIBUTE_EL = "-no-quoteAttributeEL"; - protected static final String SHOW_SUCCESS ="-s"; - protected static final String LIST_ERRORS = "-l"; - protected static final int INC_WEBXML = 10; - protected static final int ALL_WEBXML = 20; - protected static final int DEFAULT_DIE_LEVEL = 1; - protected static final int NO_DIE_LEVEL = 0; - protected static final Set insertBefore = new HashSet(); - - static { - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - } - - protected String classPath = null; - protected ClassLoader loader = null; - protected boolean trimSpaces = false; - protected boolean genStringAsCharArray = false; - protected boolean validateTld; - protected boolean validateXml; - protected boolean blockExternal = true; - protected boolean quoteAttributeEL = true; - protected boolean xpoweredBy; - protected boolean mappedFile = false; - protected boolean poolingEnabled = true; - protected File scratchDir; - protected String ieClassId = DEFAULT_IE_CLASS_ID; - protected String targetPackage; - protected String targetClassName; - protected String uriBase; - protected String uriRoot; - protected int dieLevel; - protected boolean helpNeeded = false; - protected boolean compile = false; - protected boolean smapSuppressed = true; - protected boolean smapDumped = false; - protected boolean caching = true; - protected final Map cache = - new HashMap(); - - protected String compiler = null; - - protected String compilerTargetVM = "1.6"; - protected String compilerSourceVM = "1.6"; - - protected boolean classDebugInfo = true; - - /** - * Throw an exception if there's a compilation error, or swallow it. - * Default is true to preserve old behavior. - */ - protected boolean failOnError = true; - - /** - * The file extensions to be handled as JSP files. - * Default list is .jsp and .jspx. - */ - protected List extensions; - - /** - * The pages. - */ - protected final List pages = new Vector(); - - /** - * Needs better documentation, this data member does. - * True by default. - */ - protected boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * The java file encoding. Default - * is UTF-8. Added per bugzilla 19622. - */ - protected String javaEncoding = "UTF-8"; - - // Generation of web.xml fragments - protected String webxmlFile; - protected int webxmlLevel; - protected String webxmlEncoding; - protected boolean addWebXmlMappings = false; - - protected Writer mapout; - protected CharArrayWriter servletout; - protected CharArrayWriter mappingout; - - /** - * The servlet context. - */ - protected JspCServletContext context; - - /** - * The runtime context. - * Maintain a dummy JspRuntimeContext for compiling tag files. - */ - protected JspRuntimeContext rctxt; - - /** - * Cache for the TLD locations - */ - protected TldLocationsCache tldLocationsCache = null; - - protected JspConfig jspConfig = null; - protected TagPluginManager tagPluginManager = null; - - protected boolean verbose = false; - protected boolean listErrors = false; - protected boolean showSuccess = false; - protected int argPos; - protected boolean fullstop = false; - protected String args[]; - - public static void main(String arg[]) { - if (arg.length == 0) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - JspC jspc = new JspC(); - try { - jspc.setArgs(arg); - if (jspc.helpNeeded) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - jspc.execute(); - } - } catch (JasperException je) { - System.err.println(je); - if (jspc.dieLevel != NO_DIE_LEVEL) { - System.exit(jspc.dieLevel); - } - } catch (RuntimeException je) { - System.err.println(je); - if (jspc.dieLevel != NO_DIE_LEVEL) { - System.exit(jspc.dieLevel); - } - } - } - } - - /** - * Apply command-line arguments. - * - * @param arg - * The arguments - */ - public void setArgs(String[] arg) throws JasperException { - args = arg; - String tok; - - dieLevel = NO_DIE_LEVEL; - - while ((tok = nextArg()) != null) { - if (tok.equals(SWITCH_VERBOSE)) { - verbose = true; - showSuccess = true; - listErrors = true; - } else if (tok.equals(SWITCH_OUTPUT_DIR)) { - tok = nextArg(); - setOutputDir( tok ); - } else if (tok.equals(SWITCH_PACKAGE_NAME)) { - targetPackage = nextArg(); - } else if (tok.equals(SWITCH_COMPILE)) { - compile=true; - } else if (tok.equals(SWITCH_CLASS_NAME)) { - targetClassName = nextArg(); - } else if (tok.equals(SWITCH_URI_BASE)) { - uriBase=nextArg(); - } else if (tok.equals(SWITCH_URI_ROOT)) { - setUriroot( nextArg()); - } else if (tok.equals(SWITCH_FILE_WEBAPP)) { - setUriroot( nextArg()); - } else if ( tok.equals( SHOW_SUCCESS ) ) { - showSuccess = true; - } else if ( tok.equals( LIST_ERRORS ) ) { - listErrors = true; - } else if (tok.equals(SWITCH_WEBAPP_INC)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = INC_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = ALL_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { - setWebXmlEncoding(nextArg()); - } else if (tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { - setAddWebXmlMappings(true); - } else if (tok.equals(SWITCH_MAPPED)) { - mappedFile = true; - } else if (tok.equals(SWITCH_XPOWERED_BY)) { - xpoweredBy = true; - } else if (tok.equals(SWITCH_TRIM_SPACES)) { - setTrimSpaces(true); - } else if (tok.equals(SWITCH_CACHE)) { - tok = nextArg(); - if ("false".equals(tok)) { - caching = false; - } else { - caching = true; - } - } else if (tok.equals(SWITCH_CLASSPATH)) { - setClassPath(nextArg()); - } else if (tok.startsWith(SWITCH_DIE)) { - try { - dieLevel = Integer.parseInt( - tok.substring(SWITCH_DIE.length())); - } catch (NumberFormatException nfe) { - dieLevel = DEFAULT_DIE_LEVEL; - } - } else if (tok.equals(SWITCH_HELP)) { - helpNeeded = true; - } else if (tok.equals(SWITCH_POOLING)) { - tok = nextArg(); - if ("false".equals(tok)) { - poolingEnabled = false; - } else { - poolingEnabled = true; - } - } else if (tok.equals(SWITCH_ENCODING)) { - setJavaEncoding(nextArg()); - } else if (tok.equals(SWITCH_SOURCE)) { - setCompilerSourceVM(nextArg()); - } else if (tok.equals(SWITCH_TARGET)) { - setCompilerTargetVM(nextArg()); - } else if (tok.equals(SWITCH_SMAP)) { - smapSuppressed = false; - } else if (tok.equals(SWITCH_DUMP_SMAP)) { - smapDumped = true; - } else if (tok.equals(SWITCH_VALIDATE_TLD)) { - setValidateTld(true); - } else if (tok.equals(SWITCH_VALIDATE_XML)) { - setValidateXml(true); - } else if (tok.equals(SWITCH_BLOCK_EXTERNAL)) { - setBlockExternal(true); - } else if (tok.equals(SWITCH_NO_BLOCK_EXTERNAL)) { - setBlockExternal(false); - } else if (tok.equals(SWITCH_QUOTE_ATTRIBUTE_EL)) { - setQuoteAttributeEL(true); - } else if (tok.equals(SWITCH_NO_QUOTE_ATTRIBUTE_EL)) { - setQuoteAttributeEL(false); - } else { - if (tok.startsWith("-")) { - throw new JasperException("Unrecognized option: " + tok + - ". Use -help for help."); - } - if (!fullstop) { - argPos--; - } - // Start treating the rest as JSP Pages - break; - } - } - - // Add all extra arguments to the list of files - while( true ) { - String file = nextFile(); - if( file==null ) { - break; - } - pages.add( file ); - } - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - @Override - public boolean getKeepGenerated() { - // isn't this why we are running jspc? - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getTrimSpaces() { - return trimSpaces; - } - - /** - * Sets the option to trim white spaces between directives or actions. - */ - public void setTrimSpaces(boolean ts) { - this.trimSpaces = ts; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - /** - * Sets the option to enable the tag handler pooling. - */ - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Sets the option to enable generation of X-Powered-By response header. - */ - public void setXpoweredBy(boolean xpoweredBy) { - this.xpoweredBy = xpoweredBy; - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - @Override - public boolean getDisplaySourceFragment() { - return true; - } - - @Override - public int getMaxLoadedJsps() { - return -1; - } - - @Override - public int getJspIdleTimeout() { - return -1; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - /** - * Sets the option to issue a compilation error if the class attribute - * specified in useBean action is invalid. - */ - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getMappedFile() { - return mappedFile; - } - - public void setMappedFile(boolean b) { - mappedFile = b; - } - - /** - * Sets the option to include debug information in compiled class. - */ - public void setClassDebugInfo( boolean b ) { - classDebugInfo=b; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getClassDebugInfo() { - // compile with debug info - return classDebugInfo; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isCaching() { - return caching; - } - - /** - * Sets the option to enable caching. - * - * @see Options#isCaching() - */ - public void setCaching(boolean caching) { - this.caching = caching; - } - - /** - * {@inheritDoc} - */ - @Override - public Map getCache() { - return cache; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - @Override - public int getCheckInterval() { - return 0; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - @Override - public int getModificationTestInterval() { - return 0; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - @Override - public boolean getRecompileOnFail() { - return false; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - @Override - public boolean getDevelopment() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSmapSuppressed() { - return smapSuppressed; - } - - /** - * Sets smapSuppressed flag. - */ - public void setSmapSuppressed(boolean smapSuppressed) { - this.smapSuppressed = smapSuppressed; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSmapDumped() { - return smapDumped; - } - - /** - * Sets smapDumped flag. - * - * @see Options#isSmapDumped() - */ - public void setSmapDumped(boolean smapDumped) { - this.smapDumped = smapDumped; - } - - - /** - * Determines whether text strings are to be generated as char arrays, - * which improves performance in some cases. - * - * @param genStringAsCharArray true if text strings are to be generated as - * char arrays, false otherwise - */ - public void setGenStringAsCharArray(boolean genStringAsCharArray) { - this.genStringAsCharArray = genStringAsCharArray; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean genStringAsCharArray() { - return genStringAsCharArray; - } - - /** - * Sets the class-id value to be sent to Internet Explorer when using - * <jsp:plugin> tags. - * - * @param ieClassId - * Class-id value - */ - public void setIeClassId(String ieClassId) { - this.ieClassId = ieClassId; - } - - /** - * {@inheritDoc} - */ - @Override - public String getIeClassId() { - return ieClassId; - } - - /** - * {@inheritDoc} - */ - @Override - public File getScratchDir() { - return scratchDir; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompiler() { - return compiler; - } - - /** - * Sets the option to determine what compiler to use. - * - * @see Options#getCompiler() - */ - public void setCompiler(String c) { - compiler=c; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerClassName() { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * Sets the compiler target VM. - * - * @see Options#getCompilerTargetVM() - */ - public void setCompilerTargetVM(String vm) { - compilerTargetVM = vm; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * Sets the compiler source VM. - * - * @see Options#getCompilerSourceVM() - */ - public void setCompilerSourceVM(String vm) { - compilerSourceVM = vm; - } - - /** - * {@inheritDoc} - */ - @Override - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - /** - * Returns the encoding to use for - * java files. The default is UTF-8. - * - * @return String The encoding - */ - @Override - public String getJavaEncoding() { - return javaEncoding; - } - - /** - * Sets the encoding to use for - * java files. - * - * @param encodingName The name, e.g. "UTF-8" - */ - public void setJavaEncoding(String encodingName) { - javaEncoding = encodingName; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getFork() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public String getClassPath() { - if( classPath != null ) - return classPath; - return System.getProperty("java.class.path"); - } - - /** - * Sets the classpath used while compiling the servlets generated from JSP - * files - */ - public void setClassPath(String s) { - classPath=s; - } - - /** - * Returns the list of file extensions - * that are treated as JSP files. - * - * @return The list of extensions - */ - public List getExtensions() { - return extensions; - } - - /** - * Adds the given file extension to the - * list of extensions handled as JSP files. - * - * @param extension The extension to add, e.g. "myjsp" - */ - protected void addExtension(final String extension) { - if(extension != null) { - if(extensions == null) { - extensions = new Vector(); - } - - extensions.add(extension); - } - } - - /** - * Base dir for the webapp. Used to generate class names and resolve - * includes. - */ - public void setUriroot( String s ) { - if (s == null) { - uriRoot = null; - return; - } - try { - uriRoot = resolveFile(s).getCanonicalPath(); - } catch( Exception ex ) { - uriRoot = s; - } - } - - /** - * Parses comma-separated list of JSP files to be processed. If the argument - * is null, nothing is done. - * - *

Each file is interpreted relative to uriroot, unless it is absolute, - * in which case it must start with uriroot.

- * - * @param jspFiles Comma-separated list of JSP files to be processed - */ - public void setJspFiles(final String jspFiles) { - if(jspFiles == null) { - return; - } - - StringTokenizer tok = new StringTokenizer(jspFiles, ","); - while (tok.hasMoreTokens()) { - pages.add(tok.nextToken()); - } - } - - /** - * Sets the compile flag. - * - * @param b Flag value - */ - public void setCompile( final boolean b ) { - compile = b; - } - - /** - * Sets the verbosity level. The actual number doesn't - * matter: if it's greater than zero, the verbose flag will - * be true. - * - * @param level Positive means verbose - */ - public void setVerbose( final int level ) { - if (level > 0) { - verbose = true; - showSuccess = true; - listErrors = true; - } - } - - public void setValidateTld( boolean b ) { - this.validateTld = b; - } - - public boolean isValidateTld() { - return validateTld; - } - - public void setValidateXml( boolean b ) { - this.validateXml = b; - } - - public boolean isValidateXml() { - return validateXml; - } - - public void setBlockExternal( boolean b ) { - this.blockExternal = b; - } - - public boolean isBlockExternal() { - return blockExternal; - } - - public void setQuoteAttributeEL(boolean b) { - quoteAttributeEL = b; - } - - @Override - public boolean getQuoteAttributeEL() { - return quoteAttributeEL; - } - - public void setListErrors( boolean b ) { - listErrors = b; - } - - public void setOutputDir( String s ) { - if( s!= null ) { - scratchDir = resolveFile(s).getAbsoluteFile(); - } else { - scratchDir=null; - } - } - - /** - * Sets the package name to be used for the generated servlet classes. - */ - public void setPackage( String p ) { - targetPackage=p; - } - - /** - * Class name of the generated file ( without package ). - * Can only be used if a single file is converted. - * XXX Do we need this feature ? - */ - public void setClassName( String p ) { - targetClassName=p; - } - - /** - * File where we generate a web.xml fragment with the class definitions. - */ - public void setWebXmlFragment( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=INC_WEBXML; - } - - /** - * File where we generate a complete web.xml with the class definitions. - */ - public void setWebXml( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=ALL_WEBXML; - } - - /** - * Sets the encoding to be used to read and write web.xml files. - * - *

- * If not specified, defaults to the platform default encoding. - *

- * - * @param encoding - * Encoding, e.g. "UTF-8". - */ - public void setWebXmlEncoding(String encoding) { - webxmlEncoding = encoding; - } - - /** - * Sets the option to merge generated web.xml fragment into the - * WEB-INF/web.xml file of the web application that we were processing. - * - * @param b - * true to merge the fragment into the existing - * web.xml file of the processed web application - * ({uriroot}/WEB-INF/web.xml), false to keep the - * generated web.xml fragment - */ - public void setAddWebXmlMappings(boolean b) { - addWebXmlMappings = b; - } - - /** - * Sets the option that throws an exception in case of a compilation error. - */ - public void setFailOnError(final boolean b) { - failOnError = b; - } - - /** - * Returns true if an exception will be thrown in case of a compilation - * error. - */ - public boolean getFailOnError() { - return failOnError; - } - - /** - * {@inheritDoc} - */ - @Override - public JspConfig getJspConfig() { - return jspConfig; - } - - /** - * {@inheritDoc} - */ - @Override - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - /** - * Adds servlet declaration and mapping for the JSP page servlet to the - * generated web.xml fragment. - * - * @param file - * Context-relative path to the JSP file, e.g. - * /index.jsp - * @param clctxt - * Compilation context of the servlet - */ - public void generateWebMapping( String file, JspCompilationContext clctxt ) - throws IOException - { - if (log.isDebugEnabled()) { - log.debug("Generating web mapping for file " + file - + " using compilation context " + clctxt); - } - - String className = clctxt.getServletClassName(); - String packageName = clctxt.getServletPackageName(); - - String thisServletName; - if ("".equals(packageName)) { - thisServletName = className; - } else { - thisServletName = packageName + '.' + className; - } - - if (servletout != null) { - servletout.write("\n \n "); - servletout.write(thisServletName); - servletout.write("\n "); - servletout.write(thisServletName); - servletout.write("\n \n"); - } - if (mappingout != null) { - mappingout.write("\n \n "); - mappingout.write(thisServletName); - mappingout.write("\n "); - mappingout.write(file.replace('\\', '/')); - mappingout.write("\n \n"); - - } - } - - /** - * Include the generated web.xml inside the webapp's web.xml. - */ - protected void mergeIntoWebXml() throws IOException { - - File webappBase = new File(uriRoot); - File webXml = new File(webappBase, "WEB-INF/web.xml"); - File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); - String insertStartMarker = - Localizer.getMessage("jspc.webinc.insertStart"); - String insertEndMarker = - Localizer.getMessage("jspc.webinc.insertEnd"); - - BufferedReader reader = null; - BufferedReader fragmentReader = null; - PrintWriter writer = null; - try { - reader = new BufferedReader(openWebxmlReader(webXml)); - fragmentReader = new BufferedReader(openWebxmlReader(new File(webxmlFile))); - writer = new PrintWriter(openWebxmlWriter(webXml2)); - // Insert the and declarations - boolean inserted = false; - int current = reader.read(); - while (current > -1) { - if (current == '<') { - String element = getElement(reader); - if (!inserted && insertBefore.contains(element)) { - // Insert generated content here - writer.println(insertStartMarker); - while (true) { - String line = fragmentReader.readLine(); - if (line == null) { - writer.println(); - break; - } - writer.println(line); - } - writer.println(insertEndMarker); - writer.println(); - writer.write(element); - inserted = true; - } else if (element.equals(insertStartMarker)) { - // Skip the previous auto-generated content - while (true) { - current = reader.read(); - if (current < 0) { - throw new EOFException(); - } - if (current == '<') { - element = getElement(reader); - if (element.equals(insertEndMarker)) { - break; - } - } - } - current = reader.read(); - while (current == '\n' || current == '\r') { - current = reader.read(); - } - continue; - } else { - writer.write(element); - } - } else { - writer.write(current); - } - current = reader.read(); - } - } finally { - if (writer != null) { - try { - writer.close(); - } catch (Exception e) { - } - } - if (reader != null) { - try { - reader.close(); - } catch (Exception e) { - } - } - if (fragmentReader != null) { - try { - fragmentReader.close(); - } catch (Exception e) { - } - } - } - - FileInputStream fis = null; - FileOutputStream fos = null; - try { - fis = new FileInputStream(webXml2); - fos = new FileOutputStream(webXml); - byte buf[] = new byte[512]; - while (true) { - int n = fis.read(buf); - if (n < 0) { - break; - } - fos.write(buf, 0, n); - } - } finally { - if (fis != null) { - try { - fis.close(); - } catch (Exception e) { - } - } - if (fos != null) { - try { - fos.close(); - } catch (Exception e) { - } - } - } - - if(!webXml2.delete() && log.isDebugEnabled()) - log.debug(Localizer.getMessage("jspc.delete.fail", - webXml2.toString())); - - if (!(new File(webxmlFile)).delete() && log.isDebugEnabled()) - log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile)); - - } - - /* - * Assumes valid xml - */ - private String getElement(Reader reader) throws IOException { - StringBuilder result = new StringBuilder(); - result.append('<'); - - boolean done = false; - - while (!done) { - int current = reader.read(); - while (current != '>') { - if (current < 0) { - throw new EOFException(); - } - result.append((char) current); - current = reader.read(); - } - result.append((char) current); - - int len = result.length(); - if (len > 4 && result.substring(0, 4).equals("")) { - done = true; - } - } else { - done = true; - } - } - - - return result.toString(); - } - - protected void processFile(String file) - throws JasperException - { - if (log.isDebugEnabled()) { - log.debug("Processing file: " + file); - } - - ClassLoader originalClassLoader = null; - - try { - // set up a scratch/output dir if none is provided - if (scratchDir == null) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = ""; - } - scratchDir = new File(new File(temp).getAbsolutePath()); - } - - String jspUri=file.replace('\\','/'); - JspCompilationContext clctxt = new JspCompilationContext - ( jspUri, this, context, null, rctxt ); - - /* Override the defaults */ - if ((targetClassName != null) && (targetClassName.length() > 0)) { - clctxt.setServletClassName(targetClassName); - targetClassName = null; - } - if (targetPackage != null) { - clctxt.setServletPackageName(targetPackage); - } - - originalClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(loader); - - clctxt.setClassLoader(loader); - clctxt.setClassPath(classPath); - - Compiler clc = clctxt.createCompiler(); - - // If compile is set, generate both .java and .class, if - // .jsp file is newer than .class file; - // Otherwise only generate .java, if .jsp file is newer than - // the .java file - if( clc.isOutDated(compile) ) { - if (log.isDebugEnabled()) { - log.debug(jspUri + " is out dated, compiling..."); - } - - clc.compile(compile, true); - } - - // Generate mapping - generateWebMapping( file, clctxt ); - if ( showSuccess ) { - log.info( "Built File: " + file ); - } - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - log.error(Localizer.getMessage("jspc.error.generalException", - file), - rootCause); - } - - // Bugzilla 35114. - if(getFailOnError()) { - throw je; - } else { - log.error(je.getMessage()); - } - - } catch (Exception e) { - if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", - e.getMessage())); - } - throw new JasperException(e); - } finally { - if(originalClassLoader != null) { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - - /** - * Locate all jsp files in the webapp. Used if no explicit - * jsps are specified. - */ - public void scanFiles( File base ) throws JasperException { - Stack dirs = new Stack(); - dirs.push(base.toString()); - - // Make sure default extensions are always included - if ((getExtensions() == null) || (getExtensions().size() < 2)) { - addExtension("jsp"); - addExtension("jspx"); - } - - while (!dirs.isEmpty()) { - String s = dirs.pop(); - File f = new File(s); - if (f.exists() && f.isDirectory()) { - String[] files = f.list(); - String ext; - for (int i = 0; (files != null) && i < files.length; i++) { - File f2 = new File(s, files[i]); - if (f2.isDirectory()) { - dirs.push(f2.getPath()); - } else { - String path = f2.getPath(); - String uri = path.substring(uriRoot.length()); - ext = files[i].substring(files[i].lastIndexOf('.') +1); - if (getExtensions().contains(ext) || - jspConfig.isJspPage(uri)) { - pages.add(path); - } - } - } - } - } - } - - /** - * Executes the compilation. - */ - public void execute() { - if(log.isDebugEnabled()) { - log.debug("execute() starting for " + pages.size() + " pages."); - } - - try { - if (uriRoot == null) { - if( pages.size() == 0 ) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.missingTarget")); - } - String firstJsp = pages.get( 0 ); - File firstJspF = new File( firstJsp ); - if (!firstJspF.exists()) { - throw new JasperException( - Localizer.getMessage("jspc.error.fileDoesNotExist", - firstJsp)); - } - locateUriRoot( firstJspF ); - } - - if (uriRoot == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.no_uriroot")); - } - - File uriRootF = new File(uriRoot); - if (!uriRootF.isDirectory()) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); - } - - if (loader == null) { - loader = initClassLoader(); - } - if (context == null) { - initServletContext(loader); - } - - // No explicit pages, we'll process all .jsp in the webapp - if (pages.size() == 0) { - scanFiles(uriRootF); - } - - initWebXml(); - - Iterator iter = pages.iterator(); - while (iter.hasNext()) { - String nextjsp = iter.next(); - File fjsp = new File(nextjsp); - if (!fjsp.isAbsolute()) { - fjsp = new File(uriRootF, nextjsp); - } - if (!fjsp.exists()) { - if (log.isWarnEnabled()) { - log.warn - (Localizer.getMessage - ("jspc.error.fileDoesNotExist", fjsp.toString())); - } - continue; - } - String s = fjsp.getAbsolutePath(); - if (s.startsWith(uriRoot)) { - nextjsp = s.substring(uriRoot.length()); - } - if (nextjsp.startsWith("." + File.separatorChar)) { - nextjsp = nextjsp.substring(2); - } - processFile(nextjsp); - } - - completeWebXml(); - - if (addWebXmlMappings) { - mergeIntoWebXml(); - } - - } catch (IOException ioe) { - throw new RuntimeException(ioe); // TODO make it our own - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - rootCause.printStackTrace(); - } - throw new RuntimeException(je); // TODO make it our own - } finally { - if (loader != null) { - LogFactory.release(loader); - } - } - } - - // ==================== protected utility methods ==================== - - protected String nextArg() { - if ((argPos >= args.length) - || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { - return null; - } else { - return args[argPos++]; - } - } - - protected String nextFile() { - if (fullstop) argPos++; - if (argPos >= args.length) { - return null; - } else { - return args[argPos++]; - } - } - - protected void initWebXml() { - try { - if (webxmlLevel >= INC_WEBXML) { - mapout = openWebxmlWriter(new File(webxmlFile)); - servletout = new CharArrayWriter(); - mappingout = new CharArrayWriter(); - } else { - mapout = null; - servletout = null; - mappingout = null; - } - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.header")); - mapout.flush(); - } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.header")); - mapout.flush(); - } - } catch (IOException ioe) { - mapout = null; - servletout = null; - mappingout = null; - } - } - - protected void completeWebXml() { - if (mapout != null) { - try { - servletout.writeTo(mapout); - mappingout.writeTo(mapout); - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.footer")); - } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.footer")); - } - mapout.close(); - } catch (IOException ioe) { - // noting to do if it fails since we are done with it - } - } - } - - protected void initServletContext(ClassLoader classLoader) - throws IOException, JasperException { - // TODO: should we use the Ant Project's log? - PrintWriter log = new PrintWriter(System.out); - URL resourceBase = new File(uriRoot).getCanonicalFile().toURI().toURL(); - context = new JspCServletContext(log, resourceBase, classLoader); - if (isValidateTld()) { - context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true"); - } - if (isValidateXml()) { - context.setInitParameter(Constants.XML_VALIDATION_INIT_PARAM, "true"); - } - context.setInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM, - String.valueOf(isBlockExternal())); - - tldLocationsCache = TldLocationsCache.getInstance(context); - rctxt = new JspRuntimeContext(context, this); - jspConfig = new JspConfig(context); - tagPluginManager = new TagPluginManager(context); - } - - /** - * Initializes the classloader as/if needed for the given - * compilation context. - * - * @throws IOException If an error occurs - */ - protected ClassLoader initClassLoader() throws IOException { - - classPath = getClassPath(); - - ClassLoader jspcLoader = getClass().getClassLoader(); - // TODO add check for 7Bee/TJWS class loader and extend CP as needed - - // Turn the classPath into URLs - ArrayList urls = new ArrayList(); - StringTokenizer tokenizer = new StringTokenizer(classPath, - File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - String path = tokenizer.nextToken(); - try { - File libFile = new File(path); - urls.add(libFile.toURI().toURL()); - } catch (IOException ioe) { - // Failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak uot - throw new RuntimeException(ioe.toString()); - } - } - - File webappBase = new File(uriRoot); - if (webappBase.exists()) { - File classes = new File(webappBase, "/WEB-INF/classes"); - try { - if (classes.exists()) { - classPath = classPath + File.pathSeparator - + classes.getCanonicalPath(); - urls.add(classes.getCanonicalFile().toURI().toURL()); - } - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - File lib = new File(webappBase, "/WEB-INF/lib"); - if (lib.exists() && lib.isDirectory()) { - String[] libs = lib.list(); - if (libs != null) { - for (int i = 0; i < libs.length; i++) { - if( libs[i].length() <5 ) continue; - String ext=libs[i].substring( libs[i].length() - 4 ); - if (! ".jar".equalsIgnoreCase(ext)) { - if (".tld".equalsIgnoreCase(ext)) { - log.warn("TLD files should not be placed in " - + "/WEB-INF/lib"); - } - continue; - } - try { - File libFile = new File(lib, libs[i]); - classPath = classPath + File.pathSeparator - + libFile.getAbsolutePath(); - urls.add(libFile.getAbsoluteFile().toURI().toURL()); - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - } - } - } - } - - URL urlsA[]=new URL[urls.size()]; - urls.toArray(urlsA); - loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); - return loader; - } - - /** - * Find the WEB-INF dir by looking up in the directory tree. - * This is used if no explicit docbase is set, but only files. - * XXX Maybe we should require the docbase. - */ - protected void locateUriRoot( File f ) { - String tUriBase = uriBase; - if (tUriBase == null) { - tUriBase = "/"; - } - try { - if (f.exists()) { - f = new File(f.getAbsolutePath()); - while (true) { - File g = new File(f, "WEB-INF"); - if (g.exists() && g.isDirectory()) { - uriRoot = f.getCanonicalPath(); - uriBase = tUriBase; - if (log.isInfoEnabled()) { - log.info(Localizer.getMessage( - "jspc.implicit.uriRoot", - uriRoot)); - } - break; - } - if (f.exists() && f.isDirectory()) { - tUriBase = "/" + f.getName() + "/" + tUriBase; - } - - String fParent = f.getParent(); - if (fParent == null) { - break; - } else { - f = new File(fParent); - } - - // If there is no acceptable candidate, uriRoot will - // remain null to indicate to the CompilerContext to - // use the current working/user dir. - } - - if (uriRoot != null) { - File froot = new File(uriRoot); - uriRoot = froot.getCanonicalPath(); - } - } - } catch (IOException ioe) { - // since this is an optional default and a null value - // for uriRoot has a non-error meaning, we can just - // pass straight through - } - } - - /** - * Resolves the relative or absolute pathname correctly - * in both Ant and command-line situations. If Ant launched - * us, we should use the basedir of the current project - * to resolve relative paths. - * - * See Bugzilla 35571. - * - * @param s The file - * @return The file resolved - */ - protected File resolveFile(final String s) { - // TODO consider some massaging of s as relative path to project home for TJWS - return new File(s); - } - - private Reader openWebxmlReader(File file) throws IOException { - FileInputStream fis = new FileInputStream(file); - try { - return webxmlEncoding != null ? new InputStreamReader(fis, - webxmlEncoding) : new InputStreamReader(fis); - } catch (IOException ex) { - fis.close(); - throw ex; - } - } - - private Writer openWebxmlWriter(File file) throws IOException { - FileOutputStream fos = new FileOutputStream(file); - try { - return webxmlEncoding != null ? new OutputStreamWriter(fos, - webxmlEncoding) : new OutputStreamWriter(fos); - } catch (IOException ex) { - fos.close(); - throw ex; - } - } -} diff --git a/1.x/src/jasper7/BeeCompiler.java b/1.x/src/jasper7/BeeCompiler.java deleted file mode 100644 index 4a1783f..0000000 --- a/1.x/src/jasper7/BeeCompiler.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintStream; -import java.io.IOException; -import java.io.ByteArrayOutputStream; -import java.util.StringTokenizer; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.net.URLClassLoader; - -import org.apache.jasper.JasperException; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * Main JSP compiler class. This class uses 7Bee for compiling. - * - * @author Dmitriy Rogatkin - */ -public class BeeCompiler extends Compiler { - private final Log log = LogFactory.getLog(BeeCompiler.class); // must not be static - - protected static Object javacLock = new Object(); - - private Class javaCompiler; - - static { - System.setErr(new SystemLogHandler(System.err)); - } - - /** - * Compile the servlet from .java file to .class file - */ - protected void generateClass(String[] smap) throws FileNotFoundException, JasperException, Exception { - - long t1 = 0; - if (log.isDebugEnabled()) - t1 = System.currentTimeMillis(); - - List parameters = new ArrayList(20); - parameters.add("-encoding"); - parameters.add(ctxt.getOptions().getJavaEncoding()); - - String javaFileName = new File(ctxt.getServletJavaFileName()).getPath(); - String classpath = ctxt.getClassPath(); - - String sep = File.pathSeparator; // System.getProperty("path.separator"); - - StringBuffer errorReport = new StringBuffer(); - - StringBuffer info = new StringBuffer(); - info.append("Compile: javaFileName=" + javaFileName + "\n"); - - // Start capturing the System.err output for this thread - SystemLogHandler.setThread(); - - // Initializing classpath - String path = System.getProperty("java.class.path"); - info.append(" cmd cp=" + path + "\n"); - info.append(" ctx cp=" + classpath + "\n"); - path += sep; - path += classpath; - - if (log.isDebugEnabled()) - log.debug("Using classpath: " + path); - - parameters.add("-classpath"); - parameters.add(path); - - // Initializing sourcepath - parameters.add("-sourcepath"); - parameters.add(options.getScratchDir().getPath()); - - info.append(" work dir=" + options.getScratchDir() + "\n"); - - // Initialize and set java extensions - String extdirs = System.getProperty("java.ext.dirs"); - if (extdirs != null) { - parameters.add("-extdirs"); - parameters.add(extdirs); - info.append(" extension dir=" + extdirs + "\n"); - } - - if (ctxt.getOptions().getFork()) { - String endorsed = System.getProperty("java.endorsed.dirs"); - if (endorsed != null) { - parameters.add("-endorseddirs"); // "-J-Djava.endorsed.dirs="+endorsed - parameters.add(endorsed); - info.append(" endorsed dir=" + endorsed + "\n"); - } else { - info.append(" no endorsed dirs specified\n"); - } - } - - if (ctxt.getOptions().getClassDebugInfo()) - parameters.add("-g"); - - Exception ie = null; - - // Set the Java compiler to use - if (javaCompiler == null) { - // assumption, there is no dynamic changing Java compiler - String compiler = options.getCompiler(); - if (compiler == null) - compiler = "com.sun.tools.javac.Main"; - // verify compiler - try { - javaCompiler = Class.forName(compiler); - } catch (ClassNotFoundException cnfe) { - // try to figure out class path to compiler - String compileClassPath = System.getProperty("java.home"); - if (compileClassPath == null) - try { - compileClassPath = System.getenv("JAVA_HOME"); - if (compileClassPath == null) - compileClassPath = System.getenv("java_home"); - } catch (SecurityException se) { - - } - - if (compileClassPath != null) { - // HACK for now - compileClassPath = compileClassPath.replace("jre", "jdk"); - compileClassPath += "/lib/tools.jar"; - info.append(" checking default compiler in " + compileClassPath + "\n"); - try { - javaCompiler = Class.forName(compiler, true, new URLClassLoader(new URL[] { new URL("file", - "localhost", compileClassPath) })); - } catch (Error er) { - log.error("Setting up Java compiler error ", er); - } catch (Exception ex) { - log.error("Setting up Java compiler exception ", ex); - } - } else - info.append(" no Java home path specified\n"); - } - info.append(" compiler=" + compiler + "\n"); - } - - if (options.getCompilerTargetVM() != null) { - parameters.add("-target"); - parameters.add(options.getCompilerTargetVM()); - info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n"); - } - - if (options.getCompilerSourceVM() != null) { - parameters.add("-source"); - parameters.add(options.getCompilerSourceVM()); - info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n"); - } - - info.append(" JavaPath=" + ctxt.getJavaPath() + "\n"); - - parameters.add(javaFileName); - - boolean compilationErrors = false; - String errorCapture = null; - if (javaCompiler != null) - try { - Integer success; - Method cm = javaCompiler.getMethod("compile", new Class[] { String[].class }); - if (ctxt.getOptions().getFork()) { - success = (Integer) cm.invoke(null, new Object[] { parameters - .toArray(new String[parameters.size()]) }); - } else { - synchronized (javacLock) { - success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters - .size()]) }); - } - } - if (success.intValue() != 0) - compilationErrors = true; - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - if (t instanceof InvocationTargetException) - t = t.getCause(); - if (t instanceof Exception) - ie = (Exception) t; - else - ie = new Exception(t); - log.error("Javac exception ", t); - log.error("Env: " + info.toString()); - } finally { - // Stop capturing the System.err output for this thread - errorCapture = SystemLogHandler.unsetThread(); - } - if (compilationErrors && errorCapture != null) { - errorReport.append(System.getProperty("line.separator")); - errorReport.append(errorCapture); - } - - if (!ctxt.keepGenerated()) { - if (new File(javaFileName).delete() == false) - log.error("Couldn't delete source: " + javaFileName); - } - - if (compilationErrors || ie != null) { - String errorReportString = errorReport.toString(); - log.error("Error compiling file: " + javaFileName + " " + errorReportString); - JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(errorReportString, javaFileName, - pageNodes); - if (javacErrors != null) { - errDispatcher.javacError(javacErrors); - } else { - errDispatcher.javacError(errorReportString, ie); - } - } - - if (log.isDebugEnabled()) { - long t2 = System.currentTimeMillis(); - log.debug("Compiled " + ctxt.getServletJavaFileName() + " " + (t2 - t1) + "ms"); - } - - if (ctxt.isPrototypeMode()) { - return; - } - - // JSR45 Support - if (!options.isSmapSuppressed()) { - log.debug("Install Smap " + (smap == null ? "null" : Arrays.toString(smap))); - SmapUtil.installSmap(smap); - } - } - - protected static class SystemLogHandler extends PrintStream { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct the handler to capture the output of the given steam. - */ - public SystemLogHandler(PrintStream wrapped) { - super(wrapped); - this.wrapped = wrapped; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped PrintStream. - */ - protected PrintStream wrapped = null; - - - /** - * Thread <-> PrintStream associations. - */ - protected static ThreadLocal streams = new ThreadLocal(); - - - /** - * Thread <-> ByteArrayOutputStream associations. - */ - protected static ThreadLocal data = new ThreadLocal(); - - - // --------------------------------------------------------- Public Methods - - - public PrintStream getWrapped() { - return wrapped; - } - - /** - * Start capturing thread's output. - */ - public static void setThread() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - data.set(baos); - streams.set(new PrintStream(baos)); - } - - - /** - * Stop capturing thread's output and return captured data as a String. - */ - public static String unsetThread() { - ByteArrayOutputStream baos = - (ByteArrayOutputStream) data.get(); - if (baos == null) { - return null; - } - streams.set(null); - data.set(null); - return baos.toString(); - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Find PrintStream to which the output must be written to. - */ - protected PrintStream findStream() { - PrintStream ps = (PrintStream) streams.get(); - if (ps == null) { - ps = wrapped; - } - return ps; - } - - - // ---------------------------------------------------- PrintStream Methods - - - public void flush() { - findStream().flush(); - } - - public void close() { - findStream().close(); - } - - public boolean checkError() { - return findStream().checkError(); - } - - protected void setError() { - //findStream().setError(); - } - - public void write(int b) { - findStream().write(b); - } - - public void write(byte[] b) - throws IOException { - findStream().write(b); - } - - public void write(byte[] buf, int off, int len) { - findStream().write(buf, off, len); - } - - public void print(boolean b) { - findStream().print(b); - } - - public void print(char c) { - findStream().print(c); - } - - public void print(int i) { - findStream().print(i); - } - - public void print(long l) { - findStream().print(l); - } - - public void print(float f) { - findStream().print(f); - } - - public void print(double d) { - findStream().print(d); - } - - public void print(char[] s) { - findStream().print(s); - } - - public void print(String s) { - findStream().print(s); - } - - public void print(Object obj) { - findStream().print(obj); - } - - public void println() { - findStream().println(); - } - - public void println(boolean x) { - findStream().println(x); - } - - public void println(char x) { - findStream().println(x); - } - - public void println(int x) { - findStream().println(x); - } - - public void println(long x) { - findStream().println(x); - } - - public void println(float x) { - findStream().println(x); - } - - public void println(double x) { - findStream().println(x); - } - - public void println(char[] x) { - findStream().println(x); - } - - public void println(String x) { - findStream().println(x); - } - - public void println(Object x) { - findStream().println(x); - } - - } - -} diff --git a/1.x/src/jasper7/JspC.java b/1.x/src/jasper7/JspC.java deleted file mode 100644 index cf0ae68..0000000 --- a/1.x/src/jasper7/JspC.java +++ /dev/null @@ -1,1603 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.servlet.jsp.tagext.TagLibraryInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.servlet.JspCServletContext; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * Shell for the jspc compiler. Handles all options associated with the - * command line and creates compilation contexts which it then compiles - * according to the specified options. - * - * This version can process files from a _single_ webapp at once, i.e. - * a single docbase can be specified. - * - * It can be used as an Ant task using: - *
- *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
- *      <classpath>
- *          <pathelement location="${java.home}/../lib/tools.jar"/>
- *          <fileset dir="${ENV.CATALINA_HOME}/lib">
- *              <include name="*.jar"/>
- *          </fileset>
- *          <path refid="myjars"/>
- *       </classpath>
- *  </taskdef>
- *
- *  <jasper verbose="0"
- *           package="my.package"
- *           uriroot="${webapps.dir}/${webapp.name}"
- *           webXmlFragment="${build.dir}/generated_web.xml"
- *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
- * 
- * - * @author Danno Ferrin - * @author Pierre Delisle - * @author Costin Manolache - * @author Yoav Shapira - */ -public class JspC implements Options { - - public static final String DEFAULT_IE_CLASS_ID = - "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - // Logger - private static final Log log = LogFactory.getLog(JspC.class); - - protected static final String SWITCH_VERBOSE = "-v"; - protected static final String SWITCH_HELP = "-help"; - protected static final String SWITCH_OUTPUT_DIR = "-d"; - protected static final String SWITCH_PACKAGE_NAME = "-p"; - protected static final String SWITCH_CACHE = "-cache"; - protected static final String SWITCH_CLASS_NAME = "-c"; - protected static final String SWITCH_FULL_STOP = "--"; - protected static final String SWITCH_COMPILE = "-compile"; - protected static final String SWITCH_SOURCE = "-source"; - protected static final String SWITCH_TARGET = "-target"; - protected static final String SWITCH_URI_BASE = "-uribase"; - protected static final String SWITCH_URI_ROOT = "-uriroot"; - protected static final String SWITCH_FILE_WEBAPP = "-webapp"; - protected static final String SWITCH_WEBAPP_INC = "-webinc"; - protected static final String SWITCH_WEBAPP_XML = "-webxml"; - protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; - protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; - protected static final String SWITCH_MAPPED = "-mapped"; - protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; - protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; - protected static final String SWITCH_CLASSPATH = "-classpath"; - protected static final String SWITCH_DIE = "-die"; - protected static final String SWITCH_POOLING = "-poolingEnabled"; - protected static final String SWITCH_ENCODING = "-javaEncoding"; - protected static final String SWITCH_SMAP = "-smap"; - protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; - protected static final String SHOW_SUCCESS ="-s"; - protected static final String LIST_ERRORS = "-l"; - protected static final int INC_WEBXML = 10; - protected static final int ALL_WEBXML = 20; - protected static final int DEFAULT_DIE_LEVEL = 1; - protected static final int NO_DIE_LEVEL = 0; - protected static final Set insertBefore = new HashSet(); - - static { - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - insertBefore.add(""); - } - - protected String classPath = null; - protected URLClassLoader loader = null; - protected boolean trimSpaces = false; - protected boolean genStringAsCharArray = false; - protected boolean xpoweredBy; - protected boolean mappedFile = false; - protected boolean poolingEnabled = true; - protected File scratchDir; - protected String ieClassId = DEFAULT_IE_CLASS_ID; - protected String targetPackage; - protected String targetClassName; - protected String uriBase; - protected String uriRoot; - protected int dieLevel; - protected boolean helpNeeded = false; - protected boolean compile = false; - protected boolean smapSuppressed = true; - protected boolean smapDumped = false; - protected boolean caching = true; - protected final Map cache = - new HashMap(); - - protected String compiler = null; - - protected String compilerTargetVM = "1.6"; - protected String compilerSourceVM = "1.6"; - - protected boolean classDebugInfo = true; - - /** - * Throw an exception if there's a compilation error, or swallow it. - * Default is true to preserve old behavior. - */ - protected boolean failOnError = true; - - /** - * The file extensions to be handled as JSP files. - * Default list is .jsp and .jspx. - */ - protected List extensions; - - /** - * The pages. - */ - protected final List pages = new Vector(); - - /** - * Needs better documentation, this data member does. - * True by default. - */ - protected boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * The java file encoding. Default - * is UTF-8. Added per bugzilla 19622. - */ - protected String javaEncoding = "UTF-8"; - - // Generation of web.xml fragments - protected String webxmlFile; - protected int webxmlLevel; - protected String webxmlEncoding; - protected boolean addWebXmlMappings = false; - - protected Writer mapout; - protected CharArrayWriter servletout; - protected CharArrayWriter mappingout; - - /** - * The servlet context. - */ - protected JspCServletContext context; - - /** - * The runtime context. - * Maintain a dummy JspRuntimeContext for compiling tag files. - */ - protected JspRuntimeContext rctxt; - - /** - * Cache for the TLD locations - */ - protected TldLocationsCache tldLocationsCache = null; - - protected JspConfig jspConfig = null; - protected TagPluginManager tagPluginManager = null; - - protected boolean verbose = false; - protected boolean listErrors = false; - protected boolean showSuccess = false; - protected int argPos; - protected boolean fullstop = false; - protected String args[]; - - public static void main(String arg[]) { - if (arg.length == 0) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - JspC jspc = new JspC(); - try { - jspc.setArgs(arg); - if (jspc.helpNeeded) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - jspc.execute(); - } - } catch (JasperException je) { - System.err.println(je); - if (jspc.dieLevel != NO_DIE_LEVEL) { - System.exit(jspc.dieLevel); - } - } catch (Exception je) { - System.err.println(je); - if (jspc.dieLevel != NO_DIE_LEVEL) { - System.exit(jspc.dieLevel); - } - } - } - } - - /** - * Apply command-line arguments. - * - * @param arg - * The arguments - */ - public void setArgs(String[] arg) throws JasperException { - args = arg; - String tok; - - dieLevel = NO_DIE_LEVEL; - - while ((tok = nextArg()) != null) { - if (tok.equals(SWITCH_VERBOSE)) { - verbose = true; - showSuccess = true; - listErrors = true; - } else if (tok.equals(SWITCH_OUTPUT_DIR)) { - tok = nextArg(); - setOutputDir( tok ); - } else if (tok.equals(SWITCH_PACKAGE_NAME)) { - targetPackage = nextArg(); - } else if (tok.equals(SWITCH_COMPILE)) { - compile=true; - } else if (tok.equals(SWITCH_CLASS_NAME)) { - targetClassName = nextArg(); - } else if (tok.equals(SWITCH_URI_BASE)) { - uriBase=nextArg(); - } else if (tok.equals(SWITCH_URI_ROOT)) { - setUriroot( nextArg()); - } else if (tok.equals(SWITCH_FILE_WEBAPP)) { - setUriroot( nextArg()); - } else if ( tok.equals( SHOW_SUCCESS ) ) { - showSuccess = true; - } else if ( tok.equals( LIST_ERRORS ) ) { - listErrors = true; - } else if (tok.equals(SWITCH_WEBAPP_INC)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = INC_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = ALL_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { - setWebXmlEncoding(nextArg()); - } else if (tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { - setAddWebXmlMappings(true); - } else if (tok.equals(SWITCH_MAPPED)) { - mappedFile = true; - } else if (tok.equals(SWITCH_XPOWERED_BY)) { - xpoweredBy = true; - } else if (tok.equals(SWITCH_TRIM_SPACES)) { - setTrimSpaces(true); - } else if (tok.equals(SWITCH_CACHE)) { - tok = nextArg(); - if ("false".equals(tok)) { - caching = false; - } else { - caching = true; - } - } else if (tok.equals(SWITCH_CLASSPATH)) { - setClassPath(nextArg()); - } else if (tok.startsWith(SWITCH_DIE)) { - try { - dieLevel = Integer.parseInt( - tok.substring(SWITCH_DIE.length())); - } catch (NumberFormatException nfe) { - dieLevel = DEFAULT_DIE_LEVEL; - } - } else if (tok.equals(SWITCH_HELP)) { - helpNeeded = true; - } else if (tok.equals(SWITCH_POOLING)) { - tok = nextArg(); - if ("false".equals(tok)) { - poolingEnabled = false; - } else { - poolingEnabled = true; - } - } else if (tok.equals(SWITCH_ENCODING)) { - setJavaEncoding(nextArg()); - } else if (tok.equals(SWITCH_SOURCE)) { - setCompilerSourceVM(nextArg()); - } else if (tok.equals(SWITCH_TARGET)) { - setCompilerTargetVM(nextArg()); - } else if (tok.equals(SWITCH_SMAP)) { - smapSuppressed = false; - } else if (tok.equals(SWITCH_DUMP_SMAP)) { - smapDumped = true; - } else { - if (tok.startsWith("-")) { - throw new JasperException("Unrecognized option: " + tok + - ". Use -help for help."); - } - if (!fullstop) { - argPos--; - } - // Start treating the rest as JSP Pages - break; - } - } - - // Add all extra arguments to the list of files - while( true ) { - String file = nextFile(); - if( file==null ) { - break; - } - pages.add( file ); - } - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - @Override - public boolean getKeepGenerated() { - // isn't this why we are running jspc? - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getTrimSpaces() { - return trimSpaces; - } - - /** - * Sets the option to trim white spaces between directives or actions. - */ - public void setTrimSpaces(boolean ts) { - this.trimSpaces = ts; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - /** - * Sets the option to enable the tag handler pooling. - */ - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Sets the option to enable generation of X-Powered-By response header. - */ - public void setXpoweredBy(boolean xpoweredBy) { - this.xpoweredBy = xpoweredBy; - } - - /** - * In JspC this always returns true. - * {@inheritDoc} - */ - @Override - public boolean getDisplaySourceFragment() { - return true; - } - - @Override - public int getMaxLoadedJsps() { - return -1; - } - - @Override - public int getJspIdleTimeout() { - return -1; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - /** - * Sets the option to issue a compilation error if the class attribute - * specified in useBean action is invalid. - */ - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getMappedFile() { - return mappedFile; - } - - /** - * Sets the option to include debug information in compiled class. - */ - public void setClassDebugInfo( boolean b ) { - classDebugInfo=b; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getClassDebugInfo() { - // compile with debug info - return classDebugInfo; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isCaching() { - return caching; - } - - /** - * Sets the option to enable caching. - * - * @see Options#isCaching() - */ - public void setCaching(boolean caching) { - this.caching = caching; - } - - /** - * {@inheritDoc} - */ - @Override - public Map getCache() { - return cache; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - @Override - public int getCheckInterval() { - return 0; - } - - /** - * In JspC this always returns 0. - * {@inheritDoc} - */ - @Override - public int getModificationTestInterval() { - return 0; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - @Override - public boolean getRecompileOnFail() { - return false; - } - - - /** - * In JspC this always returns false. - * {@inheritDoc} - */ - @Override - public boolean getDevelopment() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSmapSuppressed() { - return smapSuppressed; - } - - /** - * Sets smapSuppressed flag. - */ - public void setSmapSuppressed(boolean smapSuppressed) { - this.smapSuppressed = smapSuppressed; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSmapDumped() { - return smapDumped; - } - - /** - * Sets smapDumped flag. - * - * @see Options#isSmapDumped() - */ - public void setSmapDumped(boolean smapDumped) { - this.smapDumped = smapDumped; - } - - - /** - * Determines whether text strings are to be generated as char arrays, - * which improves performance in some cases. - * - * @param genStringAsCharArray true if text strings are to be generated as - * char arrays, false otherwise - */ - public void setGenStringAsCharArray(boolean genStringAsCharArray) { - this.genStringAsCharArray = genStringAsCharArray; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean genStringAsCharArray() { - return genStringAsCharArray; - } - - /** - * Sets the class-id value to be sent to Internet Explorer when using - * <jsp:plugin> tags. - * - * @param ieClassId - * Class-id value - */ - public void setIeClassId(String ieClassId) { - this.ieClassId = ieClassId; - } - - /** - * {@inheritDoc} - */ - @Override - public String getIeClassId() { - return ieClassId; - } - - /** - * {@inheritDoc} - */ - @Override - public File getScratchDir() { - return scratchDir; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompiler() { - return compiler; - } - - /** - * Sets the option to determine what compiler to use. - * - * @see Options#getCompiler() - */ - public void setCompiler(String c) { - compiler=c; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerClassName() { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * Sets the compiler target VM. - * - * @see Options#getCompilerTargetVM() - */ - public void setCompilerTargetVM(String vm) { - compilerTargetVM = vm; - } - - /** - * {@inheritDoc} - */ - @Override - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * Sets the compiler source VM. - * - * @see Options#getCompilerSourceVM() - */ - public void setCompilerSourceVM(String vm) { - compilerSourceVM = vm; - } - - /** - * {@inheritDoc} - */ - @Override - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - /** - * Returns the encoding to use for - * java files. The default is UTF-8. - * - * @return String The encoding - */ - @Override - public String getJavaEncoding() { - return javaEncoding; - } - - /** - * Sets the encoding to use for - * java files. - * - * @param encodingName The name, e.g. "UTF-8" - */ - public void setJavaEncoding(String encodingName) { - javaEncoding = encodingName; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean getFork() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public String getClassPath() { - if( classPath != null ) - return classPath; - return System.getProperty("java.class.path"); - } - - /** - * Sets the classpath used while compiling the servlets generated from JSP - * files - */ - public void setClassPath(String s) { - classPath=s; - } - - /** - * Returns the list of file extensions - * that are treated as JSP files. - * - * @return The list of extensions - */ - public List getExtensions() { - return extensions; - } - - /** - * Adds the given file extension to the - * list of extensions handled as JSP files. - * - * @param extension The extension to add, e.g. "myjsp" - */ - protected void addExtension(final String extension) { - if(extension != null) { - if(extensions == null) { - extensions = new Vector(); - } - - extensions.add(extension); - } - } - - /** - * Base dir for the webapp. Used to generate class names and resolve - * includes. - */ - public void setUriroot( String s ) { - if (s == null) { - uriRoot = null; - return; - } - try { - uriRoot = resolveFile(s).getCanonicalPath(); - } catch( Exception ex ) { - uriRoot = s; - } - } - - /** - * Parses comma-separated list of JSP files to be processed. If the argument - * is null, nothing is done. - * - *

Each file is interpreted relative to uriroot, unless it is absolute, - * in which case it must start with uriroot.

- * - * @param jspFiles Comma-separated list of JSP files to be processed - */ - public void setJspFiles(final String jspFiles) { - if(jspFiles == null) { - return; - } - - StringTokenizer tok = new StringTokenizer(jspFiles, ","); - while (tok.hasMoreTokens()) { - pages.add(tok.nextToken()); - } - } - - /** - * Sets the compile flag. - * - * @param b Flag value - */ - public void setCompile( final boolean b ) { - compile = b; - } - - /** - * Sets the verbosity level. The actual number doesn't - * matter: if it's greater than zero, the verbose flag will - * be true. - * - * @param level Positive means verbose - */ - public void setVerbose( final int level ) { - if (level > 0) { - verbose = true; - showSuccess = true; - listErrors = true; - } - } - - public void setValidateXml( boolean b ) { - org.apache.jasper.xmlparser.ParserUtils.validating=b; - } - - public void setListErrors( boolean b ) { - listErrors = b; - } - - public void setOutputDir( String s ) { - if( s!= null ) { - scratchDir = resolveFile(s).getAbsoluteFile(); - } else { - scratchDir=null; - } - } - - /** - * Sets the package name to be used for the generated servlet classes. - */ - public void setPackage( String p ) { - targetPackage=p; - } - - /** - * Class name of the generated file ( without package ). - * Can only be used if a single file is converted. - * XXX Do we need this feature ? - */ - public void setClassName( String p ) { - targetClassName=p; - } - - /** - * File where we generate a web.xml fragment with the class definitions. - */ - public void setWebXmlFragment( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=INC_WEBXML; - } - - /** - * File where we generate a complete web.xml with the class definitions. - */ - public void setWebXml( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=ALL_WEBXML; - } - - /** - * Sets the encoding to be used to read and write web.xml files. - * - *

- * If not specified, defaults to the platform default encoding. - *

- * - * @param encoding - * Encoding, e.g. "UTF-8". - */ - public void setWebXmlEncoding(String encoding) { - webxmlEncoding = encoding; - } - - /** - * Sets the option to merge generated web.xml fragment into the - * WEB-INF/web.xml file of the web application that we were processing. - * - * @param b - * true to merge the fragment into the existing - * web.xml file of the processed web application - * ({uriroot}/WEB-INF/web.xml), false to keep the - * generated web.xml fragment - */ - public void setAddWebXmlMappings(boolean b) { - addWebXmlMappings = b; - } - - /** - * Sets the option that throws an exception in case of a compilation error. - */ - public void setFailOnError(final boolean b) { - failOnError = b; - } - - /** - * Returns true if an exception will be thrown in case of a compilation - * error. - */ - public boolean getFailOnError() { - return failOnError; - } - - /** - * {@inheritDoc} - */ - @Override - public JspConfig getJspConfig() { - return jspConfig; - } - - /** - * {@inheritDoc} - */ - @Override - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - /** - * Adds servlet declaration and mapping for the JSP page servlet to the - * generated web.xml fragment. - * - * @param file - * Context-relative path to the JSP file, e.g. - * /index.jsp - * @param clctxt - * Compilation context of the servlet - */ - public void generateWebMapping( String file, JspCompilationContext clctxt ) - throws IOException - { - if (log.isDebugEnabled()) { - log.debug("Generating web mapping for file " + file - + " using compilation context " + clctxt); - } - - String className = clctxt.getServletClassName(); - String packageName = clctxt.getServletPackageName(); - - String thisServletName; - if ("".equals(packageName)) { - thisServletName = className; - } else { - thisServletName = packageName + '.' + className; - } - - if (servletout != null) { - servletout.write("\n \n "); - servletout.write(thisServletName); - servletout.write("\n "); - servletout.write(thisServletName); - servletout.write("\n \n"); - } - if (mappingout != null) { - mappingout.write("\n \n "); - mappingout.write(thisServletName); - mappingout.write("\n "); - mappingout.write(file.replace('\\', '/')); - mappingout.write("\n \n"); - - } - } - - /** - * Include the generated web.xml inside the webapp's web.xml. - */ - protected void mergeIntoWebXml() throws IOException { - - File webappBase = new File(uriRoot); - File webXml = new File(webappBase, "WEB-INF/web.xml"); - File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); - String insertStartMarker = - Localizer.getMessage("jspc.webinc.insertStart"); - String insertEndMarker = - Localizer.getMessage("jspc.webinc.insertEnd"); - - BufferedReader reader = new BufferedReader(openWebxmlReader(webXml)); - BufferedReader fragmentReader = new BufferedReader( - openWebxmlReader(new File(webxmlFile))); - PrintWriter writer = new PrintWriter(openWebxmlWriter(webXml2)); - - // Insert the and declarations - boolean inserted = false; - int current = reader.read(); - while (current > -1) { - if (current == '<') { - String element = getElement(reader); - if (!inserted && insertBefore.contains(element)) { - // Insert generated content here - writer.println(insertStartMarker); - while (true) { - String line = fragmentReader.readLine(); - if (line == null) { - writer.println(); - break; - } - writer.println(line); - } - writer.println(insertEndMarker); - writer.println(); - writer.write(element); - inserted = true; - } else if (element.equals(insertStartMarker)) { - // Skip the previous auto-generated content - while (true) { - current = reader.read(); - if (current < 0) { - throw new EOFException(); - } - if (current == '<') { - element = getElement(reader); - if (element.equals(insertEndMarker)) { - break; - } - } - } - current = reader.read(); - while (current == '\n' || current == '\r') { - current = reader.read(); - } - continue; - } else { - writer.write(element); - } - } else { - writer.write(current); - } - current = reader.read(); - } - writer.close(); - - reader.close(); - fragmentReader.close(); - - FileInputStream fis = new FileInputStream(webXml2); - FileOutputStream fos = new FileOutputStream(webXml); - - byte buf[] = new byte[512]; - while (true) { - int n = fis.read(buf); - if (n < 0) { - break; - } - fos.write(buf, 0, n); - } - - fis.close(); - fos.close(); - - if(!webXml2.delete() && log.isDebugEnabled()) - log.debug(Localizer.getMessage("jspc.delete.fail", - webXml2.toString())); - - if (!(new File(webxmlFile)).delete() && log.isDebugEnabled()) - log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile)); - - } - - /* - * Assumes valid xml - */ - private String getElement(Reader reader) throws IOException { - StringBuilder result = new StringBuilder(); - result.append('<'); - - boolean done = false; - - while (!done) { - int current = reader.read(); - while (current != '>') { - if (current < 0) { - throw new EOFException(); - } - result.append((char) current); - current = reader.read(); - } - result.append((char) current); - - int len = result.length(); - if (len > 4 && result.substring(0, 4).equals("")) { - done = true; - } - } else { - done = true; - } - } - - - return result.toString(); - } - - protected void processFile(String file) - throws JasperException - { - if (log.isDebugEnabled()) { - log.debug("Processing file: " + file); - } - - ClassLoader originalClassLoader = null; - - try { - // set up a scratch/output dir if none is provided - if (scratchDir == null) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = ""; - } - scratchDir = new File(new File(temp).getAbsolutePath()); - } - - String jspUri=file.replace('\\','/'); - JspCompilationContext clctxt = new JspCompilationContext - ( jspUri, this, context, null, rctxt ); - - /* Override the defaults */ - if ((targetClassName != null) && (targetClassName.length() > 0)) { - clctxt.setServletClassName(targetClassName); - targetClassName = null; - } - if (targetPackage != null) { - clctxt.setServletPackageName(targetPackage); - } - - originalClassLoader = Thread.currentThread().getContextClassLoader(); - if( loader==null ) { - initClassLoader( clctxt ); - } - Thread.currentThread().setContextClassLoader(loader); - - clctxt.setClassLoader(loader); - clctxt.setClassPath(classPath); - - Compiler clc = clctxt.createCompiler(); - - // If compile is set, generate both .java and .class, if - // .jsp file is newer than .class file; - // Otherwise only generate .java, if .jsp file is newer than - // the .java file - if( clc.isOutDated(compile) ) { - if (log.isDebugEnabled()) { - log.debug(jspUri + " is out dated, compiling..."); - } - - clc.compile(compile, true); - } - - // Generate mapping - generateWebMapping( file, clctxt ); - if ( showSuccess ) { - log.info( "Built File: " + file ); - } - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - log.error(Localizer.getMessage("jspc.error.generalException", - file), - rootCause); - } - - // Bugzilla 35114. - if(getFailOnError()) { - throw je; - } else { - log.error(je.getMessage()); - } - - } catch (Exception e) { - if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", - e.getMessage())); - } - throw new JasperException(e); - } finally { - if(originalClassLoader != null) { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - - /** - * Locate all jsp files in the webapp. Used if no explicit - * jsps are specified. - */ - public void scanFiles( File base ) throws JasperException { - Stack dirs = new Stack(); - dirs.push(base.toString()); - - // Make sure default extensions are always included - if ((getExtensions() == null) || (getExtensions().size() < 2)) { - addExtension("jsp"); - addExtension("jspx"); - } - - while (!dirs.isEmpty()) { - String s = dirs.pop(); - File f = new File(s); - if (f.exists() && f.isDirectory()) { - String[] files = f.list(); - String ext; - for (int i = 0; (files != null) && i < files.length; i++) { - File f2 = new File(s, files[i]); - if (f2.isDirectory()) { - dirs.push(f2.getPath()); - } else { - String path = f2.getPath(); - String uri = path.substring(uriRoot.length()); - ext = files[i].substring(files[i].lastIndexOf('.') +1); - if (getExtensions().contains(ext) || - jspConfig.isJspPage(uri)) { - pages.add(path); - } - } - } - } - } - } - - /** - * Executes the compilation. - * - * @throws JasperException If an error occurs - */ - public void execute() { - if(log.isDebugEnabled()) { - log.debug("execute() starting for " + pages.size() + " pages."); - } - - try { - if (uriRoot == null) { - if( pages.size() == 0 ) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.missingTarget")); - } - String firstJsp = pages.get( 0 ); - File firstJspF = new File( firstJsp ); - if (!firstJspF.exists()) { - throw new JasperException( - Localizer.getMessage("jspc.error.fileDoesNotExist", - firstJsp)); - } - locateUriRoot( firstJspF ); - } - - if (uriRoot == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.no_uriroot")); - } - - File uriRootF = new File(uriRoot); - if (!uriRootF.isDirectory()) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); - } - - if(context == null) { - initServletContext(); - } - - // No explicit pages, we'll process all .jsp in the webapp - if (pages.size() == 0) { - scanFiles(uriRootF); - } - - initWebXml(); - - Iterator iter = pages.iterator(); - while (iter.hasNext()) { - String nextjsp = iter.next().toString(); - File fjsp = new File(nextjsp); - if (!fjsp.isAbsolute()) { - fjsp = new File(uriRootF, nextjsp); - } - if (!fjsp.exists()) { - if (log.isWarnEnabled()) { - log.warn - (Localizer.getMessage - ("jspc.error.fileDoesNotExist", fjsp.toString())); - } - continue; - } - String s = fjsp.getAbsolutePath(); - if (s.startsWith(uriRoot)) { - nextjsp = s.substring(uriRoot.length()); - } - if (nextjsp.startsWith("." + File.separatorChar)) { - nextjsp = nextjsp.substring(2); - } - processFile(nextjsp); - } - - completeWebXml(); - - if (addWebXmlMappings) { - mergeIntoWebXml(); - } - - } catch (IOException ioe) { - throw new RuntimeException("Build - "+ioe, ioe); - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - rootCause.printStackTrace(); - } - throw new RuntimeException("Build - "+je, je); - } finally { - if (loader != null) { - LogFactory.release(loader); - } - } - } - - // ==================== protected utility methods ==================== - - protected String nextArg() { - if ((argPos >= args.length) - || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { - return null; - } else { - return args[argPos++]; - } - } - - protected String nextFile() { - if (fullstop) argPos++; - if (argPos >= args.length) { - return null; - } else { - return args[argPos++]; - } - } - - protected void initWebXml() { - try { - if (webxmlLevel >= INC_WEBXML) { - mapout = openWebxmlWriter(new File(webxmlFile)); - servletout = new CharArrayWriter(); - mappingout = new CharArrayWriter(); - } else { - mapout = null; - servletout = null; - mappingout = null; - } - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.header")); - mapout.flush(); - } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.header")); - mapout.flush(); - } - } catch (IOException ioe) { - mapout = null; - servletout = null; - mappingout = null; - } - } - - protected void completeWebXml() { - if (mapout != null) { - try { - servletout.writeTo(mapout); - mappingout.writeTo(mapout); - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.footer")); - } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.footer")); - } - mapout.close(); - } catch (IOException ioe) { - // noting to do if it fails since we are done with it - } - } - } - - protected void initServletContext() { - try { - context =new JspCServletContext - (new PrintWriter(System.out), - new URL("file:" + uriRoot.replace('\\','/') + '/')); - tldLocationsCache = TldLocationsCache.getInstance(context); - } catch (MalformedURLException me) { - System.out.println("**" + me); - } - rctxt = new JspRuntimeContext(context, this); - jspConfig = new JspConfig(context); - tagPluginManager = new TagPluginManager(context); - } - - /** - * Initializes the classloader as/if needed for the given - * compilation context. - * - * @param clctxt The compilation context - * @throws IOException If an error occurs - */ - protected void initClassLoader(JspCompilationContext clctxt) - throws IOException { - - classPath = getClassPath(); - - ClassLoader jspcLoader = getClass().getClassLoader(); - // TODO add 7Bee class loader - // Turn the classPath into URLs - ArrayList urls = new ArrayList(); - StringTokenizer tokenizer = new StringTokenizer(classPath, - File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - String path = tokenizer.nextToken(); - try { - File libFile = new File(path); - urls.add(libFile.toURI().toURL()); - } catch (IOException ioe) { - // Failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak uot - throw new RuntimeException(ioe.toString()); - } - } - - File webappBase = new File(uriRoot); - if (webappBase.exists()) { - File classes = new File(webappBase, "/WEB-INF/classes"); - try { - if (classes.exists()) { - classPath = classPath + File.pathSeparator - + classes.getCanonicalPath(); - urls.add(classes.getCanonicalFile().toURI().toURL()); - } - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - File lib = new File(webappBase, "/WEB-INF/lib"); - if (lib.exists() && lib.isDirectory()) { - String[] libs = lib.list(); - for (int i = 0; i < libs.length; i++) { - if( libs[i].length() <5 ) continue; - String ext=libs[i].substring( libs[i].length() - 4 ); - if (! ".jar".equalsIgnoreCase(ext)) { - if (".tld".equalsIgnoreCase(ext)) { - log.warn("TLD files should not be placed in " - + "/WEB-INF/lib"); - } - continue; - } - try { - File libFile = new File(lib, libs[i]); - classPath = classPath + File.pathSeparator - + libFile.getAbsolutePath(); - urls.add(libFile.getAbsoluteFile().toURI().toURL()); - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - } - } - } - - // What is this ?? - urls.add(new File( - clctxt.getRealPath("/")).getCanonicalFile().toURI().toURL()); - - URL urlsA[]=new URL[urls.size()]; - urls.toArray(urlsA); - loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); - context.setClassLoader(loader); - } - - /** - * Find the WEB-INF dir by looking up in the directory tree. - * This is used if no explicit docbase is set, but only files. - * XXX Maybe we should require the docbase. - */ - protected void locateUriRoot( File f ) { - String tUriBase = uriBase; - if (tUriBase == null) { - tUriBase = "/"; - } - try { - if (f.exists()) { - f = new File(f.getAbsolutePath()); - while (true) { - File g = new File(f, "WEB-INF"); - if (g.exists() && g.isDirectory()) { - uriRoot = f.getCanonicalPath(); - uriBase = tUriBase; - if (log.isInfoEnabled()) { - log.info(Localizer.getMessage( - "jspc.implicit.uriRoot", - uriRoot)); - } - break; - } - if (f.exists() && f.isDirectory()) { - tUriBase = "/" + f.getName() + "/" + tUriBase; - } - - String fParent = f.getParent(); - if (fParent == null) { - break; - } else { - f = new File(fParent); - } - - // If there is no acceptable candidate, uriRoot will - // remain null to indicate to the CompilerContext to - // use the current working/user dir. - } - - if (uriRoot != null) { - File froot = new File(uriRoot); - uriRoot = froot.getCanonicalPath(); - } - } - } catch (IOException ioe) { - // since this is an optional default and a null value - // for uriRoot has a non-error meaning, we can just - // pass straight through - } - } - - /** - * Resolves the relative or absolute pathname correctly - * in both Ant and command-line situations. If Ant launched - * us, we should use the basedir of the current project - * to resolve relative paths. - * - * See Bugzilla 35571. - * - * @param s The file - * @return The file resolved - */ - protected File resolveFile(final String s) { - // TODO consider some massaging of s as relative path to project home - return new File(s); - } - - private Reader openWebxmlReader(File file) throws IOException { - FileInputStream fis = new FileInputStream(file); - try { - return webxmlEncoding != null ? new InputStreamReader(fis, - webxmlEncoding) : new InputStreamReader(fis); - } catch (IOException ex) { - fis.close(); - throw ex; - } - } - - private Writer openWebxmlWriter(File file) throws IOException { - FileOutputStream fos = new FileOutputStream(file); - try { - return webxmlEncoding != null ? new OutputStreamWriter(fos, - webxmlEncoding) : new OutputStreamWriter(fos); - } catch (IOException ex) { - fos.close(); - throw ex; - } - } -} diff --git a/1.x/src/jasper7/JspCompilationContext.java b/1.x/src/jasper7/JspCompilationContext.java deleted file mode 100644 index df5a177..0000000 --- a/1.x/src/jasper7/JspCompilationContext.java +++ /dev/null @@ -1,794 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JarResource; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.JspUtil; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.ServletWriter; -import org.apache.jasper.compiler.TldLocation; -import org.apache.jasper.servlet.JasperLoader; -import org.apache.jasper.servlet.JspServletWrapper; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * A place holder for various things that are used through out the JSP - * engine. This is a per-request/per-context data structure. Some of - * the instance variables are set at different points. - * - * Most of the path-related stuff is here - mangling names, versions, dirs, - * loading resources and dealing with uris. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Pierre Delisle - * @author Costin Manolache - * @author Kin-man Chung - */ -public class JspCompilationContext { - - private final Log log = LogFactory.getLog(JspCompilationContext.class); // must not be static - - protected Map tagFileJarUrls; - - protected String className; - protected String jspUri; - protected String basePackageName; - protected String derivedPackageName; - protected String servletJavaFileName; - protected String javaPath; - protected String classFileName; - protected ServletWriter writer; - protected Options options; - protected JspServletWrapper jsw; - protected Compiler jspCompiler; - protected String classPath; - - protected String baseURI; - protected String outputDir; - protected ServletContext context; - protected ClassLoader loader; - - protected JspRuntimeContext rctxt; - - protected volatile int removed = 0; - - protected URLClassLoader jspLoader; - protected URL baseUrl; - protected Class servletClass; - - protected boolean isTagFile; - protected boolean protoTypeMode; - protected TagInfo tagInfo; - protected JarResource tagJarResource; - - // jspURI _must_ be relative to the context - public JspCompilationContext(String jspUri, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt) { - - this.jspUri = canonicalURI(jspUri); - this.options = options; - this.jsw = jsw; - this.context = context; - - this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); - // hack fix for resolveRelativeURI - if (baseURI == null) { - baseURI = "/"; - } else if (baseURI.charAt(0) != '/') { - // strip the base slash since it will be combined with the - // uriBase to generate a file - baseURI = "/" + baseURI; - } - if (baseURI.charAt(baseURI.length() - 1) != '/') { - baseURI += '/'; - } - - this.rctxt = rctxt; - this.tagFileJarUrls = new HashMap(); - this.basePackageName = Constants.JSP_PACKAGE_NAME; - } - - public JspCompilationContext(String tagfile, - TagInfo tagInfo, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt, - JarResource tagJarResource) { - this(tagfile, options, context, jsw, rctxt); - this.isTagFile = true; - this.tagInfo = tagInfo; - this.tagJarResource = tagJarResource; - } - - /* ==================== Methods to override ==================== */ - - /** ---------- Class path and loader ---------- */ - - /** - * The classpath that is passed off to the Java compiler. - */ - public String getClassPath() { - if( classPath != null ) - return classPath; - return rctxt.getClassPath(); - } - - /** - * The classpath that is passed off to the Java compiler. - */ - public void setClassPath(String classPath) { - this.classPath = classPath; - } - - /** - * What class loader to use for loading classes while compiling - * this JSP? - */ - public ClassLoader getClassLoader() { - if( loader != null ) - return loader; - return rctxt.getParentClassLoader(); - } - - public void setClassLoader(ClassLoader loader) { - this.loader = loader; - } - - public ClassLoader getJspLoader() { - if( jspLoader == null ) { - jspLoader = new JasperLoader - (new URL[] {baseUrl}, - getClassLoader(), - rctxt.getPermissionCollection()); - } - return jspLoader; - } - - /** ---------- Input/Output ---------- */ - - /** - * The output directory to generate code into. The output directory - * is make up of the scratch directory, which is provide in Options, - * plus the directory derived from the package name. - */ - public String getOutputDir() { - if (outputDir == null) { - createOutputDir(); - } - - return outputDir; - } - - /** - * Create a "Compiler" object based on some init param data. This - * is not done yet. Right now we're just hardcoding the actual - * compilers that are created. - */ - public Compiler createCompiler() { - if (jspCompiler != null ) { - return jspCompiler; - } - jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); - if (jspCompiler == null) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); - } - jspCompiler.init(this, jsw); - return jspCompiler; - } - - protected Compiler createCompiler(String className) { - Compiler compiler = null; - try { - compiler = (Compiler) Class.forName(className).newInstance(); - } catch (InstantiationException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (IllegalAccessException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (NoClassDefFoundError e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } catch (ClassNotFoundException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } - return compiler; - } - - public Compiler getCompiler() { - return jspCompiler; - } - - /** ---------- Access resources in the webapp ---------- */ - - /** - * Get the full value of a URI relative to this compilations context - * uses current file as the base. - */ - public String resolveRelativeUri(String uri) { - // sometimes we get uri's massaged from File(String), so check for - // a root directory separator char - if (uri.startsWith("/") || uri.startsWith(File.separator)) { - return uri; - } else { - return baseURI + uri; - } - } - - /** - * Gets a resource as a stream, relative to the meanings of this - * context's implementation. - * @return a null if the resource cannot be found or represented - * as an InputStream. - */ - public java.io.InputStream getResourceAsStream(String res) { - return context.getResourceAsStream(canonicalURI(res)); - } - - - public URL getResource(String res) throws MalformedURLException { - URL result = null; - - if (res.startsWith("/META-INF/")) { - // This is a tag file packaged in a jar that is being compiled - JarResource jarResource = tagFileJarUrls.get(res); - if (jarResource == null) { - jarResource = tagJarResource; - } - if (jarResource != null) { - result = jarResource.getEntry(res.substring(1)); - } else { - // May not be in a JAR in some IDE environments - result = context.getResource(canonicalURI(res)); - } - } else if (res.startsWith("jar:jndi:")) { - // This is a tag file packaged in a jar that is being checked - // for a dependency - result = new URL(res); - - } else { - result = context.getResource(canonicalURI(res)); - } - return result; - } - - - public Set getResourcePaths(String path) { - return context.getResourcePaths(canonicalURI(path)); - } - - /** - * Gets the actual path of a URI relative to the context of - * the compilation. - */ - public String getRealPath(String path) { - if (context != null) { - return context.getRealPath(path); - } - return path; - } - - /** - * Returns the tag-file-name-to-JAR-file map of this compilation unit, - * which maps tag file names to the JAR files in which the tag files are - * packaged. - * - * The map is populated when parsing the tag-file elements of the TLDs - * of any imported taglibs. - */ - public JarResource getTagFileJarResource(String tagFile) { - return this.tagFileJarUrls.get(tagFile); - } - - public void setTagFileJarResource(String tagFile, JarResource jarResource) { - this.tagFileJarUrls.put(tagFile, jarResource); - } - - /** - * Returns the JAR file in which the tag file for which this - * JspCompilationContext was created is packaged, or null if this - * JspCompilationContext does not correspond to a tag file, or if the - * corresponding tag file is not packaged in a JAR. - */ - public JarResource getTagFileJarResource() { - return this.tagJarResource; - } - - /* ==================== Common implementation ==================== */ - - /** - * Just the class name (does not include package name) of the - * generated class. - */ - public String getServletClassName() { - - if (className != null) { - return className; - } - - if (isTagFile) { - className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - if (lastIndex != -1) { - className = className.substring(lastIndex + 1); - } - } else { - int iSep = jspUri.lastIndexOf('/') + 1; - className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); - } - return className; - } - - public void setServletClassName(String className) { - this.className = className; - } - - /** - * Path of the JSP URI. Note that this is not a file name. This is - * the context rooted URI of the JSP file. - */ - public String getJspFile() { - return jspUri; - } - - /** - * @deprecated Will be removed in Tomcat 8.0.x. Use - * {@link #getLastModified(String)} instead. - */ - @Deprecated - public long getJspLastModified() { - long result = -1; - URLConnection uc = null; - try { - URL jspUrl = getResource(getJspFile()); - if (jspUrl == null) { - incrementRemoved(); - return result; - } - uc = jspUrl.openConnection(); - if (uc instanceof JarURLConnection) { - result = ((JarURLConnection) uc).getJarEntry().getTime(); - } else { - result = uc.getLastModified(); - } - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } finally { - if (uc != null) { - try { - uc.getInputStream().close(); - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } - } - } - return result; - } - - - public Long getLastModified(String resource) { - long result = -1; - URLConnection uc = null; - try { - URL jspUrl = getResource(resource); - if (jspUrl == null) { - incrementRemoved(); - return Long.valueOf(result); - } - File resFile = new File(jspUrl.getFile()); // TJWS on Android - if (resFile.exists()) { - result = resFile.lastModified(); - } else { - uc = jspUrl.openConnection(); - if (uc instanceof JarURLConnection) { - result = ((JarURLConnection) uc).getJarEntry().getTime(); - } else { - result = uc.getLastModified(); - } - } - //System.out.printf("Jasper ctx %s modified %d / %s%n", uc, result, resFile); - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } finally { - if (uc != null) { - try { - uc.getInputStream().close(); - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage( - "jsp.error.lastModified", getJspFile()), e); - } - result = -1; - } - } - } - return Long.valueOf(result); - } - - public boolean isTagFile() { - return isTagFile; - } - - public TagInfo getTagInfo() { - return tagInfo; - } - - public void setTagInfo(TagInfo tagi) { - tagInfo = tagi; - } - - /** - * True if we are compiling a tag file in prototype mode. - * ie we only generate codes with class for the tag handler with empty - * method bodies. - */ - public boolean isPrototypeMode() { - return protoTypeMode; - } - - public void setPrototypeMode(boolean pm) { - protoTypeMode = pm; - } - - /** - * Package name for the generated class is make up of the base package - * name, which is user settable, and the derived package name. The - * derived package name directly mirrors the file hierarchy of the JSP page. - */ - public String getServletPackageName() { - if (isTagFile()) { - String className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - String pkgName = ""; - if (lastIndex != -1) { - pkgName = className.substring(0, lastIndex); - } - return pkgName; - } else { - String dPackageName = getDerivedPackageName(); - if (dPackageName.length() == 0) { - return basePackageName; - } - return basePackageName + '.' + getDerivedPackageName(); - } - } - - protected String getDerivedPackageName() { - if (derivedPackageName == null) { - int iSep = jspUri.lastIndexOf('/'); - derivedPackageName = (iSep > 0) ? - JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : ""; - } - return derivedPackageName; - } - - /** - * The package name into which the servlet class is generated. - */ - public void setServletPackageName(String servletPackageName) { - this.basePackageName = servletPackageName; - } - - /** - * Full path name of the Java file into which the servlet is being - * generated. - */ - public String getServletJavaFileName() { - if (servletJavaFileName == null) { - servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; - } - return servletJavaFileName; - } - - /** - * Get hold of the Options object for this context. - */ - public Options getOptions() { - return options; - } - - public ServletContext getServletContext() { - return context; - } - - public JspRuntimeContext getRuntimeContext() { - return rctxt; - } - - /** - * Path of the Java file relative to the work directory. - */ - public String getJavaPath() { - - if (javaPath != null) { - return javaPath; - } - - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - javaPath = tagName.replace('.', '/') + ".java"; - } else { - javaPath = getServletPackageName().replace('.', '/') + '/' + - getServletClassName() + ".java"; - } - return javaPath; - } - - public String getClassFileName() { - if (classFileName == null) { - classFileName = getOutputDir() + getServletClassName() + ".class"; - } - return classFileName; - } - - /** - * Where is the servlet being generated? - */ - public ServletWriter getWriter() { - return writer; - } - - public void setWriter(ServletWriter writer) { - this.writer = writer; - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the given uri is not associated with any tag library - * 'exposed' in the web application. - */ - public TldLocation getTldLocation(String uri) throws JasperException { - TldLocation location = - getOptions().getTldLocationsCache().getLocation(uri); - return location; - } - - /** - * Are we keeping generated code around? - */ - public boolean keepGenerated() { - return getOptions().getKeepGenerated(); - } - - // ==================== Removal ==================== - - public void incrementRemoved() { - if (removed == 0 && rctxt != null) { - rctxt.removeWrapper(jspUri); - } - removed++; - } - - public boolean isRemoved() { - if (removed > 0 ) { - return true; - } - return false; - } - - // ==================== Compile and reload ==================== - - public void compile() throws JasperException, FileNotFoundException { - createCompiler(); - if (jspCompiler.isOutDated()) { - if (isRemoved()) { - throw new FileNotFoundException(jspUri); - } - try { - jspCompiler.removeGeneratedFiles(); - jspLoader = null; - jspCompiler.compile(); - jsw.setReload(true); - jsw.setCompilationException(null); - } catch (JasperException ex) { - // Cache compilation exception - jsw.setCompilationException(ex); - if (options.getDevelopment() && options.getRecompileOnFail()) { - // Force a recompilation attempt on next access - jsw.setLastModificationTest(-1); - } - throw ex; - } catch (Exception ex) { - JasperException je = new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), - ex); - // Cache compilation exception - jsw.setCompilationException(je); - throw je; - } - } - } - - // ==================== Manipulating the class ==================== - - public Class load() throws JasperException { - try { - getJspLoader(); - - String name = getFQCN(); - servletClass = jspLoader.loadClass(name); - } catch (ClassNotFoundException cex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), - cex); - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), - ex); - } - removed = 0; - return servletClass; - } - - public String getFQCN() { - String name; - if (isTagFile()) { - name = tagInfo.getTagClassName(); - } else { - name = getServletPackageName() + "." + getServletClassName(); - } - return name; - } - - // ==================== protected methods ==================== - - static Object outputDirLock = new Object(); - - public void checkOutputDir() { - if (outputDir != null) { - if (!(new File(outputDir)).exists()) { - makeOutputDir(); - } - } else { - createOutputDir(); - } - } - - protected boolean makeOutputDir() { - synchronized(outputDirLock) { - File outDirFile = new File(outputDir); - return (outDirFile.exists() || outDirFile.mkdirs()); - } - } - - protected void createOutputDir() { - String path = null; - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - path = tagName.replace('.', File.separatorChar); - path = path.substring(0, path.lastIndexOf(File.separatorChar)); - } else { - path = getServletPackageName().replace('.',File.separatorChar); - } - - // Append servlet or tag handler path to scratch dir - try { - File base = options.getScratchDir(); - baseUrl = base.toURI().toURL(); - outputDir = base.getAbsolutePath() + File.separator + path + - File.separator; - if (!makeOutputDir()) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); - } - } catch (MalformedURLException e) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); - } - } - - protected static final boolean isPathSeparator(char c) { - return (c == '/' || c == '\\'); - } - - protected static final String canonicalURI(String s) { - if (s == null) return null; - StringBuilder result = new StringBuilder(); - final int len = s.length(); - int pos = 0; - while (pos < len) { - char c = s.charAt(pos); - if ( isPathSeparator(c) ) { - /* - * multiple path separators. - * 'foo///bar' -> 'foo/bar' - */ - while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) { - ++pos; - } - - if (pos+1 < len && s.charAt(pos+1) == '.') { - /* - * a single dot at the end of the path - we are done. - */ - if (pos+2 >= len) break; - - switch (s.charAt(pos+2)) { - /* - * self directory in path - * foo/./bar -> foo/bar - */ - case '/': - case '\\': - pos += 2; - continue; - - /* - * two dots in a path: go back one hierarchy. - * foo/bar/../baz -> foo/baz - */ - case '.': - // only if we have exactly _two_ dots. - if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) { - pos += 3; - int separatorPos = result.length()-1; - while (separatorPos >= 0 && - ! isPathSeparator(result - .charAt(separatorPos))) { - --separatorPos; - } - if (separatorPos >= 0) - result.setLength(separatorPos); - continue; - } - } - } - } - result.append(c); - ++pos; - } - return result.toString(); - } -} - diff --git a/1.x/src/rogatkin/app/Main.java b/1.x/src/rogatkin/app/Main.java deleted file mode 100644 index 68f8f49..0000000 --- a/1.x/src/rogatkin/app/Main.java +++ /dev/null @@ -1,184 +0,0 @@ -/* tjws - Main.java - * Copyright (C) 1999-2010 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: Main.java,v 1.16 2013/03/20 03:49:46 cvs Exp $ - * Created on Mar 27, 2007 - * @author Dmitriy - */ -package rogatkin.app; - -import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.HashSet; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; - -import rogatkin.web.WebApp; -import rogatkin.web.WebAppServlet; -import Acme.Utils; - -public class Main { - public static final String APP_MAIN_CLASS = "tjws.app.main"; - - public static final String APP_MAIN_CLASSPATH = "tjws.app.main.classpath"; - - public static final String APP_MAIN_STRIP_PARAM_RIGHT = "tjws.app.main.striprightparam"; - - public static final String APP_MAIN_STRIP_PARAM_LEFT = "tjws.app.main.stripleftparam"; - - /** - * @param args - */ - public static void main(String[] args) { - String mainClass = System.getProperty(APP_MAIN_CLASS); - if (mainClass == null) - Acme.Serve.Main.main(initAppServer(args)); - else { - URLClassLoader cl = null; - try { - String cp = System.getProperty(APP_MAIN_CLASSPATH); - if (cp != null) { - String[] cps = cp.split(File.pathSeparator); - URL urls[] = new URL[cps.length]; - for (int i = 0; i < cps.length; i++) { - if (cps[i].startsWith("file:") == false && cps[i].startsWith("http:") == false - && cps[i].startsWith("https:") == false) - urls[i] = new URL("file:/" + cps[i]); // new URL("file", "localhost/", cps[i]) - else - urls[i] = new URL(cps[i]); - } - cl = new URLClassLoader(urls); - } - Class main = cl == null ? Class.forName(mainClass) : Class.forName(mainClass, true, cl); - if (cl != null) - Thread.currentThread().setContextClassLoader(cl); - main.getDeclaredMethod("main", String[].class).invoke(null, - new Object[] { rangeParam(initAppServer(args)) }); - } catch (Exception e) { - System.err.printf("Can't launch a user app %s (%s) due: %s", mainClass, - Arrays.toString(cl == null ? new URL[] {} : cl.getURLs()), e); - e.printStackTrace(); - } - } - } - - protected static String[] rangeParam(String... params) { - String range = System.getProperty(APP_MAIN_STRIP_PARAM_RIGHT); - if (range != null) - return Utils.copyOf(params, Integer.parseInt(range)); - range = System.getProperty(APP_MAIN_STRIP_PARAM_LEFT); - if (range != null) - return Utils.copyOfRange(params, Integer.parseInt(range), params.length); - return params; - } - - protected static String[] initAppServer(String... args) { - // defaulting JNDI - if (System.getProperty(Context.INITIAL_CONTEXT_FACTORY) == null) - System.getProperties().setProperty(Context.INITIAL_CONTEXT_FACTORY, SimpleJndi.class.getName()); - if (System.getProperty(Context.PROVIDER_URL) == null) - System.getProperties() - .setProperty(Context.PROVIDER_URL, "http://localhost:1221"/*"tjws://localhost:1221"*/); - try { - final Context namingContext = new InitialContext(); - WebAppServlet.setAppContextDelegator(new WebAppServlet.AppContextDelegator() { - public Object lookup(String name) { - try { - return namingContext.lookup(name); - } catch (NamingException nce) { - throw new RuntimeException("Can't delegate naming context operation", nce); - } - } - - public Object lookupLink(String name) { - try { - return namingContext.lookupLink(name); - } catch (NamingException nce) { - throw new RuntimeException("Can't delegate naming context operation", nce); - } - } - - public void add(String name, Object obj) { - - try { - if (obj instanceof WebApp.MetaContext) { - SimpleDataSource sds = new SimpleDataSource(((WebApp.MetaContext) obj).getPath(), ((WebApp.MetaContext) obj).getClassLoader()); - // TODO all data sources created form App class path have to be destroyed at the app destroy - if (sds.isScopeApp()) { - HashSet dsmap = (HashSet)namingContext.getEnvironment().get(name); - if (dsmap == null) { - dsmap = new HashSet(); - namingContext.addToEnvironment(name, dsmap); - } - dsmap.add(sds); //System.err.printf("Adding %s for %s%n", sds, name); - } - } else - namingContext.addToEnvironment(name, obj); - } catch (NamingException nce) { - throw new RuntimeException("Can't delegate naming context operation", nce); - } - } - - @Override - public Object remove(String name) { - Object result = null; - try { - result = namingContext.removeFromEnvironment(name); - if (result instanceof HashSet) { - for (SimpleDataSource sds:(HashSet)result) //{ - sds.invalidate(); //System.err.printf("Invalidating %s for %s%n", sds, name);} - } - return result; - } catch (NamingException e) { - //throw new RuntimeException("Can't resolve context in environment"); - } - return result; - } - - }); - } catch (NamingException nce) { - System.err.printf("Can not obtain initial naming context (%s) because %s%n", - System.getProperty(Context.INITIAL_CONTEXT_FACTORY), nce); - } - // Perhaps it should be set Context.URL_PKG_PREFIXES - //System.out.println("Xmx set "+Runtime.getRuntime().maxMemory()); - if (args.length == 0) - args = Acme.Serve.Main.readArguments(System.getProperty("user.dir", "."), Acme.Serve.Main.CLI_FILENAME); - if (args != null) - for (int i = 0; i < args.length; i++) { - if ("-dataSource".equals(args[i])) { - try { - new SimpleDataSource(args[++i], null); - } catch (IllegalArgumentException e) { - System.err.printf("Data source %s wasn't created because %s%n", args[i], e); - } - } - } - return args; - } -} diff --git a/1.x/src/rogatkin/app/ObjectPool.java b/1.x/src/rogatkin/app/ObjectPool.java deleted file mode 100644 index c692ee6..0000000 --- a/1.x/src/rogatkin/app/ObjectPool.java +++ /dev/null @@ -1,181 +0,0 @@ -/* tjws - ObjectPool.java - * Copyright (C) 2010 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: ObjectPool.java,v 1.15 2012/06/23 06:59:29 dmitriy Exp $ - * Created on Mar 5, 2008 - * @author Dmitriy - * - */ -package rogatkin.app; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; - -public abstract class ObjectPool { - protected String[] descardMethods = { "destroy", "close" }; - - protected BlockingQueue pool; - - protected ArrayList borrowed; - - protected int timeout; - - private boolean monitor; - - public static Class Wrapper; - - static { - try { - Wrapper = Class.forName("java.sql.Wrapper"); - } catch (ClassNotFoundException e) { - System.err.printf("Your Java runtime doesn't support JDBC 3.0 (%s), some functionality can be supressed.", e); - } - } - - protected abstract O create(); - - protected void discard(O obj) { - //System.err.printf("Discard %s%n", obj); - if (Wrapper != null && Wrapper.isAssignableFrom(obj.getClass())) - try { - //obj = (O)((Wrapper)obj).unwrap(obj.getClass()); - obj = (O) obj.getClass().getMethod("unwrap", Class.class).invoke(obj, obj.getClass()); - } catch (Exception e1) { - } - for (int i = 0; i < descardMethods.length; i++) { - try { - obj.getClass().getMethod(descardMethods[i], new Class[] {}).invoke(obj, new Object[] {}); - break; - } catch (IllegalArgumentException e) { - } catch (SecurityException e) { - } catch (IllegalAccessException e) { - } catch (InvocationTargetException e) { - } catch (NoSuchMethodException e) { - } - } - } - - public ObjectPool(BlockingQueue bq) { - if (bq != null) { - pool = bq; - borrowed = new ArrayList(bq.size()); - } else - throw new NullPointerException(); - } - - public O get() { - O result = get1(); - if (result != null) { - assert (borrowed.contains(result) == false); - synchronized (borrowed) { - borrowed.add(result); - // new Exception(String.format("Added in used %s size %d", result, borrowed.size())).printStackTrace(); - } - if (monitor) { - // get stack trace for identifying a caller and store the information among with request time - if (result instanceof Monitor) - ((Monitor) result).putMark(getClass().getName()); - } - } - return result; - } - - private O get1() { - if (pool.isEmpty() && borrowed.size() < getCapacity()) - return create(); - //System.err.printf("get %s%n", o); - try { - if (timeout > 0) - return pool.poll(timeout, TimeUnit.MILLISECONDS); - return pool.take(); - } catch (InterruptedException e) { - } - return null; - } - - public void put(O obj) { - assert borrowed.contains(obj); - synchronized (borrowed) { - if (borrowed.remove(obj) == false) - return; // connection already removed - } - // no synchronization between increasing limit and offering the connection for consumption is considered - // as acceptable, offering connection first and then decreasing limit can issue objects starvation, - // it will also require using set for borrowing list - //new Exception(String.format("returned %s, still in use: %d", obj, borrowed.size())).printStackTrace(); - if (pool.offer(obj) == false) { - // no room, discard the object - discard(obj); - } - } - - public void remove(O obj) { - if (borrowed.contains(obj)) - synchronized (borrowed) { - if (borrowed.remove(obj) == false) - System.err.println("Object " + obj + " wasn't removed"); - } - else { - if (pool.remove(obj) == false) - System.err.println("Object " + obj + " wasn't removed from pool"); - } - // TODO generally discard can have side effect - discard(obj); - } - - public void setTimeout(int to) { - timeout = to; - } - - /** resizes the pool - * - * @param newSize - */ - public abstract int getCapacity(); - - public void invalidate() { - ArrayList forDiscard = new ArrayList(); - pool.drainTo(forDiscard); - for (O o : forDiscard) - discard(o); - if (borrowed.size() > 0) - throw new IllegalStateException("Pool invalidate with borrowed objects"); - } - - /** The interface is used for marking pooled object by requester id - * and access time - * @author dmitriy - * - */ - public static interface Monitor { - void putMark(String boundaryClassName); - - String getMarkCaller(); - - long getMarkTime(); - } - -} diff --git a/1.x/src/rogatkin/app/SimpleDataSource.java b/1.x/src/rogatkin/app/SimpleDataSource.java deleted file mode 100644 index eb2b42b..0000000 --- a/1.x/src/rogatkin/app/SimpleDataSource.java +++ /dev/null @@ -1,522 +0,0 @@ -/* tjws - SimpleDataSource.java - * Copyright (C) 1999-2010 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: SimpleDataSource.java,v 1.30 2013/03/20 03:49:46 cvs Exp $ - * Created on Mar 25, 2007 - * @author Dmitriy - */ -package rogatkin.app; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Properties; -import java.util.concurrent.ArrayBlockingQueue; -import java.sql.SQLFeatureNotSupportedException; -import java.util.logging.Logger; - -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.sql.DataSource; -import javax.sql.RowSet; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -/** - * The class presents data source, which is created based on a property file - *

- * The following properties are allowed:
- *

    - *
  • jndi-name - under this name the data source will be registered in - * JNDI if name starts with jdbc, then prefix - * java:comp/env/ will be added. - *
  • driver-class - class name of JDBC driver - *
  • url - JDBC connection URL - *
  • user - connection user - *
  • password - connection password - *
  • pool-size - max number of allocated connections, 0 = no size - * limitation, -1 = no pool used - *
  • access-timeout - timeout in ms before getting an exception on - * connection request when no connections are available, 0 means wait forever - *
  • driver-class-path - defines class path to driver archive, unless - * it is already in boot classpath - *
  • prob-query defines a query to verify that given connection is - * valid, executed at time getting a connection from pool. If - * isValid is specified as value, then isValid() method of SQL - * connection is used (note that it is available only in Java 6 drivers). If - * isClosed is specified, then isClosed() method used for a - * connection validation. - *
  • exception-handler - a name of class implementing static public - * method boolean validate(SQLException, Connection). This class is used to - * verify if SQLException indicates that the connection isn't valid anymore and - * has to be removed from the pool. The method returns true, if the connection - * still good for further use. - *
  • pool-shrink-size - max available connections in pool (not implemented yet) - *
- * - * @author dmitriy - * - */ -public class SimpleDataSource extends ObjectPool implements DataSource { - public final static String RW_ISVALID = "isValid"; - - public final static String RW_ISCLOSED = "isClosed"; - - public final static String CP_DEFAULT = "application"; - - protected final static int DEFAULT_CAPACITY = 20; - - protected Properties dataSourceProperties, conectionProperties; - - protected Driver driver; - - private int capacity; - - private PrintWriter logWriter; - - private Method connectionValidateMethod; - - private String validateQuery; - - private boolean appCP; - - public SimpleDataSource(String definitionPropertiesLocation, ClassLoader appCL) { - super(new ArrayBlockingQueue(DEFAULT_CAPACITY)); - logWriter = new PrintWriter(System.out); - InputStream propertiesStream = null; - File f = new File(definitionPropertiesLocation); - try { - if (f.exists()) - propertiesStream = new FileInputStream(f); - else { - propertiesStream = new URL(definitionPropertiesLocation).openStream(); - } - dataSourceProperties = new Properties(); - if (definitionPropertiesLocation.toLowerCase().endsWith("context.xml")) - contextToProperties(propertiesStream); - else if (definitionPropertiesLocation.toLowerCase().endsWith(".xml")) - dataSourceProperties.loadFromXML(propertiesStream); - else - dataSourceProperties.load(propertiesStream); - init(appCL); - } catch (FileNotFoundException e) { - throw new IllegalArgumentException(e); - } catch (MalformedURLException e) { - throw new IllegalArgumentException( - "Data source properties file doesn't exist, and can't be resolved as URL", e); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException("Connection validator class problem", e); - } catch (Exception e) { - throw new IllegalArgumentException(e); - } finally { - if (propertiesStream != null) - try { - propertiesStream.close(); - } catch (IOException e) { - } - } - } - - protected void init(ClassLoader classLoader) throws Exception { - String classPath = dataSourceProperties.getProperty("driver-class-path"); - if (classPath == null) { - //if (classLoader != null) - //Class.forName(dataSourceProperties.getProperty("driver-class"), true, classLoader); - //else - String driverClass = dataSourceProperties.getProperty("driver-class"); - if (driverClass == null) - return; // no data source - Class.forName(driverClass); - driver = DriverManager.getDriver(dataSourceProperties.getProperty("url")); - } else { - String[] classPaths = classPath.split(File.pathSeparator); - URL[] urls = new URL[classPaths.length]; - for (int i = 0; i < urls.length; i++) - urls[i] = new URL("file:" + classPaths[i]); - if (CP_DEFAULT.equalsIgnoreCase(classPath)) { - driver = (Driver) Class - .forName(dataSourceProperties.getProperty("driver-class"), true, - classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader) - .newInstance(); - appCP = true; - } else - driver = (Driver) Class - .forName(dataSourceProperties.getProperty("driver-class"), true, - classLoader = new URLClassLoader(urls, DriverManager.class.getClassLoader())) - .newInstance(); - } - conectionProperties = new Properties(); - if (dataSourceProperties.getProperty("user") != null) { - conectionProperties.setProperty("user", dataSourceProperties.getProperty("user")); - if (dataSourceProperties.getProperty("password") != null) - conectionProperties.setProperty("password", dataSourceProperties.getProperty("password")); - } - try { - setTimeout(Integer.parseInt(dataSourceProperties.getProperty("access-timeout"))); - } catch (Exception e) { - } - try { - capacity = Integer.parseInt(dataSourceProperties.getProperty("pool-size")); - this.pool = new ArrayBlockingQueue(capacity, true); - this.borrowed = new ArrayList(capacity); - } catch (Exception e) { - capacity = DEFAULT_CAPACITY; - } - validateQuery = dataSourceProperties.getProperty("prob-query"); - String conValClass = dataSourceProperties.getProperty("exception-handler"); - if (conValClass != null) - connectionValidateMethod = (classLoader == null ? Class.forName(conValClass) - : Class.forName(conValClass, true, classLoader)).getMethod("validate", SQLException.class, - Connection.class); - String jndiName = dataSourceProperties.getProperty("jndi-name"); - if (jndiName != null) { - if (jndiName.startsWith("jdbc/")) - jndiName = "java:comp/env/" + jndiName; - InitialContext ic = new InitialContext(); - try { - ic.lookup(jndiName); - ic.rebind(jndiName, this); - } catch (NamingException ne) { - ic.bind(jndiName, this); - } - } - } - - public Connection getConnection() throws SQLException { - Connection realConn = validateQuery == null ? get() : getValidated(); - return (Connection) Proxy.newProxyInstance(realConn.getClass().getClassLoader(), Wrapper != null ? new Class[] { - Connection.class, Wrapper } : new Class[] { Connection.class }, new ConnectionWrapperHandler(realConn)); - } - - @Override - public String toString() { - Properties masked = (Properties) dataSourceProperties.clone(); - masked.setProperty("password", "*******"); - Properties maskedConn = (Properties) conectionProperties.clone(); - maskedConn.setProperty("password", "*******"); - return "Pooled data source : " + masked + "\n" + maskedConn + "\n capacity:" + capacity - + ", available: " + pool.size() + ", borrowed: " + borrowed.size(); - } - - public boolean isScopeApp() { - return appCP; - } - - private Connection getValidated() { - boolean bad = true; - do { - Connection result = get(); - Statement statement = null; - try { - if (validateQuery.equals(RW_ISVALID)) - try { - if ((Boolean) result.getClass().getMethod("isValid", int.class).invoke(10)) - return result; - else - ; - } catch (Exception e) { - e.printStackTrace(); - } - else if (validateQuery.equals(RW_ISCLOSED)) { - if (result.isClosed() == false) - return result; - } else { - // TODO it can be reasonable to execute the query in a - // thread and join in millis - // because dropped connection can hung a query - statement = result.createStatement(); - statement.execute(validateQuery); - return result; - } - } catch (SQLException e) { - log("Discarding connection %s because %s%n", null, result, e); - } finally { - if (statement != null) - try { - statement.close(); - } catch (SQLException e) { - } - } - remove(result); - } while (bad); - throw new IllegalStateException(); - } - - public Connection getConnection(String user, String password) throws SQLException { - conectionProperties.setProperty("user", user); - conectionProperties.setProperty("password", password); - return getConnection(); - } - - public PrintWriter getLogWriter() throws SQLException { - return logWriter; - } - - public int getLoginTimeout() throws SQLException { - return timeout; - } - - public void setLogWriter(PrintWriter timeout) throws SQLException { - logWriter = timeout; - } - - public void setLoginTimeout(int timeout) throws SQLException { - // not quite what it is - setTimeout(timeout); - } - - public boolean isWrapperFor(Class cl) throws SQLException { - return DataSource.class.equals(cl) || ObjectPool.class.equals(cl); - } - - public T unwrap(Class arg0) throws SQLException { - if (isWrapperFor(arg0)) - return (T) this; - return null; - } - - protected void log(String message, Throwable ex, Object... args) { - if (args == null || args.length == 0) - logWriter.write(message + "\n"); // ?? lineSeparator? - else - logWriter.write(String.format(message, args)); - if (ex != null) - ex.printStackTrace(logWriter); - logWriter.flush(); - } - - @Override - protected void discard(Connection obj) { - Connection unwrapped = null; - try {//System.err.printf("Discarding %s%n", obj); - unwrapped = (Connection) obj.getClass().getMethod("unwrap", Class.class).invoke(obj, Connection.class); - unwrapped.close(); - } catch (Exception e) {//e.printStackTrace(); - if (unwrapped == null) - try { - obj.close(); - } catch (SQLException e1) { - //e1.printStackTrace(); - } - } - } - - @Override - protected Connection create() { - try { - return driver.connect(dataSourceProperties.getProperty("url"), conectionProperties); - } catch (SQLException e) { - log("Can't create connection for %s%n", e, dataSourceProperties.getProperty("url")); - throw new IllegalArgumentException( - "Can't create connection, check connection parameters and class path for JDBC driver", e); - } - } - - private Throwable processException(InvocationTargetException ite, Connection conn, Connection proxyConn) - throws IllegalArgumentException, IllegalAccessException { - if (connectionValidateMethod != null) { - Throwable se = ite.getCause(); - //System.err.println("Cause*********"+se+" instance sql:"+(se instanceof SQLException)); - try { - if (se instanceof SQLException && connectionValidateMethod.invoke(null, se, conn).equals(Boolean.FALSE)) - remove(conn); - } catch (InvocationTargetException e) { - - } - return se; - } - return ite.getCause(); - } - - @Override - public int getCapacity() { - return capacity; - } - - //@Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException(); - } - - private void contextToProperties(InputStream contextXmlStream) throws XPathExpressionException { - XPath xp = XPathFactory.newInstance().newXPath(); - Node document = (Node) xp.evaluate("/Context", new InputSource(contextXmlStream), XPathConstants.NODE); - NodeList nodes = (NodeList) xp.evaluate("Resource", document, XPathConstants.NODESET); - int nodesLen = nodes.getLength(); - if (nodesLen > 1) - throw new IllegalArgumentException("Only one resource is supported"); - for (int p = 0; p < nodesLen; p++) { - NamedNodeMap attrs = nodes.item(p).getAttributes(); - Node metadataAttr = attrs.getNamedItem("name"); - dataSourceProperties.setProperty("jndi-name", "java:comp/env/" + metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("type"); - if ("javax.sql.DataSource".equals(metadataAttr.getTextContent()) == false) - throw new IllegalArgumentException("Only SQL data sources are supported"); - metadataAttr = attrs.getNamedItem("auth"); - metadataAttr = attrs.getNamedItem("username"); - if (metadataAttr != null) - dataSourceProperties.setProperty("user", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("password"); - if (metadataAttr != null) - dataSourceProperties.setProperty("password", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("driverClassName"); - if (metadataAttr != null) - dataSourceProperties.setProperty("driver-class", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("url"); - if (metadataAttr == null) - throw new IllegalArgumentException("Data source URL is required"); - dataSourceProperties.setProperty("url", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("driverClassPath"); - if (metadataAttr != null) - dataSourceProperties.setProperty("driver-class-path", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("validationQuery"); - if (metadataAttr != null) - dataSourceProperties.setProperty("prob-query", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("maxActive"); - if (metadataAttr != null) - dataSourceProperties.setProperty("pool-size", metadataAttr.getTextContent()); - metadataAttr = attrs.getNamedItem("maxIdle"); - if (metadataAttr != null) - dataSourceProperties.setProperty("pool-shrink-size", metadataAttr.getTextContent()); - } - } - - class ConnectionWrapperHandler implements InvocationHandler { - - private Connection realConn; - - ConnectionWrapperHandler(Connection conn) { - realConn = conn; - } - - public Object invoke(final Object proxyConn, Method methd, Object[] params) throws Throwable { - if (realConn == null) - throw new SQLException("The connection is closed"); - if (methd.getName().equals("close")) { - // log("Closing %s%n", null, proxyConn); - if (realConn.getAutoCommit() == false) - try { - realConn.rollback(); - } catch (SQLException se) { - - } - put(realConn); - realConn = null; - } else if (methd.getName().equals("unwrap")) // && - return realConn; - else if (methd.getName().equals("isWrapperFor")) - return ((Class) params[0]).isInstance(realConn); - else if (methd.getName().equals("equals")) - return proxyConn == params[0]; - else { - try { - final Object realStmt = methd.invoke(realConn, params); - if (realStmt instanceof Statement == false) - return realStmt; - // wrap statement - return Proxy.newProxyInstance(realStmt.getClass().getClassLoader(), Wrapper != null ? new Class[] { - CallableStatement.class, PreparedStatement.class, Statement.class, Wrapper } : new Class[] { - CallableStatement.class, PreparedStatement.class, Statement.class }, - new InvocationHandler() { - public Object invoke(final Object proxyStmt, Method methd, Object[] params) - throws Throwable { - if (methd.getName().equals("getConnection")) { - return proxyConn; - } else if (methd.getName().equals("unwrap")) - return realStmt; // real statement - else if (methd.getName().equals("isWrapperFor")) - return ((Class) params[0]).isInstance(realStmt); - try { - final Object realRS = methd.invoke(realStmt, params); - if (realRS instanceof ResultSet == false) - return realRS; - return Proxy - .newProxyInstance(realRS.getClass().getClassLoader(), - Wrapper != null ? new Class[] { RowSet.class, ResultSet.class, - Wrapper } - : new Class[] { RowSet.class, ResultSet.class }, - new InvocationHandler() { - public Object invoke(final Object proxyRS, Method methd, - Object[] params) throws Throwable { - if (methd.getName().equals("getStatement")) { - return proxyStmt; - } else if (methd.getName().equals("unwrap")) - return realRS; // resultset - else if (methd.getName().equals("isWrapperFor")) - return ((Class) params[0]).isInstance(realRS); - try { - return methd.invoke(realRS, params); - } catch (InvocationTargetException ite) { - throw processException(ite, realConn, - (Connection) proxyConn); - } - } - }); - } catch (InvocationTargetException ite) { - throw processException(ite, realConn, (Connection) proxyConn); - } - } - }); - } catch (InvocationTargetException ite) { - throw processException(ite, realConn, (Connection) proxyConn); - } - } - return null; - } - } - - @Override - protected void finalize() throws Throwable { - //System.err.printf("finilize%s%n", dataSourceProperties); - invalidate(); - super.finalize(); - } - -} diff --git a/1.x/src/rogatkin/app/WebAppServ.java b/1.x/src/rogatkin/app/WebAppServ.java deleted file mode 100644 index efdb9dd..0000000 --- a/1.x/src/rogatkin/app/WebAppServ.java +++ /dev/null @@ -1,50 +0,0 @@ -/* TJWS WebAppServ - * Copyright (C) 2010 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: WebAppServ.java,v 1.3 2009/12/31 05:02:13 dmitriy Exp $ - * Created on Mar 5, 2008 - * @author dmitriy - */ -package rogatkin.app; - -import rogatkin.web.WebApp; -import Acme.Utils; - -public class WebAppServ extends Main { - - /** launches embedded app with app server settings - * @param args - */ - public static void main(String[] args) { - if (args.length == 0) - try { - initAppServer(Utils.splitStr(WebApp.readDescriptor()[0])); - } catch (NullPointerException npe) { - //npe.printStackTrace(); - } - else - initAppServer(args); - WebApp.main(args); - } -} diff --git a/1.x/src/rogatkin/web/WarRoller.java b/1.x/src/rogatkin/web/WarRoller.java deleted file mode 100644 index 9e9da9b..0000000 --- a/1.x/src/rogatkin/web/WarRoller.java +++ /dev/null @@ -1,409 +0,0 @@ -/* tjws - WarRoller.java - * Copyright (C) 2004-2010 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: WarRoller.java,v 1.30 2013/07/02 07:11:28 cvs Exp $ - * Created on Dec 13, 2004 - */ -package rogatkin.web; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; - -import javax.servlet.ServletException; - -import Acme.Utils; -import Acme.Serve.Serve; -import Acme.Serve.WarDeployer; - -public class WarRoller implements WarDeployer { - - public static final String DEPLOY_ARCH_EXT = ".war"; - - public static final String DEPLOYMENT_DIR_TARGET = ".web-apps-target"; - - public static final String DEF_DEPLOY_DYNAMICALLY = "tjws.wardeploy.dynamically"; - - public static final String DEF_DEPLOY_NOINCREMENTAL = "tjws.wardeploy.noincremental"; - - public static final String DEF_VIRTUAL = "tjws.virtual"; - - public static final String DEPLOY_FAILED_EXT = ".failed"; - - /** - * in deploy mode scans for all wars in war directory (app deployment dir) - * for each war looks in corresponding place of deploy directory and figures - * a difference, like any file in war exists and no corresponding file in - * deploy directory or it's older if difference positive, then delete target - * deploy directory unpack war if run mode process all WEB-INF/web.xml and - * build app descriptor, including context name, servlet names, servlet - * urls, class parameters process every app descriptor as standard servlet - * connection proc dispatch for every context name assigned an app - * dispatcher, it uses the rest to find servlet and do resource mapping - * - */ - - public void deploy(File warDir, final File deployTarDir, final String virtualHost) { - // by list - if (warDir.listFiles(new FileFilter() { - public boolean accept(File pathname) { - if (pathname.isFile() && pathname.getName().toLowerCase().endsWith(DEPLOY_ARCH_EXT)) { - deployWar(pathname, deployTarDir); - return true; - } - return false; - } - }).length == 0) - server.log("No .war packaged web apps found in " + (virtualHost == null ? "default" : virtualHost)); - if (deployTarDir.listFiles(new FileFilter() { - public boolean accept(File file) { - if (file.isDirectory()) - try { - attachApp(WebAppServlet.create(file, file.getName(), server, virtualHost), virtualHost); - markSucceeded(file.getParentFile(), file.getName()); // assumes that parent always exists - return true; - } catch (ServletException se) { - server.log( - "Deployment of aplication " + file.getName() + " failed, reason: " + se.getRootCause(), - se.getRootCause()); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - server.log("Unexpected problem in deployment of application " + file.getName(), t); - } - return false; - } - }).length == 0) - server.log("No web apps have been deployed in " + (virtualHost == null ? "default" : virtualHost)); - } - - public boolean deployWar(File warFile, File deployTarDir) { - String context = warFile.getName(); - assert context.toLowerCase().endsWith(DEPLOY_ARCH_EXT); - context = context.substring(0, context.length() - DEPLOY_ARCH_EXT.length()); - File failedMark = new File(deployTarDir, context + DEPLOY_FAILED_EXT); - if (failedMark.exists() && failedMark.lastModified() > warFile.lastModified()) - return false; // skipping deploy failed - - server.log("Deploying " + context); - ZipFile zipFile = null; - File deployDir = new File(deployTarDir, context); - boolean noincremental = System.getProperty(DEF_DEPLOY_NOINCREMENTAL) != null; - if (assureDir(deployDir) == false) { - server.log("Can't reach deployment dir " + deployDir); - return false; - } - Exception lastException = null; - deploy: do { - try { - // some overhead didn't check that doesn't exist - zipFile = new ZipFile(warFile); - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry ze = entries.nextElement(); - String en = ze.getName(); - if (File.separatorChar == '/') - en = en.replace('\\', File.separatorChar); - File outFile = new File(deployDir, en); - if (ze.isDirectory()) { - outFile.mkdirs(); - } else { - OutputStream os = null; - InputStream is = null; - File parentFile = outFile.getParentFile(); - if (parentFile.exists() == false) - parentFile.mkdirs(); - if (outFile.exists() && outFile.lastModified() >= ze.getTime()) { - continue; - } - if (noincremental) { - deleteFiles(deployDir, deployDir.list()); - noincremental = false; - continue deploy; - } - try { - os = new FileOutputStream(outFile); - is = zipFile.getInputStream(ze); - copyStream(is, os); - } catch (IOException ioe2) { - server.log("Problem in extracting " + en + " " + ioe2); - // TODO decide to propagate the exception up and stop deployment? - lastException = ioe2; - } finally { - try { - os.close(); - } catch (Exception e2) { - - } - try { - is.close(); - } catch (Exception e2) { - - } - } - outFile.setLastModified(ze.getTime()); - } - } - } catch (ZipException ze) { - server.log("Invalid .war format"); - lastException = ze; - } catch (IOException ioe) { - server.log("Can't read " + warFile + "/ " + ioe); - lastException = ioe; - } finally { - try { - zipFile.close(); - } catch (Exception e) { - - } - zipFile = null; - } - } while (false); - if (lastException == null) { - deployDir.setLastModified(warFile.lastModified()); - return true; - } - deployDir.setLastModified(0); - return false; - } - - protected void attachApp(WebAppServlet appServlet, String virtualHost) { - server.addServlet(appServlet.contextPath + "/*", appServlet, virtualHost); - } - - /** Returns auto deployment directory - *

- * The method can be overriden to give more control of choosing the directory - * @return autodeployment directory location as local file system string - */ - protected String getDeployDirectory() { - String webapp_dir = System.getProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR); - if (webapp_dir == null) - webapp_dir = System.getProperty("user.dir") + File.separator + "webapps"; - return webapp_dir; - } - - public void deploy(Serve server) { - this.server = server; - final File file_webapp = new File(getDeployDirectory()); - if (assureDir(file_webapp) == false) { - server.log("Deployment source location " + file_webapp + " isn't a directory, deployment is impossible."); - return; - } - final File file_deployDir = new File(file_webapp, DEPLOYMENT_DIR_TARGET); - if (assureDir(file_deployDir) == false) { - server.log("Target deployment location " + file_deployDir + " isn't a directory, deployment is impossible."); - return; - } - deploy(file_webapp, file_deployDir, null); - - int td = 0; - if (System.getProperty(DEF_DEPLOY_DYNAMICALLY) != null) { - td = 20; - try { - td = Integer.parseInt(System.getProperty(DEF_DEPLOY_DYNAMICALLY)); - } catch (NumberFormatException nfe) { - server.log("Default redeployment check interval: " + td + " is used"); - } - } - final int interval = td * 1000; - createWatcherThread(file_webapp, file_deployDir, interval, null); - if (null != System.getProperty(DEF_VIRTUAL)) { - file_webapp.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - String virtualHost; - if (pathname.isDirectory() - && (virtualHost = pathname.getName()).equals(DEPLOYMENT_DIR_TARGET) == false) { - - final File file_deployDir = new File(pathname, DEPLOYMENT_DIR_TARGET); - if (assureDir(file_deployDir) == false) { - WarRoller.this.server.log("Target deployment location " + file_deployDir - + " isn't a directory, deployment is impossible."); - } else { - deploy(pathname, file_deployDir, virtualHost); - createWatcherThread(pathname, file_deployDir, interval, virtualHost); - return true; - } - } - return false; - } - }); - } - } - - protected void createWatcherThread(final File file_webapp, final File file_deployDir, final int interval, - final String virtualHost) { - if (interval <= 0) - return; - Thread watcher = new Thread("Deploy update watcher for " + (virtualHost == null ? "main" : virtualHost)) { - public void run() { - for (;;) - try { - deployWatch(file_webapp, file_deployDir, virtualHost); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - WarRoller.this.server.log("Unhandled " + t, t); - } finally { - try { - Thread.sleep(interval); - } catch (InterruptedException e) { - break; - } - } - } - }; - watcher.setDaemon(true); - watcher.start(); - } - - protected boolean assureDir(File fileDir) { - if (fileDir.exists() == false) - fileDir.mkdirs(); - return fileDir.isDirectory(); - } - - protected synchronized void deployWatch(File warDir, final File deployTarDir, String virtualHost) { - server.setHost(virtualHost); - final HashSet apps = new HashSet(); - warDir.listFiles(new FileFilter() { - public boolean accept(File file) { - if (file.isDirectory() == false) { - String name = file.getName(); - if (name.endsWith(DEPLOY_ARCH_EXT)) - apps.add(name.substring(0, name.length() - DEPLOY_ARCH_EXT.length())); - } - return false; - } - }); - Enumeration se = server.getServlets(); - ArrayList markedServlets = new ArrayList(10); - while (se.hasMoreElements()) { - Object servlet = se.nextElement(); - if (servlet instanceof WebAppServlet) { - WebAppServlet was = (WebAppServlet) servlet; - String name = was.deployDir.getName(); - File war = new File(warDir, name + DEPLOY_ARCH_EXT); - apps.remove(name); - if (war.exists() && war.lastModified() > was.deployDir.lastModified()) { - // deployWar(new File(warDir, was.deployDir.getName() + - // DEPLOY_ARCH_EXT), deployTarDir); - markedServlets.add(was); - } - } - } - for (WebAppServlet was : markedServlets) { - redeploy(warDir, deployTarDir, was, virtualHost); - } - for (String name : apps) { - // remaining not deployed yet apps - try { - if (deployWar(new File(warDir, name + DEPLOY_ARCH_EXT), deployTarDir)) { - WebAppServlet was = WebAppServlet.create(new File(deployTarDir, name), name, server, virtualHost); - attachApp(was, virtualHost); - } - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - markFailed(deployTarDir, name); - server.log("Unexpected problem in deployment of aplication " + name, t); - } - } - } - - public void redeploy(File warDir, File deployTarDir, WebAppServlet was, String virtualHost) { - was = (WebAppServlet) server.unloadServlet(was); - if (was == null) - return; - server.unloadSessions(was.getServletContext()); - was.destroy(); - - // TODO use pre-saved war name - if (deployWar(new File(warDir, was.deployDir.getName() + DEPLOY_ARCH_EXT), deployTarDir)) - try { - was = WebAppServlet.create(was.deployDir, was.deployDir.getName(), server, virtualHost); - attachApp(was, virtualHost); - server.restoreSessions(was.getServletContext()); - markSucceeded(deployTarDir, was.deployDir.getName()); - } catch (ServletException sex) { - markFailed(deployTarDir, was.deployDir.getName()); - server.log("Deployment of a web app " + was.contextName + " failed due " + sex.getRootCause(), - sex.getRootCause()); - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath) t; - markFailed(deployTarDir, was.deployDir.getName()); - server.log("Unexpected problem in deployment of aplication " + was.contextName, t); - } - } - - static private boolean markFailed(File deployTarDir, String appName) { - File markFile = new File(deployTarDir, appName + DEPLOY_FAILED_EXT); - - if (markFile.exists()) { - File appDeployDir = new File(deployTarDir, appName); - if (appDeployDir.exists()) - markFile.setLastModified(appDeployDir.lastModified()+1); - return true; - } - try { - return markFile.createNewFile(); - } catch (IOException e) { - return false; - } - } - - static private boolean markSucceeded(File deployTarDir, String appName) { - if (new File(deployTarDir, appName + DEPLOY_FAILED_EXT).exists()) - return new File(deployTarDir, appName+DEPLOY_FAILED_EXT).delete(); - return true; - } - - static void copyStream(InputStream is, OutputStream os) throws IOException { - Utils.copyStream(is, os, -1); - } - - static void deleteFiles(File folder, String[] files) throws IOException { - for (String fn : files) { - File f = new File(folder, fn); - if (f.isDirectory()) { - deleteFiles(f, f.list()); - if (f.delete() == false) - throw new IOException("Can't delete :" + f); - } else { - if (f.delete() == false) - throw new IOException("Can't delete :" + f); - } - } - } - - protected Serve server; -} \ No newline at end of file diff --git a/1.x/src/rogatkin/wskt/SimpleProvider.java b/1.x/src/rogatkin/wskt/SimpleProvider.java deleted file mode 100644 index 8222766..0000000 --- a/1.x/src/rogatkin/wskt/SimpleProvider.java +++ /dev/null @@ -1,556 +0,0 @@ -/* tjws - JSR356 - * Copyright (C) 2004-2015 Dmitriy Rogatkin. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Created on Jan 11, 2015 -*/ -package rogatkin.wskt; - -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLDecoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.nio.channels.ByteChannel; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.SocketChannel; - -import Acme.Utils; -import Acme.Serve.Serve; -import Acme.Serve.Serve.ServeConnection; -import Acme.Serve.Serve.WebsocketProvider; - -import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; -import javax.servlet.Servlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.ServletException; -import javax.websocket.CloseReason; -import javax.websocket.DeploymentException; -import javax.websocket.Endpoint; -import javax.websocket.Extension; -import javax.websocket.server.HandshakeRequest; -import javax.websocket.server.ServerApplicationConfig; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; - -import io.github.lukehutch.fastclasspathscanner.*; -import io.github.lukehutch.fastclasspathscanner.matchprocessor.*; - -public class SimpleProvider implements WebsocketProvider, Runnable { - public static final String WSKT_KEY = "Sec-WebSocket-Key"; - public static final String WSKT_ORIGIN = "Origin"; - public static final String WSKT_PROTOCOL = "Sec-WebSocket-Protocol"; - public static final String WSKT_VERSION = "Sec-WebSocket-Version"; - public static final String WSKT_ACEPT = "Sec-WebSocket-Accept"; - public static final String WSKT_EXTS = "Sec-WebSocket-Extensions"; // HandshakeRequest.SEC_WEBSOCKET_EXTENSIONS - - public static final String WSKT_RFC4122 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - - public static final String PROP_WSKT_MAIN_CONTAINER = "tjws.websocket.container"; - - //static final ForkJoinPool mainPool = new ForkJoinPool(); - - protected Selector selector; - protected Serve serve; - protected ExecutorService messageFlowExec; - protected ConcurrentLinkedQueue penndingSessions; - - protected boolean rootContainerUse; - - static final boolean __debugOn = false; - - @Override - public void init(Serve s) { - serve = s; - try { - penndingSessions = new ConcurrentLinkedQueue(); - selector = Selector.open(); - Thread t = new Thread(this, "websocket provider selector"); - t.setDaemon(true); - t.start(); - } catch (IOException ioe) { - throw new RuntimeException("Can't initialize selector, websocket functionality is disabled", ioe); - } - rootContainerUse = Boolean.getBoolean(PROP_WSKT_MAIN_CONTAINER); - - messageFlowExec = Executors.newCachedThreadPool(); - } - - @Override - public void handshake(Socket socket, String path, Servlet servlet, HttpServletRequest req, HttpServletResponse resp) - throws IOException { - if (socket.getChannel() == null) { - resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Websockets implemented only with SelectorAcceptor"); - return; - } - String ver = req.getHeader(WSKT_VERSION); - if (ver == null || "13".equals(ver.trim()) == false) { - resp.addHeader(WSKT_VERSION, "13"); - resp.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - String key = req.getHeader(WSKT_KEY); - if (key == null) { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Sec Key is missed"); - return; - } - String contextPath; - try { - contextPath = (String) servlet.getClass().getMethod("getContextPath").invoke(servlet); - } catch (Exception e) { - if (rootContainerUse) - contextPath = ""; - else { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No endpoints associated with container allowed"); - return; - } - } - SimpleServerContainer container; - if (servlet != null) - container = (SimpleServerContainer) servlet.getServletConfig().getServletContext() - .getAttribute("javax.websocket.server.ServerContainer"); - else - container = (SimpleServerContainer) serve.getAttribute("javax.websocket.server.ServerContainer"); - - if (container == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No end points associated with path " + path); - return; - } - - String found = null; - int hops = -1; - Map foundVarMap = null; - for (String p : container.endpoints.keySet()) { - Map varMap = matchTemplate(path, contextPath + p); - if (varMap != null) { - if (found == null || hops > varMap.size()) { - found = p; - hops = varMap.size(); - foundVarMap = varMap; - } - } - } - if (found == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No matching endpoint found for " + path); - return; - } - ServerEndpointConfig epc = container.endpoints.get(found); - //Objects.requireNonNull(epc.getConfigurator()); - if (epc.getConfigurator().checkOrigin(req.getHeader(WSKT_ORIGIN)) == false) { - resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin check failed : " + req.getHeader(WSKT_ORIGIN)); - return; - } - epc.getConfigurator().modifyHandshake(epc, new SimpleHSRequest(req), new SimpleHSResponse(resp)); - - req.setAttribute("javax.websocket.server.ServerEndpointConfig", epc); - req.setAttribute("javax.websocket.server.PathParametersMap", foundVarMap); - - resp.setHeader(WSKT_ACEPT, getSHA1Base64(key.trim() + WSKT_RFC4122)); - resp.setHeader(Serve.ServeConnection.UPGRADE, Serve.ServeConnection.WEBSOCKET); - //resp.setHeader(Serve.ServeConnection.CONNECTION, Serve.ServeConnection.KEEPALIVE + ", " - // + Serve.ServeConnection.UPGRADE); - //resp.addHeader(Serve.ServeConnection.CONNECTION, Serve.ServeConnection.UPGRADE); - if (container.getDefaultMaxSessionIdleTimeout() > 0) - resp.setHeader(Serve.ServeConnection.KEEPALIVE, "timeout=" + container.getDefaultMaxSessionIdleTimeout() - / 1000); - resp.setStatus(resp.SC_SWITCHING_PROTOCOLS); - } - - @Override - public void upgrade(Socket socket, String path, Servlet servlet, HttpServletRequest req, HttpServletResponse resp) - throws IOException { - SocketChannel sc = socket.getChannel(); - sc.configureBlocking(false); - ByteChannel bc = sc; - try { - bc = (ByteChannel) socket.getClass().getMethod("getByteChannel").invoke(socket); - } catch (Exception e) { - if (__debugOn) - serve.log(e, "No byte channel"); - } - SimpleServerContainer container = null; - if (servlet != null) - container = (SimpleServerContainer) servlet.getServletConfig().getServletContext() - .getAttribute("javax.websocket.server.ServerContainer"); - else if (rootContainerUse) - container = (SimpleServerContainer) serve.getAttribute("javax.websocket.server.ServerContainer"); - ServerEndpointConfig epc = (ServerEndpointConfig) req - .getAttribute("javax.websocket.server.ServerEndpointConfig"); - - final SimpleSession ss = new SimpleSession(bc, container); - ss.addMessageHandler(epc); - ss.pathParamsMap = (Map) req.getAttribute("javax.websocket.server.PathParametersMap"); - if (req.getSession(false) != null) { - ss.id = req.getSession(false).getId(); - // TODO this approach isn't robust and flexible, so consider as temporarly - req.getSession(false).setAttribute("javax.websocket.server.session", new HttpSessionBindingListener() { - - @Override - public void valueBound(HttpSessionBindingEvent arg0) { - - } - - @Override - public void valueUnbound(HttpSessionBindingEvent arg0) { - try { - ss.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "Session invalidate")); - } catch (IOException e) { - if (__debugOn) - serve.log(e, "At closing on session invalidation"); - } - - } - }); - } else - ss.id = "wskt-" + serve.generateSessionId(); - ss.principal = req.getUserPrincipal(); - ss.setMaxIdleTimeout(container.getDefaultMaxSessionIdleTimeout()); - ss.paramsMap = new HashMap>(); - for (Map.Entry e : req.getParameterMap().entrySet()) { - ss.paramsMap.put(e.getKey(), Arrays.asList(e.getValue())); - } - ss.query = req.getQueryString(); - try { - ss.uri = new URI(req.getRequestURL().toString()); - } catch (URISyntaxException e) { - - } - String protocol = req.getHeader(WSKT_PROTOCOL); - if (protocol != null) { - ss.subprotocol = epc.getConfigurator().getNegotiatedSubprotocol(epc.getSubprotocols(), - Arrays.asList(protocol.split(","))); - } - if (epc.getExtensions().size() > 0) { - // TODO maybe it should be going in handshake? - ss.extensions = epc.getConfigurator().getNegotiatedExtensions(epc.getExtensions(), - parseToExtensions(req.getHeader(HandshakeRequest.SEC_WEBSOCKET_EXTENSIONS))); - if (ss.extensions.size() == 0) { - ss.close(new CloseReason(CloseReason.CloseCodes.NO_EXTENSION, "")); - return; - } - } - if (req instanceof ServeConnection) { - ss.conn = (ServeConnection) req; - ((ServeConnection) req).spawnAsync(ss); - } else - serve.log("Request isn't of ServeConnection type " + req.getClass()); - penndingSessions.add(ss); - selector.wakeup(); - //sc.register(selector, SelectionKey.OP_READ, ss); - //ss.open(); - } - - @Override - public void destroy() { - if (rootContainerUse) - try { - ((SimpleServerContainer) serve.getAttribute("javax.websocket.server.ServerContainer")) - .contextDestroyed(null); - } catch (Exception e) { - - } - messageFlowExec.shutdown(); - try { - selector.close(); - } catch (IOException e) { - - } - } - - @Override - public void deploy(final ServletContext servCtx, final List cp) { - final SimpleServerContainer ssc = new SimpleServerContainer(this); - final HashSet appCfgs = new HashSet(); - final HashSet> annSeps = new HashSet>(); - final HashSet> endps = new HashSet>(); - new FastClasspathScanner("") { - @Override - public List getUniqueClasspathElements() { - if (cp == null) { - if (servCtx != null) { - ClassLoader ccl = servCtx.getClass().getClassLoader(); - if (ccl instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) ccl).getURLs(); - if (urls != null && urls.length > 0) { - ArrayList result = new ArrayList(urls.length); - for (URL url : urls) - try { - result.add(new File(URLDecoder.decode(url.getFile(), "UTF-8"))); - } catch (UnsupportedEncodingException e) { - serve.log("Can't add path component " + url + " :" + e); - } - return result; - } - } - } - return super.getUniqueClasspathElements(); - } - return cp; - } - - @Override - public ClassLoader getClassLoader() { - if (servCtx != null) - try { - return (ClassLoader) servCtx.getClass().getMethod("getClassLoader").invoke(servCtx); - } catch (Exception e) { - return servCtx.getClass().getClassLoader(); - } - return null; - } - }.matchClassesImplementing(ServerApplicationConfig.class, - new InterfaceMatchProcessor() { - - @Override - public void processMatch(Class arg0) { - try { - appCfgs.add(arg0.newInstance()); - } catch (InstantiationException e) { - serve.log(e, "Error at deployment"); - } catch (IllegalAccessException e) { - serve.log(e, "Error at deployment"); - } - } - - }).matchClassesWithAnnotation(ServerEndpoint.class, new ClassAnnotationMatchProcessor() { - public void processMatch(Class matchingClass) { - annSeps.add(matchingClass); - } - }).matchSubclassesOf(Endpoint.class, new SubclassMatchProcessor() { - - @Override - public void processMatch(Class arg0) { - endps.add(arg0); - } - }).scan(); - - if (appCfgs.size() > 0) { - for (ServerApplicationConfig sac : appCfgs) { - for (Class se : sac.getAnnotatedEndpointClasses(annSeps)) - try { - ssc.addEndpoint(se); - serve.log("Deployed ServerEndpoint " + se); - } catch (DeploymentException de) { - - } - for (ServerEndpointConfig epc : sac.getEndpointConfigs(endps)) - try { - ssc.addEndpoint(epc); - serve.log("Deployed ServerEndpointConfig " + epc); - } catch (DeploymentException de) { - - } - } - } else { - for (Class se : annSeps) - try { - ssc.addEndpoint(se); - serve.log("Deployed ServerEndpoint " + se); - } catch (DeploymentException de) { - - } - } - servCtx.setAttribute("javax.websocket.server.ServerContainer", ssc); - try { - servCtx.addListener(ssc); - } catch (Error e) { - // serve is still on old servlet spec - } - } - - String getSHA1Base64(String key) { - try { - MessageDigest cript = MessageDigest.getInstance("SHA-1"); - cript.reset(); - cript.update(key.getBytes()); - return Utils.base64Encode(cript.digest()); - } catch (NoSuchAlgorithmException nsa) { - - } - return null; - } - - Map matchTemplate(String uri, String template) { - //System.err.printf("Matching %s to %s%n", uri, template); - Map parsed = parseTemplate(template); - Pattern p = Pattern.compile(parsed.get(0)); - Matcher m = p.matcher(uri); - if (m.matches()) { - HashMap result = new HashMap(); - for (int i = 0; i < m.groupCount(); i++) - result.put(parsed.get(i + 1), m.group(i + 1)); - //System.err.printf("Success %s%n", result); - return result; - } - //System.err.printf("unsucc %s%n", parsed); - return null; - } - - static final int s_invar = 1, s_inuri = 0; - - Map parseTemplate(String template) { - HashMap result = new HashMap(); - String regExp = ""; - int vi = 0; - int st = s_inuri; - String varName = null; - for (int i = 0, n = template.length(); i < n; i++) { - char c = template.charAt(i); - switch (st) { - case s_inuri: - if (c == '/') - regExp += c; - else if (c == '{') { - st = s_invar; - varName = ""; - } else { - // TODO check if reg exp escape needed - regExp += c; - } - break; - case s_invar: - if (c == '}') { - vi++; - regExp += "((?:[a-zA-Z0-9-\\._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)"; - st = s_inuri; - result.put(vi, varName); - } else { - // TODO check if valid character ALPHA, DIGIT, _, or %DD - varName += c; - } - break; - } - } - result.put(0, regExp); - return result; - } - - /** - * parses ext1;param=val param=val, ext2 - * - * @param parse - * @return - */ - List parseToExtensions(String parse) { - if (parse == null || parse.isEmpty()) - return Collections.emptyList(); - return Collections.emptyList(); - } - - @Override - public void run() { - while (selector.isOpen()) { - try { - for (SimpleSession ss = penndingSessions.poll(); ss != null; ss = penndingSessions.poll()) { - SocketChannel sc = null; - if (ss.channel instanceof SocketChannel) - sc = (SocketChannel) ss.channel; - else - try { - sc = (SocketChannel) ss.channel.getClass().getMethod("unwrapChannel").invoke(ss.channel); - } catch (Exception e) { - - } - if (sc != null) { - sc.register(selector, SelectionKey.OP_READ, ss); - ss.open(); - } else - serve.log("Session with not proper channel will be closed"); - } - - int readyChannels = selector.select(1000); - if (readyChannels == 0) - continue; - - Set selectedKeys = selector.selectedKeys(); - - Iterator keyIterator = selectedKeys.iterator(); - - while (keyIterator.hasNext()) { - - SelectionKey key = keyIterator.next(); - if (__debugOn) - serve.log("key:" + key + " " + key.isValid() + " chan " + key.channel()); - - if (!key.isValid()) { - continue; - } - if (key.isAcceptable()) { - // a connection was accepted by a ServerSocketChannel. - - } else if (key.isConnectable()) { - // a connection was established with a remote server. - - } else if (key.isReadable()) { - // a channel is ready for reading - if (key.channel().isOpen() && !messageFlowExec.isShutdown()) { - messageFlowExec.submit(((SimpleSession) key.attachment())); - //((SimpleSession) key.attachment()).run(); - } else { - if (__debugOn) - serve.log("Cancel key :" + key + ", channel closed"); - key.cancel(); - } - } else if (key.isWritable()) { - // a channel is ready for writing - // TODO perhaps trigger flag in session too execute writing bach - } - - keyIterator.remove(); - } - } catch (Exception e) { - serve.log("Websocket runtime problem", e); - if (!selector.isOpen()) - break; - } - } - } -} diff --git a/1.x/test/java/tjws/test/EchoServer.java b/1.x/test/java/tjws/test/EchoServer.java deleted file mode 100644 index 64846ba..0000000 --- a/1.x/test/java/tjws/test/EchoServer.java +++ /dev/null @@ -1,76 +0,0 @@ -package tjws.test; - -import java.io.IOException; - -import java.util.Date; - -import javax.servlet.http.HttpSession; -import javax.websocket.EndpointConfig; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -/** - * @ServerEndpoint gives the relative name for the end point - * This will be accessed via ws://localhost:8080/EchoChamber/echo - * Where "localhost" is the address of the host, - * "EchoChamber" is the name of the package - * and "echo" is the address to access this class from the server - */ -@ServerEndpoint(value="/echo/{room}", configurator = GetHttpSessionConfigurator.class) -public class EchoServer { - /** - * @OnOpen allows us to intercept the creation of a new session. - * The session class allows us to send data to the user. - * In the method onOpen, we'll let the user know that the handshake was - * successful. - */ - @OnOpen - public void onOpen(Session session, EndpointConfig config){ - System.out.println(session.getId() + " has opened a connection"); - boolean htp_sess = config.getUserProperties() - .containsKey(HttpSession.class.getName()); - try { - session.getBasicRemote().sendText((session.isSecure()?"Secure c":"C")+"onnection Established at "+new Date() +" htp session "+htp_sess); - session.setMaxIdleTimeout(60*1000); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - - /** - * When a user sends a message to the server, this method will intercept the message - * and allow us to react to it. For now the message is read as a String. - */ - @OnMessage - public String onMessage(Session session, String message, @javax.websocket.server.PathParam("room") String room){ - System.out.printf("Message from %s/%dms : %s (%s)%n", session.getId(), session.getMaxIdleTimeout(), message, room); - /*try { - session.getBasicRemote().sendText(message); - - } catch (IOException ex) { - ex.printStackTrace(); - }*/ - String fromShare = ""; - for (Session s : session.getOpenSessions()) { - if (s != session && s.isOpen() && s.getUserProperties().get("SHARE") != null) - fromShare += " "+ (String) s.getUserProperties().get("SHARE"); - } - session.getUserProperties().put("SHARE", message); - if (fromShare .length() > 0) - message += " from others "+fromShare; - return message; - } - - /** - * The user closes the connection. - * - * Note: you can't send messages to the client from this method - */ - @OnClose - public void onClose(Session session){ - System.out.println("Session " +session.getId()+" has ended at "+new Date()); - } -} \ No newline at end of file diff --git a/1.x/test/java/tjws/test/GetHttpSessionConfigurator.java b/1.x/test/java/tjws/test/GetHttpSessionConfigurator.java deleted file mode 100644 index e1adadd..0000000 --- a/1.x/test/java/tjws/test/GetHttpSessionConfigurator.java +++ /dev/null @@ -1,17 +0,0 @@ -package tjws.test; - -import javax.servlet.http.HttpSession; -import javax.websocket.HandshakeResponse; -import javax.websocket.server.HandshakeRequest; -import javax.websocket.server.ServerEndpointConfig; - -public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator { - @Override - public void modifyHandshake(ServerEndpointConfig config, - HandshakeRequest request, - HandshakeResponse response) - { - HttpSession httpSession = (HttpSession)request.getHttpSession(); - config.getUserProperties().put(HttpSession.class.getName(),httpSession); - } -} diff --git a/ASTJWSApp/.gitignore b/ASTJWSApp/.gitignore new file mode 100644 index 0000000..d0c26de --- /dev/null +++ b/ASTJWSApp/.gitignore @@ -0,0 +1,7 @@ +/**/.DS_Store +/**/build +/**/captures +.externalNativeBuild +/.gradle +/.idea +/local.properties diff --git a/ASTJWSApp/ADB Info.txt b/ASTJWSApp/ADB Info.txt new file mode 100755 index 0000000..86b4a86 --- /dev/null +++ b/ASTJWSApp/ADB Info.txt @@ -0,0 +1,16 @@ +=> How to access your app data. <= +adb shell +run-as com.rslakra.android.tjwsasapp +cp /data/data/com.rslakra.android.tjwsasapp/ +cp /data/user/0/com.rslakra.android.tjwsasapp/ + + + +adb shell su -c "chmod 777 /data" +adb shell su -c "chmod 777 /data/data" +adb shell su -c "chmod 777 /data/user/0/com.rslakra.android.tjwsasapp/files" + + +Pull Command: Copies the file from android device to local machine +Convention: adb pull +adb pull "/data/user/0/com.rslakra.android.tjwsasapp/files/logs/android.log" android.log \ No newline at end of file diff --git a/ASTJWSApp/ASTJWSApp.iml b/ASTJWSApp/ASTJWSApp.iml new file mode 100644 index 0000000..016b11d --- /dev/null +++ b/ASTJWSApp/ASTJWSApp.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/.gitignore b/ASTJWSApp/ATJWSApp/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/ASTJWSApp/ATJWSApp/.gitignore @@ -0,0 +1 @@ +/build diff --git a/ASTJWSApp/ATJWSApp/ATJWSApp.iml b/ASTJWSApp/ATJWSApp/ATJWSApp.iml new file mode 100644 index 0000000..71cfff4 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/ATJWSApp.iml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/build.gradle b/ASTJWSApp/ATJWSApp/build.gradle new file mode 100644 index 0000000..371818e --- /dev/null +++ b/ASTJWSApp/ATJWSApp/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 26 + buildToolsVersion '27.0.3' + + defaultConfig { + applicationId "com.rslakra.android.tjwsasapp" + minSdkVersion 22 + targetSdkVersion 22 + + // testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation(name:'androidLogger-release', ext:'aar') + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support.constraint:constraint-layout:1.0.2' +// compile 'com.google.android.gms:play-services-auth:11.8.0' +} diff --git a/ASTJWSApp/ATJWSApp/libs/androidLogger-release.aar b/ASTJWSApp/ATJWSApp/libs/androidLogger-release.aar new file mode 100644 index 0000000..3bbf5a3 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/libs/androidLogger-release.aar differ diff --git a/ASTJWSApp/ATJWSApp/libs/bcprov-jdk15on-159.jar b/ASTJWSApp/ATJWSApp/libs/bcprov-jdk15on-159.jar new file mode 100644 index 0000000..9049e56 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/libs/bcprov-jdk15on-159.jar differ diff --git a/ASTJWSApp/ATJWSApp/libs/javax.servlet-3.0.jar b/ASTJWSApp/ATJWSApp/libs/javax.servlet-3.0.jar new file mode 100755 index 0000000..3b84634 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/libs/javax.servlet-3.0.jar differ diff --git a/ASTJWSApp/ATJWSApp/libs/tjws-v1.0.0.jar b/ASTJWSApp/ATJWSApp/libs/tjws-v1.0.0.jar new file mode 100644 index 0000000..5cf85b6 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/libs/tjws-v1.0.0.jar differ diff --git a/ASTJWSApp/ATJWSApp/proguard-rules.pro b/ASTJWSApp/ATJWSApp/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/ASTJWSApp/ATJWSApp/src/main/AndroidManifest.xml b/ASTJWSApp/ATJWSApp/src/main/AndroidManifest.xml new file mode 100755 index 0000000..1562f61 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/AndroidManifest.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar"> + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/client.pem b/ASTJWSApp/ATJWSApp/src/main/assets/client.pem new file mode 100644 index 0000000..0505102 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/client.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEVDCCAzygAwIBAgIJAIMm2sQ52OuOMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MRUwEwYDVQQKEwxSU0xha3JhIEluYy4xFTATBgNVBAsTDFJTTGFrcmEgSW5jLjES +MBAGA1UEAxMJbG9jYWxob3N0MB4XDTE4MDQwNDE5NDQyOVoXDTE5MDQwNDE5NDQy +OVoweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcT +Ck1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMGA1UECxMMUlNM +YWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDV3ncpZuOYFPOulGZry+6KKdoT1k2mpyYHno1QM8g6pKIP +6br+X44ne4uJ6qKIE5YQYg5aPE0XJsrRanOqDJg1g47nuC9Vw0Vb0RshUul1fcJU +K0yI4Fefo3UuyUDNqfFVE8pM8791e91WyG+yyCsRbKxTjWqFs4atBegIn4JItmGJ +NEB9/Bc94vGWrXSP2FM1Q0b2PFLeJE6a1OWmrw4DKcCl3i+vhJpz63mz2BJCGi5e +E2zzxnBXa6RnxxCyrqndQfOTUIpYHN657+sObBglDlGTldgjedFtkHM8Ekb+HZ/c +EZ8fdUGESAyhhQTKgFrV6v2qqjqAE62OcRmQkJmPAgMBAAGjgd4wgdswHQYDVR0O +BBYEFDbqGED46eF43mtsQP3G8eM05XqvMIGrBgNVHSMEgaMwgaCAFDbqGED46eF4 +3mtsQP3G8eM05XqvoX2kezB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv +cm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazEVMBMGA1UEChMMUlNMYWtyYSBJbmMu +MRUwEwYDVQQLEwxSU0xha3JhIEluYy4xEjAQBgNVBAMTCWxvY2FsaG9zdIIJAIMm +2sQ52OuOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAML2kaN/YFD5 +dsKO3eFOK5R2mKBbXDcQXzz4YDW1AE+NsqkElPdGSdStmjq812PGTG1LDR6zJlbZ +UJeC9V3DKHxK8xgCHoiyj/j+2dDrwcovy/2w9JbYs3Ul9cqMxAUQCN9r7wkCI6Ga +iAnsQ9OYRD77+cRmxd6arhgLqTYWyekGtA4g47Vh3aCGXdbOoX2Pdo7hwuGofBty +CJaeCEvmBBBuQwukL5E02CHwjbnj5S+ZraidEc0AMvtCOmzJZObbdfdVd1YFx1m/ +P48xh6eVut4OvCWsUYPw1tNistc9pippzJO7VbAQo28TGuBCsDf3DE2IPk7WaHk1 +y+HtyQzn4tw= +-----END CERTIFICATE----- diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/conf/info.txt b/ASTJWSApp/ATJWSApp/src/main/assets/conf/info.txt new file mode 100755 index 0000000..dfe9ca0 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/conf/info.txt @@ -0,0 +1,24 @@ +How to create the certificate for testing. +======================================================================================================================================================== +Using this certificate for R&D +======================================================================================================================================================== +--.jks certificate +keytool -genkey -keyalg RSA -alias selfsigned -keystore tjws.jks -storepass password -validity 65537 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1 -validity 9999 +keytool -importkeystore -srckeystore tjws.jks -destkeystore tjws.jks -deststoretype pkcs12 +openssl x509 -in tjws.jks -text -noout + + +--.bks certificate +keytool -genkey -keyalg RSA -alias selfsigned -keystore tjws.bks -storepass password -validity 65537 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1 -validity 9999 +keytool -importkeystore -srckeystore tjws.bks -destkeystore tjws.bks -deststoretype pkcs12 +openssl x509 -in tjws.bks -text -noout + + +======================================================================================================================================================== +================ Generate the self-signed key and certficate ================ +Password:password +openssl req -newkey rsa:2048 -nodes -keyout tjws.key -out tjws.csr +openssl req -newkey rsa:2048 -nodes -keyout tjws.key -x509 -days 65537 -out tjws.crt + +#If you want to decode certificates on your own computer, run this OpenSSL command: +openssl x509 -in tjws.crt -text -noout diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.bks b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.bks new file mode 100644 index 0000000..4396087 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.bks differ diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.crt b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.crt new file mode 100644 index 0000000..4821914 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIJAL7OuDjhmcFlMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwIBcNMTgwMzE5MTY1OTU2WhgPMjE5NzA4MjQxNjU5NTZa +MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ +bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDG81u6dp7dMBWKUTvpOcBrh19u3msjUwjMw+gEd6oG0R8RUxPKs+tQ +M5ovbbUQfzn3SBro5QrvE82wZzOefAt2ariCJ8ehl1BNXBIcoKvWwHPiZNyboGOP +Ie3vqsMBa7mFhHdgGVLZh/X0IBSg6S2vMbDw03Hmte33fQn0yKCXwyG8SLUTd6hs +OUvxPHc3sVxtb2kudfGqZa+KNVf+X3VKIqF4+A0dTACh2xK0fu2NKO+qP1jj9WeM +rN/zp7xqFp7EJ1T0OXDpeqh6qNvnD5nhP7Q/SF+rff6G5UW/2mBm6n8+z3gA/fMw +NrtKdpgdJKjiqBnSW167ixY3ls9grYi5AgMBAAGjgacwgaQwHQYDVR0OBBYEFBWA +HEE3vY1NG15RtqWQa61v7H9jMHUGA1UdIwRuMGyAFBWAHEE3vY1NG15RtqWQa61v +7H9joUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8G +A1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkAvs64OOGZwWUwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAbEgqG+zxwFm/TUFo/slvJZzIdhTK +AeQ9hmdjn8vCcSvRQ2zTzq6YLVk3NEyd7EWb2RZop5+7aGoXT3zqnNjzI6QFLcfK ++C2BLj5oA25ZnZSD8z76FyQKPR8z8iLDaqfFZ5AGsT0xSb61yVdrvf3oV+m5j0uR +ElNDNs/YDy/vRoK/NXdqdozPbZv4Ed63jNnbtswanuZ4x/tG868fsaaxjF+i7I8Z +L2Mgx8ymKXPPlKTHiPXQGkNvxlrTn7p5DrYyNNTp27X/0VymnKcKQ0G29CbqOuQl +/LBlkGw+ZiPhojh80/RmWx3aQeSjfyiVRr0e9FCW93rY9kEaV+qCUYvn3g== +-----END CERTIFICATE----- diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.csr b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.csr new file mode 100644 index 0000000..78bf86b --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.csr @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC1zCCAb8CAQAweTELMAkGA1UEBhMCQ0ExEzARBgNVBAgTCkNhbGlmb3JuaWEx +EzARBgNVBAcTCk1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMG +A1UECxMMUlNMYWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzIO6T9/Zr6ekzgggelCNBHMPQ+rEvEqb3 +Z49pTjmhfMJRd46PmYW5eufLw++AYPQPQowdTGiFqb75yKw+etVBYmz+fQ/7orI5 +9esl18undpR67CgrlgRHhR6Qpc8147C86ou2bKpCU4iCtkwZO1Sh0Z5+FkSOm93s +P8kGoW63OIUaZYo2e9REkbUqZWvT3gcgxTKcfTU28HBPtICE5Ic1q7CLEnrnsAYC +30VWgxIryxdt1vCP2mdj9SmDJGlJkP7y+S20HQ8d6v7kQ2Q3f+3uCoAzzv6uGNCK +lokHPdn94+rMLACAfTbdRHfvL8GPLXRPnQXCWfx1auqadhKCp1LDAgMBAAGgGTAX +BgkqhkiG9w0BCQcxChMIcGFzc3dvcmQwDQYJKoZIhvcNAQEFBQADggEBAJiLGXtf +tANO+nj83/K1iPXb8Bpa1bbcwLcJGJbrcJsQvh9bzXHsKSTeovbAwvRnRyXGpAt8 +4gXdvDqwDmnw4ZI9ui5FHcDgYfnwS7HLxhN5YDHaKOHr4wpZY6enLrYER8H4y7Ky +aHLJvYN8MeARfWPShPUdpjT6qnuEwf6SUbeoCTH9SUEJysG54uAp9L/Ky4DY85W6 +SRhCnlcw515D4EM0FmGBEIynqqi12yzZibbB9PpiObg0+YGlBjjiFob4gz49RThU +B2ffVTiATF2uP7aRkPxvLqJbiyY2tvbDgMblLskKgye6FakKVtfVFxZNy9zruLni ++Dbg8vWYULcKXgw= +-----END CERTIFICATE REQUEST----- diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.jks b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.jks new file mode 100644 index 0000000..69bf5e8 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.jks differ diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.key b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.key new file mode 100644 index 0000000..e2f3fd8 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/conf/tjws.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxvNbunae3TAVilE76TnAa4dfbt5rI1MIzMPoBHeqBtEfEVMT +yrPrUDOaL221EH8590ga6OUK7xPNsGcznnwLdmq4gifHoZdQTVwSHKCr1sBz4mTc +m6BjjyHt76rDAWu5hYR3YBlS2Yf19CAUoOktrzGw8NNx5rXt930J9Migl8MhvEi1 +E3eobDlL8Tx3N7FcbW9pLnXxqmWvijVX/l91SiKhePgNHUwAodsStH7tjSjvqj9Y +4/VnjKzf86e8ahaexCdU9Dlw6Xqoeqjb5w+Z4T+0P0hfq33+huVFv9pgZup/Ps94 +AP3zMDa7SnaYHSSo4qgZ0lteu4sWN5bPYK2IuQIDAQABAoIBAFUoTZcetxlOP6oY +42ANDEP6ierW4V0ZaabcJC/lWK3aTUYJHWuiX5LQw6qRdvM8wf8KqhoOEAQNoflj +80BfMDjbrWZoyJZuQj0ar9X5IBSoA/Jf4d3rZTIa/9GaciXlil+QN9i2fjQGckyw +fqPxq1BWILq0hwiNzvIkX2KbjcHnTdhYvEc1csz6x5WCV3fRuBRF1rX+HN8HAx8V +AaeGluHcCTRJW8FYIfkYrMdieGoKN4APuVjnVXcV4+UhrAGtxPi2inwSdTgNPZp0 +/YwqcdUjY/49xjq+6AoY9g0Gan/J86eg3ErZ6TEDVrHkD0MjbZH/RPZmcgOXXcD5 +BVN4ZAECgYEA/JP26fcQ/qhKDGd7G5MmfSl0eMzzwNW7L2pQC+lmpkoTQF1d+Prz +CQ+hG3SdLbvXcVGVWbdlNBsZL2GFK75n7yLiKSCEWsK3+zWCADzZ0vUTh8DNRv++ +F5U8zwTvzLN9mlzfAMvbJlcSaw7kpQRXS5fGMUieE785DOKIGHM2M+ECgYEAyaVk +17SITRjT3YXw/H6atzPwCJ7vyPesj8P6dmvZLKoamDBZW3lfi0Dx9qo5SW6D9smd +Bm68+CPBzZmj9cqoYhwusTlTLAfbHoHVax0WSuxquw/33Itu/BIHFHG45lyK57cn +ALgp9Fre9YvjtQxLHOxwnE2fkz6GhDNNhC7db9kCgYAEJpZXL/U6ih91ZrnyMQ/f +3K+KUKvszlZeKBwapgJG107Lrv0dW1plGrmmDtuKZdzbguC2cbobChr22V5r4pwo +pOUckek66JpHaZCyWk2mFtr0TynQceF4174BFO6v6X816zLK+46laabm1X7Sa2jX +2C2sn6nhXzIb0Rk1dac9YQKBgAx218Ppmd9CIJ550AqbfM7EPBscT/AZNyZv08SM +KBF1tk0f9/YKi5hc/Ffl78KVPTz8+2LRZ4bjFvCxhYwE6eGeolg8FeML3USGe/2x +/5XEBVjoxMZyK/sS1jMyUF6U69Uk4hlOSPGcyFlfO0UOrHnuN4vB1JJSdBgp36nD +B9cJAoGBAL+BclnADVfBMDJX6oHf4KdYbgvhNo2UCnwe0q3LDaFAGKiXtgd+yRXT +0RR0H3ErNSoMioCCxA3EUjZ6URdqiwh0m+ieYZ8yMy1bIgG10s9WTPv1g7P6lFBj +YXPcJxHQyUWFiVg8wJADSwn3rf7pp25kNplhQ9U9MWoXIXLhonXU +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/icon.png b/ASTJWSApp/ATJWSApp/src/main/assets/icon.png new file mode 100755 index 0000000..d376c81 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/assets/icon.png differ diff --git a/1.x/src/Acme/Resource/mime.properties b/ASTJWSApp/ATJWSApp/src/main/assets/mime.properties old mode 100644 new mode 100755 similarity index 100% rename from 1.x/src/Acme/Resource/mime.properties rename to ASTJWSApp/ATJWSApp/src/main/assets/mime.properties diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/newConf/tjws.bks b/ASTJWSApp/ATJWSApp/src/main/assets/newConf/tjws.bks new file mode 100644 index 0000000..67933ca Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/assets/newConf/tjws.bks differ diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/newConf/tjws.pem b/ASTJWSApp/ATJWSApp/src/main/assets/newConf/tjws.pem new file mode 100644 index 0000000..7edbcae --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/newConf/tjws.pem @@ -0,0 +1,53 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA9BbaX1Sm20TMsiz8rKa8Z1ndlUYaEBeg59mZQ7bhXZZHkbT3 +qNJ7ad4o+vStiNsMsIpIM1os466Uj+EfKc3heGIAp+NPogDXtFuhUjn9Qg18Lra1 +HMMvYCCbvHsJAUJCVmN8sDTl0SM3QFU+qRlrZ0+hB4ZoLumf6cNSCXSqbZ5oG/vo +RFp83j0QFT8tf6r7rVcLsYyOZIJHe0/LkRhrYm8ZC/+2Zde+a5Kn+4o4jcbifKEu +VsBVMhKMGLuDshOVQWacOaLR7y3tmKFpbNOMucg6FMMtVbIn5idck5KHFGZEFkxR ++/3nftve1DvkvDFufycBI6oMectZHxR9fr56PQIDAQABAoIBACvSZoYy9nnrUiyy +8vI0RSLw+V0xZsB43YSChoenr7JTpqm8KbJ/h3SsVAMqJnWpjg+r4+aETAbccwOZ +0TR6J/6q6Z86qjNVn2RcBwxyKMvRC/h/COkPCdRiRlOCa010jeBgoCQqexAfGG5O +X5+QVr4Hh8uID/BMNU+Mp4/XCDoBmr6inuqP668pXQzceNT6TtMdwlgqcWpQmR1c +kqhdu294hyaP4IMeMF7tb/vZ0Ryq9TVGVv71mrkCuBzeIhspT6S+fVQOZlepCTyg +/yeljwvEQQVz05icfhR/j7xCP+jPxpdLvAotbQmickzEsqiPPZCOXSUJXAjdJckV +OcxLOAECgYEA/dBUS6H5mLz9D5X3nPDGZJPuSvm08A3LFyxOJxtxF13ZSaH9knag +vdyv5Mt/ZA5qRs7UEehsUcEeWMZDSa4gkn2/LLmbzmOolGmGMK1zmHGC0i1KjIKb +uYuxqFeudVCKTGniGmTh6k8Uz/GdFveBv0g5tPyDeZSa/TNEo2BN2z0CgYEA9jEU +q7VVOUP+8SzI/FBWNnbpImlS3NqF2th6T0emScQCaSEvX3EMit5kav9wraC8hLKk +KEhIZtwwAmuHb43y3Nx/kvQAWOuo1ldPLvx0ZCyynKaomkmqJnHV0vWoXOSLyCzS +O6OcHWiIWqmM2C9B2W3B9nwJsy2/Hkxv7OJpCwECgYEA4LOjLSJE+ne2AipegM6Y +lUpx2GahTTSo6+cJeY3N3UX0rD+BYj0rqWrLPd769PXeGLna/c+qteYmm6lKwNwr +cgVpTosz6NBJ2rphVo74m6lCjBgUu7iVbPrDWanmhW28QlIrHfraFrnUTxQ0YrTU +ZSfoDtbO/sAVRrwwtAL6anECgYEA6gv++r6JJsfdtqo86KH3VA/30x8OB6g3WLY0 +kOoszDPrlsZVowZ2Rg7mqFHvbSFCF2U9ao5NRnxNp/9R4luwZwe4wJv3OJHREPQv +8xtOC23y37oQz5z4hVPzU3r3dFhSCxuRQeFoqQyXlJlbrKpAj9QocYu6LP1wk/1W +6nzUIAECgYB+QZw0NfQu2CzNqHohPqRGmMO8X9HudMkCyrXHRl22gRyuq9iumV0+ +DzUk8GKLMZQWW8KoCUL3HMin6i9yhp3jzVlsM9wgKExeNLjb0KDJqTqMNhDmKC3I +LKn9xR1eX5pJXDQW0xspoqb6xAZE0b6U9TvG16FMZjyVq/02t9rNNQ== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIEVDCCAzygAwIBAgIJAIzbknJicnvDMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MRUwEwYDVQQKEwxSU0xha3JhIEluYy4xFTATBgNVBAsTDFJTTGFrcmEgSW5jLjES +MBAGA1UEAxMJbG9jYWxob3N0MB4XDTE4MDMyMjIwNDUwNloXDTE5MDMyMjIwNDUw +NloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcT +Ck1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMGA1UECxMMUlNM +YWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQD0FtpfVKbbRMyyLPysprxnWd2VRhoQF6Dn2ZlDtuFdlkeR +tPeo0ntp3ij69K2I2wywikgzWizjrpSP4R8pzeF4YgCn40+iANe0W6FSOf1CDXwu +trUcwy9gIJu8ewkBQkJWY3ywNOXRIzdAVT6pGWtnT6EHhmgu6Z/pw1IJdKptnmgb +++hEWnzePRAVPy1/qvutVwuxjI5kgkd7T8uRGGtibxkL/7Zl175rkqf7ijiNxuJ8 +oS5WwFUyEowYu4OyE5VBZpw5otHvLe2YoWls04y5yDoUwy1VsifmJ1yTkocUZkQW +TFH7/ed+297UO+S8MW5/JwEjqgx5y1kfFH1+vno9AgMBAAGjgd4wgdswHQYDVR0O +BBYEFJcaTkWuhygoR7burILh/H1dj3LSMIGrBgNVHSMEgaMwgaCAFJcaTkWuhygo +R7burILh/H1dj3LSoX2kezB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv +cm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazEVMBMGA1UEChMMUlNMYWtyYSBJbmMu +MRUwEwYDVQQLEwxSU0xha3JhIEluYy4xEjAQBgNVBAMTCWxvY2FsaG9zdIIJAIzb +knJicnvDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALuGwnBWj7qe +SxcNLjkVTWFdJGlR4yGju1pgfehDZjC2MidIJq24zl2WFlAZiZUTsBzHR4/d7tbV +YnxU/+a4WhlIk1FMHscj86/4Vqyq4gh2FbEtZh8njonMQbmWDipnhl0NEi2RRWBW +0OqQWFGO8AK6+irzaO/4tAIbzkkHwRooFLoRU1UQ53TIisfgfuInPXt8r6xD2QQx +j9hYxRhZGb/olCYDqJixJ5JjMQCYDeH7ssEe3iBPaxIQ3KwSykHILgOaPSb3ZabR +vmSu69sorIM/6ayZFkvvlAShKDp4Y5KjAikZ3ux7bzVwvwZEqMYp0cs+9coCdSUo +oft+kt0KRps= +-----END CERTIFICATE----- diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/web/index.html b/ASTJWSApp/ATJWSApp/src/main/assets/web/index.html new file mode 100644 index 0000000..d94bb5a --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/web/index.html @@ -0,0 +1,23 @@ + + + + + TJWS Index + + + + +

Embedded TJWS Welcome you!

+ +
+
+
+
+ +
+
+
+ + + diff --git a/ASTJWSApp/ATJWSApp/src/main/assets/web/rsl.js b/ASTJWSApp/ATJWSApp/src/main/assets/web/rsl.js new file mode 100644 index 0000000..9513927 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/assets/web/rsl.js @@ -0,0 +1,19 @@ +/** + * Adds the default contents into the div. + */ +function addDefaults(idDiv) { + var div = document.getElementById(idDiv); + if (div) { + div.innerHTML += 'Rohtash Singh Lakra'; + } +} + +/** + * Clears the div contents. + */ +function clearDefaults(idDiv) { + var div = document.getElementById(idDiv); + if (div) { + div.innerHTML = ''; + } +} \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/AllCertsTrustManager.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/AllCertsTrustManager.java new file mode 100644 index 0000000..975855c --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/AllCertsTrustManager.java @@ -0,0 +1,77 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.X509TrustManager; + +/** + * Create a trust manager that does not validate certificate chains. + * + * @author Rohtash Singh Lakra + * @date 03/22/2018 03:58:24 PM + */ +public class AllCertsTrustManager implements X509TrustManager { + + /** + * (non-Javadoc) + * + * @see X509TrustManager#checkClientTrusted(X509Certificate[], + * String) + */ + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + // TODO Auto-generated method stub + } + + /** + * (non-Javadoc) + * + * @see X509TrustManager#checkServerTrusted(X509Certificate[], + * String) + */ + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + // TODO Auto-generated method stub + } + + /** + * (non-Javadoc) + * + * @see X509TrustManager#getAcceptedIssuers() + */ + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/AllHostNameVerifier.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/AllHostNameVerifier.java new file mode 100644 index 0000000..5248083 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/AllHostNameVerifier.java @@ -0,0 +1,50 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +/** + * @author Rohtash Singh Lakra + * @date 03/22/2018 03:56:15 PM + */ +public class AllHostNameVerifier implements HostnameVerifier { + /** + * @see HostnameVerifier#verify(String, + * SSLSession) + */ + @Override + public boolean verify(String hostName, SSLSession sslSession) { + return true; + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/BaseActivity.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/BaseActivity.java new file mode 100644 index 0000000..e6824b3 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/BaseActivity.java @@ -0,0 +1,97 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.app.Activity; +import android.os.Bundle; + +import com.rslakra.android.framework.events.AndroidEvent; +import com.rslakra.android.framework.events.EventListener; +import com.rslakra.android.logger.LogHelper; +import com.rslakra.android.server.TJWSService; + +/** + * @Author: Rohtash Singh Lakra + * @Created: 2018/03/20 10:45 AM + */ +public abstract class BaseActivity extends Activity implements EventListener { + + /** LOG_TAG */ + private static final String LOG_TAG = "BaseActivity"; + + //mTJWSApp + private TJWSApp mTJWSApp; + + public BaseActivity() { + + } + + /** + * @param savedInstanceState + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //initialize the singleton instance. + mTJWSApp = (TJWSApp) getApplication(); + } + + /** + * This service is started and bound on Application start, so we don't need to rebind for every + * activity. + */ + public TJWSApp getTJWSApp() { + return mTJWSApp; + } + + /** + * This service is started and bound on Application start, so we don't need to rebind for every + * activity. + */ + public TJWSService getTJWSService() { + return TJWSApp.getTJWSService(); + } + + + /** + * Override? to receive messages from your events. + * + * Call super( ) ? Always. BVActivity provides basic functionality + * for logging out when needed, and invokes methods enabling you to make + * features available when the app goes online and offline. + * + * @param event The event object itself. + */ + public void onEvent(AndroidEvent event) { + LogHelper.d(LOG_TAG, event); + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/LocalServerService.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/LocalServerService.java new file mode 100644 index 0000000..f231f96 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/LocalServerService.java @@ -0,0 +1,154 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.app.IntentService; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; + +import com.rslakra.android.logger.LogHelper; + +/** + * @Author: Rohtash Singh Lakra + * @Created: 2018/03/21 2:36 PM + */ +public class LocalServerService extends IntentService { + + /** LOG_TAG */ + private static final String LOG_TAG = "LocalServerService"; + + /** mBinder */ + private final IBinder mBinder = new LocalBinder(); + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class LocalBinder extends Binder { + public LocalServerService getService() { + // Return this instance of LocalService so clients can call public + // methods + return LocalServerService.this; + } + } + + /** + * @param name + */ + public LocalServerService(final String name) { + super(name); + } + + /** + * + */ + public LocalServerService() { + this(LOG_TAG); + + } + + // ---------------------------------------------------------------- + // System startup messages + // ---------------------------------------------------------------- + + /** + * @see android.app.IntentService#onCreate() + */ + @Override + public void onCreate() { + super.onCreate(); + LogHelper.i(LOG_TAG, "JUPService is created."); + } + + /** + * Call this method to (a) wake up the service if it isn't already awake, + * and (b) get an object which lets you call methods directly on the + * service. + * + * @param intent + * @return + * @see android.app.IntentService#onBind(android.content.Intent) + */ + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** + * @param intent + * @return + * @see android.app.Service#onUnbind(android.content.Intent) + */ + @Override + public boolean onUnbind(Intent intent) { + return super.onUnbind(intent); + } + + /** + * This method is invoked on my process' UI thread. (!!!) That means: if + * this method does something long-running, it will interrupt any Activity + * currently visible, even though this is "in the background." So we have to + * get off the main thread as fast as possible. + * + * @param intent + * @param flags + * @param startId + * @return + * @see android.app.IntentService#onStartCommand(android.content.Intent, * int, int) + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + + /** + * Cleans up our threads when the Service is stopped, whether by the user, + * an internal configuration, the system, or the control panel. + * + * WARNING! If we do NOT clean up the threads, they seem to live FOREVER. + */ + @Override + public void onDestroy() { + LogHelper.i(LOG_TAG, "JUPService is destroyed."); + super.onDestroy(); + } + + /** + * @param intent + * @see android.app.IntentService#onHandleIntent(android.content.Intent) + */ + @Override + protected void onHandleIntent(Intent intent) { + TJWSApp.getTJWSService().startLocalServer(false); + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/MainActivity.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/MainActivity.java new file mode 100644 index 0000000..5eed081 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/MainActivity.java @@ -0,0 +1,297 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.annotation.SuppressLint; +import android.app.ActionBar; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.FrameLayout; + +import com.rslakra.android.logger.LogHelper; + +/** + * The Main Activity. + * + * @author Rohtash Singh + * @version 1.0.0 + * @since Apr 28, 2015 7:14:11 PM + */ +public class MainActivity extends BaseActivity { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "MainActivity"; + + /** + * webViewContainer + */ + private FrameLayout webViewContainer; + + /** + * mWebView + */ + private WebView mWebView; + + public MainActivity() { + LogHelper.i(LOG_TAG, "MainActivity()"); + } + + /** + * Starts the MainActivity. + * + * @param activity + * @param finishPrevious + */ + public static void startMainActivity(final Activity activity, final boolean finishPrevious) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Intent intent = new Intent(activity, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + activity.startActivity(intent); + if(finishPrevious) { + activity.finish(); + } + } + }); + } + + /** + * Initialize the components. + * + * @see android.app.Activity#onCreate(android.os.Bundle) + */ + @SuppressLint("SetJavaScriptEnabled") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LogHelper.d(LOG_TAG, "+onCreate()"); + // set main activity + setContentView(R.layout.activity_main); + getTJWSApp().setParentActivity(this); + + // initialize WebView. + initWebView(); + + // Load WebView Contents. + loadWebviewContents(); + LogHelper.i(LOG_TAG, "-onCreate()"); + } + + + /** + * Initializes the WebView with default settings and web view client. + */ + @SuppressLint("SetJavaScriptEnabled") + private void initWebView() { + webViewContainer = (FrameLayout) findViewById(R.id.webViewContainer); + if(mWebView == null) { + try { + // jupWebView = (WebView) findViewById(R.id.jupWebView); + mWebView = new WebView(this); + } catch(Throwable ex) { + LogHelper.e(LOG_TAG, ex); + } + + mWebView.setLayoutParams(new ViewGroup.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT)); + /* + * page loading webpage loses its focus so this line just bring the + * focus back to page. + */ + mWebView.requestFocus(View.FOCUS_DOWN); + + WebSettings jupWebSettings = mWebView.getSettings(); + // enable JavaScript + jupWebSettings.setJavaScriptEnabled(true); + jupWebSettings.setDomStorageEnabled(true); + // loads the WebView completely zoomed out + jupWebSettings.setLoadWithOverviewMode(true); + + /* + * true makes the Webview have a normal viewport such as a normal + * desktop browser when false the webview will have a viewport + * constrained to it's own dimensions + */ + jupWebSettings.setUseWideViewPort(true); + + /* + * While this will allow pinch-to-zoom, it will also display a zoom + * overlay control (Galaxy S3). In order to disable the on-screen + * zoom tool, but retain the pinch-to-zoom functionality, you need + * to call webView.setDisplayZoomControls(false) as well. + */ + jupWebSettings.setBuiltInZoomControls(false); + jupWebSettings.setDisplayZoomControls(false); + + // override the web client to open all links in the same webview + mWebView.setWebViewClient(new TJWSWebViewClient(this)); + mWebView.setWebChromeClient(new TJWSWebClient()); + + /* + * Injects the supplied Java object into this WebView. The object is + * injected into the JavaScript context of the main frame, using the + * supplied name. This allows the Java object's public methods to be + * accessed from JavaScript. + */ + WebView.setWebContentsDebuggingEnabled(true); + // mWebView.addJavascriptInterface(new JavaScriptProxy(getApplicationContext(), this), "Android"); + + /* disable WebView cache */ + mWebView.clearCache(true); + jupWebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); + jupWebSettings.setAppCacheEnabled(false); + + // jupWebSettings.setSaveFormData(false); + // jupWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + // getApplicationContext().deleteDatabase("webview.db"); + // getApplicationContext().deleteDatabase("webviewCache.db"); + + // stops the long selection options. + // jupWebView.setOnLongClickListener(new OnLongClickListener() { + // /** + // * @see + // android.view.View.OnLongClickListener#onLongClick(android.view.View) + // */ + // @Override + // public boolean onLongClick(View v) { + // return true; + // } + // }); + // jupWebView.setLongClickable(false); + } else { + // Remove existing WebView from its placeholder. + webViewContainer.removeView(mWebView); + } + + // Attach the WebView to its placeholder + webViewContainer.addView(mWebView); + } + + /** + * This methods loads the static contents .ZIP file from server and loads + * the root URL of an application. + */ + private void loadWebviewContents() { + // get the path of home directory + this.runOnUiThread(new Runnable() { + /** + * Loads the contents of the webpage. + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { +// String urlString = "https://www.google.com/"; + String urlString = TJWSApp.getTJWSService().getServerUrl(); + LogHelper.i(LOG_TAG, "urlString:" + urlString); + mWebView.loadUrl(urlString); + } + }); + } + + + /** + * Saves the state of the WebView. + * + * @see android.app.Activity#onSaveInstanceState(android.os.Bundle) + */ + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // Save the state of the WebView + mWebView.saveState(outState); + } + + /** + * Restores the state of the WebView. + * + * @see android.app.Activity#onRestoreInstanceState(android.os.Bundle) + */ + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + // Restore the state of the WebView + mWebView.restoreState(savedInstanceState); + } + + /** + * @see android.app.Activity#onDestroy() + */ + @Override + protected void onDestroy() { + LogHelper.d(LOG_TAG, "onDestroy()"); + super.onDestroy(); + } + + /** + * + */ + @Override + protected void onResume() { + super.onResume(); + initWebView(); + } + + /** + * @param visible + */ + public void showHideWebView(final boolean visible) { + this.runOnUiThread(new Runnable() { + /** + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + if(mWebView != null) { + mWebView.setVisibility((visible ? View.VISIBLE : View.GONE)); + } + } + }); + } + + + /** + * Reloads the webView. + */ + public void reload() { + if(mWebView != null) { + loadWebviewContents(); + } + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/NetworkStatusMonitor.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/NetworkStatusMonitor.java new file mode 100644 index 0000000..6bc3a78 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/NetworkStatusMonitor.java @@ -0,0 +1,101 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Responds to system messages indicating a change in the + * network's status. + *

+ * + * This is an Android BroadcastReceiver, which means that + * it is instantiated specifically to receive the specified + * event. A single method is executed (onReceive()); then + * this object is deleted. In addition, onReceive() runs + * on the main thread. So we have to do whatever we're going + * to do very quickly, and have one chance to get a message + * into the body of our app before this object is killed. + *

+ * + * Also, the documentation says that we MUST check the source of + * the sender, because any other application could launch this + * object. (John suggests that, in contrast, we can merely make + * it "not exported" in the Manifest file, which means only + * the system can use this. Awesome!) + *

+ * + * For more information: + *

+ * + * - See onReceive (): + * http://developer.android.com/reference/android/content/BroadcastReceiver.html#onReceive(android.content.Context,%20android.content.Intent) + *

+ * + * - See registerReceiver (): + * http://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter,%20java.lang.String,%20android.os.Handler) + *

+ * + * - The BroacastReceiver lifecycle: + * http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle + * + * @author Rohtash Singh Lakra + */ +public final class NetworkStatusMonitor extends BroadcastReceiver { + + /* + * @see android.content.BroadcastReceiver#onReceive(android.content.Context, + * android.content.Intent) + */ + @Override + public void onReceive(final Context context, Intent intent) { + //check service is started or not. + TJWSApp.checkReachability(context); + } + + /** + * Returns true if the device network is available otherwise false. + * + * @param context + * @return + */ + public static boolean isNetworkAvailable(Context context) { + ConnectivityManager cnnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cnnectivityManager.getActiveNetworkInfo(); + // should check null because in airplane mode it will be null + return (netInfo != null && netInfo.isConnected()); + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/NoSSLv3SocketFactory.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/NoSSLv3SocketFactory.java new file mode 100644 index 0000000..a4e7f2e --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/NoSSLv3SocketFactory.java @@ -0,0 +1,442 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.SocketChannel; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + + +/** + * @Author: Rohtash Singh Lakra + * @Created: 2018/03/27 9:50 AM + */ +public class NoSSLv3SocketFactory extends SSLSocketFactory { + /** delegate */ + private final SSLSocketFactory delegate; + + public NoSSLv3SocketFactory() { + this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory(); + } + + public NoSSLv3SocketFactory(SSLSocketFactory delegate) { + this.delegate = delegate; + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + private Socket makeSocketSafe(Socket socket) { + if(socket instanceof SSLSocket) { + socket = new NoSSLv3SSLSocket((SSLSocket) socket); + } + return socket; + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return makeSocketSafe(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return makeSocketSafe(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort)); + } + + private class NoSSLv3SSLSocket extends DelegateSSLSocket { + + private NoSSLv3SSLSocket(SSLSocket delegate) { + super(delegate); + + } + + @Override + public void setEnabledProtocols(String[] protocols) { +// if(protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) { +// +// List enabledProtocols = new ArrayList(Arrays.asList(delegate.getEnabledProtocols())); +// if(enabledProtocols.size() > 1) { +// enabledProtocols.remove("SSLv3"); +// System.out.println("Removed SSLv3 from enabled protocols"); +// } else { +// System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols)); +// } +// protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]); +// } + + protocols = new String[]{"SSLv3"}; + + super.setEnabledProtocols(protocols); + } + } + + public class DelegateSSLSocket extends SSLSocket { + + protected final SSLSocket delegate; + + DelegateSSLSocket(SSLSocket delegate) { + this.delegate = delegate; + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public String[] getEnabledCipherSuites() { + return delegate.getEnabledCipherSuites(); + } + + @Override + public void setEnabledCipherSuites(String[] suites) { + delegate.setEnabledCipherSuites(suites); + } + + @Override + public String[] getSupportedProtocols() { + return delegate.getSupportedProtocols(); + } + + @Override + public String[] getEnabledProtocols() { + return delegate.getEnabledProtocols(); + } + + @Override + public void setEnabledProtocols(String[] protocols) { + delegate.setEnabledProtocols(protocols); + } + + @Override + public SSLSession getSession() { + return delegate.getSession(); + } + + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) { + delegate.addHandshakeCompletedListener(listener); + } + + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) { + delegate.removeHandshakeCompletedListener(listener); + } + + @Override + public void startHandshake() throws IOException { + delegate.startHandshake(); + } + + @Override + public void setUseClientMode(boolean mode) { + delegate.setUseClientMode(mode); + } + + @Override + public boolean getUseClientMode() { + return delegate.getUseClientMode(); + } + + @Override + public void setNeedClientAuth(boolean need) { + delegate.setNeedClientAuth(need); + } + + @Override + public void setWantClientAuth(boolean want) { + delegate.setWantClientAuth(want); + } + + @Override + public boolean getNeedClientAuth() { + return delegate.getNeedClientAuth(); + } + + @Override + public boolean getWantClientAuth() { + return delegate.getWantClientAuth(); + } + + @Override + public void setEnableSessionCreation(boolean flag) { + delegate.setEnableSessionCreation(flag); + } + + @Override + public boolean getEnableSessionCreation() { + return delegate.getEnableSessionCreation(); + } + + @Override + public void bind(SocketAddress localAddr) throws IOException { + delegate.bind(localAddr); + } + + @Override + public synchronized void close() throws IOException { + delegate.close(); + } + + @Override + public void connect(SocketAddress remoteAddr) throws IOException { + delegate.connect(remoteAddr); + } + + @Override + public void connect(SocketAddress remoteAddr, int timeout) throws IOException { + delegate.connect(remoteAddr, timeout); + } + + @Override + public SocketChannel getChannel() { + return delegate.getChannel(); + } + + @Override + public InetAddress getInetAddress() { + return delegate.getInetAddress(); + } + + @Override + public InputStream getInputStream() throws IOException { + return delegate.getInputStream(); + } + + @Override + public boolean getKeepAlive() throws SocketException { + return delegate.getKeepAlive(); + } + + @Override + public InetAddress getLocalAddress() { + return delegate.getLocalAddress(); + } + + @Override + public int getLocalPort() { + return delegate.getLocalPort(); + } + + @Override + public SocketAddress getLocalSocketAddress() { + return delegate.getLocalSocketAddress(); + } + + @Override + public boolean getOOBInline() throws SocketException { + return delegate.getOOBInline(); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return delegate.getOutputStream(); + } + + @Override + public int getPort() { + return delegate.getPort(); + } + + @Override + public synchronized int getReceiveBufferSize() throws SocketException { + return delegate.getReceiveBufferSize(); + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return delegate.getRemoteSocketAddress(); + } + + @Override + public boolean getReuseAddress() throws SocketException { + return delegate.getReuseAddress(); + } + + @Override + public synchronized int getSendBufferSize() throws SocketException { + return delegate.getSendBufferSize(); + } + + @Override + public int getSoLinger() throws SocketException { + return delegate.getSoLinger(); + } + + @Override + public synchronized int getSoTimeout() throws SocketException { + return delegate.getSoTimeout(); + } + + @Override + public boolean getTcpNoDelay() throws SocketException { + return delegate.getTcpNoDelay(); + } + + @Override + public int getTrafficClass() throws SocketException { + return delegate.getTrafficClass(); + } + + @Override + public boolean isBound() { + return delegate.isBound(); + } + + @Override + public boolean isClosed() { + return delegate.isClosed(); + } + + @Override + public boolean isConnected() { + return delegate.isConnected(); + } + + @Override + public boolean isInputShutdown() { + return delegate.isInputShutdown(); + } + + @Override + public boolean isOutputShutdown() { + return delegate.isOutputShutdown(); + } + + @Override + public void sendUrgentData(int value) throws IOException { + delegate.sendUrgentData(value); + } + + @Override + public void setKeepAlive(boolean keepAlive) throws SocketException { + delegate.setKeepAlive(keepAlive); + } + + @Override + public void setOOBInline(boolean oobinline) throws SocketException { + delegate.setOOBInline(oobinline); + } + + @Override + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { + delegate.setPerformancePreferences(connectionTime, latency, bandwidth); + } + + @Override + public synchronized void setReceiveBufferSize(int size) throws SocketException { + delegate.setReceiveBufferSize(size); + } + + @Override + public void setReuseAddress(boolean reuse) throws SocketException { + delegate.setReuseAddress(reuse); + } + + @Override + public synchronized void setSendBufferSize(int size) throws SocketException { + delegate.setSendBufferSize(size); + } + + @Override + public void setSoLinger(boolean on, int timeout) throws SocketException { + delegate.setSoLinger(on, timeout); + } + + @Override + public synchronized void setSoTimeout(int timeout) throws SocketException { + delegate.setSoTimeout(timeout); + } + + @Override + public void setTcpNoDelay(boolean on) throws SocketException { + delegate.setTcpNoDelay(on); + } + + @Override + public void setTrafficClass(int value) throws SocketException { + delegate.setTrafficClass(value); + } + + @Override + public void shutdownInput() throws IOException { + delegate.shutdownInput(); + } + + @Override + public void shutdownOutput() throws IOException { + delegate.shutdownOutput(); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public boolean equals(Object object) { + return delegate.equals(object); + } + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/SplashActivity.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/SplashActivity.java new file mode 100755 index 0000000..2e5dd10 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/SplashActivity.java @@ -0,0 +1,214 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.view.Window; + +import com.rslakra.android.framework.events.AndroidEvent; +import com.rslakra.android.framework.events.EventManager; +import com.rslakra.android.framework.events.EventType; +import com.rslakra.android.logger.LogHelper; + +public class SplashActivity extends BaseActivity { + + /** LOG_TAG */ + private static final String LOG_TAG = "SplashActivity"; + + public SplashActivity() { + LogHelper.i(LOG_TAG, "SplashActivity()"); + } + + + /** + * Starts Next activity. + */ + private void startNextActivity() { + LogHelper.d(LOG_TAG, "startNextActivity"); + + final boolean withService = false; + EventManager.subscribe(this, EventType.SERVER_STARTED, EventType.ERROR); + if(withService) { + this.startService(new Intent(this, LocalServerService.class)); + } else { + getTJWSService().startLocalServer(true); + } + } + + + /** + * @param savedInstanceState + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LogHelper.d(LOG_TAG, "onCreate()"); + this.requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.activity_splash); + TJWSApp.setParentActivity(this); + +// try { +// ProviderInstaller.installIfNeeded(this); +// } catch(GooglePlayServicesRepairableException ex) { +// // Thrown when Google Play Services is not installed, up-to-date, or enabled +// // Show dialog to allow users to install, update, or otherwise enable Google Play services. +// GooglePlayServicesUtil.getErrorDialog(ex.getConnectionStatusCode(), this, 0); +// } catch(GooglePlayServicesNotAvailableException ex) { +// LogHelper.e(LOG_TAG, "Google Play Services not available.", ex); +// } + + if(getTJWSService() != null) { + startNextActivity(); + } else { + EventManager.subscribe(this, EventType.SERVICE_CONNECTED); + } + } + + + /** + * Override? to receive messages from your events. + * + * Call super( ) ? Always. BVActivity provides basic functionality + * for logging out when needed, and invokes methods enabling you to make + * features available when the app goes online and offline. + * + * @param event The event object itself. + */ + public void onEvent(AndroidEvent event) { + LogHelper.d(LOG_TAG, event); + switch(event.getType()) { + case SERVICE_CONNECTED: + startNextActivity(); + break; + + case SERVER_STARTED: + startMainActivity(); + break; + + case SERVER_STOPPED: + case ERROR: + LogHelper.d(LOG_TAG, "Show Error Message!", event); + handleError(this, false); + break; + + default: + break; + } + } + + + /** + * Starts the main activity. + */ + private void startMainActivity() { + // check if the server is started properly + if(TJWSApp.getTJWSService().isWebServerRunning()) { + EventManager.unsubscribe(this, EventType.SERVICE_CONNECTED, EventType.SERVER_STARTED); + final boolean useWebView = true; + if(useWebView) { + MainActivity.startMainActivity(this, true); + } else { + final Context mContext = TJWSApp.getInstance().getApplicationContext(); + TestConnection testConnection = new TestConnection(mContext, true); + final boolean checkSocketConnection = false; + if(checkSocketConnection) { + testConnection.testSSLSocketConnection(); + } else { + testConnection.testSSLConnection(); + } + } + } else { + LogHelper.i(LOG_TAG, "The local server hasn't started yet!"); + handleError(this, false); + } + } + + /** + * Shows the provided error message. + * Closes the progress dialog, if visible. + * + * @param activity + * @param exitApplication + */ + private void handleError(final BaseActivity activity, final boolean exitApplication) { + try { + LogHelper.i(LOG_TAG, "handleError(" + activity + ", " + exitApplication + ")"); + activity.runOnUiThread(new Runnable() { + /** + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + // now show error message. + final AlertDialog.Builder mAlertBuilder = new AlertDialog.Builder(activity); + mAlertBuilder.setCancelable(true); + + String errorMessage = "ERROR!"; + if(exitApplication) { + errorMessage = errorMessage = activity.getString(R.string.fatalErrorMessage); + } else { + errorMessage = activity.getString(R.string.errorMessage); + } + + LogHelper.i(LOG_TAG, "errorMessage:" + errorMessage); + mAlertBuilder.setMessage(errorMessage); + mAlertBuilder.setTitle(activity.getString(R.string.errorDialogTitle)); + mAlertBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + + /** + * + */ + public void onClick(DialogInterface dialog, int id) { + if(exitApplication) { + LogHelper.w(LOG_TAG, "Killing the app!"); + + // final int mErrorDisplayTimeout = + // StringUtils.stringAsInteger(activity.getString(R.string.error_display_timeout)); + // Debug.w(DEBUG_KEY, "mErrorDisplayTimeout:" + + // mErrorDisplayTimeout); + // Thread.sleep(mErrorDisplayTimeout); + System.exit(0); + } + } + }); + mAlertBuilder.show(); + } + }); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSApp.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSApp.java new file mode 100755 index 0000000..9b70076 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSApp.java @@ -0,0 +1,315 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.Application; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Environment; +import android.os.IBinder; + +import com.rslakra.android.framework.events.EventManager; +import com.rslakra.android.framework.events.EventType; +import com.rslakra.android.logger.LogHelper; +import com.rslakra.android.logger.LogType; +import com.rslakra.android.server.TJWSService; +import com.rslakra.logger.LogManager; + +import org.apache.log4j.Level; + +import java.io.File; + +/** + * @author Rohtash Singh Lakra + * @date 03/15/2018 03:39:08 PM + */ +public class TJWSApp extends Application { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "TJWSApp"; + + /** + * EXTERNAL_STORAGE_DATA_DIRECTORY + */ + private static File EXTERNAL_STORAGE_DATA_DIRECTORY = Environment.getExternalStoragePublicDirectory("/Android/data"); + + /** + * EXTERNAL_STORAGE_DATA_DIRECTORY + */ + private static final boolean ENABLE_EXTERNAL_STORAGE = false; + + /** + * SPLASH_WAIT_TIME + */ + private static final int SPLASH_WAIT_TIME = 1000; + + /** + * instance + */ + private static TJWSApp sInstance; + + /** + * serviceControl + */ + private static TJWSService sTJWSService; + + /* parentActivity */ + private static BaseActivity sParentActivity; + + // DEBUG_KEY + private static final String DEBUG_KEY = "BvApplication"; + + + /** + * Default Constructor. + */ + public TJWSApp() { + } + + /** + * @return + */ + public static TJWSApp getInstance() { + return sInstance; + } + + /** + * @return + */ + public static TJWSService getTJWSService() { + return sTJWSService; + } + + /** + * @return BaseActivity + */ + public static BaseActivity getParentActivity() { + return sParentActivity; + } + + /** + * @param parentActivity + */ + public static void setParentActivity(final BaseActivity parentActivity) { + sParentActivity = parentActivity; + } + + /** + * Returns the package name of the application. + *

+ * This package name must match as per the AndroidManifest.xml + * file 'package="com.boardvantage.meetxjup"' + * + * @return + */ + public String getAppPackageName() { + return getInstance().getApplicationContext().getPackageName(); + } + + /** + * Returns the application's home directory path. + * + * @return + * @throws Exception + */ + public String getAppHomeDir() { + if(ENABLE_EXTERNAL_STORAGE) { + return LogHelper.pathString(EXTERNAL_STORAGE_DATA_DIRECTORY.getAbsolutePath(), getAppPackageName()); + } else { + return getInstance().getApplicationContext().getFilesDir().getAbsolutePath(); + } + } + + + /** + * Returns the application's home directory path. + * + * @return + * @throws Exception + */ + public String getLogsFolder() { + return LogHelper.pathString(getAppHomeDir(), "logs"); + } + + /** + * @return + */ + public String getDeployFolder() { + return LogHelper.pathString(getAppHomeDir(), "webapps"); + } + + /** + * + */ + @Override + public void onCreate() { + super.onCreate(); + //initialize the singleton instance. + if(TJWSApp.getInstance() == null) { + synchronized(TJWSApp.class) { + if(TJWSApp.getInstance() == null) { + TJWSApp.sInstance = this; + } + } + } + + if(Thread.getDefaultUncaughtExceptionHandler() == null) { + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + + public void uncaughtException(Thread thread, Throwable ex) { + LogHelper.e(LOG_TAG, "Unhandled exception " + ex + " in the thread: " + thread, ex); + } + }); + } + + // initialize logger + LogHelper.log4jConfigure(getInstance().getLogsFolder(), LogType.DEBUG); + LogHelper.i(LOG_TAG, "onCreate()"); +// LogManager.setLogLevel(Level.DEBUG); + + // initialize service + initService(); + } + + /** + * @param sleepTime + */ + private void broadcastAppServiceConnectedEvent(final int sleepTime) { + Thread loginStartThread = new Thread(new Runnable() { + public void run() { + if(sleepTime > 0) { + try { + Thread.sleep(sleepTime); + } catch(InterruptedException ex) { + //ignore me! + } + } + + //send notification that server is connected. + EventManager.sendEvent(EventType.SERVICE_CONNECTED); + } + }); + + loginStartThread.start(); + } + + /** + * Defines callbacks for service binding, passed to bindService() + */ + private final ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + LogHelper.d(LOG_TAG, "onServiceConnected(" + className + ", " + service + ")"); + // We've bound to LocalService, cast the IBinder and get + // LocalService instance + TJWSService.LocalBinder binder = (TJWSService.LocalBinder) service; + sTJWSService = (TJWSService) binder.getService(); + // can send notification to activities here serviceControl = service; + broadcastAppServiceConnectedEvent(SPLASH_WAIT_TIME); + } + + /** + * @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName) + */ + @Override + public void onServiceDisconnected(ComponentName componentName) { + LogHelper.d(LOG_TAG, "onServiceDisconnected(" + componentName + ")"); + EventManager.sendEvent(EventType.SERVICE_DISCONNECTED); + // appService.onServiceDisconnected(); + sTJWSService = null; + } + }; + + /** + * + */ + public void initService() { + // sanity + if(getTJWSService() != null) { + return; + } + + final Thread serviceCreationThread = new Thread(new Runnable() { + public void run() { + /** This starts only if t is not currently running. So we don't need to worry about multiple starts.*/ + final Intent serviceIntent = new Intent(TJWSApp.this, TJWSService.class); + if(!isServiceRunning(TJWSService.class)) { + TJWSApp.this.startService(serviceIntent); + } + /** Defines callbacks for service binding, passed to bindService() */ + bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); + } + }); + serviceCreationThread.run(); + } + + /** + * Returns true if the given class service is running otherwise false. + * + * @param serviceClass + * @return + */ + private boolean isServiceRunning(Class serviceClass) { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + for(RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if(serviceClass.getName().equals(service.service.getClassName())) { + return true; + } + } + + return false; + } + + + /** + * Send myself a message with a correctly-formatted Intent. + * To do that, I have to "start" myself, even though I'm already + * started. No problem. + *

+ * This method is intended to be used by the + * NetworkConnectivityTester's BroadcastReceiver when it hears + * about an actual network-reachability change. + * + * @param mContext The context passed to the broadcast receiver. No idea what it is, but I + * don't care, because it lets me send myself a message. + */ + public static void checkReachability(final Context mContext) { + // only the key matters to me, not the payload. See onStartCommand(). + mContext.startService(new Intent(mContext, TJWSService.class)); + } + +} \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSWebClient.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSWebClient.java new file mode 100644 index 0000000..2d316b2 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSWebClient.java @@ -0,0 +1,64 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.app.AlertDialog; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebView; + +import com.rslakra.android.logger.LogHelper; + +/** + * @author Rohtash Singh + * @version 1.0.0 + * @since Jun 15, 2015 1:04:16 PM + */ +public class TJWSWebClient extends WebChromeClient { + + /** LOG_TAG */ + private static final String LOG_TAG = "TJWSWebClient"; + + /** + * Displays alert message in Web View. + * + * @param webView + * @param url + * @param message + */ + @Override + public boolean onJsAlert(WebView webView, String url, String message, JsResult jsResult) { + LogHelper.d(LOG_TAG, "onJsAlert(" + webView + ", " + url + ", " + message + ", " + jsResult + ")"); + new AlertDialog.Builder(webView.getContext()).setMessage(message).setCancelable(true).show(); + jsResult.confirm(); + return true; + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSWebViewClient.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSWebViewClient.java new file mode 100755 index 0000000..24a15d1 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TJWSWebViewClient.java @@ -0,0 +1,198 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.graphics.Bitmap; +import android.net.http.SslError; +import android.webkit.ClientCertRequest; +import android.webkit.HttpAuthHandler; +import android.webkit.SslErrorHandler; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import com.rslakra.android.framework.SSLHelper; +import com.rslakra.android.logger.LogHelper; + +import java.io.InputStream; +import java.security.cert.Certificate; + +/** + * Provides an opportunity to intercept the WebView calls. + * + * @author Rohtash Singh + * @version 1.0.0 + * @since Apr 28, 2015 7:16:05 PM + */ +public class TJWSWebViewClient extends WebViewClient { + + /** LOG_TAG */ + private static final String LOG_TAG = "TJWSWebViewClient"; + + /** mParentActivity */ + private final Activity mParentActivity; + + /** mProgressDialog */ + private ProgressDialog mProgressDialog; + + /** + * + */ + public TJWSWebViewClient(Activity parentActivity) { + super(); + this.mParentActivity = parentActivity; + if(mProgressDialog == null) { + mProgressDialog = new ProgressDialog(mParentActivity); + mProgressDialog.setTitle(mParentActivity.getString(R.string.loading)); + mProgressDialog.setMessage(mParentActivity.getString(R.string.please_wait)); + } + } + + /** + * Shows or Hides the progress dialog. + * + * @param show + */ + private void showHideProgressDialog(final boolean show) { + if(show) { + if(mProgressDialog != null && !mProgressDialog.isShowing()) { + mProgressDialog.show(); + } + } else { + if(mParentActivity != null && !mParentActivity.isFinishing()) { + if(mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } + } + } + } + + /** + * Notify the host application that a page has started loading. This method + * is called once for each main frame load so a page with iframes or + * framesets will call onPageStarted one time for the main frame. This also + * means that onPageStarted will not be called when the contents of an + * embedded frame changes, i.e. clicking a link whose target is an iframe. + * + * @see android.webkit.WebViewClient#onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap) + */ + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + LogHelper.d(LOG_TAG, "onPageStarted(" + view + ", " + url + ", " + favicon + ")"); + showHideProgressDialog(true); + } + + /** + * @see android.webkit.WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String) + */ + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + LogHelper.d(LOG_TAG, "shouldOverrideUrlLoading(" + view + ", " + url + ")"); + return true; + } + + /** + * Notify the host application that a page has finished loading. This method + * is called only for main frame. When onPageFinished() is called, the + * rendering picture may not be updated yet. To get the notification for the + * new Picture, use {@link WebView.PictureListener#onNewPicture}. + * + * @see android.webkit.WebViewClient#onPageFinished(android.webkit.WebView, java.lang.String) + */ + @Override + public void onPageFinished(WebView view, String urlString) { + LogHelper.d(LOG_TAG, "onPageFinished(" + view + ", " + urlString + ")"); + // super.onPageFinished(view, url); + showHideProgressDialog(false); + } + + /** + * onReceivedError + */ + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + LogHelper.d(LOG_TAG, "onReceivedError(" + view + ", " + errorCode + ", " + description + ", " + failingUrl + ")"); + LogHelper.showToastMessage(view.getContext(), description); + } + + @Override + public void onReceivedSslError(WebView mWebView, SslErrorHandler handler, SslError error) { + LogHelper.d(LOG_TAG, "onReceivedSslError(" + mWebView + ", " + handler + ", " + error + ")"); + try { + /** + * Ignore SSL certificate errors (if this is only for self-signed certificate) + * + * The MITM attacks (where the attacker secretly relays and possibly alters the + * communication between two parties who believe they are directly communicating with + * each other) are not hidden and to handle them seamlessly, the best solution is to + * pinning the certificates. + * + * NOTE: Sadly, SSLError gives us an SslCertificate when you call getCertificate(). + * SslCertificate is kind of useless. It's public API doesn't allow you to verify the + * public key, only the created on, expired date, issued to, issued by, etc.. + * However, if you open up this class you will see an X509Certificate member variable + * that is un-exposed. + * + * Instead of going into it deep, lets implement the solution. But there is an API for + * getting the Bundle, and that X509 Certificate member variable gets stored in there. + * So we access it that way, because the Certificate has a lot more useful methods on it. + */ + // if(error != null && error.getUrl() != null && error.getUrl().contains("localhost") && error.getCertificate() != null && "RSLakra Inc.".equals(error.getCertificate().getIssuedBy().getOName())) { + if(error != null && error.getUrl() != null && error.getUrl().contains("localhost")) { + InputStream certStream = LogHelper.readAssets(mWebView.getContext(), "client.pem"); + final Certificate pinnedCertificate = SSLHelper.toCertificate(SSLHelper.loadPEMCertificate(certStream)); + final Certificate serverCertificate = SSLHelper.toCertificate(error.getCertificate()); + if(pinnedCertificate.equals(serverCertificate)) { + handler.proceed(); + } else { + super.onReceivedSslError(mWebView, handler, error); + } + } else { + super.onReceivedSslError(mWebView, handler, error); + } + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + } + + @Override + public void onReceivedClientCertRequest(WebView view, ClientCertRequest certRequest) { + LogHelper.d(LOG_TAG, "onReceivedClientCertRequest(" + view + ", " + certRequest + ")"); + } + + @Override + public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { + LogHelper.d(LOG_TAG, "onReceivedHttpAuthRequest(" + view + ", " + handler + ", " + host + ", " + realm + ")"); + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TLSSocketFactory.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TLSSocketFactory.java new file mode 100755 index 0000000..2e3bf1b --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TLSSocketFactory.java @@ -0,0 +1,107 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import com.rslakra.android.server.TJWSServer; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +/** + * @Author: Rohtash Singh Lakra + * @Created: 2018/03/23 1:05 PM + */ +public final class TLSSocketFactory extends SSLSocketFactory { + + /** mSSLSocketFactory */ + private final SSLSocketFactory mSSLSocketFactory; + + public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException { + SSLContext context = SSLContext.getInstance(TJWSServer.PROTOCOLS[0]); + context.init(null, null, null); + mSSLSocketFactory = context.getSocketFactory(); + } + + @Override + public String[] getDefaultCipherSuites() { + return mSSLSocketFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return mSSLSocketFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket() throws IOException { + return enableTLSOnSocket(mSSLSocketFactory.createSocket()); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return enableTLSOnSocket(mSSLSocketFactory.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return enableTLSOnSocket(mSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return enableTLSOnSocket(mSSLSocketFactory.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return enableTLSOnSocket(mSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return enableTLSOnSocket(mSSLSocketFactory.createSocket(address, port, localAddress, localPort)); + } + + private Socket enableTLSOnSocket(final Socket socket) { + if(socket != null && (socket instanceof SSLSocket)) { + ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}); + } + return socket; + } +} \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TestConnection.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TestConnection.java new file mode 100755 index 0000000..123ef57 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/atjwsapp/TestConnection.java @@ -0,0 +1,330 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.atjwsapp; + +import android.content.Context; +import android.os.Build; + +import com.rslakra.android.logger.LogHelper; +import com.rslakra.android.server.TJWSServer; +import com.rslakra.android.framework.SSLHelper; + +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyStore; +import java.security.SecureRandom; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import Acme.IOHelper; + +/** + * How to Turn Off Certificate Validation in Java HTTPS Connections? + *

+ * Avoiding these exceptions is possible by switching off the certificate + * validation and host verification for SSL for the current Java virtual + * machine. This can be done by replacing the default SSL trust manager and the + * default SSL hostname verifier using this class. + *

+ * Voilla! Now the code runs as expected: it downloads the resource from an + * https address with invalid certificate. + *

+ * Note: - + * Be careful when using this hack! Skipping certificate validation is dangerous + * and should be done in testing environments only. + * + * @author Rohtash Singh Lakra + * @date 03/19/2018 10:19:17 AM + */ +public final class TestConnection { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "TestConnection"; + + /** + * mContext + */ + private final Context mContext; + private final boolean sslEnabled; + + /** + * @param context + * @param sslEnabled + */ + public TestConnection(final Context context, final boolean sslEnabled) { + this.mContext = context; + this.sslEnabled = sslEnabled; + IOHelper.addBouncyCastleProvider(); + } + + /** + * @return + * @throws Exception + */ + private SSLContext makeSSLContext() throws Exception { + // Load CAs from an InputStream + final InputStream certStream = LogHelper.readAssets(mContext, "client.pem"); + // Create a KeyStore containing our trusted CAs + final KeyStore trustStore = SSLHelper.loadPEMTrustStore(certStream); + + // Create a TrustManager that trusts the CAs in our KeyStore + TrustManagerFactory trustManagerFactory = SSLHelper.initTrustManager(trustStore); + + // Create an SSLContext that uses our TrustManager + final SSLContext sslContext = SSLContext.getInstance("TLS"); + LogHelper.d(LOG_TAG, "sslContext - Protocol:" + sslContext.getProtocol() + ", Provider:" + sslContext.getProvider()); + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + + return sslContext; + } + + /** + * Create and initialize the SSLContext + * + * @param mContext + * @param keyStoreFile + * @param password + * @return + */ + public SSLContext createSSLContext(final Context mContext, final String keyStoreFile, final String password) { + SSLContext sslContext = null; + try { + final InputStream keyStoreStream = LogHelper.readAssets(mContext, keyStoreFile); + final KeyStore keyStore = SSLHelper.initKeyStore(keyStoreStream, password); + + // Create key manager + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, password.toCharArray()); + final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); + + // Create trust manager + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + // Initialize SSLContext + sslContext = SSLContext.getInstance(TJWSServer.PROTOCOLS[3]); + // sslContext = SSLContext.getInstance(TJWSServer.PROTOCOLS[2]); + sslContext.init(keyManagers, trustManagers, new SecureRandom()); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + + return sslContext; + } + + /** + * Create a socket factory with certificate. + * + * @return + */ + public final SSLSocketFactory newSSLSocketFactory() { + SSLSocketFactory sslSocketFactory = null; + try { + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + sslSocketFactory = new TLSSocketFactory(); + } else { + sslSocketFactory = createSSLContext(mContext, SSLHelper.CLEINT_KEY_STORE_FILE, SSLHelper.PASSWORD).getSocketFactory(); + } + // sslSocketFactodry = createSSLContext(mContext, keyStoreFile, PASSWORD).getSocketFactory(); + } catch(Exception ex) { + LogHelper.d(LOG_TAG, ex); + } + + return sslSocketFactory; + } + + /** + * Create a socket factory that trusts all certificates. + * + * @return + */ + public final SSLSocketFactory newSSLSocketFactoryWithTrustAllCerts() { + SSLSocketFactory sslSocketFactory = null; + try { + // final InputStream keyStoreStream = LogHelper.readAssets(mContext, keyStoreFile); + final InputStream keyStoreStream = LogHelper.readRAWResources(mContext, "tjws"); + final KeyStore keyStore = SSLHelper.initKeyStore(keyStoreStream, SSLHelper.PASSWORD); + // Create key manager + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, SSLHelper.PASSWORD.toCharArray()); + final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); + + final SSLContext sslContext = SSLContext.getInstance(TJWSServer.PROTOCOLS[0]); + sslContext.init(keyManagers, new TrustManager[]{new AllCertsTrustManager()}, new SecureRandom()); + sslSocketFactory = sslContext.getSocketFactory(); + } catch(Exception ex) { + LogHelper.d(LOG_TAG, ex); + } + + return sslSocketFactory; + } + + /** + * Test the server connection. + */ + public void testSSLConnection() { + SSLSocketFactory sslSocketFactory = null; +// BufferedReader bReader = null; + try { + HttpURLConnection urlConnection = null; + if(sslEnabled) { + urlConnection = (HttpsURLConnection) new URL("https://localhost:9161/").openConnection(); + } else { + urlConnection = (HttpURLConnection) new URL("http://localhost:5161/").openConnection(); + } + + if(sslEnabled && (urlConnection instanceof HttpsURLConnection)) { + // Create socket factory + if(sslSocketFactory == null) { + // sslSocketFactory = newSSLSocketFactory(); + /* + sslSocketFactory = newSSLSocketFactoryWithTrustAllCerts(); + */ + /* + SSLContext sslContext = SSLContext.getInstance(TJWSServer.PROTOCOLS[0]); + sslContext.init(null, null, null); + sslSocketFactory = new NoSSLv3SocketFactory(sslContext.getSocketFactory()); + sslSocketFactory = sslContext.getSocketFactory(); + */ + + /* + SSLContext sslContext = SSLContext.getInstance("SSLv3"); + sslContext.init(null, null, null); + sslSocketFactory = new TLSSocketFactory(); + */ + + // SSLContext sslContext = null; + // final InputStream keyStoreStream = LogHelper.readAssets(mContext, SSLHelper.CLEINT_KEY_STORE_FILE); + // final KeyStore keyStore = SSLHelper.initKeyStore(keyStoreStream, SSLHelper.PASSWORD); + /* Only 1 will be out of comments from these 4. + + sslContext = SSLHelper.makeSSLContext(TJWSServer.PROTOCOLS[3], null, null, null); + sslContext = SSLHelper.makeSSLContext(TJWSServer.PROTOCOLS[3], keyStore, SSLHelper.PASSWORD.toCharArray(), true); + sslContext = SSLHelper.makeSSLContext(TJWSServer.PROTOCOLS[3], keyStore, null, false); + sslContext = SSLHelper.makeSSLContext(TJWSServer.PROTOCOLS[3], keyStore, SSLHelper.PASSWORD.toCharArray(), false); + */ + // sslContext = SSLHelper.makeSSLContext(TJWSServer.PROTOCOLS[3], null, null, null); + // sslSocketFactory = new NoSSLv3SocketFactory(sslContext.getSocketFactory()); + + // sslSocketFactory = sslContext.getSocketFactory(); + sslSocketFactory = makeSSLContext().getSocketFactory(); + } + + // final byte[] authBytes = "admin:admin".getBytes("UTF-8"); + // final byte[] authBytes = PASSWORD.getBytes("UTF-8"); + // final String authString = Base64.encodeToString(authBytes, Base64.DEFAULT); + // urlConnection.setRequestProperty("Authorization", "Basic " + authString); + + // Install the SSL socket factory on the connection. + ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory); + } + + urlConnection.connect(); + LogHelper.i(LOG_TAG, "ResponseCode:" + urlConnection.getResponseCode()); + LogHelper.d(LOG_TAG, "Response:" + SSLHelper.readStream(urlConnection.getInputStream(), true)); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } finally { +// IOHelper.safeClose(bReader); + } + } + + /** + * Test the SSL server connection. + */ + public void testSSLSocketConnection() { + SSLSocketFactory sslSocketFactory = null; + try { + if(sslEnabled) { + // Create socket factory + // sslSocketFactory = newSSLSocketFactory(); + // sslSocketFactory = newSSLSocketFactoryWithTrustAllCerts(); + // HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory); + /* + // Install the all-trusting host verifier + HttpsURLConnection.setDefaultHostnameVerifier(new AllHostNameVerifier()); + */ + sslSocketFactory = makeSSLContext().getSocketFactory(); + } + + // Open SSLSocket + final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket("localhost", 9161); + sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); + + // Start handshake + sslSocket.startHandshake(); + + /** + * Verify that the certificate hostname is for [localhost], + * This is due to lack of SNI support in the current SSLSocket. + */ + final HostnameVerifier hostNameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + final SSLSession sslSession = sslSocket.getSession(); + if(!hostNameVerifier.verify("localhost", sslSession)) { + throw new SSLHandshakeException("Expected [localhost], found:" + sslSession.getPeerPrincipal()); + } + + SSLHelper.logServerCertificate(sslSocket); + SSLHelper.logSocketInfo(sslSocket); + + final PrintWriter outWriter = new PrintWriter(new OutputStreamWriter(sslSocket.getOutputStream())); + + // Send request to server. + outWriter.println("html"); + outWriter.println(); + outWriter.flush(); + + LogHelper.d(LOG_TAG, "Response:" + SSLHelper.readStream(sslSocket.getInputStream(), true)); + sslSocket.close(); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + } +} + + + diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/AndroidClassLoader.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/AndroidClassLoader.java new file mode 100755 index 0000000..3f0e6a2 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/AndroidClassLoader.java @@ -0,0 +1,138 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework; + +import com.rslakra.android.logger.LogHelper; + +import java.io.File; +import java.net.URL; +import java.util.Arrays; + +import dalvik.system.DexClassLoader; + +/** + * This class loader loads the classes for the webs server. Default java class + * loader will not work in Android, so added this custom class loader as per the + * Android specification. + * + * @author Rohtash Singh + * @version 1.0.0 + * @since Apr 28, 2015 7:16:21 PM + */ +public class AndroidClassLoader extends DexClassLoader { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "AndroidClassLoader"; + + /** + * PATH_SEPARATOR + */ + private static final String PATH_SEPARATOR = System.getProperty("path.separator"); + + /** + * DEX_DIR_PATH + */ + private static final String DEX_DIR_PATH = "META-INF/DEX/TJWS"; + + /** + * parentClassLoader + */ + private ClassLoader parentClassLoader; + + /** + * @param classPath + * @param parentClassLoader + */ + public AndroidClassLoader(URL[] classPath, ClassLoader parentClassLoader) { + super(convertFilePaths(classPath), assureClassStorage(classPath), null, parentClassLoader); + this.parentClassLoader = parentClassLoader; + LogHelper.d(LOG_TAG, "AndroidClassLoader()"); + } + + /** + * @param urls + * @return + */ + private static String convertFilePaths(URL[] urls) { + StringBuilder filePaths = new StringBuilder(""); + for(URL url : urls) { + filePaths.append(url.getPath()); + filePaths.append(PATH_SEPARATOR); + } + + LogHelper.d(LOG_TAG, "Class path:" + filePaths.toString()); + return filePaths.toString(); + } + + /** + * @param classPath + * @return + */ + private static String assureClassStorage(URL[] classPath) { + for(URL url : classPath) { + String file = url.getFile(); + int webINFIndex = file.indexOf("WEB-INF"); + if(webINFIndex >= 0) { + File dexDirFile = new File(file.substring(0, webINFIndex) + DEX_DIR_PATH.intern()); + LogHelper.d(LOG_TAG, "Dex dir:" + dexDirFile + " " + file); + if(!dexDirFile.exists()) { + boolean dirCreated = dexDirFile.mkdirs(); + if(!dirCreated) { + LogHelper.w(LOG_TAG, "Unable to create dir:" + dexDirFile); + } + } + + if(dexDirFile.exists() && dexDirFile.isDirectory()) { + return dexDirFile.getPath(); + } + } + } + + throw new RuntimeException("Can't create dex temporary storage of " + Arrays.toString(classPath)); + } + + /** + * @see dalvik.system.BaseDexClassLoader#findResource(java.lang.String) + */ + @Override + protected URL findResource(String name) { + LogHelper.d(LOG_TAG, "Request for resource:" + name); + try { + return super.findResource(name); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, "Error loading resource with name:" + name); + } + + return parentClassLoader.getResource(name); + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/ExecHelper.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/ExecHelper.java new file mode 100644 index 0000000..f127535 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/ExecHelper.java @@ -0,0 +1,152 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework; + +import android.util.Log; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.DatagramSocket; +import java.net.Socket; + +/** + * @Author: Rohtash Singh Lakra + * @Created: 2018/03/26 12:59 PM + */ +public final class ExecHelper { + /** + * LOG_TAG + */ + private static final String LOG_TAG = "ExecHelper"; + + /** Singleton object */ + private ExecHelper() { + throw new UnsupportedOperationException("Object creation not allowed for this class."); + } + + /** + * Closes all the objects safely. + * + * Note: - On Android API levels prior to 19, Socket class does not implement + * Closeable interface. + * + * @param objects + */ + public static final void closeSafely(final Object... objects) { + for(Object object : objects) { + if(object != null) { + try { + Log.d(LOG_TAG, "Closing:" + object); + if(object instanceof Closeable) { + ((Closeable) object).close(); + } else if(object instanceof Socket) { + ((Socket) object).close(); + } else if(object instanceof DatagramSocket) { + ((DatagramSocket) object).close(); + } else { + final String message = "Unable to close:" + object; + Log.d(LOG_TAG, message); + throw new RuntimeException(message); + } + } catch(Throwable ex) { + Log.e(LOG_TAG, Log.getStackTraceString(ex)); + } + } + } + } + + /** + * Reads the mInputStream and return the response as string. + * + * @param mInputStream + * @return + * @throws IOException + */ + public static final String readFully(final InputStream mInputStream) throws IOException { + String result = null; + ByteArrayOutputStream mOutputStream = null; + try { + mOutputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length = 0; + while((length = mInputStream.read(buffer)) != -1) { + mOutputStream.write(buffer, 0, length); + } + result = mOutputStream.toString("UTF-8"); + } catch(IOException ex) { + Log.e(LOG_TAG, Log.getStackTraceString(ex)); + throw ex; + } finally { + closeSafely(mOutputStream); + } + + return result; + } + + /** + * Runs the commands on the application terminal (you can find it in google play). + * + * @param commands + * @return + */ + public static final String execCommands(final String... commands) { + String result = ""; + DataOutputStream outputStream = null; + InputStream response = null; + try { + final Process mProcess = Runtime.getRuntime().exec("su"); + outputStream = new DataOutputStream(mProcess.getOutputStream()); + response = mProcess.getInputStream(); + + for(final String string : commands) { + outputStream.writeBytes(string + "\n"); + outputStream.flush(); + } + + outputStream.writeBytes("exit\n"); + outputStream.flush(); + try { + mProcess.waitFor(); + } catch(InterruptedException ex) { + } + result = readFully(response); + } catch(IOException ex) { + Log.e(LOG_TAG, Log.getStackTraceString(ex)); + } finally { + closeSafely(outputStream, response); + } + + return result; + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/NetHelper.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/NetHelper.java new file mode 100755 index 0000000..2dbcc8b --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/NetHelper.java @@ -0,0 +1,187 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework; + +import com.rslakra.android.logger.LogHelper; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.regex.Pattern; + +/** + * @author Rohtash Singh Lakra + * @date 03/15/2018 03:39:08 PM + */ +public final class NetHelper { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "NetHelper"; + /** + * APACHE InetAddressUtils is deprecated in API level 22 + */ + private static final Pattern IPV4_PATTERN = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$"); + private static final Pattern IPV6_STD_PATTERN = Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$"); + private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$"); + + /** + * @param input + * @return + */ + public static boolean isIPv4Address(final String input) { + return IPV4_PATTERN.matcher(input).matches(); + } + + /** + * @param input + * @return + */ + public static boolean isIPv6StdAddress(final String input) { + return IPV6_STD_PATTERN.matcher(input).matches(); + } + + /** + * @param input + * @return + */ + public static boolean isIPv6HexCompressedAddress(final String input) { + return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches(); + } + + /** + * @param input + * @return + */ + public static boolean isIPv6Address(final String input) { + return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input); + } + + /** + * Returns the loopback address, if the loopBackAddressOnly it + * set to true otherwise returns non-loopback address. + * + * @return + */ + public static InetAddress lookupINetAddress(boolean onlyLoopBackAddress) { + InetAddress resultAddress = null; + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + if(networkInterfaces != null) { + while(networkInterfaces.hasMoreElements()) { + NetworkInterface networkInterface = networkInterfaces.nextElement(); + Enumeration iNetAddresses = networkInterface.getInetAddresses(); + while(iNetAddresses.hasMoreElements()) { + InetAddress netAddress = iNetAddresses.nextElement(); + if(onlyLoopBackAddress) { + if(netAddress.isLoopbackAddress()) { + if(isIPv4Address(netAddress.getHostAddress())) { + return netAddress; + } + + resultAddress = netAddress; + } + } else { + if(!netAddress.isLoopbackAddress()) { + if(!netAddress.isSiteLocalAddress() && isIPv4Address(netAddress.getHostAddress())) { + return netAddress; + } + + resultAddress = netAddress; + } + } + } + } + } + } catch(SocketException ex) { + LogHelper.e(LOG_TAG, ex.toString()); + } + + return resultAddress; + } + + + /** + * @return + */ + public static InetAddress getLookBackAddress() { + InetAddress iNetAddress = null; + try { + for(Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) { + NetworkInterface networkInterface = networkInterfaces.nextElement(); + for(Enumeration itrAddress = networkInterface.getInetAddresses(); itrAddress.hasMoreElements(); ) { + InetAddress inetAddress = itrAddress.nextElement(); + if(inetAddress.isLoopbackAddress()) { + if(isIPv4Address(inetAddress.getHostAddress())) { + return inetAddress; + } + + iNetAddress = inetAddress; + LogHelper.d(LOG_TAG, "processed address:" + iNetAddress); + } + } + } + } catch(SocketException ex) { + LogHelper.e(LOG_TAG, ex); + } + + return iNetAddress; + } + + /** + * @param onlyLoopBackAddress + * @return + */ + public static InetAddress getNonLookupAddress(boolean onlyLoopBackAddress) { + InetAddress result = null; + try { + for(Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { + NetworkInterface intf = en.nextElement(); + for(Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if(!inetAddress.isLoopbackAddress()) { + if((!inetAddress.isSiteLocalAddress() || onlyLoopBackAddress) && isIPv4Address(inetAddress.getHostAddress())) { + return inetAddress; + } + result = inetAddress; + } + } + } + } catch(SocketException ex) { + LogHelper.e(LOG_TAG, ex); + } + + return result; + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/SSLHelper.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/SSLHelper.java new file mode 100755 index 0000000..fe275d4 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/SSLHelper.java @@ -0,0 +1,668 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework; + +import android.net.http.SslCertificate; +import android.os.Bundle; +import android.util.Base64; + +import com.rslakra.android.logger.LogHelper; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +/** + * @Author: Rohtash Singh Lakra + * @Created: 2018/03/22 3:51 PM + */ +public final class SSLHelper { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "SSLHelper"; + + /* TODO - MOVE THESE TO RESPECTIVE LOCATION, AFTER IT WORKS. */ + public static final String PASSWORD = "password"; + public static final String SERVER_KEY_STORE_FILE = "raw/client.bks"; + public static final String CLEINT_KEY_STORE_FILE = "client.pem"; + + + /** + * SSL_SUPPORTED_PROTOCOLS + */ + private static final String[] SSL_SUPPORTED_PROTOCOLS = new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + + + /** + * Singleton object + */ + private SSLHelper() { + throw new UnsupportedOperationException("Object creation not allowed for this class."); + } + + /** + * Returns the SSL supported protocols. + * + * @return + */ + public static String[] getSSLSupportedProtocols() { + return SSL_SUPPORTED_PROTOCOLS; + } + + /** + * Converts the exception into IOException. + * + * @param exception + * @return + */ + public static IOException makeIOException(final Exception exception) { + return new IOException(exception); + } + + /** + * Closes the given mCloseable object. + * + * @param mCloseable + * @param nullify + */ + public static final void closeSilently(Object mCloseable, final boolean nullify) { + try { + if(mCloseable != null) { + if(mCloseable instanceof Closeable) { + ((Closeable) mCloseable).close(); + } else if(mCloseable instanceof Socket) { + ((Socket) mCloseable).close(); + } else if(mCloseable instanceof ServerSocket) { + ((ServerSocket) mCloseable).close(); + } else { + throw new IllegalArgumentException("mCloseable is not an instance of closeable object!"); + } + } + } catch(IOException ex) { + LogHelper.d(LOG_TAG, ex); + } finally { + if(nullify) { + mCloseable = null; + } + } + } + + /** + * Closes the given mCloseable object. + * + * @param mCloseable + */ + public static final void closeSilently(Object mCloseable) { + closeSilently(mCloseable, false); + } + + /** + * @param keyStoreStream + * @param passChars + * @param excludeParams + * @return + */ + public static KeyStore initKeyStore(final InputStream keyStoreStream, final char[] passChars, final boolean excludeParams) { + LogHelper.d(LOG_TAG, "+initKeyStore(" + keyStoreStream + ", " + passChars + ")"); + + KeyStore keyStore = null; + if(!excludeParams) { + if(LogHelper.isNull(keyStoreStream)) { + throw new IllegalArgumentException("Invalid keyStoreStream:" + keyStoreStream); + } + + if(LogHelper.isNull(passChars)) { + throw new IllegalArgumentException("Invalid passChars:" + passChars); + } + } + + try { + keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + LogHelper.d(LOG_TAG, "trustStoreType:" + keyStore.getType()); + if(excludeParams) { + keyStore.load(null, null); + } else { + keyStore.load(keyStoreStream, passChars); + } + } catch(NoSuchAlgorithmException ex) { + LogHelper.e(LOG_TAG, ex); + } catch(CertificateException ex) { + LogHelper.e(LOG_TAG, ex); + } catch(KeyStoreException ex) { + LogHelper.e(LOG_TAG, ex); + } catch(IOException ex) { + LogHelper.e(LOG_TAG, ex); + } + + LogHelper.d(LOG_TAG, "-initKeyStore(), keyStore:" + keyStore); + return keyStore; + } + + /** + * @param keyStoreStream + * @param keyStorePassword + * @return + */ + public static KeyStore initKeyStore(final InputStream keyStoreStream, final String keyStorePassword) { + return initKeyStore(keyStoreStream, keyStorePassword.toCharArray(), false); + } + + + /** + * Reads and decodes a base-64 encoded DER certificate (a .pem certificate), typically the server's CA cert. + * + * @param certificateStream an InputStream from which to read the cert + * @return a byte[] containing the decoded certificate + * @throws IOException + */ + public static byte[] loadPEMCertificate(final InputStream certificateStream) throws IOException { + byte[] certBytes = null; + BufferedReader bReader = null; + try { + final StringBuilder pemBuilder = new StringBuilder(); + bReader = new BufferedReader(new InputStreamReader(certificateStream)); + String line = bReader.readLine(); + while(line != null) { + if(!line.startsWith("--")) { + pemBuilder.append(line); + } + line = bReader.readLine(); + } + certBytes = Base64.decode(pemBuilder.toString(), Base64.DEFAULT); + } finally { + closeSilently(bReader); + } + + return certBytes; + } + + /** + * Converts the certBytes into Certificate object. + * + * @param certBytes + * @return + */ + public static Certificate toCertificate(final byte[] certBytes) { + Certificate mCertificate = null; + if(LogHelper.isNotNull(certBytes)) { + try { + final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + mCertificate = certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes)); + } catch(CertificateException ex) { + LogHelper.e(LOG_TAG, ex); + } + } + + return mCertificate; + } + + /** + * Produces a KeyStore from a String containing a PEM certificate (typically, the server's CA certificate) + * + * @param keyStoreStream A String containing the PEM-encoded certificate + * @return a KeyStore (to be used as a trust store) that contains the certificate + * @throws Exception + */ + public static KeyStore loadPEMTrustStore(final InputStream keyStoreStream) throws Exception { + byte[] certBytes = loadPEMCertificate(keyStoreStream); + X509Certificate x509Certificate = (X509Certificate) toCertificate(certBytes); + LogHelper.d(LOG_TAG, "ca=" + x509Certificate.getSubjectDN()); + final String alias = x509Certificate.getSubjectX500Principal().getName(); + + final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null); + trustStore.setCertificateEntry(alias, x509Certificate); + + return trustStore; + } + + /** + * Converts the SslCertificate to Certificate object. + * + * @param sslCertificate + * @return + */ + public static Certificate toCertificate(final SslCertificate sslCertificate) { + final Bundle bundle = sslCertificate.saveState(sslCertificate); + byte[] certBytes = bundle.getByteArray("x509-certificate"); + return toCertificate(certBytes); + } + + /** + * Creates and returns the KeyManagerFactory that trusts the CAs in the given + * loadedKeyStore. + * + * @param loadedKeyStore + * @param password + * @return + * @throws Exception + */ + public static KeyManagerFactory initKeyManager(final KeyStore loadedKeyStore, final char[] password) throws Exception { + LogHelper.d(LOG_TAG, "+initKeyManager(" + loadedKeyStore + ", " + loadedKeyStore + ", " + password + ")"); + // Create a KeyStoreManager that trusts the CAs in our KeyStore + final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + LogHelper.d(LOG_TAG, "keyManagerType:" + keyManagerFactory.getAlgorithm()); + if(LogHelper.isNull(loadedKeyStore)) { + keyManagerFactory.init(null, null); + } else { + keyManagerFactory.init(loadedKeyStore, password); + } + + LogHelper.d(LOG_TAG, "-initKeyManager(), keyManagerFactory:" + keyManagerFactory); + return keyManagerFactory; + } + + /** + * Creates and returns the TrustManagerFactory that trusts the CAs in the given + * keyStore. + * + * @param keyStore + * @return + * @throws Exception + */ + public static TrustManagerFactory initTrustManager(final KeyStore keyStore) throws Exception { + LogHelper.d(LOG_TAG, "+initTrustManager(" + keyStore + ")"); + // Create a TrustManager that trusts the CAs in our KeyStore + final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + LogHelper.d(LOG_TAG, "trustManagerType:" + trustManagerFactory.getAlgorithm()); + trustManagerFactory.init(keyStore); + + LogHelper.d(LOG_TAG, "-initTrustManager(), trustManagerFactory:" + trustManagerFactory); + return trustManagerFactory; + } + + + /** + * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and an array of loaded + * KeyManagers. These objects must properly loaded/initialized by the caller. + * + * @param protocol + * @param keyManagers + * @param trustManagers + * @param secureRandom + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final String protocol, final KeyManager[] keyManagers, final TrustManager[] trustManagers, final SecureRandom secureRandom) throws Exception { + LogHelper.d(LOG_TAG, "+makeSSLContext(" + protocol + ", " + keyManagers + ", " + trustManagers + ", " + secureRandom + ")"); + // Create an SSLContext that uses our TrustManager + SSLContext sslContext = null; + final boolean useDefaultContext = false; + if(useDefaultContext) { + sslContext = SSLContext.getInstance("Default"); + } else { + if(LogHelper.isNullOrEmpty(protocol)) { + sslContext = SSLContext.getDefault(); + } else { + sslContext = SSLContext.getInstance(protocol); + } + + if(LogHelper.isNotNull(keyManagers) && LogHelper.isNotNull(trustManagers)) { + sslContext.init(keyManagers, trustManagers, secureRandom); + } else if(LogHelper.isNotNull(keyManagers) && LogHelper.isNull(trustManagers)) { + sslContext.init(keyManagers, null, secureRandom); + } else if(LogHelper.isNull(keyManagers) && LogHelper.isNotNull(trustManagers)) { + sslContext.init(null, trustManagers, secureRandom); + } else { + sslContext.init(null, null, secureRandom); + } + } + + LogHelper.d(LOG_TAG, "-makeSSLContext(), sslContext:" + sslContext); + return sslContext; + } + + /** + * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and an array of loaded + * KeyManagers. These objects must properly loaded/initialized by the caller. + * + * @param protocol + * @param keyManagers + * @param trustManagers + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final String protocol, final KeyManager[] keyManagers, final TrustManager[] trustManagers) throws Exception { + return makeSSLContext(protocol, keyManagers, trustManagers, null); + } + + /** + * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and an array of loaded + * KeyManagers. These objects must properly loaded/initialized by the caller. + * + * @param keyManagers + * @param trustManagers + * @param secureRandom + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final KeyManager[] keyManagers, final TrustManager[] trustManagers, final SecureRandom secureRandom) throws Exception { + return makeSSLContext("TLS", keyManagers, trustManagers, secureRandom); + } + + + /** + * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and an array of loaded + * KeyManagers. These objects must properly loaded/initialized by the caller. + * + * @param keyManagers + * @param trustManagers + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final KeyManager[] keyManagers, final TrustManager[] trustManagers) throws Exception { + return makeSSLContext(keyManagers, trustManagers, null); + } + + + /** + * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and a loaded KeyManagerFactory. + * These objects must properly loaded/initialized by the caller. + * + * @param protocol + * @param loadedKeyStore + * @param passphrase + * @param excludeTrustManager + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final String protocol, final KeyStore loadedKeyStore, final char[] passphrase, final boolean excludeTrustManager) throws Exception { + if(LogHelper.isNotNull(loadedKeyStore) && LogHelper.isNotNull(passphrase) && !excludeTrustManager) { + final KeyManager[] keyManagers = initKeyManager(loadedKeyStore, passphrase).getKeyManagers(); + final TrustManager[] trustManagers = initTrustManager(loadedKeyStore).getTrustManagers(); + return makeSSLContext(protocol, keyManagers, trustManagers); + } else if(LogHelper.isNotNull(loadedKeyStore) && LogHelper.isNull(passphrase) && !excludeTrustManager) { + final TrustManager[] trustManagers = initTrustManager(loadedKeyStore).getTrustManagers(); + return makeSSLContext(protocol, null, trustManagers); + } else if(LogHelper.isNotNull(loadedKeyStore) && LogHelper.isNotNull(passphrase) && excludeTrustManager) { + final KeyManager[] keyManagers = initKeyManager(loadedKeyStore, passphrase).getKeyManagers(); + return makeSSLContext(protocol, keyManagers, null); + } else if(LogHelper.isNotNull(loadedKeyStore) && LogHelper.isNull(passphrase) && !excludeTrustManager) { + final TrustManager[] trustManagers = initTrustManager(loadedKeyStore).getTrustManagers(); + return makeSSLContext(protocol, null, trustManagers); + } else { + return makeSSLContext(protocol, null, null, null); + } + } + + + /** + * Creates an SSLSocketFactory for HTTPS. Pass a KeyStore resource with your certificate and + * passphrase + * + * @param protocol + * @param keyAndTrustStoreFilePath + * @param passphrase + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final String protocol, final String keyAndTrustStoreFilePath, final char[] passphrase) throws Exception { + final KeyStore keystore = initKeyStore(new FileInputStream(keyAndTrustStoreFilePath), passphrase, false); + return makeSSLContext(protocol, keystore, passphrase, false); + } + + /** + * Creates a SSLSocketFactory for HTTPS connection with the given '.crt' (certificate) file. + * + * @param certStream + * @return + * @throws Exception + */ + public static SSLContext makeSSLContext(final InputStream certStream) throws Exception { + // Load CAs from an InputStream + CertificateFactory mCertFactory = CertificateFactory.getInstance("X.509"); + InputStream caInputStream = new BufferedInputStream(certStream); + Certificate mCertificate; + try { + mCertificate = mCertFactory.generateCertificate(caInputStream); + LogHelper.d(LOG_TAG, "CA=" + ((X509Certificate) mCertificate).getSubjectDN()); + } finally { + closeSilently(caInputStream); + } + + // Create a KeyStore containing our trusted CAs + final KeyStore keyStore = initKeyStore(null, null, true); + keyStore.setCertificateEntry("ca", mCertificate); + return makeSSLContext(null, initTrustManager(keyStore).getTrustManagers()); + } + + /** + * The 'javax.net.ssl.trustStore' to be set with the 'JKS'/'BKS' file path. + * + * @param trustStoreFile + */ + public static void setSSLTrustStore(final File trustStoreFile) { + System.setProperty("javax.net.ssl.trustStore", trustStoreFile.getAbsolutePath()); + } + + /** + * The 'javax.net.ssl.trustStore' to be set with the 'JKS' or 'BKS' file path. + * + * @param trustStoreFilePath + */ + public static void setSSLTrustStore(final String trustStoreFilePath) { + setSSLTrustStore(new File(trustStoreFilePath)); + } + + /** + * Returns true if the hostName contains any of the allowedhostNames + * otherwise false. + * + * @param hostName + * @param allowedHostNames + * @return + */ + public static boolean isAllowedHostname(final String hostName, final String... allowedHostNames) { + if(hostName != null && allowedHostNames != null) { + for(String host : allowedHostNames) { + if(hostName.contains(host)) { + return true; + } + } + } + + return false; + } + + /** + * It must be called before setting the SSL factory. The hostName is real host + * name, which handles the SSL requests. If the hostName is null, by default + * 'localhost' is used. + * + * @param hostName + * @param allowedHostNames + */ + public static void setDefaultHostnameVerifier(final String hostName, final String... allowedHostNames) { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + + /** + * Verify the SSL host name. + * @param hostname + * @param sslSession + * @return + */ + public boolean verify(String hostname, SSLSession sslSession) { + if(hostname == null || hostname.trim().length() == 0) { + hostname = hostName; + } + + // HostnameVerifier hostNameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + // if(hostNameVerifier != null) { + // return hostNameVerifier.verify(hostname, sslSession); + // } + + if(hostname.equals("localhost")) { + return true; + } else if(hostname.equals(hostName)) { + return true; + } else if(isAllowedHostname(hostname, allowedHostNames)) { + return true; + } + + return false; + } + }); + } + + + /** + * Returns true if the key store is supported otherwise false. + * + * @param keyStoreStream + * @param keyStorePassword + * @return + */ + public static boolean isKeyStoreSupported(final InputStream keyStoreStream, final String keyStorePassword) { + /* + int keyStoreVersion; + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + keyStoreVersion = -1; //The BKS file + } else { + keyStoreVersion = -1; //The BKS (v-1) file + } + */ + + return (initKeyStore(keyStoreStream, keyStorePassword) != null); + } + + /** + * Logs the server certificates. + * + * @param sslSocket + */ + public static void logServerCertificate(final SSLSocket sslSocket) { + try { + Certificate[] serverCerts = sslSocket.getSession().getPeerCertificates(); + for(int i = 0; i < serverCerts.length; i++) { + final Certificate mCertificate = serverCerts[i]; + LogHelper.i(LOG_TAG, "==== Certificate:" + (i + 1) + " ===="); + LogHelper.i(LOG_TAG, "Public Key:" + mCertificate.getPublicKey()); + LogHelper.i(LOG_TAG, "Certificate Type:" + mCertificate.getType()); + LogHelper.i(LOG_TAG, "\n"); + } + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + } + + /** + * Logs the socket information. + * + * @param sslSocket + */ + public static void logSocketInfo(final SSLSocket sslSocket) { + LogHelper.i(LOG_TAG, "Socket Class: " + sslSocket.getClass()); + LogHelper.i(LOG_TAG, "Remote Address:" + sslSocket.getInetAddress().toString()); + LogHelper.i(LOG_TAG, "Remote Port:" + sslSocket.getPort()); + LogHelper.i(LOG_TAG, "Local Socket Address:" + sslSocket.getLocalSocketAddress().toString()); + LogHelper.i(LOG_TAG, "Local Address:" + sslSocket.getLocalAddress().toString()); + LogHelper.i(LOG_TAG, "Local Port:" + sslSocket.getLocalPort()); + LogHelper.i(LOG_TAG, "Need Client Authentication:" + sslSocket.getNeedClientAuth()); + LogHelper.i(LOG_TAG, "Bound:" + sslSocket.isBound()); + LogHelper.i(LOG_TAG, "Closed:" + sslSocket.isClosed()); + LogHelper.i(LOG_TAG, "Connected:" + sslSocket.isConnected()); + LogHelper.i(LOG_TAG, "SupportedCipherSuites:" + LogHelper.toString(sslSocket.getSupportedCipherSuites())); + LogHelper.i(LOG_TAG, "SupportedProtocols:" + LogHelper.toString(sslSocket.getSupportedProtocols())); + LogHelper.i(LOG_TAG, "\n"); + + /* session information. */ + // Get session after the connection is established + final SSLSession sslSession = sslSocket.getSession(); + LogHelper.i(LOG_TAG, "SSLSession:"); + LogHelper.i(LOG_TAG, "Cipher Suite:" + sslSession.getCipherSuite()); + LogHelper.i(LOG_TAG, "Protocol:" + sslSession.getProtocol()); + LogHelper.i(LOG_TAG, "\n"); + } + + /** + * Returns the response of the given inputStream. if closeStream is + * set to be true, the inputStream stream is also closed. + * + * @param inputStream + * @param closeStream + * @return + */ + public static String readStream(final InputStream inputStream, final boolean closeStream) { + final StringBuilder resBuilder = new StringBuilder(); + BufferedReader resReader = null; + try { + resReader = new BufferedReader(new InputStreamReader(inputStream)); + String line = resReader.readLine(); + boolean firstLine = true; + while(!LogHelper.isNullOrEmpty(line)) { + if(firstLine) { + firstLine = false; + } else { + resBuilder.append("\n"); + } + resBuilder.append(line); + line = resReader.readLine(); + } + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } finally { + if(closeStream) { + closeSilently(resReader); + } + } + + return resBuilder.toString(); + } + +} \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/AndroidEvent.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/AndroidEvent.java new file mode 100644 index 0000000..1cbb23a --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/AndroidEvent.java @@ -0,0 +1,83 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +import android.os.Message; + +/** + * The Framework specific wrapper around an Android + * Message object. Presumes we shoved our own data + * into that Message using the static methods in {@link EventManager}. + * + * We're not using all the fields of a Message object + * (currently ignoring the "arg2" and "data" fields). + * We will probably use more of those fields as we + * evolve this event system. + */ +public class AndroidEvent { + + private EventType type = EventType.UNKNOWN; + private EventReason reason = EventReason.UNKNOWN; + private Object payload = null; + + /** + * @param mMessage + */ + public AndroidEvent(final Message mMessage) { + this.type = EventType.toEventType(mMessage.what); + this.reason = EventReason.toEventReason(mMessage.arg1); + this.payload = mMessage.obj; + } + + /** The purpose of this event. */ + public EventType getType() { + return type; + } + + /** + * Explanation for why the event was sent. Allows more + * granular information than just a "type." For example, + * the "logout" event happens for several possible + * reasons. + */ + public EventReason getReason() { + return reason; + } + + /** + * Binary data sent along with the event. + * + * @return + */ + public Object getPayload() { + return payload; + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventListener.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventListener.java new file mode 100644 index 0000000..4739df9 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventListener.java @@ -0,0 +1,42 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +/** + * @author Rohtash Singh Lakra + * @version 1.0.0 + */ +public interface EventListener { + /** + * @param event + */ + public void onEvent(AndroidEvent event); +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventManager.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventManager.java new file mode 100755 index 0000000..c2578c1 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventManager.java @@ -0,0 +1,413 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Process; + +import com.rslakra.android.logger.LogHelper; + +import java.util.HashMap; +import java.util.HashSet; + +/* + * class EventManager: + * This class handles all events sending and receiving across all components/activities in the application. + * This is a singleton, available to the whole app. + * The events receiving thread starts when the object is first created (in the constructor). + * Typically the activities call getEventManager() and use the EventManager object to + * send events and subscribe and unsubscribe events. + * + * Make sure to call shutdown() before the application exits for clean shutdown. + */ +public class EventManager { + + /** LOG_TAG */ + private static final String LOG_TAG = "EventManager"; + /** NO_EVENT */ + private static final int NO_EVENT = -1; + + // Note that this declaration must come last; it uses the objects above. + private static EventManager sInstance; + + /** mLock */ + private final Object mLock = new Object(); + /** mEventHandlerLooper */ + private Looper mEventHandlerLooper; + /** mEventHandler */ + private EventHandler mEventHandler; + /** mEventHandlerThread */ + private HandlerThread mEventHandlerThread; + /** mSubscribers */ + private final HashMap> mSubscribers = new HashMap>(); + /** mEventTypes */ + private final EventType[] mEventTypes = EventType.values(); + + /** + * Singleton + */ + private EventManager() { + this.start(); + } + + /** + * @return + */ + public static EventManager getInstance() { + if(sInstance == null) { + synchronized(EventManager.class) { + if(sInstance == null) { + sInstance = new EventManager(); + } + } + } + + return sInstance; + } + + /** + * @return + */ + private boolean isStarted() { + return (mEventHandlerLooper != null); + } + + /** + * + */ + public void start() { + synchronized(mLock) { + // Start only if it was not started before. + if(!isStarted()) { + initSubscribers(false); + mEventHandlerThread = new HandlerThread("EventHandlerThread", Process.THREAD_PRIORITY_BACKGROUND); + mEventHandlerThread.start(); + mEventHandlerLooper = mEventHandlerThread.getLooper(); + mEventHandler = new EventHandler(mEventHandlerLooper); + } + } + } + + + // Call shutdown when exiting the application. + public void shutdown() throws InActiveEventHandlerException { + synchronized(mLock) { + if(!isStarted()) { + throw new InActiveEventHandlerException(); + } + if(mEventHandlerLooper != null) { + mEventHandlerLooper.quit(); + } + mEventHandlerThread = null; + mEventHandler = null; + mEventHandlerLooper = null; + initSubscribers(true); + } + } + + + /** + * @param unInitialize + */ + private void initSubscribers(final boolean unInitialize) { + if(unInitialize) { + mSubscribers.clear(); + } else { + for(EventType eventType : mEventTypes) { + mSubscribers.put(eventType, new HashSet()); + } + } + } + + // ---------------------------------------------------------------- + // Boardcast Events + // ---------------------------------------------------------------- + + /** + * Broadcasts an event with the specified Type.

+ * + * Note: Android's underlying Message object allows us to send more + * parameters for "free," and we can certainly embed more into + * the Object (or a Bundle). We're evolving this system as we + * need it. + */ + public static void sendEvent(EventType type) { + getInstance().sendEvent(type, EventReason.UNKNOWN, null, null); + } + + /** + * Broadcasts an event with the specified Type and Reason.

+ * + * Note: Android's underlying Message object allows us to send more + * parameters for "free," and we can certainly embed more into + * the Object (or a Bundle). We're evolving this system as we + * need it. + */ + public static void sendEvent(EventType type, EventReason reason) { + getInstance().sendEvent(type, reason, null, null); + } + + /** + * Broadcasts an event with the specified Type and payload.

+ * + * Note: Android's underlying Message object allows us to send more + * parameters for "free," and we can certainly embed more into + * the Object (or a Bundle). We're evolving this system as we + * need it. + */ + public static void sendEvent(EventType type, Object payload) { + getInstance().sendEvent(type, EventReason.UNKNOWN, payload, null); + } + + /** + * Broadcasts an event with the specified Type, Reason, and payload.

+ * + * Note: Android's underlying Message object allows us to send more + * parameters for "free," and we can certainly embed more into + * the Object (or a Bundle). We're evolving this system as we + * need it. + */ + public static void sendEvent(EventType type, EventReason reason, Object payload) { + getInstance().sendEvent(type, reason, payload, null); + } + + /** + * Internal method that translates from "our language" (types, + * reasons, etc.) to Android's built-in "message" language + * (raw integers, an object, and a bundle). + */ + private void sendEvent(EventType type, EventReason reason, Object objectPayload, Bundle bundlePayload) { + this.sendEvent(type.ordinal(), reason.ordinal(), NO_EVENT, objectPayload, bundlePayload); + } + + /** + * This method illustrates the superset of all parameters we can + * send through an Android Message: three integers, an Object, + * and a Bundle. We'll create wrapper methods as we need them. + */ + private void sendEvent(int what, int arg1, int arg2, Object obj, Bundle bundle) { + synchronized(mLock) { + if(isStarted()) { + Message msg = mEventHandler.obtainMessage(what, arg1, arg2, obj); + msg.setData(bundle); + mEventHandler.sendMessage(msg); + } else { + LogHelper.e(LOG_TAG, new InActiveEventHandlerException()); + } + } + } + + + // ---------------------------------------------------------------- + // Subscribe and Unsubscribe + // ---------------------------------------------------------------- + + /** + * Subscribe to one or more events. For example: + * + *

+     *   EventManager.subscribe (this, EventType.Logout);
+     *   EventManager.subscribe (this, EventType.Online, EventType.Offline, EventType.OpenDocument);
+     * 
+ * + * @param listener + * @param types + */ + public static void subscribe(EventListener listener, EventType... types) { + for(EventType type : types) { + try { + getInstance().registerSubscriber(type, listener); + } catch(InActiveEventHandlerException e) { + LogHelper.e(LOG_TAG, e); + } + } + } + + /** + * Unsubscribe from one or more events. For example: + * + *
+     *   EventManager.unsubscribe (this, EventType.Logout);
+     *   EventManager.unsubscribe (this, EventType.Online, EventType.Offline,
+     * EventType.OpenDocument);
+     * 
+ * + * @param listener + * @param types + */ + public static void unsubscribe(EventListener listener, EventType... types) { + for(EventType type : types) { + try { + getInstance().unregisterSubscriber(type, listener); + } catch(InActiveEventHandlerException e) { + LogHelper.e(LOG_TAG, e); + } + } + } + + + /** + * Register an event subscriber. + * + * @param eventType + * @param eventListener + * @return + * @throws InActiveEventHandlerException + */ + private boolean registerSubscriber(EventType eventType, EventListener eventListener) throws InActiveEventHandlerException { + boolean subscriberRegistered = false; + synchronized(mLock) { + if(!isStarted()) { + throw new InActiveEventHandlerException(); + } + + HashSet eventListeners = mSubscribers.get(eventType); + if(eventListeners != null) { + synchronized(eventListeners) { + subscriberRegistered = eventListeners.add(eventListener); + } + } + } + + return subscriberRegistered; + } + + + /** + * Unregister an event subscriber. + * + * @param eventType + * @param eventListener + * @return + * @throws InActiveEventHandlerException + */ + private boolean unregisterSubscriber(EventType eventType, EventListener eventListener) throws InActiveEventHandlerException { + boolean subscriberUnRegistered = false; + synchronized(mLock) { + if(!isStarted()) { + throw new InActiveEventHandlerException(); + } + + HashSet eventListeners = mSubscribers.get(eventType); + if(eventListeners != null) { + synchronized(eventListeners) { + subscriberUnRegistered = eventListeners.remove(eventListener); + } + } + } + + return subscriberUnRegistered; + } + + // ---------------------------------------------------------------- + // Distributing Events + // ---------------------------------------------------------------- + + // Event handler class + private final class EventHandler extends Handler { + + /** + * @param looper + */ + public EventHandler(Looper looper) { + super(looper); + } + + // TODO: Message object is derived from Parcelable class (which is used for interprocess communication). + // Although I still believe that event sending/handling happens within our processes' address space, + // research more and make sure it is the case. If there is any potential danger, then re-write the + // message handling part. + @Override + public void handleMessage(final Message mMessage) { + if(mMessage.what >= 0 && mMessage.what < mSubscribers.size()) { + final HashSet mEventListeners = mSubscribers.get(mEventTypes[mMessage.what]); + if(mEventListeners != null) { + synchronized(mEventListeners) { + + /* + * Publish event to all subscribers. + * TODO: Let's keep an eye on this (algorithm for publishing events). Two issues: + * + * - Each message is sent sequentially, on the same thread. + * So if any one of the subscribers hangs or crashes, this + * method will do the same, and the remaining subscribers + * won't get their messages. That situation will also block + * all messages from getting sent for the rest of the life + * of the application, because ALL messages are sent on this + * thread. + * + * - This algorithm requires the subscribers to exist. + * Another implementation might be: use WeakReferences to + * those subscribers, and if one happens to be gone (null) + * by the time we get to it, purge it from the list. + */ + /* + * Comments by John to the above observations: + * 1. It is expected of the subscribers to finish quickly (start a new thread if necessary). + * Only other way I can think of is, span a thread for each subscriber, which opens up + * whole lot of complications (creating a thread for each event and each subscriber will be a nightmare). + * Even 3rd party APIs usually suggest that the subscriber finish quickly and return. If not the app will + * behave strangely. Subscribers need to follow the rules. And also we're not talking about 100s of + * subscribers for each message (at-the most 2 or 3 subscribers for one event ocationally, so not a problem). + * + * 2. As for dangling subscriptions, if some activity doesn't unregister, it is bad programming, and we should not + * push the bad code under the carpet by weak-references. At-the most we could probably enforce unregister by + * making abstract function in BvActivity and make each activity to unregister there. Or even better keep a list + * of all registered events in BvActivity and unregister them on onDestroy, but this will take the freedom away + * from the child Activities to unregister where they want to (for eg, some Activities might want to unregister + * in onPause, and some one onDestroy). + * + * Over all, this is not a distributed system to build "fault tolerant" systems. Publisher is us and Subscriber + * is our code too. We should make both robust enough instead of one component trying to cover up silly mistakes + * of other components. + */ + if(!mEventListeners.isEmpty()) { + for(EventListener eventListener : mEventListeners) { + try { + eventListener.onEvent(new AndroidEvent(mMessage)); + } catch(Throwable ex) { + LogHelper.e(LOG_TAG, ex, "Unable to send event to subscriber:" + eventListener); + } + } + } + } + } + } else { + //Undefined event received + throw new InvalidEventException(); + } + } + } +} \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventReason.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventReason.java new file mode 100644 index 0000000..476eb7c --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventReason.java @@ -0,0 +1,59 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +/** + * @author Rohtash Singh + * @version 1.0.0 + * @since Sep 21, 2015 12:54:22 PM + */ +public enum EventReason { + + UNKNOWN, SERVICE_STARTED, SERVICE_STOPPPED, LOCAL_SERVER_STARTED, LOCAL_SERVER_STOPPED,; + + /** + * Returns the EventReason corresponding to an integer you acquired by + * calling {@link #ordinal()}. + * + * @param eventReason + * @return + */ + public static EventReason toEventReason(final int eventReason) { + EventReason mEventReason = UNKNOWN; + EventReason[] eventReasons = EventReason.values(); + + if(eventReason >= 0 && eventReason < eventReasons.length) { + mEventReason = eventReasons[eventReason]; + } + + return mEventReason; + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventType.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventType.java new file mode 100644 index 0000000..345d009 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/EventType.java @@ -0,0 +1,58 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +/** + * TODO: Change/add/delete and make sense out of this enum. + * + * @author John, Ron + * @author Rohtash Singh + */ +public enum EventType { + UNKNOWN, ERROR, SERVICE_CONNECTED, SERVICE_DISCONNECTED, SERVER_STARTED, SERVER_STOPPED,; + + /** + * Returns the EventType corresponding to an integer you acquired by calling + * {@link #ordinal()}. + * + * @param eventType + * @return + */ + public static EventType toEventType(int eventType) { + EventType mEventType = UNKNOWN; + final EventType[] eventTypes = EventType.values(); + if(eventType >= 0 && eventType < eventTypes.length) { + mEventType = eventTypes[eventType]; + } + + return mEventType; + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/InActiveEventHandlerException.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/InActiveEventHandlerException.java new file mode 100644 index 0000000..64822ce --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/InActiveEventHandlerException.java @@ -0,0 +1,44 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +import java.io.NotActiveException; + +/** + * + */ +public class InActiveEventHandlerException extends NotActiveException { + private static final long serialVersionUID = 4536567900065477325L; + + public InActiveEventHandlerException() { + super("Event Manager is not running. Restart it!"); + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/InvalidEventException.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/InvalidEventException.java new file mode 100644 index 0000000..9cd7316 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/framework/events/InvalidEventException.java @@ -0,0 +1,37 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.framework.events; + +import java.security.InvalidParameterException; + +public class InvalidEventException extends InvalidParameterException { + private static final long serialVersionUID = 6175400114740210036L; +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/EmbeddedServlet.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/EmbeddedServlet.java new file mode 100755 index 0000000..ba6a4bf --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/EmbeddedServlet.java @@ -0,0 +1,138 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.server; + +import android.content.Context; + +import com.rslakra.android.atjwsapp.TJWSApp; +import com.rslakra.android.logger.LogHelper; + +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import Acme.IOHelper; + +/** + * The EmbeddedServlet handles all local requests. + * + * @author Rohtash Singh Lakra + * @date 03/15/2018 03:39:08 PM + */ +public final class EmbeddedServlet extends HttpServlet { + + /** serialVersionUID */ + private static final long serialVersionUID = 1L; + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "EmbeddedServlet"; + + /** + * INVALID_REQUEST + */ + private static final byte[] INVALID_REQUEST = "Invalid Request".intern().getBytes(); + + public EmbeddedServlet() { + LogHelper.i(LOG_TAG, "EmbeddedServlet()"); + } + + /** + * @param servletConfig + * @throws ServletException + * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) + */ + public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + LogHelper.d(LOG_TAG, "init(" + servletConfig + ")"); + } + + /** + * @param request + * @param response + * @throws ServletException + * @throws IOException + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + process(request, response); + } + + /** + * @param request + * @param response + * @throws ServletException + * @throws IOException + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + process(request, response); + } + + /** + * Processes all requests. + * + * @param servletRequest + * @param servletResponse + * @throws ServletException + * @throws IOException + */ + private void process(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { + LogHelper.d(LOG_TAG, "process(" + servletRequest + "," + servletResponse + ")"); + try { + byte[] dataBytes = INVALID_REQUEST; + final Context mContext = TJWSApp.getParentActivity().getApplicationContext(); + String pathSegment = servletRequest.getRequestURI(); + LogHelper.d(LOG_TAG, "pathSegment:" + pathSegment); + if(pathSegment.endsWith("/") || pathSegment.endsWith("html")) { + dataBytes = IOHelper.readBytes(LogHelper.readAssets(mContext, "web/index.html"), true); + LogHelper.d(LOG_TAG, "dataBytes:\n" + IOHelper.toUTF8String(dataBytes) + "\n"); + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_HTML, dataBytes, servletResponse); + } else if(pathSegment.endsWith("favicon.ico")) { + dataBytes = IOHelper.readIconBytes(LogHelper.readAssets(mContext, "icon.png")); + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_ICON, dataBytes, servletResponse); + } else if(pathSegment.endsWith(".js")) { + if(pathSegment.startsWith("/")) { + pathSegment = pathSegment.substring(1); + } + dataBytes = IOHelper.readBytes(LogHelper.readAssets(mContext, pathSegment), true); + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_JSON, dataBytes, servletResponse); + } else { + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_HTML, dataBytes, servletResponse); + } + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/TJWSServer.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/TJWSServer.java new file mode 100755 index 0000000..02652f9 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/TJWSServer.java @@ -0,0 +1,267 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.server; + +import com.rslakra.android.logger.LogHelper; +import com.rslakra.android.atjwsapp.TJWSApp; + +import java.io.File; +import java.io.PrintStream; +import java.util.Properties; + +import Acme.IOHelper; +import rogatkin.web.WarRoller; +import rogatkin.web.WebApp; +import rogatkin.web.WebAppServlet; + +/** + * @author Rohtash Singh Lakra + * @version 1.0.0 + * @date 03/15/2018 04:00:49 PM + */ +public final class TJWSServer extends Acme.Serve.Serve { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "TJWSServer"; + + /** PROTOCOLS */ + public static final String[] PROTOCOLS = new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + + /** + * mWarRoller + */ + private WarRoller mWarRoller; + + /** + * deployed + */ + private boolean deployed; + + /** + * The default constructor which is the only one that works in android. + * + * @param arguments + * @param logStream + * @param runtime + */ + public TJWSServer(final Properties arguments, PrintStream logStream, Object runtime) { + super(arguments, logStream); + /* provide SERVLET context for Android environment access */ + try { + WebAppServlet.setRuntimeEnv(runtime); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex); + } + //addWebsocketProvider(WSProvider.class.toString()); + LogHelper.i(LOG_TAG, "TJWSServer(" + arguments + ", " + logStream + ", " + runtime + ")"); + } + + /** + * @return + */ + public boolean isDeployed() { + return deployed; + } + + /** + * The deployed to be set. + * + * @param deployed + */ + public void setDeployed(boolean deployed) { + LogHelper.d(LOG_TAG, "setDeployed(" + deployed + ")"); + this.deployed = deployed; + } + + /** + * Returns the WAR deployer. + * + * @return + */ + public WarRoller getDeployer() { + return mWarRoller; + } + + /** + * Returns the web-server deployment folder path. + * + * @return + */ + public final String getDeployFolder() { + return (String) getProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR); + } + + @Override + public void initMime() { + mime = new Properties(); + try { + mime.load(LogHelper.readAssets(TJWSApp.getInstance().getApplicationContext(), "mime.properties")); + LogHelper.d(LOG_TAG, "MIME map is loaded successfully!"); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, ex, "MIME map can't be loaded!"); + } + } + + /** + * @param provider + */ + @Override + public void addWebsocketProvider(String provider) { + if(IOHelper.isNullOrEmpty(provider)) { + websocketProvider = null; + } else { + websocketProvider = new WSProvider(); + websocketProvider.init(this); + websocketProvider.deploy(this, null); + } + } + + /** + * Overriding method for public access + * + * @param mappingTable + * @see Acme.Serve.Serve#setMappingTable(Acme.Serve.Serve.PathTreeDictionary) + */ + @Override + public void setMappingTable(PathTreeDictionary mappingTable) { + LogHelper.d(LOG_TAG, "setMappingTable(" + mappingTable + ")"); + super.setMappingTable(mappingTable); + } + + /** + * (non-Javadoc) + * + * @see Acme.Serve.Serve#setRealms(Acme.Serve.Serve.PathTreeDictionary) + */ + @Override + protected void setRealms(PathTreeDictionary realms) { + LogHelper.d(LOG_TAG, "setRealms(" + realms + ")"); + super.setRealms(realms); + } + + /** + * Returns the value of the given property. + * + * @param key + * @return + */ + public synchronized final Object getProperty(final Object key) { + return super.arguments.get(key); + } + + /** + * @param key + * @param value + */ + @SuppressWarnings("unchecked") + public synchronized void setProperty(Object key, Object value) { + LogHelper.d(LOG_TAG, "setProperty(" + key + ", " + value + ")"); + if(super.arguments == null) { + super.arguments = new Properties(); + } + + super.arguments.put(key, value); + } + + /** + * Removes the specified property. + * + * @param key + */ + public synchronized void removeProperty(Object key) { + LogHelper.d(LOG_TAG, "removeProperty(" + key + ")"); + if(super.arguments != null) { + super.arguments.remove(key); + } + } + + /** + * Deploy the local web server into the warDeployer. + */ + public synchronized void deployApplications() { + LogHelper.d(LOG_TAG, "+deployApplications(), deployed:" + isDeployed()); + + if(!isDeployed()) { + try { + if(getDeployer() == null) { + mWarRoller = new WarRoller(); + } + getDeployer().deploy(this); + setDeployed(true); + } catch(Throwable ex) { + LogHelper.e(LOG_TAG, "Unexpected problem in deployment!", ex); + if(ex instanceof ThreadDeath) { + throw (ThreadDeath) ex; + } + } + } + + LogHelper.d(LOG_TAG, "-deployApplications(), deployed:" + isDeployed()); + } + + /** + * Deploys the given app in the local web-server. + * + * @param appName + * @return + */ + public synchronized boolean deployApplication(String appName) { + // deployer must be not null + try { + WebAppServlet webAppServlet = WebAppServlet.create(new File(new File(getDeployFolder(), WarRoller.DEPLOYMENT_DIR_TARGET), appName), appName, this, null); + addServlet(webAppServlet.getContextPath() + "/*", webAppServlet, null); + return true; + } catch(Throwable ex) { + LogHelper.e(LOG_TAG, "Unexpected problem in deployment appName:" + appName, ex); + if(ex instanceof ThreadDeath) { + throw (ThreadDeath) ex; + } + } + + return false; + } + + /** + * @param logEnabled + */ + protected void setLogEnabled(boolean logEnabled) { + if(logEnabled) { + setProperty(ARG_LOG_OPTIONS, "L"); + } else { + removeProperty(ARG_LOG_OPTIONS); + } + + setAccessLogged(); + } + +} \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/TJWSService.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/TJWSService.java new file mode 100755 index 0000000..0e5d54c --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/TJWSService.java @@ -0,0 +1,562 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.server; + +import android.app.Service; +import android.content.Intent; +import android.net.wifi.WifiManager.WifiLock; +import android.os.Binder; +import android.os.IBinder; + +import com.rslakra.android.framework.AndroidClassLoader; +import com.rslakra.android.framework.events.EventManager; +import com.rslakra.android.framework.events.EventType; +import com.rslakra.android.logger.LogHelper; +import com.rslakra.android.atjwsapp.TJWSApp; +import com.rslakra.android.framework.NetHelper; +import com.rslakra.android.framework.SSLHelper; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.KeyStore; +import java.util.Properties; + +import Acme.IOHelper; +import Acme.Serve.SSLAcceptor; +import Acme.Serve.Serve; +import rogatkin.web.WebApp; +import rogatkin.web.WebAppServlet; + +/** + * Android TJWS server service + * + * @author Rohtash Singh Lakra + * @date 03/15/2018 03:39:08 PM* + */ +public class TJWSService extends Service { + + /** + * LOG_TAG + */ + private static final String LOG_TAG = "TJWSService"; + + static { + IOHelper.addBouncyCastleProvider(); + } + + /** + * sslEnabled + */ + private boolean sslEnabled; + + /** + * bindAddress + */ + private String bindAddress; + + /** + * port + */ + private int port; + + /** + * logStream + */ + private PrintStream logStream; + + /** + * webServer + */ + private TJWSServer webServer; + + /** + * wifiLock + */ + private WifiLock wifiLock; + + /** + * mBinder + */ + private final IBinder mBinder = new LocalBinder(); + + /** + * Default Constructor. + */ + public TJWSService() { + LogHelper.i(LOG_TAG, "TJWSService()"); + } + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class LocalBinder extends Binder { + public TJWSService getService() { + return TJWSService.this; + } + } + + /** + * @param intent + * @return + */ + @Override + public IBinder onBind(Intent intent) { + LogHelper.d(LOG_TAG, "Binding from " + intent.getClass().getName()); + return mBinder; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + // We want this service to continue running until it is explicitly + // stopped, so return sticky. + return START_STICKY; + } + + /** + * Starts the local server. + * + * @param sslEnabled + */ + public void startLocalServer(final boolean sslEnabled) { + if(!isWebServerRunning()) { + initServer(sslEnabled); + updateNetworkSettings(); + try { + startServer(); + } finally { + if(isWebServerRunning()) { + LogHelper.i(LOG_TAG, "TJWSServer has started!!!"); + EventManager.sendEvent(EventType.SERVER_STARTED); + } + } + } else { + LogHelper.w(LOG_TAG, "TJWSServer is already running!!!"); + } + } + + /** + * @return + */ + public boolean isSSLEnabled() { + return sslEnabled; + } + + /** + * @param sslEnabled + */ + public void setSSLEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + /** + * @return + */ + public String getBindAddress() { + return bindAddress; + } + + /** + * @return + */ + public int getPort() { + return port; + } + + /** + * Sets the default port. + */ + public void setDefaultPort() { + if(isSSLEnabled()) { + setPort(9161); + } else { + setPort(5161); + } + } + + /** + * @param port + */ + public void setPort(int port) { + LogHelper.d(LOG_TAG, "setPort(" + port + ")"); + this.port = port; + } + + /** + * Returns true if the web server is running. + * + * @return + */ + public boolean isWebServerRunning() { + return (webServer != null && webServer.isRunning()); + } + + /** + * @return + */ + public String getScheme() { + return (isSSLEnabled() ? "https" : "http"); + } + + /** + * Returns the local server URL string. + * + * @return + */ + public String getServerUrl() { + return (getScheme() + "://" + getBindAddress() + ":" + getPort() + "/"); + } + + /** + * Initializes the logging stream. + */ + // @SuppressLint("NewApi") + private void initLogging() { + if(logStream != null) { + return; + } + + File logDir = new File(TJWSApp.getInstance().getLogsFolder()); + // make sure, the folder exists. + if(!logDir.exists()) { + LogHelper.w(LOG_TAG, "The logs folder [" + logDir.getAbsolutePath() + "] does not exist!"); + } + + // initialize the logs file. + try { + logStream = new PrintStream(new File(logDir, "access-" + System.currentTimeMillis() + ".log"), "UTF-8"); + } catch(Exception ex) { + LogHelper.e(LOG_TAG, "Unable to create log file!", ex); + } + + if(logStream == null) { + logStream = System.out; + } else { + System.setErr(logStream); + } + } + + /** + * Initializes the embedded web server. + * + * @param sslEnabled + */ + public void initServer(final boolean sslEnabled) { + if(webServer != null) { + LogHelper.i(LOG_TAG, "Web server is already initialized!"); + return; + } + + setSSLEnabled(sslEnabled); + initLogging(); + setDefaultPort(); + + File deployFolder = new File(TJWSApp.getInstance().getDeployFolder()); + // make sure, the folder exists. + if(!deployFolder.exists()) { + if(!deployFolder.mkdir()) { + LogHelper.w(LOG_TAG, "Unable to create deploy folder:" + deployFolder.getAbsolutePath()); + } + } + + // setting properties for the server, and exchangeable Acceptors + Properties properties = new Properties(); + properties.setProperty(Serve.ARG_NOHUP, Serve.ARG_NOHUP); + + // log properties + properties.setProperty(Serve.ARG_ACCESS_LOG_FMT, "{0} {2} [{3,date,yyyy/MM/dd HH:mm:ss Z}] \"{4} {5} {6}\" {7,number,#}"); + properties.setProperty(Serve.ARG_LOG_DIR, TJWSApp.getInstance().getLogsFolder()); + + /* JSP */ + // properties.setProperty(Serve.ARG_JSP, "org.apache.jasper.servlet.JspServlet"); + // properties.setProperty("org.apache.jasper.servlet.JspServlet.classpath", "%classpath%"); + // properties.setProperty("org.apache.jasper.servlet.JspServlet.scratchdir", "%deploydir%/META-INF/jsp-classes"); + + if(isSSLEnabled()) { + final boolean useAssetsPath = false; + // SSL configurations. + properties.setProperty(Serve.ARG_ACCEPTOR_CLASS, "Acme.Serve.SSLAcceptor"); + // properties.setProperty(Serve.ARG_ACCEPTOR_CLASS, "rogatkin.wskt.SSLSelectorAcceptor"); + + final String keyStoreFile = SSLHelper.SERVER_KEY_STORE_FILE; + String keyStoreFilePath = null; + if(useAssetsPath) { + String parentFolderPath = IOHelper.pathString(TJWSService.class); + LogHelper.d(LOG_TAG, "parentFolderPath:" + parentFolderPath); + keyStoreFilePath = IOHelper.pathString(parentFolderPath, keyStoreFile); + LogHelper.d(LOG_TAG, "keyStoreFilePath:" + keyStoreFilePath); + } else { + keyStoreFilePath = IOHelper.pathString(TJWSApp.getInstance().getDeployFolder(), keyStoreFile); + final File fileKeyStore = new File(keyStoreFilePath); + if(!fileKeyStore.getParentFile().exists()) { + if(!fileKeyStore.getParentFile().mkdirs()) { + LogHelper.d(LOG_TAG, "Unable to create folder:" + fileKeyStore.getParentFile().getAbsolutePath()); + } + } + try { +// final InputStream keyStoreStream = LogHelper.readAssets(TJWSApp.getInstance().getApplicationContext(), keyStoreFile); + final InputStream keyStoreStream = LogHelper.readRAWResources(TJWSApp.getInstance().getApplicationContext(), "client"); +// SSLHelper.setSSLTrustStore(keyStoreFilePath); + int keyStoreBytes = IOHelper.copyStream(keyStoreStream, new FileOutputStream(keyStoreFilePath), true); + LogHelper.d(LOG_TAG, "keyStoreBytes:" + keyStoreBytes); + } catch(IOException ex) { + LogHelper.e(LOG_TAG, ex); + } finally { + LogHelper.d(LOG_TAG, "fileKeyStore:" + fileKeyStore); + if(!fileKeyStore.exists()) { + LogHelper.w(LOG_TAG, "File does not exists at keyStoreFilePath:" + fileKeyStore.getAbsolutePath()); + } + } + } + + properties.setProperty(SSLAcceptor.ARG_KEYSTOREFILE, keyStoreFilePath); + properties.setProperty(SSLAcceptor.ARG_KEYSTORETYPE, KeyStore.getDefaultType()); + properties.setProperty(SSLAcceptor.ARG_PROTOCOL, TJWSServer.PROTOCOLS[3]); + // properties.setProperty(SSLAcceptor.ARG_PROTOCOL, + // TJWSServer.PROTOCOLS[1]); + // properties.setProperty(SSLAcceptor.ARG_PROTOCOL, + // TJWSServer.PROTOCOLS[2]); + properties.setProperty(SSLAcceptor.ARG_CLIENTAUTH, "false"); + properties.setProperty(SSLAcceptor.ARG_KEYSTOREPASS, "password"); + } else { + properties.remove(Serve.ARG_ACCEPTOR_CLASS); + // this acceptor is required for web-socket support + // properties.setProperty("acceptorImpl", + // "Acme.Serve.SelectorAcceptor"); + } + + // set port + properties.setProperty(Serve.ARG_PORT, String.valueOf(getPort())); + + webServer = new TJWSServer(properties, logStream, this); + // Add root servlet + webServer.addServlet("/", new EmbeddedServlet()); + + // add shutdown hook. + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + stopServer(true); + } + })); + + /** Set System properties. */ + System.setProperty(WebAppServlet.WAR_NAME_AS_CONTEXTPATH, "yes"); + // set dex class loader 'AndroidClassLoader' + System.setProperty(WebApp.DEF_WEBAPP_CLASSLOADER, AndroidClassLoader.class.getName()); + System.setProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR, TJWSApp.getInstance().getDeployFolder()); + LogHelper.d(LOG_TAG, "webappdir:" + System.getProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR) + ", for app:" + TJWSApp.getInstance().getDeployFolder()); + + // // initialize the deploy directory + // webServer.deployApplications(); + } + + /** + * Returns the binding address. + * + * @return + */ + private InetAddress getLocalIPAddress() { + try { + if(LogHelper.isNullOrEmpty(getBindAddress())) { + return NetHelper.getLookBackAddress(); + } else { + return InetAddress.getByName(getBindAddress()); + } + } catch(UnknownHostException ex) { + LogHelper.e(LOG_TAG, "Unable to resolve IP address!", ex); + return null; + } + } + + /** + * Returns the hostname. + * + * @return + */ + public void updateNetworkSettings() { + InetAddress localAddress = getLocalIPAddress(); + if(localAddress != null) { + bindAddress = localAddress.getCanonicalHostName(); + // Android bug + if(!LogHelper.isNullOrEmpty(bindAddress) && "null".equals(bindAddress) == false) { + if(!localAddress.isAnyLocalAddress()) { + webServer.setProperty(Serve.ARG_BINDADDRESS, localAddress.getHostAddress()); + LogHelper.d(LOG_TAG, "hostName:" + getBindAddress() + ", bindAddress:" + localAddress.getHostAddress()); + } else { + webServer.removeProperty(Serve.ARG_BINDADDRESS); + localAddress = NetHelper.lookupINetAddress(false); + if(localAddress != null && NetHelper.isIPv4Address(localAddress.getHostAddress())) { + LogHelper.d(LOG_TAG, "hostName:" + getBindAddress() + ", bindAddress:" + localAddress.getHostAddress()); + } + } + } + } + + if(LogHelper.isNullOrEmpty(bindAddress)) { + webServer.removeProperty(Serve.ARG_BINDADDRESS); + LogHelper.e(LOG_TAG, "No address bound"); + try { + bindAddress = InetAddress.getLocalHost().getHostAddress(); + } catch(UnknownHostException e) { + bindAddress = "127:0:0:1"; + } + } + + if(!LogHelper.isNullOrEmpty(bindAddress)) { + // bind address + LogHelper.d(LOG_TAG, "bind to " + getBindAddress() + ", deployed to:" + TJWSApp.getInstance().getDeployFolder()); + // logging configurations. + webServer.setLogEnabled(true); + + // port configurations. + if(isSSLEnabled()) { + webServer.setProperty(SSLAcceptor.ARG_PORT, getPort()); + } else { + webServer.setProperty(Serve.ARG_PORT, getPort()); + } + } + + // initialize the deploy directory + webServer.setProperty(SSLAcceptor.ARG_IFADDRESS, webServer.getProperty(Serve.ARG_BINDADDRESS)); + webServer.deployApplications(); + } + + /** + * Starts the server. + */ + private void startServer() { + if(!isWebServerRunning()) { + /** thread to check server status. */ + new Thread() { + /** + * Check the staus of the server. + * + * @see Thread#run() + */ + @Override + public void run() { + try { + // give a chance to server to run + Thread.sleep(1000); + } catch(InterruptedException ex) { + // ignore me! + } finally { + LogHelper.i(LOG_TAG, "Serve Running:" + webServer.isRunning()); + if(isWebServerRunning()) { + LogHelper.i(LOG_TAG, "TJWSServer has started!!!"); + EventManager.sendEvent(EventType.SERVER_STARTED); + } else { + LogHelper.i(LOG_TAG, "TJWSServer has not started!!!"); + EventManager.sendEvent(EventType.SERVER_STOPPED); + } + } + } + }.start(); + + /** thread to run the server. */ + new Thread() { + /** + * Starts the web server here. + * + * @see Thread#run() + */ + @Override + public void run() { + // getApplicationContext().getSystemService(Context.WIFI_SERVICE); + // WifiManager wifiManager = (WifiManager) + // getApplicationContext().getSystemService(Context.WIFI_SERVICE); + // wifiLock = wifiManager.createWifiLock(LOG_TAG); + // + try { + // lock on wifi to start server. + // wifiLock.acquire(); + Serve.Status result = webServer.serve(); + LogHelper.i(LOG_TAG, "Serve result:" + result); + } catch(Throwable throwable) { + LogHelper.e(LOG_TAG, throwable); + } finally { + // unlock the wifi lock after server start call. + // if(wifiLock != null && wifiLock.isHeld()) { + // wifiLock.release(); + // } + } + } + }.start(); + } + } + + /** + * Stops the webServer and all it's services. + * + * @param stopAllServices + */ + public void stopServer(final boolean stopAllServices) { + if(isWebServerRunning()) { + webServer.notifyStop(); + } + + if(stopAllServices) { + webServer.destroyAllServlets(); + webServer.setDeployed(false); + webServer = null; + + if(logStream != System.out && logStream != null) { + logStream.close(); + logStream = null; + } + } + + LogHelper.i(LOG_TAG, "Web Server is stopped successfully!"); + } + + /** + * Stops the web server. + */ + public void stopServer() { + stopServer(true); + } + + /** + * Destroys the current service. + */ + @Override + public void onDestroy() { + LogHelper.d(LOG_TAG, "Service Destroyed!"); + // just in case, not stoppped yet. + stopServer(true); + super.onDestroy(); + } +} diff --git a/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/WSProvider.java b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/WSProvider.java new file mode 100755 index 0000000..f9e8236 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/java/com/rslakra/android/server/WSProvider.java @@ -0,0 +1,137 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.android.server; + +import java.util.List; + +import javax.servlet.ServletContext; + +import rogatkin.wskt.SimpleProvider; + +//import javax.websocket.DeploymentException; +//import javax.websocket.Endpoint; +//import javax.websocket.server.ServerApplicationConfig; +//import javax.websocket.server.ServerEndpointConfig; + +public class WSProvider extends SimpleProvider { + + public WSProvider() { + // TODO Auto-generated constructor stub + } + + @Override + public void deploy(ServletContext servCtx, List cp) { +// SimpleServerContainer ssc = new SimpleServerContainer(this); +// HashSet appCfgs = new HashSet(); +// HashSet> annSeps = new HashSet>(); +// HashSet> endps = new HashSet>(); +// if (servCtx instanceof WebAppServlet) { +// WebAppServlet webApp = (WebAppServlet)servCtx; +// File wsInfo = new File(webApp.getDeploymentDir(), "META-INF/websocket/websocket.info"); +// if (wsInfo.exists()) { +// BufferedReader fr = null; +// try { +// fr = new BufferedReader(new FileReader(wsInfo)); +// String s = +// fr.readLine(); +// while(s != null) { +// if (s.startsWith("ServerEndpoint ")) { +// try { +// annSeps.add(Class.forName(s.substring("ServerEndpoint ".length()), true, webApp.getClassLoader())); +// } catch (ClassNotFoundException e) { +// serve.log(e, "Server Endpoint not found"); +// } +// } else if (s.startsWith("ServerApplicationConfig ")) { +// try { +// appCfgs.add((ServerApplicationConfig) Class.forName(s.substring("ServerApplicationConfig ".length()), true, webApp.getClassLoader()).newInstance()); +// } catch (InstantiationException e) { +// serve.log(e, "Error at deployment"); +// } catch (IllegalAccessException e) { +// serve.log(e, "Error at deployment"); +// } catch (ClassNotFoundException e) { +// serve.log(e, "Endpoint config not found"); +// } +// } else if (s.startsWith("Endpoint ")) { +// try { +// endps.add((Class) Class.forName(s.substring("Endpoint ".length()), true, webApp.getClassLoader())); +// } catch (ClassNotFoundException e) { +// serve.log(e, "Endpoint not found"); +// } +// } +// s = fr.readLine(); +// } +// } catch(IOException e) { +// +// } finally { +// if (fr != null) +// try { +// fr.close(); +// } catch(Exception e) { +// +// } +// } +// } +// } +// if (appCfgs.size() > 0) { +// for (ServerApplicationConfig sac : appCfgs) { +// for (Class se : sac.getAnnotatedEndpointClasses(annSeps)) +// try { +// ssc.addEndpoint(se); +// serve.log("Deployed ServerEndpoint " + se); +// } catch (DeploymentException de) { +// +// } +// for (ServerEndpointConfig epc : sac.getEndpointConfigs(endps)) +// try { +// ssc.addEndpoint(epc); +// serve.log("Deployed ServerEndpointConfig " + epc); +// } catch (DeploymentException de) { +// +// } +// } +// } else { +// for (Class se : annSeps) +// try { +// ssc.addEndpoint(se); +// serve.log("Deployed ServerEndpoint " + se); +// } catch (DeploymentException de) { +// +// } +// } +// servCtx.setAttribute("javax.websocket.server.ServerContainer", ssc); +// try { +// servCtx.addListener(ssc); +// } catch (Error e) { +// // serve is still on old servlet spec +// } + } + +} diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable-hdpi/ic_launcher.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..a2f5908 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable-hdpi/logo.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable-hdpi/logo.png new file mode 100644 index 0000000..f950aa5 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable-hdpi/logo.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable-ldpi/ic_launcher.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000..a2f5908 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable-ldpi/ic_launcher.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable-ldpi/logo.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable-ldpi/logo.png new file mode 100644 index 0000000..f950aa5 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable-ldpi/logo.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable-mdpi/ic_launcher.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..a2f5908 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable-mdpi/logo.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable-mdpi/logo.png new file mode 100644 index 0000000..f950aa5 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable-mdpi/logo.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable/ic_launcher.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable/ic_launcher.png new file mode 100644 index 0000000..a2f5908 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable/ic_launcher.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/drawable/logo.png b/ASTJWSApp/ATJWSApp/src/main/res/drawable/logo.png new file mode 100644 index 0000000..f950aa5 Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/drawable/logo.png differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/layout/activity_main.xml b/ASTJWSApp/ATJWSApp/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..b2f4ff2 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/res/layout/activity_main.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/res/layout/activity_splash.xml b/ASTJWSApp/ATJWSApp/src/main/res/layout/activity_splash.xml new file mode 100755 index 0000000..8495c5f --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/res/layout/activity_splash.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/ASTJWSApp/ATJWSApp/src/main/res/raw/client.bks b/ASTJWSApp/ATJWSApp/src/main/res/raw/client.bks new file mode 100644 index 0000000..ccbd95c Binary files /dev/null and b/ASTJWSApp/ATJWSApp/src/main/res/raw/client.bks differ diff --git a/ASTJWSApp/ATJWSApp/src/main/res/values/strings.xml b/ASTJWSApp/ATJWSApp/src/main/res/values/strings.xml new file mode 100755 index 0000000..8567306 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/res/values/strings.xml @@ -0,0 +1,15 @@ + + + ATJWSApp + ATJWS - An Android Web Container + + + Loading + Please wait ... + + + Error Message + Error Occurred! Please Check Logs for More Info! + Error!!! + + diff --git a/ASTJWSApp/ATJWSApp/src/main/res/xml/network_security_config.xml b/ASTJWSApp/ATJWSApp/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..f390682 --- /dev/null +++ b/ASTJWSApp/ATJWSApp/src/main/res/xml/network_security_config.xml @@ -0,0 +1,23 @@ + + + + localhost + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ASTJWSApp/Certs/Create Self-Signed Certificate for Android.txt b/ASTJWSApp/Certs/Create Self-Signed Certificate for Android.txt new file mode 100644 index 0000000..dba0926 --- /dev/null +++ b/ASTJWSApp/Certs/Create Self-Signed Certificate for Android.txt @@ -0,0 +1,98 @@ +1. CREATE PRIVATE KEYS +openssl genrsa -des3 -out key.pem 2048 + +2. CREATE SELF-SIGNED CERTIFICATES (365 *25 days) +openssl req -new -x509 -key key.pem -out client.pem -days 9125 + +3. COMBINE KEYS AND CERTIFICATES +openssl pkcs12 -export -out client.p12 -inkey key.pem -in client.pem +openssl pkcs12 -export -out client.pfx -inkey key.pem -in client.pem + +4. GENERATE .BKS FILE FOR ANDROID (use the portecle tool to convert .bks file.) +java -jar portecle.jar +Then follow instructions to convert to .bks file. + +4. CREATE TRUST STORES (Here use the portecle tool to convert .bks file.) +keytool \ + -import \ + -v \ + -trustcacerts \ + -alias 0 \ + -file <(openssl x509 -in client.pem) \ + -keystore client.bks \ + -storetype BKS \ + -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ + -providerpath ./bcprov-jdk15on-159.jar \ + -storepass password + + + +openssl x509 -in client.pem -text -noout +openssl x509 -in server.pem -text -noout + +========================================================================================================================================== +Using shell, create a key using keytool: +keytool -genkey -keystore serverkeystore -keyalg rsa -alias serverkeystore + +keytool -importkeystore -srckeystore serverkeystore -destkeystore serverkeystore.pkcs12 -deststoretype pkcs12 + +openssl pkcs12 -in serverkeystore.pkcs12 -clcerts -nokeys -out serverkeystore.crt + +openssl x509 -in serverkeystore.crt -text -noout + +========================================================================================================================================== +-REF - +http://www.gtopia.org/blog/2010/02/der-vs-crt-vs-cer-vs-pem-certificates/ + +DER VS. CRT VS. CER VS. PEM CERTIFICATES +Home / Tech / Public Key Infrastructure ( PKI ) / DER vs. CRT vs. CER vs. PEM Certificates +Certificates and Encodings +At its core an X.509 certificate is a digital document that has been encoded and/or digitally signed according to RFC 5280. + +In fact, the term X.509 certificate usually refers to the IETF’s PKIX Certificate and CRL Profile of the X.509 v3 certificate standard, as specified in RFC 5280, commonly referred to as PKIX for Public Key Infrastructure (X.509). + +X509 File Extensions +The first thing we have to understand is what each type of file extension is. There is a lot of confusion about what DER, PEM, CRT, and CER are and many have incorrectly said that they are all interchangeable. While in certain cases some can be interchanged the best practice is to identify how your certificate is encoded and then label it correctly. Correctly labeled certificates will be much easier to manipulat + +Encodings (also used as extensions) +.DER = The DER extension is used for binary DER encoded certificates. These files may also bear the CER or the CRT extension. Proper English usage would be “I have a DER encoded certificate” not “I have a DER certificate”. +.PEM = The PEM extension is used for different types of X.509v3 files which contain ASCII (Base64) armored data prefixed with a “—– BEGIN …” line. +Common Extensions +.CRT = The CRT extension is used for certificates. The certificates may be encoded as binary DER or as ASCII PEM. The CER and CRT extensions are nearly synonymous. Most common among *nix systems +CER = alternate form of .crt (Microsoft Convention) You can use MS to convert .crt to .cer (.both DER encoded .cer, or base64[PEM] encoded .cer) The .cer file extension is also recognized by IE as a command to run a MS cryptoAPI command (specifically rundll32.exe cryptext.dll,CryptExtOpenCER) which displays a dialogue for importing and/or viewing certificate contents. +.KEY = The KEY extension is used both for public and private PKCS#8 keys. The keys may be encoded as binary DER or as ASCII PEM. +The only time CRT and CER can safely be interchanged is when the encoding type can be identical. (ie PEM encoded CRT = PEM encoded CER) + +Common OpenSSL Certificate Manipulations +There are four basic types of certificate manipulations. View, Transform, Combination , and Extraction + +View +Even though PEM encoded certificates are ASCII they are not human readable. Here are some commands that will let you output the contents of a certificate in human readable form; + +View PEM encoded certificate +Use the command that has the extension of your certificate replacing cert.xxx with the name of your certificate +openssl x509 -in cert.pem -text -noout +openssl x509 -in cert.cer -text -noout +openssl x509 -in cert.crt -text -noout + +View DER encoded Certificate +openssl x509 -in certificate.der -inform der -text -noout + + +Transform +Transforms can take one type of encoded certificate to another. (ie. PEM To DER conversion) + +PEM to DER +openssl x509 -in cert.crt -outform der -out cert.der +openssl x509 -in cert.crt -outform der -out cert.der + +DER to PEM +openssl x509 -in cert.crt -inform der -outform pem -out cert.pem +openssl x509 -in cert.crt -inform der -outform pem -out cert.pem + +Combination +In some cases it is advantageous to combine multiple pieces of the X.509 infrastructure into a single file. One common example would be to combine both the private key and public key into the same certificate. +The easiest way to combine certs keys and chains is to convert each to a PEM encoded certificate then simple copy the contents of each file into a new file. This is suitable for combining files to use in applications lie Apache. + +Extraction +Some certs will come in a combined form. Where one file can contain any one of: Certificate, Private Key, Public Key, Signed Certificate, Certificate Authority (CA), and/or Authority Chain. \ No newline at end of file diff --git a/ASTJWSApp/Certs/Creating self-signed certificates for use on Android.txt b/ASTJWSApp/Certs/Creating self-signed certificates for use on Android.txt new file mode 100755 index 0000000..7c04499 --- /dev/null +++ b/ASTJWSApp/Certs/Creating self-signed certificates for use on Android.txt @@ -0,0 +1,70 @@ +1. CREATE PRIVATE KEYS +openssl genrsa -des3 -out client_key.pem 2048 +openssl genrsa -des3 -out server_key.pem 2048 + + +2. CREATE SELF-SIGNED CERTIFICATES +openssl req -new -x509 -key client_key.pem -out client.pem -days 365 +openssl req -new -x509 -key server_key.pem -out server.pem -days 365 + +3. CREATE TRUST STORES +keytool \ + -import \ + -v \ + -trustcacerts \ + -alias 0 \ + -file <(openssl x509 -in server.pem) \ + -keystore clienttruststore.bks \ + -storetype BKS \ + -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ + -providerpath ../../../../libs/bcprov-jdk15-146.jar \ + -storepass password + + +keytool \ + -import \ + -v \ + -trustcacerts \ + -alias 0 \ + -file <(openssl x509 -in client.pem) \ + -keystore servertruststore.jks \ + -storetype JKS \ + -storepass password + +4. COMBINE KEYS AND CERTIFICATES +openssl pkcs12 -export -out client.p12 -inkey client_key.pem -in client.pem +openssl pkcs12 -export -out server.p12 -inkey server_key.pem -in server.pem + +openssl pkcs12 -export -out client.pfx -inkey client_key.pem -in client.pem +openssl pkcs12 -export -out server.pfx -inkey server_key.pem -in server.pem + +5. CONVERT FROM PKCS12 (this step is not working, even i tried the same in stop 3 here) +keytool –importkeystore –srckeystore client.p12 –srcstoretype pkcs12 –destkeystore client.bks –deststoretype bks –provider org.bouncycastle.jce.provider.BouncyCastleProvider –providerpath +keytool –importkeystore –srckeystore server.p12 –srcstoretype pkcs12 –destkeystore server.jks –deststoretype jks +keytool -import -alias tjws -file tjws.cer -keystore tjws.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ./BouncyCastle/bcprov-jdk15on-159.jar + + +--------------------------------------------------------------------------------------------------- +getSupportedProtocols +0 = "SSLv3" +1 = "TLSv1" +2 = "TLSv1.1" +3 = "TLSv1.2" + + +--------------------------------------------------------------------------------------------------- +adb shell su -c "chmod 777 /data" +adb shell su -c "chmod 777 /data/data" +adb shell su -c "chmod 777 /data/user/0/com.rslakra.android.tjwsasapp/files" + + +Pull Command: Copies the file from android device to local machine +Convention: adb pull +adb pull "/data/user/0/com.rslakra.android.tjwsasapp/files/logs/android.log" android.log + +--------------------------------------------------------------------------------------------------- +Instructions on generating the pin for the end-entity certificate of localhost: +openssl x509 -in tjws.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64 +OR +(this will only works when the server is already running). +openssl s_client -servername localhost -connect localhost:9161 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64 \ No newline at end of file diff --git a/ASTJWSApp/Certs/How Can I Determine What SSL:TLS Versions Are Available for HTTPS Communication.txt b/ASTJWSApp/Certs/How Can I Determine What SSL:TLS Versions Are Available for HTTPS Communication.txt new file mode 100644 index 0000000..6e81229 --- /dev/null +++ b/ASTJWSApp/Certs/How Can I Determine What SSL:TLS Versions Are Available for HTTPS Communication.txt @@ -0,0 +1,14 @@ +http://thenubbyadmin.com/2014/02/17/how-can-i-determine-what-ssltls-versions-are-available-for-https-communication/ + +=> Not Enabled or +TJWS: IO error: javax.net.ssl.SSLHandshakeException: Client requested protocol SSLv3 not enabled or not supported in processing a request (NULL) from /127.0.0.1:9161 / sun.security.ssl.SSLSocketImpl + +openssl s_client -connect localhost:9161 -ssl3 +openssl s_client -connect localhost:9161 -ssl2 +openssl s_client -connect localhost:9161 -tls1 + + +openssl s_client -connect localhost:9161 -fallback_scsv -no_tls1 + + +openssl s_client -connect localhost:9161 -serverpref \ No newline at end of file diff --git a/ASTJWSApp/Certs/SelfSignedCertificate.txt b/ASTJWSApp/Certs/SelfSignedCertificate.txt new file mode 100644 index 0000000..8cb3562 --- /dev/null +++ b/ASTJWSApp/Certs/SelfSignedCertificate.txt @@ -0,0 +1,80 @@ +1. CREATE PRIVATE KEYS +openssl genrsa -des3 -out client_key.pem 2048 +openssl genrsa -des3 -out server_key.pem 2048 + + +2. CREATE SELF-SIGNED CERTIFICATES +openssl req -new -x509 -key client_key.pem -out client.pem -days 365 +openssl req -new -x509 -key server_key.pem -out server.pem -days 365 + +3. CREATE TRUST STORES +keytool \ + -import \ + -v \ + -trustcacerts \ + -alias 0 \ + -file <(openssl x509 -in server.pem) \ + -keystore clienttruststore.bks \ + -storetype BKS \ + -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ + -providerpath ./bcprov-jdk15on-159.jar \ + -storepass password + +keytool \ + -import \ + -v \ + -trustcacerts \ + -alias 0 \ + -file <(openssl x509 -in client.pem) \ + -keystore servertruststore.bks \ + -storetype BKS \ + -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ + -providerpath ./bcprov-jdk15on-159.jar \ + -storepass password + + +4. COMBINE KEYS AND CERTIFICATES +openssl pkcs12 -export -out client.p12 -inkey client_key.pem -in client.pem +openssl pkcs12 -export -out server.p12 -inkey server_key.pem -in server.pem + +openssl pkcs12 -export -out client.pfx -inkey client_key.pem -in client.pem +openssl pkcs12 -export -out server.pfx -inkey server_key.pem -in server.pem + +5. CONVERT FROM PKCS12 (this step is not working, even i tried the same in stop 3 here) +keytool –importkeystore –srckeystore client.p12 –srcstoretype pkcs12 –destkeystore client.bks –deststoretype bks –provider org.bouncycastle.jce.provider.BouncyCastleProvider –providerpath ./bcprov-jdk15on-159.jar +keytool –importkeystore –srckeystore server.p12 –srcstoretype pkcs12 –destkeystore server.bks –deststoretype bks –provider org.bouncycastle.jce.provider.BouncyCastleProvider –providerpath ./bcprov-jdk15on-159.jar + + + +openssl x509 -in client.pem -text -noout +openssl x509 -in server.pem -text -noout + +========================================================================================== + +Step 1: Create your self-signed certificate and create .bks file +keytool -genkey -alias tjws -keystore tjws.keystore -validity 365 +keytool -export -alias tjws -keystore tjws.keystore -file tjws.cer +keytool -import -alias tjws -file tjws.cer -keystore tjws.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ./BouncyCastle/bcprov-jdk15on-159.jar + +Setp-2: Put our .keystore file in /androidappdir/res/raw/ + + + +======== +openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 +keytool -import -file cert.pem -keystore tjws.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ../bcprov-jdk15on-159.jar +--------- + +openssl genrsa -out tjws.key 4096 +openssl rsa -in tjws.key -out tjws.key +openssl req -sha256 -new -key tjws.key -out tjws.csr -subj '/CN=localhost' +openssl x509 -req -sha256 -days 365 -in tjws.csr -signkey tjws.key -out tjws.crt +cat tjws.crt tjws.key > cert.pem +keytool -import -file cert.pem -keystore tjws.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ../bcprov-jdk15on-159.jar + + +openssl x509 -req -sha256 -days 365 -in tjws.csr -signkey tjws.key -out tjws.pem +keytool -import -file cert.pem -keystore tjws.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ../bcprov-jdk15-146.jar + + + diff --git a/ASTJWSApp/Certs/android-certificate.txt b/ASTJWSApp/Certs/android-certificate.txt new file mode 100755 index 0000000..957fce5 --- /dev/null +++ b/ASTJWSApp/Certs/android-certificate.txt @@ -0,0 +1,13 @@ +keytool -importcert -trustcacerts -alias tjws -file tjws.crt -keypass password -keystore tjws.bks -storepass password -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ../../../../libs/bcprov-jdk15-146.jar + + + +/* java.io.IOException: Wrong version of key store. */ + +openssl req -x509 -newkey rsa:2048 -keyout tjws.pem -out tjws.pem -days 365 -nodes +keytool -importcert -v -trustcacerts -alias `openssl x509 -inform PEM -subject_hash -noout -in tjws.pem` \ + -file tjws.pem \ + -keystore keyStore.bks -storetype BKS \ + -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \ + -providerpath ../../../../libs/bcprov-jdk15-146.jar\ + -storepass password \ No newline at end of file diff --git a/ASTJWSApp/Certs/keyStoreBKSConvertor.sh b/ASTJWSApp/Certs/keyStoreBKSConvertor.sh new file mode 100755 index 0000000..e26dc7d --- /dev/null +++ b/ASTJWSApp/Certs/keyStoreBKSConvertor.sh @@ -0,0 +1,13 @@ +clear +echo +keytool \ + -import \ + -v \ + -trustcacerts \ + -alias 0 \ + -file <(openssl x509 -in tjws.pem) \ + -keystore tjws.bks \ + -storetype BKS \ + -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ + -providerpath ../../../../libs/bcprov-jdk15on-159.jar \ + -storepass password diff --git a/ASTJWSApp/Certs/keyStoreGenerator.sh b/ASTJWSApp/Certs/keyStoreGenerator.sh new file mode 100755 index 0000000..8e0324e --- /dev/null +++ b/ASTJWSApp/Certs/keyStoreGenerator.sh @@ -0,0 +1 @@ +openssl req -x509 -newkey rsa:2048 -keyout tjws.pem -out tjws.pem -days 365 -nodes diff --git a/ASTJWSApp/TJWSASApp.iml b/ASTJWSApp/TJWSASApp.iml new file mode 100644 index 0000000..00eb96e --- /dev/null +++ b/ASTJWSApp/TJWSASApp.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ASTJWSApp/build.gradle b/ASTJWSApp/build.gradle new file mode 100644 index 0000000..f7fbbeb --- /dev/null +++ b/ASTJWSApp/build.gradle @@ -0,0 +1,31 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.0' + + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + + flatDir { + dirs 'libs' + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/ASTJWSApp/gradle.properties b/ASTJWSApp/gradle.properties new file mode 100644 index 0000000..aac7c9b --- /dev/null +++ b/ASTJWSApp/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/ASTJWSApp/gradlew b/ASTJWSApp/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/ASTJWSApp/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/ASTJWSApp/gradlew.bat b/ASTJWSApp/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/ASTJWSApp/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ASTJWSApp/makeBuild.sh b/ASTJWSApp/makeBuild.sh new file mode 100755 index 0000000..8a77c5c --- /dev/null +++ b/ASTJWSApp/makeBuild.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# makeBuild.sh +# +# Build Android Studio project (MeetX-H5). +# The debug build is automatically signed with a debug key provided by the SDK tools (it's insecure +# and you cannot publish this APK to Google Play Store), and the release build must be signed with +# your own private key. The DEBUG build APK is created under named module_name-debug.apk in +# project_name/module_name/build/outputs/apk/ +# +# Commands: +# ./gradlew assembleDebug +# ./gradlew assembleDebug --debug --stacktrace +# +# OR +# +# ./gradlew assembleRelease +# ./gradlew assembleRelease --debug --stacktrace +# + +clear +./gradlew clean build +#./gradlew assembleDebug --debug --stacktrace +#./gradlew assembleRelease --debug --stacktrace diff --git a/ASTJWSApp/resources/bccert/cert.pem b/ASTJWSApp/resources/bccert/cert.pem new file mode 100644 index 0000000..0020706 --- /dev/null +++ b/ASTJWSApp/resources/bccert/cert.pem @@ -0,0 +1,78 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCAowCCQDVcREQk38U8jANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwls +b2NhbGhvc3QwHhcNMTgwMzI5MTc1NjM4WhcNMTkwMzI5MTc1NjM4WjAUMRIwEAYD +VQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO +9vDcWKUk/NLmyT9LvSxOeLBBwSiqr5kngMT70nuK0D5ihpM/eAsSnNpgsH7V506J +vSFzU/zYp+zDcjPaD3a7Iwl1xHoomUY7lPGEDeykHiwTl6TkzoKrUu/Zgzt3N3Mh +gkSPTqCRpGLzn8jOnbpfIZnErF5DlHhOExxjFWsVkQH8P2Q9FJU+cufuKWDMZlRA +o92bC2PIvsSJTb7j3eGfI0HkQ61u0cRcVr+YrIxBTOPUX5hpBlVhondNSvBEsLRr +6IJ14GKrR17Mvrtdh6VJcfXPuXMIObRqoI83V44vTSc+ggwsu+Krt4+rtgGixfuq +0C6uHWVKl84RDcbiR416cadwLynU7G6CNSk+DbXaCQevjB/cUXiD2rjcVolQ9LmC +d+FEQBlJXHsAvbBFuik7OGVzGtmebT33s+m1Fj7ca5BxvdF/8DPaJa5X3Sk+xKLT +gJs+KHdL+27UQf61U6bqIPLEs0szBXt6gU+UePPBjPaC/R9Evz92JrccPGK6I3py +9GvBzRw1PiP4M4ZhROTahBFnWQt3lTJGAebiQ2Hb+u1sssba1F61+ubuZOPsJis4 +g26MMDoAsdcBjcczk000Uwr7ZaVNMuluAyGCyRoRAX1iXXV894hxNqvx56CoBYAd +PRfNdN9sSeZ1EIP9ycBlEUMnZwc1gpukQ65uNTEYKwIDAQABMA0GCSqGSIb3DQEB +CwUAA4ICAQCwjbK07nCqGjLOJwetic8/+aZf9BTsM5UMPbIYuKlv9KjDyAYaTy/P +BRab3COkrHz0Iss4T04cSdOynsivtG+6ut+wFtDKPGGqeJMQ3Z50r7ph4XaEhrZt +BNC7rcp9Gkw7knztrOdvWDjxyDYR4+Bv+lgs6Mo0JHyKXzJeuCeB2DaLheg8qqh6 +jKC7DDtYadMo4wOWmeJ0abamVxistwU/TBaqkBqB0mIff1czO6+ZIbnl5emUzUc8 +xfqy/nsakleUF5VVveDuN0oU04TKEx0ySRzRfdhn76NMSLQ/l+7ms4XSsNZFUFEn +BP6xTdsYbGhD4gLTDh5fGVSVmk5hHoDbLnGDevi6TnBzMIxGLW0vs8YyY7GbGeRs +HPOXueJkPrc5UlJn1bU2WKn0+jXpFQ3MwfhKDfun6hLphOV8Gu2hS+Z1Jl8vvy72 +xsXVwo5g6DFV9h2+rYyWZrmItbBqUyPzXhRER06uzg5bmhnaSAjV9ryH4YpKEgU/ +5VgdfLj2nm0JYvzg+DdSNMfQs4CYb1lRHJb0SxwGSsPAe8e9J6QWppW0KH0zLupz +B6k0bqIfHmfgIlgpy+uJkAs3LFaRtaJI+ZTkeDjoj6fEfw9yDsexa7IroTAjEUZf +iUmFKUHdR360kuy1Rrgjh22ziXR5AMqAhSZ4mbPgn9Yu53hE/pBaTA== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIJKQIBAAKCAgEAzvbw3FilJPzS5sk/S70sTniwQcEoqq+ZJ4DE+9J7itA+YoaT +P3gLEpzaYLB+1edOib0hc1P82Kfsw3Iz2g92uyMJdcR6KJlGO5TxhA3spB4sE5ek +5M6Cq1Lv2YM7dzdzIYJEj06gkaRi85/Izp26XyGZxKxeQ5R4ThMcYxVrFZEB/D9k +PRSVPnLn7ilgzGZUQKPdmwtjyL7EiU2+493hnyNB5EOtbtHEXFa/mKyMQUzj1F+Y +aQZVYaJ3TUrwRLC0a+iCdeBiq0dezL67XYelSXH1z7lzCDm0aqCPN1eOL00nPoIM +LLviq7ePq7YBosX7qtAurh1lSpfOEQ3G4keNenGncC8p1OxugjUpPg212gkHr4wf +3FF4g9q43FaJUPS5gnfhREAZSVx7AL2wRbopOzhlcxrZnm0997PptRY+3GuQcb3R +f/Az2iWuV90pPsSi04CbPih3S/tu1EH+tVOm6iDyxLNLMwV7eoFPlHjzwYz2gv0f +RL8/dia3HDxiuiN6cvRrwc0cNT4j+DOGYUTk2oQRZ1kLd5UyRgHm4kNh2/rtbLLG +2tRetfrm7mTj7CYrOINujDA6ALHXAY3HM5NNNFMK+2WlTTLpbgMhgskaEQF9Yl11 +fPeIcTar8eegqAWAHT0XzXTfbEnmdRCD/cnAZRFDJ2cHNYKbpEOubjUxGCsCAwEA +AQKCAgEApWpBABvpgjJ/7e0TJdnAu8dCOIvFkQZgBm6pAgwsqbne4qhkr+mmD+5F +q9nkxdnlr7j2L1MFV7R/S4bPYo3Re6h5OyMZ77DxrVVR4xWt+U4UNGSTajyTu5LC +GLsGoDY1UqbnXRKey0jzvXwL5vexqa8VU1fgz2qu7NfhbGAGAmqvh4iy+Q6mag80 +x+lScIuo8zEFQZJM4nl2Y7c7xqvkVGi9lU9yIoyNwK+k2sWuI9LslSUCj458V1ie +uawXdQ82ZLik7Mm2kuasIkCfSBXOSXFH4gp6oixcwowpazYTckLcBt2yFV7lwBEq +Rzdk/0/14YQaixb7ii7iiEbWmqxNqguM1iMRdQ7gRbNoQFduntR3LrVtEx6hQTtO +VGlAMvNUdDb2kNz1wbO4OVokY1uHdC7pdDrYAGKMsJCqjuOmpO1zG7Y5nitoB54i +M4EI/dGTzgfey6bPvAOAwitF0ijzLv/ttHbzxMckzC9302Hz3VFjoEYtrXQSioMN +8W/eDGxC7VM+GuYGM4y8q44DsPqxVak+VfKqvJaTeWPbXVGI2gtUz6+FLFU9mR2N +0LJQsPVQIHc+oG8BuFlJQOUxtP4iaCqBLh1rBbLZr5obP3qWL73CnN6Ywewp+8vy +GTChzx8M+/u/BpEe5c4G2tzeCrioa3EVvdSyRT6WitUDR0pjAOECggEBAOi8Ab3c +0vgoCiisZo9qz24L6iO51ecz4xZ6ta881PCovkOte8Tb9T/7yUv9o8dzF13JTMnh +5s6IybvxpsbqxHu/0AZrU+khhH98uFL0qpRmf8eD2hC+uYGgJEqJw8CWa3ReRlUW +IaHiBIW2KJQQKDkGVxVYbD4c+kD4WIC2gEapkgriRsuqk0mPQMalc+mUBB7bpHyB +ZbxZm/mey8wsqafuH+xgOAee52fP4/inL2Ar1XL7X7vrRelPk0R470daonZfayzZ +ZkKkLZoKjDrDWCwcSVs1uh8DlGbvM3wkKXXWU7873cn/lPpENQ73hWmOuEBs3ifR +ZDjSpALH4s0W+RcCggEBAOOncyKJv0T4CKNXWN+EgXhzBts7qKNKv2XXNHod9K1n +3Ia5+KxQv2k4FygL6FiW5sUY+iIRQKsszpSLdf1Fn8QQKWcQXha4UGs+TYOdY5hy +IQhrQqy/2a26F/gzIhoqAdDwRr8h3yb9DI0lFpxYQQlVNuckQTjmR1I5C0Fzvwqp +nZLHhRywwAcS2R2M95vHTi6HvGe/YntrUwVidEdwGeLyB9ePpsGswRbvy0IF8aAV +/zpyUKbkFy3JjlDg0XvJuECttfWKdHKmFmtX8A5/LZBCr3mXKgXzzkvd8+nR2TUw +GLPSCGqWsTlnIM52KpNH6/4CkieJDLHeEX+Q1prwXg0CggEAKLCGFW3ALMbDT+0k +WTqxXWoT238oGK4Hq+x0S1j1WcYGzcpM81QJgtBAl1qXAc3rbeg91qX6Nm3P514O +bISrKX+VnSmyl/XWNnvVths0n5F0EavJule+Ex2ueqGvacJiswuwfDvMUYM0izQX +0BsrDR1AqGi3M/zY+/bvckF2F+SZtfFtszn1Wk0DZDeVFmdceRCpp2LwKIf6LyBG +PUIpv0RwrGD+Ksbrakj8cIK6U7QWM24jhLVTmcDh3HzQSMdd1BhGoqa3rDsMBfyG +G9f/WGbxpFK2Yam8jmqPs8qWvRVluu96jVBz+XVnWWCJILVlHU5rYMbJIO4i4qGT +04uKrQKCAQEAzuU6/ROlMiAdcZ2LlrANHpOjkpE4pRbktcCM38LjwMjYodTYTHqi +SxT/7pRL2F9kYZJemaGGXUs+f7/zPngNSBnMFu/IIuvlomGf/tKGVmC65rTchrVh +NsMez6JhBthQiDwmf8Rf00Y9JvWjA/otOTcpy42mfPjDrtVLBnQUFrOqEmCj+Dwm +eQdHLNUVn4zV3/HaZ4uHDFWwwP8GYHpf/GIsgFr8mZ3QanEKD/no662yJMMJy3MW +IbXBUn3PxKnCe32kFgB77kpFq87iy7oHhcklQuL//SLjxQ11hHYD6pPIj3x9y6ki +beHs7dZ0wR+nOVXK0IV8dRY2XvIaJ/v17QKCAQAFmzFsvQp7Wuq37BAYyi516xAL +PXJoXLVARX+n2nfFpLIPjbu/tZPtJmF2+t2K6B7vMxkyo5NAIGI1686OFHu8mArv +ZDEI1tgwR/YKceW/vsc63vGkTBm3XPe/H9/QtGtqbEl0xtZQzyRT2asfhjU1anIw +ZqiLcZrCrySpFLDVq3OQ49EPl+23OmA1Zw3PF7sAkqkO9AitBZNzbTzLHNTYta1o +ECUlTzpALtfLVHWSLZL1pfU6hcWs9+gnqMhSIytrLK5GNNBJReuVectl1uYgnh0w +Ob7nr2NROjOIh/Es5e47LM8UE2ZyZrCeALfkTFp5V4gMzFYgHledQ69qCYmw +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/bccert/tjws.bks b/ASTJWSApp/resources/bccert/tjws.bks new file mode 100644 index 0000000..5403bc0 Binary files /dev/null and b/ASTJWSApp/resources/bccert/tjws.bks differ diff --git a/ASTJWSApp/resources/bccert/tjws.crt b/ASTJWSApp/resources/bccert/tjws.crt new file mode 100644 index 0000000..da1a341 --- /dev/null +++ b/ASTJWSApp/resources/bccert/tjws.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCAowCCQDVcREQk38U8jANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwls +b2NhbGhvc3QwHhcNMTgwMzI5MTc1NjM4WhcNMTkwMzI5MTc1NjM4WjAUMRIwEAYD +VQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO +9vDcWKUk/NLmyT9LvSxOeLBBwSiqr5kngMT70nuK0D5ihpM/eAsSnNpgsH7V506J +vSFzU/zYp+zDcjPaD3a7Iwl1xHoomUY7lPGEDeykHiwTl6TkzoKrUu/Zgzt3N3Mh +gkSPTqCRpGLzn8jOnbpfIZnErF5DlHhOExxjFWsVkQH8P2Q9FJU+cufuKWDMZlRA +o92bC2PIvsSJTb7j3eGfI0HkQ61u0cRcVr+YrIxBTOPUX5hpBlVhondNSvBEsLRr +6IJ14GKrR17Mvrtdh6VJcfXPuXMIObRqoI83V44vTSc+ggwsu+Krt4+rtgGixfuq +0C6uHWVKl84RDcbiR416cadwLynU7G6CNSk+DbXaCQevjB/cUXiD2rjcVolQ9LmC +d+FEQBlJXHsAvbBFuik7OGVzGtmebT33s+m1Fj7ca5BxvdF/8DPaJa5X3Sk+xKLT +gJs+KHdL+27UQf61U6bqIPLEs0szBXt6gU+UePPBjPaC/R9Evz92JrccPGK6I3py +9GvBzRw1PiP4M4ZhROTahBFnWQt3lTJGAebiQ2Hb+u1sssba1F61+ubuZOPsJis4 +g26MMDoAsdcBjcczk000Uwr7ZaVNMuluAyGCyRoRAX1iXXV894hxNqvx56CoBYAd +PRfNdN9sSeZ1EIP9ycBlEUMnZwc1gpukQ65uNTEYKwIDAQABMA0GCSqGSIb3DQEB +CwUAA4ICAQCwjbK07nCqGjLOJwetic8/+aZf9BTsM5UMPbIYuKlv9KjDyAYaTy/P +BRab3COkrHz0Iss4T04cSdOynsivtG+6ut+wFtDKPGGqeJMQ3Z50r7ph4XaEhrZt +BNC7rcp9Gkw7knztrOdvWDjxyDYR4+Bv+lgs6Mo0JHyKXzJeuCeB2DaLheg8qqh6 +jKC7DDtYadMo4wOWmeJ0abamVxistwU/TBaqkBqB0mIff1czO6+ZIbnl5emUzUc8 +xfqy/nsakleUF5VVveDuN0oU04TKEx0ySRzRfdhn76NMSLQ/l+7ms4XSsNZFUFEn +BP6xTdsYbGhD4gLTDh5fGVSVmk5hHoDbLnGDevi6TnBzMIxGLW0vs8YyY7GbGeRs +HPOXueJkPrc5UlJn1bU2WKn0+jXpFQ3MwfhKDfun6hLphOV8Gu2hS+Z1Jl8vvy72 +xsXVwo5g6DFV9h2+rYyWZrmItbBqUyPzXhRER06uzg5bmhnaSAjV9ryH4YpKEgU/ +5VgdfLj2nm0JYvzg+DdSNMfQs4CYb1lRHJb0SxwGSsPAe8e9J6QWppW0KH0zLupz +B6k0bqIfHmfgIlgpy+uJkAs3LFaRtaJI+ZTkeDjoj6fEfw9yDsexa7IroTAjEUZf +iUmFKUHdR360kuy1Rrgjh22ziXR5AMqAhSZ4mbPgn9Yu53hE/pBaTA== +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/bccert/tjws.csr b/ASTJWSApp/resources/bccert/tjws.csr new file mode 100644 index 0000000..0f111ca --- /dev/null +++ b/ASTJWSApp/resources/bccert/tjws.csr @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEWTCCAkECAQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAzvbw3FilJPzS5sk/S70sTniwQcEoqq+ZJ4DE+9J7 +itA+YoaTP3gLEpzaYLB+1edOib0hc1P82Kfsw3Iz2g92uyMJdcR6KJlGO5TxhA3s +pB4sE5ek5M6Cq1Lv2YM7dzdzIYJEj06gkaRi85/Izp26XyGZxKxeQ5R4ThMcYxVr +FZEB/D9kPRSVPnLn7ilgzGZUQKPdmwtjyL7EiU2+493hnyNB5EOtbtHEXFa/mKyM +QUzj1F+YaQZVYaJ3TUrwRLC0a+iCdeBiq0dezL67XYelSXH1z7lzCDm0aqCPN1eO +L00nPoIMLLviq7ePq7YBosX7qtAurh1lSpfOEQ3G4keNenGncC8p1OxugjUpPg21 +2gkHr4wf3FF4g9q43FaJUPS5gnfhREAZSVx7AL2wRbopOzhlcxrZnm0997PptRY+ +3GuQcb3Rf/Az2iWuV90pPsSi04CbPih3S/tu1EH+tVOm6iDyxLNLMwV7eoFPlHjz +wYz2gv0fRL8/dia3HDxiuiN6cvRrwc0cNT4j+DOGYUTk2oQRZ1kLd5UyRgHm4kNh +2/rtbLLG2tRetfrm7mTj7CYrOINujDA6ALHXAY3HM5NNNFMK+2WlTTLpbgMhgska +EQF9Yl11fPeIcTar8eegqAWAHT0XzXTfbEnmdRCD/cnAZRFDJ2cHNYKbpEOubjUx +GCsCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQCcBosPQaL1Sn3ADoVyLgxJpRkN +AuXAAehYnDAHrs+OU4X/NtxjFPpksHt/FI14YkQLz5lrD7YnTkb8Kiqdmwlfl0nB +9LPxMYpPpyCqzv3+/Fty7pysvieu8WRsIRWdJgObuF9mPthHEvrP5Sb2yoWGnCA1 +i2OUys5sUs7fXkt8vKMgficMi85xLsru7jGocQ46fygDPRARu5vpc9cm66DJI4Qp +GKWPXxCgAm9oTKSZyrALb9BoRjX18fa3uqWQx+LYboXX+93K8y9IJIIaSvhpqfXh +HWgxHmezqPA6mp8bfsFbBV+N2zEeObOLBnL+iOKzMnxRO4NBWcKHQ7eQuwpVsO6z +Ti2FgAtXhTQu7qVk7d7thxnXxwAxgt2/HhbyvAOryBb3DO738OvKUGn2q2Itbjjg +v3APdnoyMBr30UQ1vY80gk/KLQoyXOdYlaFK27GBmkCnmnP/fLNM2Sdm5lbhjtmy +ds5neNmqVbfrPxLG0VxSO7Bd4VMk69ouravKjfFgfRlf7sgGJwiWGgtKpieWts2f +FdHOHoFbMJ8rR2X89MLO4A2XaoIVo+qjkkco+njV7azXYSfh6IHZ8wuBSzlp3LYD +4erBkF79e3e9Pp41UaRIUdKjhu8VN83x1wCVL8iDIYYOU94LTQKo1BkJ653QHisQ +rNCXPtV7TMy+sr2dnw== +-----END CERTIFICATE REQUEST----- diff --git a/ASTJWSApp/resources/bccert/tjws.key b/ASTJWSApp/resources/bccert/tjws.key new file mode 100644 index 0000000..4b7b9b8 --- /dev/null +++ b/ASTJWSApp/resources/bccert/tjws.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKQIBAAKCAgEAzvbw3FilJPzS5sk/S70sTniwQcEoqq+ZJ4DE+9J7itA+YoaT +P3gLEpzaYLB+1edOib0hc1P82Kfsw3Iz2g92uyMJdcR6KJlGO5TxhA3spB4sE5ek +5M6Cq1Lv2YM7dzdzIYJEj06gkaRi85/Izp26XyGZxKxeQ5R4ThMcYxVrFZEB/D9k +PRSVPnLn7ilgzGZUQKPdmwtjyL7EiU2+493hnyNB5EOtbtHEXFa/mKyMQUzj1F+Y +aQZVYaJ3TUrwRLC0a+iCdeBiq0dezL67XYelSXH1z7lzCDm0aqCPN1eOL00nPoIM +LLviq7ePq7YBosX7qtAurh1lSpfOEQ3G4keNenGncC8p1OxugjUpPg212gkHr4wf +3FF4g9q43FaJUPS5gnfhREAZSVx7AL2wRbopOzhlcxrZnm0997PptRY+3GuQcb3R +f/Az2iWuV90pPsSi04CbPih3S/tu1EH+tVOm6iDyxLNLMwV7eoFPlHjzwYz2gv0f +RL8/dia3HDxiuiN6cvRrwc0cNT4j+DOGYUTk2oQRZ1kLd5UyRgHm4kNh2/rtbLLG +2tRetfrm7mTj7CYrOINujDA6ALHXAY3HM5NNNFMK+2WlTTLpbgMhgskaEQF9Yl11 +fPeIcTar8eegqAWAHT0XzXTfbEnmdRCD/cnAZRFDJ2cHNYKbpEOubjUxGCsCAwEA +AQKCAgEApWpBABvpgjJ/7e0TJdnAu8dCOIvFkQZgBm6pAgwsqbne4qhkr+mmD+5F +q9nkxdnlr7j2L1MFV7R/S4bPYo3Re6h5OyMZ77DxrVVR4xWt+U4UNGSTajyTu5LC +GLsGoDY1UqbnXRKey0jzvXwL5vexqa8VU1fgz2qu7NfhbGAGAmqvh4iy+Q6mag80 +x+lScIuo8zEFQZJM4nl2Y7c7xqvkVGi9lU9yIoyNwK+k2sWuI9LslSUCj458V1ie +uawXdQ82ZLik7Mm2kuasIkCfSBXOSXFH4gp6oixcwowpazYTckLcBt2yFV7lwBEq +Rzdk/0/14YQaixb7ii7iiEbWmqxNqguM1iMRdQ7gRbNoQFduntR3LrVtEx6hQTtO +VGlAMvNUdDb2kNz1wbO4OVokY1uHdC7pdDrYAGKMsJCqjuOmpO1zG7Y5nitoB54i +M4EI/dGTzgfey6bPvAOAwitF0ijzLv/ttHbzxMckzC9302Hz3VFjoEYtrXQSioMN +8W/eDGxC7VM+GuYGM4y8q44DsPqxVak+VfKqvJaTeWPbXVGI2gtUz6+FLFU9mR2N +0LJQsPVQIHc+oG8BuFlJQOUxtP4iaCqBLh1rBbLZr5obP3qWL73CnN6Ywewp+8vy +GTChzx8M+/u/BpEe5c4G2tzeCrioa3EVvdSyRT6WitUDR0pjAOECggEBAOi8Ab3c +0vgoCiisZo9qz24L6iO51ecz4xZ6ta881PCovkOte8Tb9T/7yUv9o8dzF13JTMnh +5s6IybvxpsbqxHu/0AZrU+khhH98uFL0qpRmf8eD2hC+uYGgJEqJw8CWa3ReRlUW +IaHiBIW2KJQQKDkGVxVYbD4c+kD4WIC2gEapkgriRsuqk0mPQMalc+mUBB7bpHyB +ZbxZm/mey8wsqafuH+xgOAee52fP4/inL2Ar1XL7X7vrRelPk0R470daonZfayzZ +ZkKkLZoKjDrDWCwcSVs1uh8DlGbvM3wkKXXWU7873cn/lPpENQ73hWmOuEBs3ifR +ZDjSpALH4s0W+RcCggEBAOOncyKJv0T4CKNXWN+EgXhzBts7qKNKv2XXNHod9K1n +3Ia5+KxQv2k4FygL6FiW5sUY+iIRQKsszpSLdf1Fn8QQKWcQXha4UGs+TYOdY5hy +IQhrQqy/2a26F/gzIhoqAdDwRr8h3yb9DI0lFpxYQQlVNuckQTjmR1I5C0Fzvwqp +nZLHhRywwAcS2R2M95vHTi6HvGe/YntrUwVidEdwGeLyB9ePpsGswRbvy0IF8aAV +/zpyUKbkFy3JjlDg0XvJuECttfWKdHKmFmtX8A5/LZBCr3mXKgXzzkvd8+nR2TUw +GLPSCGqWsTlnIM52KpNH6/4CkieJDLHeEX+Q1prwXg0CggEAKLCGFW3ALMbDT+0k +WTqxXWoT238oGK4Hq+x0S1j1WcYGzcpM81QJgtBAl1qXAc3rbeg91qX6Nm3P514O +bISrKX+VnSmyl/XWNnvVths0n5F0EavJule+Ex2ueqGvacJiswuwfDvMUYM0izQX +0BsrDR1AqGi3M/zY+/bvckF2F+SZtfFtszn1Wk0DZDeVFmdceRCpp2LwKIf6LyBG +PUIpv0RwrGD+Ksbrakj8cIK6U7QWM24jhLVTmcDh3HzQSMdd1BhGoqa3rDsMBfyG +G9f/WGbxpFK2Yam8jmqPs8qWvRVluu96jVBz+XVnWWCJILVlHU5rYMbJIO4i4qGT +04uKrQKCAQEAzuU6/ROlMiAdcZ2LlrANHpOjkpE4pRbktcCM38LjwMjYodTYTHqi +SxT/7pRL2F9kYZJemaGGXUs+f7/zPngNSBnMFu/IIuvlomGf/tKGVmC65rTchrVh +NsMez6JhBthQiDwmf8Rf00Y9JvWjA/otOTcpy42mfPjDrtVLBnQUFrOqEmCj+Dwm +eQdHLNUVn4zV3/HaZ4uHDFWwwP8GYHpf/GIsgFr8mZ3QanEKD/no662yJMMJy3MW +IbXBUn3PxKnCe32kFgB77kpFq87iy7oHhcklQuL//SLjxQ11hHYD6pPIj3x9y6ki +beHs7dZ0wR+nOVXK0IV8dRY2XvIaJ/v17QKCAQAFmzFsvQp7Wuq37BAYyi516xAL +PXJoXLVARX+n2nfFpLIPjbu/tZPtJmF2+t2K6B7vMxkyo5NAIGI1686OFHu8mArv +ZDEI1tgwR/YKceW/vsc63vGkTBm3XPe/H9/QtGtqbEl0xtZQzyRT2asfhjU1anIw +ZqiLcZrCrySpFLDVq3OQ49EPl+23OmA1Zw3PF7sAkqkO9AitBZNzbTzLHNTYta1o +ECUlTzpALtfLVHWSLZL1pfU6hcWs9+gnqMhSIytrLK5GNNBJReuVectl1uYgnh0w +Ob7nr2NROjOIh/Es5e47LM8UE2ZyZrCeALfkTFp5V4gMzFYgHledQ69qCYmw +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/bcprov-jdk15-146.jar b/ASTJWSApp/resources/bcprov-jdk15-146.jar new file mode 100644 index 0000000..daa0b54 Binary files /dev/null and b/ASTJWSApp/resources/bcprov-jdk15-146.jar differ diff --git a/ASTJWSApp/resources/bcprov-jdk15on-159.jar b/ASTJWSApp/resources/bcprov-jdk15on-159.jar new file mode 100644 index 0000000..9049e56 Binary files /dev/null and b/ASTJWSApp/resources/bcprov-jdk15on-159.jar differ diff --git a/ASTJWSApp/resources/cert/cert.pem b/ASTJWSApp/resources/cert/cert.pem new file mode 100644 index 0000000..003295c --- /dev/null +++ b/ASTJWSApp/resources/cert/cert.pem @@ -0,0 +1,36 @@ +-----BEGIN CERTIFICATE----- +MIIGSDCCBDCgAwIBAgIJAPxw/hRuMltCMA0GCSqGSIb3DQEBBQUAMHUxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MRMwEQYDVQQKEwpMYWtyYSBJbmMuMRMwEQYDVQQLEwpMYWtyYSBJbmMuMRIwEAYD +VQQDEwlsb2NhbGhvc3QwHhcNMTgwMzI4MjIzMTQ5WhcNMTkwMzI4MjIzMTQ5WjB1 +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVu +bG8gUGFyazETMBEGA1UEChMKTGFrcmEgSW5jLjETMBEGA1UECxMKTGFrcmEgSW5j +LjESMBAGA1UEAxMJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAopc02OIAbKiHlezHjp3ff2T1oUEBJYSmZQd0yPCvyr/w5HS0Pkr9o8KA +FyIBdXY+FIkDN5eqQxk1k8TpOGAX4ppTbOQcgEBxDoY1qSyLrfHj8BpTKbtT4GdM +/OjQcMO6PcGHbJF3Mk3UAG8OJRF62IC4VY4TXankoNB+zSZesrBNBh1G+hUmlJVm +OpyTqXgbwZCwVZW27cnAcLOAsUNMt5LK6B/IdPTIgDxnMapzHoSmaQGta3uUwDeA +L78DlgIwZkVUepqaeh4OrbEVWrBOjmte9B5YetAGkvxlvSkGg0/eDhO/gOTIVhtS +XjCq7AeuJe4uKcJh3q44MnGqPa8eUsHKxUMfau/gb3SUuvyKeM9cy2z7FWGPIoQJ +FrGi2hCxFfAJHq+PQXk0gjXwjCGub6CUzUNrJnWaJtK6qk0qdDqTojf+qFFIoKLl +yZYZ6H4dBvvTDdGk8tyzzFdpB9rE+R0X2F7MWc3ZhhDGSOjfnrinjh255jNYe5qE +UKwinMQf0mDVyk1rm2MiLACMjaI9Nb8E8G47oCzHq0pDOgT4+wpQvEsPnOlHt4Ny +tWljNyOpfBoWW4dJvHXZUec9Vv6TMV2V32aEErlnt+BdbFVFSBB7alSSQw2rxkBm +1JxXO/z3Pfi3m7037YEEt2sZN8hP3GtddwoWRdGX/+omatZv/c0CAwEAAaOB2jCB +1zAdBgNVHQ4EFgQUpf4tAwFPXIRcqFn/1pZp3R1pbQ0wgacGA1UdIwSBnzCBnIAU +pf4tAwFPXIRcqFn/1pZp3R1pbQ2heaR3MHUxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +EwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMRMwEQYDVQQKEwpMYWty +YSBJbmMuMRMwEQYDVQQLEwpMYWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3SC +CQD8cP4UbjJbQjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBEmFqP +XxLzPlyzlvSm0FbA0rWYz8yRKtIBcrqd7+4u811mnKtofv4zo7WMDhE0E7Hh4frB +OV/x7SfPaoOkw+VHtuFEBvdTIobbtHHKgXP3s5fE/RySqsvRgQY02Zfk/sRHat1k +qhscNwt+KQqltTTBTBAYT3i7Gy6kgsl33xtAYhwHBqeKKa/eEvmwIp5V16RTfBsB +p9Mfcbgub7XDRiE+6CFfnJO+Ss2tGNMdS7+pcnBRwwHlBoS3mjuaq2GVS9/+k1jp +bEnMXLzljoA2M7HNOAi/a/+RiHG5JTy5VvnJcr2ZWDS05QeLO9n9BEMxWuIDaQzF +l13tBjfgfUlH8p2+tHuvGJchUl79cRFjXDkhcLR0m4VW5KaJ3IjceYD69wchMb9o +A1MjOj8WxEOS3+yhm2J4QoJxmPfWFqAnrFcLwPRvUGwmh41TgeaiIXmx7SoYw9AX +UKmphFRTk+1f7/nMCDmOwUdgg6UuLSjJEncubNexpE39J/JZW86JM8KHzvcdZHB6 +0qXAZVkNLpm67E8Eg1fAjZsS2Wh/Mw245VDHksHOQ1o75JVUPyqPnOmamH7WRu7x +sASW6cAUSPDgz0oO0Fb2froOHlRgHYQnG+yPZb8mZ+4FjLkxzcCACkIZs9vMrHZb +WeaUiFPANseMq88YIdPK4DZMUGdEKEUpwf25TQ== +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/cert/key.pem b/ASTJWSApp/resources/cert/key.pem new file mode 100644 index 0000000..04969c4 --- /dev/null +++ b/ASTJWSApp/resources/cert/key.pem @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,FEB0AE71E6E06167 + +WuR0r3mIcfCIW2yUUV1v9yic32R6QzwFCF9wIA98mp+FpUKjaGnxHmCIRODvtYGh +Ld7PrqR92OAx+HY1ny6FUUI2A0wPjA+FAWVlN53o+jNnXHGgdtgUyovv17HXBt8w +6nWV1/NoO2gHtBTlRnX2mbF6ceFO/lSVmOmy1QECQc3XTNEmsNfeEA7Q9KwqFuD5 +XIYHmqifWzmon0tC5yTH4W9uLjaPIxI0HYr3/WyeujcXKAKDwW3Gw1qq+CeTUmf1 +Xxx+Ddg+zFU4bVngcK3KOk/rR8H4wjmNtpGzVhpH/Eh8seJS3UHyU2M6iKPH0hb7 +OkRe14my+2twFPRhWEbjKcLaXJ/v1/MiuYMtd2tNfoViS9c7bZ7elKJw5JrgxXVq +Y2LNwxifte+XtRyVMjZ2lPhbvyUfwnTUZsgxVDb/syLQ8tFaG9+J+ez9ybRldGFK +Tmh6JLuYBMQnccGSpz8JgcXXU4/4ATuKgy+6m/aZ+tdysQr/2x66xx2cVj28Siig +g6f/beHX82Ie3lxhBnAB/o0PSLtJwlSMBd8j6kG1jOZXOtMwWMIk7te6RIf7b3OZ +zRX8qr1IbL4cOrlrLzw3cKI2mcvdIZfwXPYJaDBWV8elhvAq09da6C3VKbETL6tL +1oOXosEr7wNd1TFJtPZHfy3R+BTdjsNJjUGEA5drY5YbFxYdHWLxnYlX6/AV1A/J +W62NY6j6kyjHXO63f/Z9UwXjhSHDnFBpGMb9W+WnaCAEwskIqB/JHK7MD7juylG1 +iQI+CABJdGTD3HrPyRtPdr3qE2PMpqu8Au4gNqz4xjxM/3Ckmxd5R/rq7vKV9jxI +WmN0KaoTRJ8LSLuVkABIHvm0qGpSSXeF+NGAgiraT+MXrGdQSpuwANlzQFd4dED6 +8qKiOYIFiDhkEt9LxsJMy26rz0nHQL+o5t7omdwpEnZTERgsL9If1TRCOu8t80f1 +H95LZ5SGhUTkieTljvsOf4UyIztePWzXc+sjPOflknHdPQoQJcXjfnNHvsxOvrim +9/lV71CiTyNspR4uQTYYA7i+A8+3GEVR+thKe8n0KsuQ1EDSuFP192rJeAWVRn+8 +4+hBt+jx0MW+wM3rTXkMzCjWwqLA4k8wdWsB4Z110XlxAN8kEh+ZgHMHBfbwHLdr +rXd/pDX6EtZ9EcL9Z00POmepNpB9zrxnZaSW8pR1QK+8o83NyfHraK3QVnExNrHf +U934mCWasPrR+ouX74SjTOwHwp1vFwgnr+QZ0hLRDgfqhhwGZcYO/zb7pLqm9c6l +wIvU/U/60Bq/9AIwL+vIBE1Jvca68nMUyAiOcthc2TmC7hLCwBEKt8gZRgwIDbKn +eMVcyeKGXeriKwtp9TrDgbyEMrgOR1J0/PHIawoP0+g6DXsoxJzMzb5F3TDFUxDp +Aj0eHG8jiX3VU/Ls6PxGJHJVLPbljVawQl+YQ7D8XBu6G3iY5mgcJhHKlk1z9H0b +z98NhvJHW5kY0qec6cTxIcF3ZRLDz0hL3DoqpXu6XOHHIX4ebpi3GlzasvJwTaCq +XCJfaaTTBRSOj5r5KjKRyMj9XbLKyW2h6/5WfFVJPlmhLjnsyV2dGc6cZUURXEEM +pkZn3aqAts3lGUGrOC7dBIrVi6T/Cm2eULTjTKhOvZLJeqr4BSlp84F2oMm7SRMP +qKOj35nqwe1ga2i7XbbjmsHKHjQehodZnIjUiPNTnxzyFBH5HxAYObz8rRK//zzp +gnwgDHAhaEnPn/oO21XK/2jJM5+pBUpYD1+BeQbqwhaRlrc3gY2qBQ/U4B+WUBzT +GKXuwze/gYVY9ge9QzzHv21hgGD+JXpy625DHaszEoezG+3n2ieP9j1NyNQdbgcJ +gPFU1Lvj79Z/AVtJSjudGJR/MQPa9DxrvwS3PzZgzR+t3gpb7SL7gDAXZW2ND408 +31LdnWtsZY56dkt9F21b7C2N3pDwvFeVPetAEpz5sb7vhVB7qGA2/bQ2qay0LJiO +Tz1U7O8eg2IhNOrIpNU7LzsL+SNm9/McyxsXXUpSMWElu60J6XFAFEDJcpdODDBA +HZTsfCFxgHlD4ENGlTNNgWiBUwNqsWqEBsfGeNSYdw2KrFXeA8GQXQ8YEYsvi812 +qgQosUCMVZP34xyJ3QdReYtbPuxLmJZGZODg9Obv+CFgXdWqZYNtd1AHRxQH0cj1 +wHaHdW6ftMpiG+6jdhpW4MHL1tjWWKNgDjLRRbY4KI/ZsFWYD3wZsHsYPupKXv8N +UqzPiwk1FOKDCSLTV+bqHuipakre0L2Tv1VG80Xuqo2tWS27vGejKtUAUrUgfbbY +ksMUqMlv6Fvus+AOq9e3DWgmzoaC6M42P6fm+03EZ+KfJoNA6Cbu+NtkZdkMtiU8 +fWp93r0ovqjG+78+fmPHXuaeD2llst8+Z3RiDIT9VUQszCy5lHX4B4ZiyJ0f0gNy +6FZuj5Gk9etrdi0CcF3YprKmiM8FhxqMOoYMTWFeId/cLD1Q25lTFjrgJ8Uz3Cxf +AEyEOT/sV2C6575JsfqFGltU+9Rpjt8lclaoa4hco09CoGpaW4+4lwfrKlJSb0dF +pR49Q0jEelFRvyGBqmN9wQWnTdoSlXuy4hMxGvL9PNhflcBVoPFdkzWPub3sURwu +8T0OEOIftZQkVj4utuE2q9SfuR1f2D1TmhJhByweD7kg7FHgYV8zAbO6JY/kr0ud +G1M15o+753GG0gZcu4W74nAJtMcnVd2/vByqhNFoYTOYZju4Qq2k2kX5r5YjYNRe +MbIe+IQ3vpxezzZXmnKjJEtaQliXx64LuCu3FdqhQPnMOLrg6EBUzz1sPiWz0Hsl +zr474vu8YvcL89oBbYZ9YVckgkmfBdMSe5BF/cCXuSMAFNXM6/QgUxpmjp4jRdTY +kaeJ7wTSangBNiyTo9HeMZYHFopbR3boJa+3zFhWilZSpbrTxQBlT/4t2uankejJ +yhJzE0KhHoZUNaHowGOxNZ3klTmEsd9uizj/fLT3yWIsyRDkG/TGyGqXqwGcrv5M +l8riuTuhYuFE7iWvNbGP+QA7ledHpobplg6uFLGmam6SNH0IXC2eZvM1yKYriTW1 +USpVrJ4cBxsDT+1BhxyodmH5BzMmRDcOpHWtcYIFeipCSxh6W0c8eHhV5Vokskwa +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/cert/tjws.bks b/ASTJWSApp/resources/cert/tjws.bks new file mode 100644 index 0000000..da183a5 Binary files /dev/null and b/ASTJWSApp/resources/cert/tjws.bks differ diff --git a/ASTJWSApp/resources/cert1/cert.pem b/ASTJWSApp/resources/cert1/cert.pem new file mode 100644 index 0000000..2c347d8 --- /dev/null +++ b/ASTJWSApp/resources/cert1/cert.pem @@ -0,0 +1,78 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCAowCCQCqVV1V/HXh3zANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwls +b2NhbGhvc3QwHhcNMTgwMzI4MjI0NzA3WhcNMTkwMzI4MjI0NzA3WjAUMRIwEAYD +VQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCn +SdMgf+6fvxA+mO7+6iTxcb7Vnghw8KwkAGbsdeQig/DXCFa02aoCR6WH4B5Cdys6 +mekaDN9VWsEf4idSKMaJb3aUmcxNy6ALhFsT3++/3YeHuyDMhAdkw/kj+4RZ+9Jw +7hvs0PBARsrJfZcuJKMByGzrLWqfkrIJaVvRex4ymRU8Cth7vjI/wZZ2DdlPXx3e +Cc791+7vaPu6GXs136HB77T+ZtHoenXSzykdygChC2T0PJINlQJgpcIciVKesx6n +gOwWafnFJcaDGlJ7BDe+0qGequ/KZblU6asiVqpYW1aRp3nLusR4SduKUIQmBOGa +7jsLM+sgBhpPBAstckIS/9ouDEgy9vHcYgFQfUj/SrCCi+KQmQzov1uxXIWXQtRX +QPC1tzsyEeYVh0+tn8J1PDFO5AeI3qqFx56mZzcmWyjcUpPeLua2TuhxqkNOflfU +BVBNXCb0BNHGzQMXiMc+GX6KZ6eZY/I1Tuajd+orWcpNs9iU44RJ6IqOu+W2CTe1 +XQ3y3LHQo2+iYCD2hzYvTHQgGc3cMWygXCxT8HRyvP3bJR2ggYXeMgsRX/RN+dLQ +OYtgcrG9xnFekTTWbFc2nBPzNO0C+vW0yERjaGGbj+w035Ewzo+SEnnpWvYgb/8T +nfn8fQeBcx4N+oalikfe8nsWDaLWqMw23oLWstY2GwIDAQABMA0GCSqGSIb3DQEB +CwUAA4ICAQBQoENtF0YxFglAFKUkb0Dys7lcdiMmYZAA7o/wXkOiaEdhyoHQ6/wZ +b0RcXxyMRlE/hZ1ri8l+NlpkswiOI+16LIkvnim3YpToNdZq/+ICyrL9DhyPzKTi +oXxbQ/r6mhkxPEZPfoh7zPEOhSm3Vif1c3R865UWSw4Kd2aoV81qvHdMkZTustlT +zSyu8y5v2/txEVRbBwrrgkZe/h57EZs6YpCjsdAyNLEeQlgtIKeEbXT/9gxABo2u +Ok6Kbpn+bMuxQc13mjiira8xJ2ieobjHWrqA8pldYBHtwxRXqylJYU7poD0votsk +MnlXdFILKMk6KSqHlPDsFRZJAL/2mK438i9sRLU1nr9KE8qcIevzDPjf5zwdZnfR +marx95mhCiXVhnmEQ4PdyCG5ZHJErWqvKCI01+eCZlJk8k/lmROU6FU2I6MW3vna +kzhuHTyZwuCjWn2tSEuXbye4cam/CslZANHtlPu59ZYBgvQn/bZfHdDowBf/FLM5 +UYa/+56IL/vhNOgW2SRf+TI0NqS8y1LbVxJx/2f22irqqCY3T1KPu89iaOGOChDO +iIKyeG3WKZFXbeZvniNR/OnDqnSVVVmza3/sCmEsfiaqAH960W/fSBGKv4ugAdPn +d1Va+D6qRYAc0vrLxerXlO/XQsOvDXgTPjF8wEk5GIoUg3fcqmYkAQ== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIJJwIBAAKCAgEAp0nTIH/un78QPpju/uok8XG+1Z4IcPCsJABm7HXkIoPw1whW +tNmqAkelh+AeQncrOpnpGgzfVVrBH+InUijGiW92lJnMTcugC4RbE9/vv92Hh7sg +zIQHZMP5I/uEWfvScO4b7NDwQEbKyX2XLiSjAchs6y1qn5KyCWlb0XseMpkVPArY +e74yP8GWdg3ZT18d3gnO/dfu72j7uhl7Nd+hwe+0/mbR6Hp10s8pHcoAoQtk9DyS +DZUCYKXCHIlSnrMep4DsFmn5xSXGgxpSewQ3vtKhnqrvymW5VOmrIlaqWFtWkad5 +y7rEeEnbilCEJgThmu47CzPrIAYaTwQLLXJCEv/aLgxIMvbx3GIBUH1I/0qwgovi +kJkM6L9bsVyFl0LUV0Dwtbc7MhHmFYdPrZ/CdTwxTuQHiN6qhceepmc3Jlso3FKT +3i7mtk7ocapDTn5X1AVQTVwm9ATRxs0DF4jHPhl+imenmWPyNU7mo3fqK1nKTbPY +lOOESeiKjrvltgk3tV0N8tyx0KNvomAg9oc2L0x0IBnN3DFsoFwsU/B0crz92yUd +oIGF3jILEV/0TfnS0DmLYHKxvcZxXpE01mxXNpwT8zTtAvr1tMhEY2hhm4/sNN+R +MM6PkhJ56Vr2IG//E535/H0HgXMeDfqGpYpH3vJ7Fg2i1qjMNt6C1rLWNhsCAwEA +AQKCAgBBbC+zQBT0SGZz9J9S9gLoodE9/YXTlWvc0INv6lMD5JGlps8x/wXrylVE +JDPxTmWLj3GIDIyy9sEcVPeHvAaY7Qx05QjvS7kVh/eOeD9sy5gbTuVu1huGHtYq +akzCXCdanuQw4y1yFb1suz8Kfq15HwbpmmNecKJL5/ZOoFWY+CFD0AIFssY4BN9w +382iqtIlabSXtYDuBCKeDyUOVp0OGU6xR0jEIFA/12B/E+bXFHuwwJdl1GaPoYOe +YV38TpSocVTjFyLlJPbTgtHK5kVezUUDploMz2eBe7i/vyDzWRUr9VE+iZYYbNn8 +56wmqjYIvy48HVvQtFJJoI02gr6vyXCzsDh10lfnyri18FLDmT9gosRcf2xaZeeQ +dSPpxwhwuATPOYcY56kOROyz4JBBuAOZ4YUAWqT9DD2G6t+hDS+DSvpqwtj62o/e +XYKmga/cimAs7y1ntdlAjRWuWFIdh7UqxBC34oT8B2N/ORo/ikaJODtIj5k9JF9R ++7RK+XFQ2/DgD/yjuA/fGoxf2f9Al5GKM2xFr2AB6dZos/M4cqX5EDl1TqTITtz8 +Fct1E/96kDBVUfS/rFfDWCj+gSNndNuKUEs3WHA5gif1EVFI+wc5jB2L1QNr75Tp +ACjW3kTWh4wklONG1LCnH+wX7GZhfuSpl22iH5ZlVKPFwBW7AQKCAQEA2NzCZKoe +Y7b1TMzc1W+ipUPmiSHr8VlcOf2Pwa/CDplhHxBN6a0kHWpFb+Y83Wz02JKYaLYQ +9qGpZGmyGBPdtQBFmkfCvXIOoyZldB+AfuKGWIvgZNewiTWU4dPdlbh7w6gj6RJv +HXqal/n+1PzKgRD8gpxBm+D9BhEqtASVq8dG/ZrvZHS0XA9C6+bFVsyCh/jBMDb7 +OJRSe8CP1llb99mi9anyrSfnTFmZyDmSs+9/GskDNKSSvBvIsEyoQASKASsgj1zz +Nyyy3d7hoAGZhKgo/+fno9zLwECt5NK2/PUhS6upydrwh6jfNjUL6LLd+k3jMgia +Sm7RKr8+rujJWwKCAQEAxXqz0iqJDPM+yzTiebdSk+9bfCPqCTLXbjw1GE32ftxV +tzntmk/NmlRmVeiu7wAULFn+kOd0MbwdKMogwMd43UnOFxGywNNEXzNTX9Ij5NNk +EPZ0NDwd/obvl9HhpyRa9U28XIw3U9zhU/wtxQ10TG1zfAXhlZGNwKYx1t/C4JAH +9dXwBhr+TpJ2ZyXaG4GZ12scs07pfFBe4NZV8o2NA0jRyIwYV/3tbo9WcZlDFEzt +cLbXt0nmkddWJ2vCcCT2PHhc6AeQrVsTq8Z2CzF1pTksYdZ5L1ch8Zu7JCLSg+HO +PWx3aBVgRu+KiJi35AqG8JBbjJpR+JlRYCvEkIciQQKCAQAcvfWNvfZVJPSR/zzt +lOQrnzo4xqQs0rkkfnTFKPRBVxbGNTT+WZJFy8X0NMGwXzZ8VcGZbzgEWBzJUDDo +fAmQab7P2d73mNxTx0z+/QXcy00fAzr0YpnlNZLL83aU12Sf4/MOewD7GTrQFbQu +qmp0fLna3bbcYA9o9HGCdnEX2UuRZS2BVO5qnSMzfNx+ypAqUU/Zgg/9ybq86CKo +OCO2T8QHZ0Tgqj8/oUh+fxLwgjeIZ0fjfERuZghNRXuvMGrSCNNB7QHXODdkrJue +x1d/e4IjmKrczvC6RFhH0Z2rHRoSm2ffdwMWF82ts44mgz5kZFpOUVGRt+pFDh/S +ssutAoIBAEmEapldOHRXwhLId1+0vctRGo/WlvQht03UoDeSHqgPwuFZcXk3KGXB +8e8dlrJnJxtzzW+ImxtA2uIqjZL3L6nCJjU0Y4WhoRyH8QwFIVO41tHxzkT79Haj +KWMtwYIF6M7Vx7/0e0x/OGuZwDhRz+/79zg+wEJ8U3da58cEunn7ZNtCb/714aLC +p82yq8X9s5YczCx8vjOHgCrX4FtSEyMb4u10KkPnxpKYTigwVGakVOjXSOt1WZ8F +uY8ncNVrDThp3ryKxHOlKmeSlLOKEDAYXst1mtvi5kIaJctII3Lxh2Qak0FuY89E +siA0KpF80cuREmP/t3CDM2ZIJP9hL4ECggEAIFDIsON5SiE3rDKEXuEHtZdCndCt +AoHlfFdl3R4HuJLIgs4+m4oQnDs5ftNSwQCywKa/fCvnPZPor79PGeCJcOtSChZC +dAhW3W4PJmS0mF4JbaMKzkU4PhjO7BK/n2A6uvSc3jBVDdqI85I73SesUuwOg/ew +nSz7nf/Ym07I3Gt1/hCpFXpdceFALR4r1opxQxu6eSYWRg/3EJo8csWH/7o67WIM +TpwVP1rNB+3G1y8wfJlVUK6Tw5Y7xXgOu7Xx0T/wgvd0EPLv0le5SQ8nQJE2sZZw +pTSxFuIo0lnMyB7Y97uJhNwf0+X5NehAAgOwgVLPG4cjSco1ClByaqLOfw== +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/cert1/tjws.bks b/ASTJWSApp/resources/cert1/tjws.bks new file mode 100644 index 0000000..0363495 Binary files /dev/null and b/ASTJWSApp/resources/cert1/tjws.bks differ diff --git a/ASTJWSApp/resources/cert1/tjws.crt b/ASTJWSApp/resources/cert1/tjws.crt new file mode 100644 index 0000000..aefc9f8 --- /dev/null +++ b/ASTJWSApp/resources/cert1/tjws.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCAowCCQCqVV1V/HXh3zANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwls +b2NhbGhvc3QwHhcNMTgwMzI4MjI0NzA3WhcNMTkwMzI4MjI0NzA3WjAUMRIwEAYD +VQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCn +SdMgf+6fvxA+mO7+6iTxcb7Vnghw8KwkAGbsdeQig/DXCFa02aoCR6WH4B5Cdys6 +mekaDN9VWsEf4idSKMaJb3aUmcxNy6ALhFsT3++/3YeHuyDMhAdkw/kj+4RZ+9Jw +7hvs0PBARsrJfZcuJKMByGzrLWqfkrIJaVvRex4ymRU8Cth7vjI/wZZ2DdlPXx3e +Cc791+7vaPu6GXs136HB77T+ZtHoenXSzykdygChC2T0PJINlQJgpcIciVKesx6n +gOwWafnFJcaDGlJ7BDe+0qGequ/KZblU6asiVqpYW1aRp3nLusR4SduKUIQmBOGa +7jsLM+sgBhpPBAstckIS/9ouDEgy9vHcYgFQfUj/SrCCi+KQmQzov1uxXIWXQtRX +QPC1tzsyEeYVh0+tn8J1PDFO5AeI3qqFx56mZzcmWyjcUpPeLua2TuhxqkNOflfU +BVBNXCb0BNHGzQMXiMc+GX6KZ6eZY/I1Tuajd+orWcpNs9iU44RJ6IqOu+W2CTe1 +XQ3y3LHQo2+iYCD2hzYvTHQgGc3cMWygXCxT8HRyvP3bJR2ggYXeMgsRX/RN+dLQ +OYtgcrG9xnFekTTWbFc2nBPzNO0C+vW0yERjaGGbj+w035Ewzo+SEnnpWvYgb/8T +nfn8fQeBcx4N+oalikfe8nsWDaLWqMw23oLWstY2GwIDAQABMA0GCSqGSIb3DQEB +CwUAA4ICAQBQoENtF0YxFglAFKUkb0Dys7lcdiMmYZAA7o/wXkOiaEdhyoHQ6/wZ +b0RcXxyMRlE/hZ1ri8l+NlpkswiOI+16LIkvnim3YpToNdZq/+ICyrL9DhyPzKTi +oXxbQ/r6mhkxPEZPfoh7zPEOhSm3Vif1c3R865UWSw4Kd2aoV81qvHdMkZTustlT +zSyu8y5v2/txEVRbBwrrgkZe/h57EZs6YpCjsdAyNLEeQlgtIKeEbXT/9gxABo2u +Ok6Kbpn+bMuxQc13mjiira8xJ2ieobjHWrqA8pldYBHtwxRXqylJYU7poD0votsk +MnlXdFILKMk6KSqHlPDsFRZJAL/2mK438i9sRLU1nr9KE8qcIevzDPjf5zwdZnfR +marx95mhCiXVhnmEQ4PdyCG5ZHJErWqvKCI01+eCZlJk8k/lmROU6FU2I6MW3vna +kzhuHTyZwuCjWn2tSEuXbye4cam/CslZANHtlPu59ZYBgvQn/bZfHdDowBf/FLM5 +UYa/+56IL/vhNOgW2SRf+TI0NqS8y1LbVxJx/2f22irqqCY3T1KPu89iaOGOChDO +iIKyeG3WKZFXbeZvniNR/OnDqnSVVVmza3/sCmEsfiaqAH960W/fSBGKv4ugAdPn +d1Va+D6qRYAc0vrLxerXlO/XQsOvDXgTPjF8wEk5GIoUg3fcqmYkAQ== +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/cert1/tjws.csr b/ASTJWSApp/resources/cert1/tjws.csr new file mode 100644 index 0000000..d3fe43d --- /dev/null +++ b/ASTJWSApp/resources/cert1/tjws.csr @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEWTCCAkECAQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAp0nTIH/un78QPpju/uok8XG+1Z4IcPCsJABm7HXk +IoPw1whWtNmqAkelh+AeQncrOpnpGgzfVVrBH+InUijGiW92lJnMTcugC4RbE9/v +v92Hh7sgzIQHZMP5I/uEWfvScO4b7NDwQEbKyX2XLiSjAchs6y1qn5KyCWlb0Xse +MpkVPArYe74yP8GWdg3ZT18d3gnO/dfu72j7uhl7Nd+hwe+0/mbR6Hp10s8pHcoA +oQtk9DySDZUCYKXCHIlSnrMep4DsFmn5xSXGgxpSewQ3vtKhnqrvymW5VOmrIlaq +WFtWkad5y7rEeEnbilCEJgThmu47CzPrIAYaTwQLLXJCEv/aLgxIMvbx3GIBUH1I +/0qwgovikJkM6L9bsVyFl0LUV0Dwtbc7MhHmFYdPrZ/CdTwxTuQHiN6qhceepmc3 +Jlso3FKT3i7mtk7ocapDTn5X1AVQTVwm9ATRxs0DF4jHPhl+imenmWPyNU7mo3fq +K1nKTbPYlOOESeiKjrvltgk3tV0N8tyx0KNvomAg9oc2L0x0IBnN3DFsoFwsU/B0 +crz92yUdoIGF3jILEV/0TfnS0DmLYHKxvcZxXpE01mxXNpwT8zTtAvr1tMhEY2hh +m4/sNN+RMM6PkhJ56Vr2IG//E535/H0HgXMeDfqGpYpH3vJ7Fg2i1qjMNt6C1rLW +NhsCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQAnEbQFBdBJyowRbvijHtvCBdB8 +PWtN3VUbbR4KzYSygyg1lSvExqhl7/gJO1knjM1q9/fxi8DQcGg/P/IK0UQSnsSx +zgG3IyYMtKNAyeNWpN2inSXc0n+RK0CGiW0lyFy2GRmCNfkZRskBGQa8VhFqrxJS +LWRMcTPtalQYpTNAhQJSDs+Ls+PK2oyi/MTY37WuFLubj753X3gIdBzu6pddIkEv +BuM2r86LNwozZOOi9DG3QoQyLXlxFH3B4BPodAIxFA7OnxYTUqHf9IiZx+WYZtiq +0tCrM6D157n7hWdTG1+ODdSeQYZwqz5xvGKW78+7u6832EuviSU7BYKYq7kNZoWs +PvPrjsiTdPWoL8CLN3f7jJI8sEVX2kmGOBVTYh4YBE9/+x0tKaXcrU0pDMcKW7lL +cr6ieNAXv3oLvfE4fH+cHSokOSvS5JcpgJ2DG+qgozySuVBbFKCKB5zmbv+Z1E0n +cbDZdPxrRsXBKc4vrvMWjoAZ/akJXAK2USygCHpo1nDZSLyAKRRJsupTfWsB3Ipg +X16EBoulKPxndRoAS53MMF0PkgQKQowK4lQz9jSS/Ofeqw3pftw3nTjF7GlMg+S5 +KOD5kREtTSoD50AgG31sFCV80dOckwMzz2QgGmuaEE6pIm5kEDTEHdGZfeUj7v75 +FoC5Z71Dw23xgvf3nQ== +-----END CERTIFICATE REQUEST----- diff --git a/ASTJWSApp/resources/cert1/tjws.key b/ASTJWSApp/resources/cert1/tjws.key new file mode 100644 index 0000000..8e03c6d --- /dev/null +++ b/ASTJWSApp/resources/cert1/tjws.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJJwIBAAKCAgEAp0nTIH/un78QPpju/uok8XG+1Z4IcPCsJABm7HXkIoPw1whW +tNmqAkelh+AeQncrOpnpGgzfVVrBH+InUijGiW92lJnMTcugC4RbE9/vv92Hh7sg +zIQHZMP5I/uEWfvScO4b7NDwQEbKyX2XLiSjAchs6y1qn5KyCWlb0XseMpkVPArY +e74yP8GWdg3ZT18d3gnO/dfu72j7uhl7Nd+hwe+0/mbR6Hp10s8pHcoAoQtk9DyS +DZUCYKXCHIlSnrMep4DsFmn5xSXGgxpSewQ3vtKhnqrvymW5VOmrIlaqWFtWkad5 +y7rEeEnbilCEJgThmu47CzPrIAYaTwQLLXJCEv/aLgxIMvbx3GIBUH1I/0qwgovi +kJkM6L9bsVyFl0LUV0Dwtbc7MhHmFYdPrZ/CdTwxTuQHiN6qhceepmc3Jlso3FKT +3i7mtk7ocapDTn5X1AVQTVwm9ATRxs0DF4jHPhl+imenmWPyNU7mo3fqK1nKTbPY +lOOESeiKjrvltgk3tV0N8tyx0KNvomAg9oc2L0x0IBnN3DFsoFwsU/B0crz92yUd +oIGF3jILEV/0TfnS0DmLYHKxvcZxXpE01mxXNpwT8zTtAvr1tMhEY2hhm4/sNN+R +MM6PkhJ56Vr2IG//E535/H0HgXMeDfqGpYpH3vJ7Fg2i1qjMNt6C1rLWNhsCAwEA +AQKCAgBBbC+zQBT0SGZz9J9S9gLoodE9/YXTlWvc0INv6lMD5JGlps8x/wXrylVE +JDPxTmWLj3GIDIyy9sEcVPeHvAaY7Qx05QjvS7kVh/eOeD9sy5gbTuVu1huGHtYq +akzCXCdanuQw4y1yFb1suz8Kfq15HwbpmmNecKJL5/ZOoFWY+CFD0AIFssY4BN9w +382iqtIlabSXtYDuBCKeDyUOVp0OGU6xR0jEIFA/12B/E+bXFHuwwJdl1GaPoYOe +YV38TpSocVTjFyLlJPbTgtHK5kVezUUDploMz2eBe7i/vyDzWRUr9VE+iZYYbNn8 +56wmqjYIvy48HVvQtFJJoI02gr6vyXCzsDh10lfnyri18FLDmT9gosRcf2xaZeeQ +dSPpxwhwuATPOYcY56kOROyz4JBBuAOZ4YUAWqT9DD2G6t+hDS+DSvpqwtj62o/e +XYKmga/cimAs7y1ntdlAjRWuWFIdh7UqxBC34oT8B2N/ORo/ikaJODtIj5k9JF9R ++7RK+XFQ2/DgD/yjuA/fGoxf2f9Al5GKM2xFr2AB6dZos/M4cqX5EDl1TqTITtz8 +Fct1E/96kDBVUfS/rFfDWCj+gSNndNuKUEs3WHA5gif1EVFI+wc5jB2L1QNr75Tp +ACjW3kTWh4wklONG1LCnH+wX7GZhfuSpl22iH5ZlVKPFwBW7AQKCAQEA2NzCZKoe +Y7b1TMzc1W+ipUPmiSHr8VlcOf2Pwa/CDplhHxBN6a0kHWpFb+Y83Wz02JKYaLYQ +9qGpZGmyGBPdtQBFmkfCvXIOoyZldB+AfuKGWIvgZNewiTWU4dPdlbh7w6gj6RJv +HXqal/n+1PzKgRD8gpxBm+D9BhEqtASVq8dG/ZrvZHS0XA9C6+bFVsyCh/jBMDb7 +OJRSe8CP1llb99mi9anyrSfnTFmZyDmSs+9/GskDNKSSvBvIsEyoQASKASsgj1zz +Nyyy3d7hoAGZhKgo/+fno9zLwECt5NK2/PUhS6upydrwh6jfNjUL6LLd+k3jMgia +Sm7RKr8+rujJWwKCAQEAxXqz0iqJDPM+yzTiebdSk+9bfCPqCTLXbjw1GE32ftxV +tzntmk/NmlRmVeiu7wAULFn+kOd0MbwdKMogwMd43UnOFxGywNNEXzNTX9Ij5NNk +EPZ0NDwd/obvl9HhpyRa9U28XIw3U9zhU/wtxQ10TG1zfAXhlZGNwKYx1t/C4JAH +9dXwBhr+TpJ2ZyXaG4GZ12scs07pfFBe4NZV8o2NA0jRyIwYV/3tbo9WcZlDFEzt +cLbXt0nmkddWJ2vCcCT2PHhc6AeQrVsTq8Z2CzF1pTksYdZ5L1ch8Zu7JCLSg+HO +PWx3aBVgRu+KiJi35AqG8JBbjJpR+JlRYCvEkIciQQKCAQAcvfWNvfZVJPSR/zzt +lOQrnzo4xqQs0rkkfnTFKPRBVxbGNTT+WZJFy8X0NMGwXzZ8VcGZbzgEWBzJUDDo +fAmQab7P2d73mNxTx0z+/QXcy00fAzr0YpnlNZLL83aU12Sf4/MOewD7GTrQFbQu +qmp0fLna3bbcYA9o9HGCdnEX2UuRZS2BVO5qnSMzfNx+ypAqUU/Zgg/9ybq86CKo +OCO2T8QHZ0Tgqj8/oUh+fxLwgjeIZ0fjfERuZghNRXuvMGrSCNNB7QHXODdkrJue +x1d/e4IjmKrczvC6RFhH0Z2rHRoSm2ffdwMWF82ts44mgz5kZFpOUVGRt+pFDh/S +ssutAoIBAEmEapldOHRXwhLId1+0vctRGo/WlvQht03UoDeSHqgPwuFZcXk3KGXB +8e8dlrJnJxtzzW+ImxtA2uIqjZL3L6nCJjU0Y4WhoRyH8QwFIVO41tHxzkT79Haj +KWMtwYIF6M7Vx7/0e0x/OGuZwDhRz+/79zg+wEJ8U3da58cEunn7ZNtCb/714aLC +p82yq8X9s5YczCx8vjOHgCrX4FtSEyMb4u10KkPnxpKYTigwVGakVOjXSOt1WZ8F +uY8ncNVrDThp3ryKxHOlKmeSlLOKEDAYXst1mtvi5kIaJctII3Lxh2Qak0FuY89E +siA0KpF80cuREmP/t3CDM2ZIJP9hL4ECggEAIFDIsON5SiE3rDKEXuEHtZdCndCt +AoHlfFdl3R4HuJLIgs4+m4oQnDs5ftNSwQCywKa/fCvnPZPor79PGeCJcOtSChZC +dAhW3W4PJmS0mF4JbaMKzkU4PhjO7BK/n2A6uvSc3jBVDdqI85I73SesUuwOg/ew +nSz7nf/Ym07I3Gt1/hCpFXpdceFALR4r1opxQxu6eSYWRg/3EJo8csWH/7o67WIM +TpwVP1rNB+3G1y8wfJlVUK6Tw5Y7xXgOu7Xx0T/wgvd0EPLv0le5SQ8nQJE2sZZw +pTSxFuIo0lnMyB7Y97uJhNwf0+X5NehAAgOwgVLPG4cjSco1ClByaqLOfw== +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/new/client.p12 b/ASTJWSApp/resources/new/client.p12 new file mode 100644 index 0000000..a298502 Binary files /dev/null and b/ASTJWSApp/resources/new/client.p12 differ diff --git a/ASTJWSApp/resources/new/client.pem b/ASTJWSApp/resources/new/client.pem new file mode 100644 index 0000000..bb406c8 --- /dev/null +++ b/ASTJWSApp/resources/new/client.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJALCrphpx3C2rMA0GCSqGSIb3DQEBBQUAMG0xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MQ8wDQYDVQQKEwZOYXNkYXExDzANBgNVBAsTBk5hc2RhcTESMBAGA1UEAxMJbG9j +YWxob3N0MB4XDTE4MDMyODE3NTUyNFoXDTE5MDMyODE3NTUyNFowbTELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcTCk1lbmxvIFBhcmsx +DzANBgNVBAoTBk5hc2RhcTEPMA0GA1UECxMGTmFzZGFxMRIwEAYDVQQDEwlsb2Nh +bGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsWGfFUXNUiqTy +/iZ9opaJrngeCnzNm0AmKu8PBM8O2k4pTyOQrMbINKJFGRxSF+NL0z4CL9n7KLPW +uTpOQj9iWm44nWSMOrSKOwU5C/Fvj1dWR84K/eTXf6AuNHCYRIkZ0JSXlI17/jCv +YyjLzq/bdcYitI+qwP5hWeMUCunSyMrvGJXNV+oRYNaPoTjAwSeYcQebnxbMwBJo +3xiduSWsNgBrO50AhHRS/ju07JPKZmkL8ajtAuc2p9XheGc8gvxvn9cm7a6EchCG +FCJGFz+TubsbaTCJJvxdY0Y7QwqVFKmI8X99cg7pwA3xsncLTcU/dA3jJJwgO70I +1RiTsNk7AgMBAAGjgdIwgc8wHQYDVR0OBBYEFCG2o+64cKgU8mWJ4bYheuq1ROxj +MIGfBgNVHSMEgZcwgZSAFCG2o+64cKgU8mWJ4bYheuq1ROxjoXGkbzBtMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFy +azEPMA0GA1UEChMGTmFzZGFxMQ8wDQYDVQQLEwZOYXNkYXExEjAQBgNVBAMTCWxv +Y2FsaG9zdIIJALCrphpx3C2rMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBAIzQ4xEige3YW3JykNM9Pyf87rVDW1imXPYcBFsx8Unw/DCJ3ycjayNsyqnj +eeKt8sYvCVKGu5Mo+KYvHhRXLpsqZuZp2v3+9xtsuaMSQrL6tDByo+t7JjVL6roA +wevf0uK1nf/Qma4qFOBWNvdU0/aYmPVWmMpxOSzzL0V1G/c/DGADzAfg7jgm5nhy +lHAnZHg5DQjwVfoxzN8nNOWQDtDPl3kuGOKkT2j28ILvWfk2J5LjYTHMoetpMDRh +rFCjbXk939a00lZm57ykYxobw8r81eWDNAw1LMKF5B/6Mtd8CrASu17WDmLRk+7q +SBTezlJqplkPjcDEw/pF2prfpJ0= +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/new/client.pfx b/ASTJWSApp/resources/new/client.pfx new file mode 100644 index 0000000..9330cdf Binary files /dev/null and b/ASTJWSApp/resources/new/client.pfx differ diff --git a/ASTJWSApp/resources/new/client_key.pem b/ASTJWSApp/resources/new/client_key.pem new file mode 100644 index 0000000..1c09414 --- /dev/null +++ b/ASTJWSApp/resources/new/client_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,8DB6F1B4BED34B78 + +gAEC3AyTLWFMzJXhAVpExaRNl6GkapzIcPY+DRed+S35aOHBJlkwhdCJAVU9F9zQ ++rW+h/nCfu9Plx8hnpVtPa4gpSwGtWfnDVK7bTYWzyKpFlPlzCI6mCtX0N2AS3JG +hinkXfUcHucfEy3iSmT9W7hbbW78ejJDOYtNWrKKG4pFRRgnbNKBp8yHD0kJ6CYy +2M8Zy2ZLKN7CgQLUInYim7EqqKdi2JBGgIBpngUsoS7wkSnBUiKqvZ96Re+EdhfS +Z3dcLkZP8WWur0zy2ADOUO6UYfIIH99rxrbskXqmA25wZct5DsFIHct1Z0iNLHMe +TQfuzJyqo7khuEH+iQadOFu5HeBVFe+GvEe9OU8hfNkIWE/YDU8VL0qVDCkukxYM +81Ht5XZJeRXo8MZyVyCXnOKvaYuY87kQxNpv5z9ws6LgbH1wzwTBQYuu+X1R2603 +jst2OAhu+vqllIYPxSbvm30IH/wiYQJVDRaoLAcHzqwHW1ghsqui8HpqNPKTO00Z +RH6DJdHrZl4UdauHS7t+hnbWEu+x5GH3a+/DlZbnU9UTsbGeXRS/kl3SqHaXIwsH +Py6wY5VpG2G0gjYBUpL9BxLH8YYjpHWAJDR8wZKPpVY4TDFEBC2wc5F+on2bx6hK +KY+WjPDb9TLtI5kO6ew0Ty+2EmmzflQ9kVI86F9jeoYcc1T/KRMFc/N44wuawsFq +RM3nXPFzWWnsFipahrpsJxgYvMjYst4tMSK3bYv0DyMy4vOrw8a7+XvZAiWySXAI +ZQ7JuQefRnTAD0Tng6GRt1ZYetm1CG6NRVCQcJg+Js2Y0VwyRQjYqXhPo23GDlPZ +Nfiwl4v4R69leMFKDGAbUwNmyJig8xS7NcNH1uMsZQBO0xlG0zURhNroYv59Q2pA +gXUfvVkfmXmKkvuNluz8nYZsDJz1oCbUqaGRUNjmHWHq1MRtPO5EGYB/6hgv+4ew +UsyUnCuG8dD5hvDZUb/6Eo4LwJUGYfE9cLRRh550FchxkFyy6pbXdUPHmK6KutU9 +d2T8HXLOD7NotfRSbdVdKDNM78m0StgTk14Kq78NIilMm6kYBbClzpNWAkFeTnrD +zaUXrpgF7LCq7cBFSWkTERg64yUS4AeQHzIcL6Yc/PdwtEqu1RQhDXlPpVXP/rFW +wMKXPh2OSfALoUGaqzeaksa02gyQ1ago3GGxC/c6Y/Dp7sQKAcutsjfXslW9nD/1 +qdprzjuy8jZ26XRyr/iXYpmr/6/S9xDb2rjoyB7q9T6d8ZDuDuEJsKZZc/I+3O6e +mYZww/fqd9NB3hmLD1R0wh0VXL7+fzX3q9djZ5zzgFvYlvgxhhQefnJkBBw4bhtM +ZgLzvRcWo0luOwVOD9JFItpRdTNeLIbIMsubYbkWS2eD/e2mvF/kiMWIuqduAaY0 +zMLrpOx8g7BA3LQdB+KLqZoaI1kPKBMKYS6c1iAcm8HfvZQE5KVrBTDzg5vREWYs +eE5qI/m5McIZWKcHwQyscVyOCgPQgbm7Dsuc+GD7V1HLbvfTF1FdQn7G9R9L4/80 +sUIuT9B65tu1C7t9Qyk9/6s6dZh4Z0+e4J+Xv/C2dnrVPfTdv8zMobPkT5fBpVZ8 +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/new/clienttruststore.bks b/ASTJWSApp/resources/new/clienttruststore.bks new file mode 100644 index 0000000..14359d8 Binary files /dev/null and b/ASTJWSApp/resources/new/clienttruststore.bks differ diff --git a/ASTJWSApp/resources/new/server.p12 b/ASTJWSApp/resources/new/server.p12 new file mode 100644 index 0000000..ac610b3 Binary files /dev/null and b/ASTJWSApp/resources/new/server.p12 differ diff --git a/ASTJWSApp/resources/new/server.pem b/ASTJWSApp/resources/new/server.pem new file mode 100644 index 0000000..df6baab --- /dev/null +++ b/ASTJWSApp/resources/new/server.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJAJsDgMZOdkxzMA0GCSqGSIb3DQEBBQUAMG0xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MQ8wDQYDVQQKEwZOYXNkYXExDzANBgNVBAsTBk5hc2RhcTESMBAGA1UEAxMJbG9j +YWxob3N0MB4XDTE4MDMyODE3NTYwMloXDTE5MDMyODE3NTYwMlowbTELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcTCk1lbmxvIFBhcmsx +DzANBgNVBAoTBk5hc2RhcTEPMA0GA1UECxMGTmFzZGFxMRIwEAYDVQQDEwlsb2Nh +bGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDf3l3BL4Q0tDLf +HTqpBxkBlA1In0i+hQfRBGMAVuLE9vq2w90GMOsv/I6dzL1EP5sPay/Bhza4UIM1 +8KCFyv4gbynAv+0KRSFDMbp1KumV0AEHhbX/Sq9iZ6JFQXzde2sPrd0g0RU6Oa6z +Oty7kjShRgu3QZA/dRjoXNUKOwU1V5p/BGBqDTEffiZ6hQ/U4nVemzoi4PnRZwqU +53yvQ7w78Og4+kQXPsLNwPVyrA+kTUSy/V7CCKYOPh1z3/41PlmQCKqNRqb6UEaF +2Pmk0CcWAZQ4n7MFz+VZSVjJ8WoC+UUY6Fr9pxEFo8/awsPiEkYp+WjnXe2HRiJH +Hyjvj1AFAgMBAAGjgdIwgc8wHQYDVR0OBBYEFFRCJz7y4CBpyn7Vb/icVSdowsKJ +MIGfBgNVHSMEgZcwgZSAFFRCJz7y4CBpyn7Vb/icVSdowsKJoXGkbzBtMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFy +azEPMA0GA1UEChMGTmFzZGFxMQ8wDQYDVQQLEwZOYXNkYXExEjAQBgNVBAMTCWxv +Y2FsaG9zdIIJAJsDgMZOdkxzMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBANQKOOeAQQ/qBSg+KGihCgsC0+e1v+8UXjV2KsjfV4bxASXIJiHmdz4vXGXq +RXf2nh4Exxty045of84ka9Bg/OIDEz/PE912Utxnbu97PgSIQrxtpbA/Yopk91Yk +NDx3FyQ8bkEw8a/q4b7PfOa33CfwSR8bqj2qOMBoadGBPXRMn6t7HTndM3D2g7tp +qe9mRP9EF/GOCL/XpaYbz1K4baXv+B07ED0v5eNniPc1S5ge6RgWdEp7+sok8FDd +irpPGIqewrfsSbNZA9phSLkDh+cdN17MRjl/tkceE3mUXTTljBV1xVczgeR3DiMq +HpZhhh4h+Wa8zaQBarYKQ/bh0c0= +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/new/server.pfx b/ASTJWSApp/resources/new/server.pfx new file mode 100644 index 0000000..15b1825 Binary files /dev/null and b/ASTJWSApp/resources/new/server.pfx differ diff --git a/ASTJWSApp/resources/new/server_key.pem b/ASTJWSApp/resources/new/server_key.pem new file mode 100644 index 0000000..6b10544 --- /dev/null +++ b/ASTJWSApp/resources/new/server_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,CF1ED9E65DB32403 + +NQGxggeBaYhS97WqDkXM9I1Ad5n8NGnaMS14wbimOVlXcLwrzfSrX1TrfIv+Ur65 +GsipLv4zLdGDPV38NlyZet8hVaAaHubAsz5slgG3c/FE3lglLn0dDZBmbKwlY9Ll +psdcNi3+tDZdlbghHapzu2Ur4BMkaKmClUvGy2X1BH+PxUFzP5x9Q+aNFxcPiasI +21+FXsaqU2UQT06UaTtGeGEAxl85fVS+AUD3Q5rNlKDu3STioWTytbKQQyIgdCrb +oj0ybzIzKD4hMwR36RaMBwWcLTWVb3UhiRdml6V2x163OXp3tW/l3pK5TgdYQLrp +FPxNth/JblzjCpLFBk3Gly0GPClfPR6n2yn8E1G2vBrlALwMdDR31UiDV/t2kSge +TUAfEBNzD7gclil/neKfyiEBjPMbnHKr5UBrY867LnsxrQDTxYUW8viZ2qJpebHX +EN4gqM60HJVnULzZJ2rOpLigDHA1JfSpOMDJxjEQBqcuVJwYcKkGaJOv0q7b9Mrz +vu6MF2xmo0wsLXXVFTKHL62ZhThR7o72q/3fYdMP4CKABQIj/VZlJ4fvwZle5ae/ +U4jUgBX79GXM5AktVof9ETUqn4j3sQee91PRlaVBTHE1Aw1cey6ehKdU7v0uQZJD +ghLIolcERhFQyI2A8hfd+I6FViMV0T4nri3WFvkfXWikowdjYvLXPVjsnDWpvI2C +EpEYJe5+c0LSlX6a5lu8P5JYtG13ikyb4rp4V7Y518ekZ1ZW6g4Aga7ieY0T8JGm +EYp8e5nnO7LG/BNIeCF4s/7cOyaEpuDL6T4L9Y42wnMx3l+rH0aSvHvbqo7gUHu2 +jlGQoSwBd92TOploF1Kn63Jphlq3EhcUHBMtSnvPKdjQjhbpVPmoyhGGN/VbhyHz +JQEX84aPw72o6M61NKpW/E3zvhPHXcBUe3AHwyVyRNGEMH1r0zfK0y2zhnuHJfBO +Bs9gLH1xYBBzme3nmNVAfvGN3uzFygTJqE3XhyJLrL3NT31/pkmE/M+APYlJh+7l +CMp1ZPeahGzhghbjJXORhNWDaOVej2037B/i5OK7EMKvVlMtEw9OjLC+tWUtnNvQ +JJp1ToBz6QOF/OAFOgh98j9Lm5sxzKR7DI3wljjMm8x8s31cUlXT0WeNgKCiIFJE +xhscBAzvY0aqlZC+RUYUf9uxSApgE3wgjlxgtz8mF9LvVOhfVu0TsMdfcf8DWozh +J/g+hv//G7sxhBUneDpNAE2jvRIN61S5BmP9E9yfhKAKTrsXkxjl1GHxqMTOpX18 +3HYc5ciu3Xmvsyc7Ze3LxZ8BK+xrtS6Mm+u9SbF+IfI7tvbPsBnjRmiBzhVwPitA +qVdA5Py71CT2J5aW0T8kHF8fmcNw/7CpAH0O3hFKECemY7IJD2hEZyfQeepZjZrb +P4YR6hHHvcaDZN8eW7H8daRByHOhkqMFSwMsmrwEmxoF5bCILvz9++jBYR8kGlWX +Cm+2A74ORA5/RKwBEdCLiLTk6QSXKcoB8LLrbeVCNIqrUPpRPJ3B5lEO2da4ch/X +miqnGm6zsxkwebJHAf+Pq0ySmmwurjKduzNwTa0HnLkzWk9gCmX5D2WLtLSu6cd5 +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/new/servertruststore.bks b/ASTJWSApp/resources/new/servertruststore.bks new file mode 100644 index 0000000..d61b69d Binary files /dev/null and b/ASTJWSApp/resources/new/servertruststore.bks differ diff --git a/ASTJWSApp/resources/raw/client.p12 b/ASTJWSApp/resources/raw/client.p12 new file mode 100644 index 0000000..9192b4b Binary files /dev/null and b/ASTJWSApp/resources/raw/client.p12 differ diff --git a/ASTJWSApp/resources/raw/client.pem b/ASTJWSApp/resources/raw/client.pem new file mode 100644 index 0000000..e2c619b --- /dev/null +++ b/ASTJWSApp/resources/raw/client.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEVDCCAzygAwIBAgIJAJbgrvcXD5iVMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MRUwEwYDVQQKEwxSU0xha3JhIEluYy4xFTATBgNVBAsTDFJTTGFrcmEgSW5jLjES +MBAGA1UEAxMJbG9jYWxob3N0MB4XDTE4MDMyMzE5MTQyNVoXDTE5MDMyMzE5MTQy +NVoweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcT +Ck1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMGA1UECxMMUlNM +YWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCz+y2eOQhDA0zgWqC/ZghFYwagN2LmxtkP7N6MxL3X27y4 ++1kaB+/INznc3ZUp6jAlvD9aRDiu26Bki717lectOCZ1xpULoQNs1EcMZEIXbgKZ +vive2mZLG5I6jYz3APZcoXMf5ImLm8bW9MGSljksPO/1/iArrSnqnILxNkgFJZDU +PYFoXKN8B+JtPYA4/hw7cZxnjDUV3xrL4+Tu2iNL/Fp7HQBT6iQMYyZrxtA1sSu4 +2BhWJvT/MlivmfuexYwbW8rfU6gBpP3ROZw318n2OHJ1nR9UCp7SMTTahTtqOu0y +U7Pewbb+/95g/s7LwH1Xaqf7GtvZFBzwHoaPV7ffAgMBAAGjgd4wgdswHQYDVR0O +BBYEFJdmLczbZS2lH3rA6Rowd0qScpryMIGrBgNVHSMEgaMwgaCAFJdmLczbZS2l +H3rA6Rowd0qScpryoX2kezB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv +cm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazEVMBMGA1UEChMMUlNMYWtyYSBJbmMu +MRUwEwYDVQQLEwxSU0xha3JhIEluYy4xEjAQBgNVBAMTCWxvY2FsaG9zdIIJAJbg +rvcXD5iVMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAIBx3KyftfNP +CiLzXWTwtrxdKTiLvJT0cP16TDfSzrEwUEzeZiB9GaOpgN7eLX+kp40uOzPasENp +3NdvyKjSxYbWNmiMJmYv4f9cd65zM4QaJshF1qsXDkcyXprQHHHmeqAxZ50+rxyD +98uYK2HS2LNYOvssWdB0EtYFqdEHLw7ACWPXJ0vh735mdWghSP4enQTum2smOR2T +GUljLVBzwUYczjot21hfipm/tWwuo5Q2thYo4g0+mTEkxyDfjk3ligwKMIAOro4q +ZIw/JpiEVcmNxmRBR4XX7Stpxrypl+993YzfY4AGvHhm29kulyiN4tSdqumph2Nr +x1UxuWX08Z4= +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/raw/client_key.pem b/ASTJWSApp/resources/raw/client_key.pem new file mode 100644 index 0000000..d44b0fb --- /dev/null +++ b/ASTJWSApp/resources/raw/client_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,6CC8A662BE175CD9 + +kIADEqIhWqzGAwN0VOldoqbQmp730pS06t9eoSOT8OfgfcHw/Zmktw6z1lUNrtGm +LhJO45PU0/fuWwbl2mXQNyluU81P73xvE8WEZOO+k0PQu0XonlMQ1RyPa8//h8zC +jj2bA3+b5KqfIJ6qDDp5nI1NQmUi0ZGGkyuxZqew/6uRcw1+tByyNfW9KGL0q/ry +h38QkRie8J6xemWX4HDKn//kiNijz7LFjIqU6eVwsB+xmNTpHJBBMnZmb4soVq9q +iBq23NCrsWfwVaONPXaMyitVJrP1QmT6lDfbQlMNb090V01XdXBOGxMvOtZO+OVh +XsT9T+Wdhw6nBcEEek5MlyftiYTQq4jxuoDKFFfl7l7cfCe9di2SllPpoBx5zfGV +lulAtcDEQDX4EIkGMcBB5uRupop94ItngpSRAXwrntMHBIZ0iadSY6ftNEL6N1JP +purj71UxbBavIrGJLu+uGcHjgjPhlGq1TCgopXQEdB426/PkPsBw2TPtMguIzutl +A3ApjvVXF3nFvSRRs12lW5hKoFaYtAFwSUqnkHW/4fTw6RpzxDj865W+KyIqJfbp +NSrtgRO6wbnCTgGU7uvMwznpbxq9SzudtJHDNDksW+Kr8hUfm5fElh0SuW0KeFj/ +Ja/zKRs1p6CCrp98J4mtdE6fh4mH5ZHNP4OJrVkfkcyAeL6mLluPcmHO444o6MvB +L4lXv6JQfGBEBqmSK0/mtaXbAEiuEioOQfJDzG4SX8riZopaYG9GeZO51N6i4aly +3LuE1xmpVsi+naEvCz5o5PJNaNgqouFBsbxPTnqVXNVdFkPrFtqm+Mr1/D3ilzQK +KmzmZxQLB676UvuF23hmpSnqgYw+FJP8FDweSQpJYlEFHsR4vXZwQjEhRc+qeQDN +e5NTNMAqL7euXLnwCVxo93XivrW+y1GEEzDvIVkhlKl9CUwK6G0OKBjcxlGu6nCa +V0AnIYT07wFPs2pmSWc+EJFW8bCcVMKPatRejQ6uxz6ZmOBtqDLLFxD5FlrQws76 +9qczxFFRdDsTzy7cvM+sC9smZ5xgVCIVVjFytCfg4oYj/SP+/y8a/2fqeXGrWDsO +XBD6oyrlhD1ZkHW0cv6/6OXF5rdyWBFggclmHvXHjoovj9OKMhRChYeOMlnL8VC+ +3Z8qs5AIfZlyjYpTxO8ppVFOW8yRVTqnKRx48kvTV8oyO/mcaUEk7d7VZGgg5UBW +nDLQjhbscJoz/cqFd0A16FFINuhIQbBPF82E8L++4911S7y0tkkNNNpDZn1OqiyQ +54HHo8nfsYq2UoBKOFPA776p3bj/t+lzDIh9oAdvz70Yb9KdLSsBN5VV5mgCti1P +WwSOFOwe8xywbxbnauGQprtX2ci79eJ92xnidsPEw+XiSGA67GWFWL1HcEqqYGYy +BhiPiTxvqjeRHLOvq0gF3IvZpePXEei/QQKNGIZtlI6iWt48x5EcsHVwi0Yxfc8x +AC1t5Wb2hZlT2TbK6EBKYEGmwfrbQPSfcZ0sK226dzjYMuDOI5VveXJ+aDOgLvWu +1ZZb9Ys2XBo9EznrxSWUZWxaJcQFGsZcVPnZzrJxmbbCf2AGgEYBBA== +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/raw/clienttruststore.bks b/ASTJWSApp/resources/raw/clienttruststore.bks new file mode 100644 index 0000000..89ca04c Binary files /dev/null and b/ASTJWSApp/resources/raw/clienttruststore.bks differ diff --git a/ASTJWSApp/resources/raw/server.p12 b/ASTJWSApp/resources/raw/server.p12 new file mode 100644 index 0000000..47f0573 Binary files /dev/null and b/ASTJWSApp/resources/raw/server.p12 differ diff --git a/ASTJWSApp/resources/raw/server.pem b/ASTJWSApp/resources/raw/server.pem new file mode 100644 index 0000000..58bc9d5 --- /dev/null +++ b/ASTJWSApp/resources/raw/server.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEVDCCAzygAwIBAgIJAKTXo3yWpEJhMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr +MRUwEwYDVQQKEwxSU0xha3JhIEluYy4xFTATBgNVBAsTDFJTTGFrcmEgSW5jLjES +MBAGA1UEAxMJbG9jYWxob3N0MB4XDTE4MDMyMzE5MTUyM1oXDTE5MDMyMzE5MTUy +M1oweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcT +Ck1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMGA1UECxMMUlNM +YWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDxEHQhIFDX7E/421vNDI3m2eivOlxP1WWxS8AIcyO9r6Ct +nOugirRFrk9ESZWaXSxJ62NO1cw6Xp25+BbgSBmSHZsnTK8ubP5uBFT+YjCHyciu +PxwXbsY2sMnrlnU7hRMS+TTFdYnpQqB8+t5EHKwqmM1hOlCxjwZ+P760AKGtMbxp +cLoZRDDOCViQ1rrJjVOQZW8BTH8IJL0aSQ93BJifl5BmRm4tO2fPsKkqpWQco/b2 +/Hgc+1gdEjIJ8oXuEIKcDpyYC/4EjQDDe/4+i3gxmjwN+WtVI7kDS+YKUsAAUrfT +9kl6Gt3BUquQN12yjjyDtDSKT08bJ22JFTngV14PAgMBAAGjgd4wgdswHQYDVR0O +BBYEFLBcLnm6umqvvoEL1j2iGDF/hnAfMIGrBgNVHSMEgaMwgaCAFLBcLnm6umqv +voEL1j2iGDF/hnAfoX2kezB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv +cm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazEVMBMGA1UEChMMUlNMYWtyYSBJbmMu +MRUwEwYDVQQLEwxSU0xha3JhIEluYy4xEjAQBgNVBAMTCWxvY2FsaG9zdIIJAKTX +o3yWpEJhMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALajjuGE5SRL ++r177bOC5xoqSmZ0feJmlr+xapookjxkGgYMN3fKt3c9xEruC37zJI6n/+L6323p +xilfaC/GyhFJxqOvfwQG5/IVAI1AqlGjouni9KbvXojXc7XGBovUMkUGN2iqhQ00 +AFv7klUihNq9LxUK++HdQgzDueCSpijg4iGj5GS7Bh7mC8VZ+L+BqxUWKbkiThdT +O41cqQXDQj101id1JZxy6HB3/PeBsw7CDFqgHhexckuqDtSX7VK1ruQe81X9UKax +pN/aNagJ1S/uttf4vqebYUi3HWmLTwyGx03zgRBhqhSxbVcYnGjdYu8q+kmavufu +kCkN0ngMMq4= +-----END CERTIFICATE----- diff --git a/ASTJWSApp/resources/raw/server_key.pem b/ASTJWSApp/resources/raw/server_key.pem new file mode 100644 index 0000000..023ae0d --- /dev/null +++ b/ASTJWSApp/resources/raw/server_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,124ED8A8710D3E81 + +lR0aj+JlGDtrPFpvwys68ybWQtGhrhY/XuOUepPOxGYTMOq/NhsiOcFKCzX5sj3O +fkNtfQ9vFzzEaJtidwMFMgYYpnruCZuAwPCFJO4fTJ2uwVrfv151CVua3tBW9RJN +ianP3o5RQRbwrCdI+P5+nEKoRQjMHD6kdwp+IY1b/vq97dbVOZQDg6x6fUeoyiJA +MBcP6w1lVK0LS5EEIMWTP4u4Dn2cHoOYw9vEQRJv1xpdaauSWJpKaCZazEER8glw +7pnPiIRAEx0t2uii5sRGjajp3QAhLKR8FKqOBXhGo2nuwkAalRV5326DvM1RQexY +xZV4i4623Ch8HBBrABZVlXZpf370vjL+V3k2/A9RhZfsCeR+NO+pFIaZZnMpOWZP +ysGlyPzaDxdvLu3BdxjPAWPGew0WsvDUggJ6T5EFuPgLB7ZGf7KV/V6kv7MFJ2Ig +FPM9wos9kg5WIb4g+1uVUoHRrbpWBNl+B4NpEBYHwV7/5DpwXYWDsPRKxlO5ZoGm +9SJ/FCubJJoO/dUHwm24Lla9Yj596IGOYduqNkTLHKvsaSxq3eedFvpvcTxDO8jM +n2BX6df0poIow4RQEggrNb4a0Softoqp+NvQxcsgRKV3a0byQfEplopeTsSLcaqj +28bVs/Eif8gIBNjntIRIMqUrmYwac4VCXvIVaVG7/4LwxgJ0YU5PXy8UCfrj15S4 ++Xn4bh0nEqi6M4lDlRxm3D9SSvAXypb0r3xs774IygbnffbIyKAuR86BU5XNt+mU +VbwcAbZcR1dcD7av8TKwSN4BoU7a6BVbfwyJI8kiF8bqMp4xAk+9IC/j98zzeRWl +qhJei0569l+d8I+PqdO4E/gdnfdTIA5r8G0iacZa2CFBTgo27AU23VL9AIdzkGJK +VBSx9ND9MFbNcpVJRA79D+GKwsr0hDJqG2XutDlAScHh/S7Vyc/BaEF4uKkZR3L3 +Ct+d5z9GdA6OtzP6A9ckccJ0l9wLsr927QtswOP1+81fUKhi7UlUHCfETUEfFHJi +30zEXH7SHHk6Tl4NjpYzIN/JLBsbuAQL44nwgxoMdB7JZKdzQDS/FuWUUEoPEnhm +jtgfAnVSmcGE867Pn15zcsTGTcj/9LUqKfLd/VzNP0RFRPPr9/w/x5dz8rUuvplf ++ycxcJ9qBPa4UTqZClsYdWxFtW5mCHdgbjT8W6WdJXczOlBOKFS8Y6Ed5x0OZihi +jSvNYT6BcNkINWMW3aekyqRkoGog+6DTgGBHb1uQXvh04XtDNc0yQsOZjt5qdZsI +DOOmEeYOl0GumDAh5iCa21YwuIqfF8DAffNXBv5PVg4yZVXFi5DHClyZOfRx8n/4 +PrOJOOdFN9RnkYBcI7AQndXmtNjk9i/50rCO5n+JsNfii455SIb7z3a7veKow2We +zBbhG8BEn65X2wbprXwQ6ZCS+JSw7k9XejT/xKuY+/NVQmcfxnaZgZYQI8O+wayc +lBySOcFLp8rkhW+0KXN4tSNktNOXyQTAxhVVPqqdSQtaN3XjDuZL5bgY6fgVH1RV +AuxVr73gfZOtaQF/magJxIYRdpRROklAr3thKor/r1tf0d1K4sQBVg== +-----END RSA PRIVATE KEY----- diff --git a/ASTJWSApp/resources/raw/servertruststore.jks b/ASTJWSApp/resources/raw/servertruststore.jks new file mode 100644 index 0000000..fbcd4d2 Binary files /dev/null and b/ASTJWSApp/resources/raw/servertruststore.jks differ diff --git a/ASTJWSApp/runBuild.sh b/ASTJWSApp/runBuild.sh new file mode 100644 index 0000000..f56cf87 --- /dev/null +++ b/ASTJWSApp/runBuild.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# This script works only when the device is rooted. +# Author: Rohtash Singh Lakra (rohtash.singh@gmail.com) + +adb push ./TJWSApp/build/outputs/apk/debug/TJWSApp-debug.apk /sdcard/ +adb shell su -c 'rm /system/app/TJWSApp-debug.apk' +adb shell su -c 'cp /sdcard/TJWSApp-debug.apk /system/app/' +sleep 5 +adb shell am start com.rslakra.android.tjwsasapp/.SplashActivity \ No newline at end of file diff --git a/ASTJWSApp/settings.gradle b/ASTJWSApp/settings.gradle new file mode 100644 index 0000000..d8de041 --- /dev/null +++ b/ASTJWSApp/settings.gradle @@ -0,0 +1 @@ +include ':ATJWSApp' diff --git a/Atjeews/.classpath b/Atjeews/.classpath new file mode 100755 index 0000000..2c4c7e3 --- /dev/null +++ b/Atjeews/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Atjeews/.gitignore b/Atjeews/.gitignore new file mode 100755 index 0000000..26b2c99 --- /dev/null +++ b/Atjeews/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/gen/ \ No newline at end of file diff --git a/Atjeews/.project b/Atjeews/.project new file mode 100755 index 0000000..c4cef81 --- /dev/null +++ b/Atjeews/.project @@ -0,0 +1,33 @@ + + + ATJEWSEclipse + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/Atjeews/.settings/org.eclipse.jdt.core.prefs b/Atjeews/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 0000000..54e493c --- /dev/null +++ b/Atjeews/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/Atjeews/AndroidManifest.xml b/Atjeews/AndroidManifest.xml new file mode 100755 index 0000000..17dd284 --- /dev/null +++ b/Atjeews/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Atjeews/README.md b/Atjeews/README.md new file mode 100755 index 0000000..e2c3c0a --- /dev/null +++ b/Atjeews/README.md @@ -0,0 +1,4 @@ +Atjeews +======= + +Android wrapper for TJWS diff --git a/Atjeews/bee-dexwar.xml b/Atjeews/bee-dexwar.xml new file mode 100755 index 0000000..945051a --- /dev/null +++ b/Atjeews/bee-dexwar.xml @@ -0,0 +1,465 @@ + + + + + + + +]> + + + &android_sdk;/build-tools/android-⌖/lib/dx.jar + + + + + / + + + + + /jre + + + \\jre + + + + + + + + + + + + + &jasper_lib; + + &servlet_lib; + + + /lib/tools.jar + + &android_sdk;/platforms/android-10/android.jar + + + + + + + + + + + + &jasper_lib; + + + + + + Jasper lib (jar) not found please check script ENTITY jasper_lib, itspecified currently as: &jasper_lib; + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + war_temp + + + + + + + + + + + + ~#args#~ + + + + + Usage: bee -- <original war path> [<destination war with 'dalvik' codes>] + + + + + + + + + + + + + + + + true + + + + + + Cleaning working folder + + + + /*/*/*/*/*/*/*/*/*/*/*/*/*/* + + + + + + + + + + Can not clean working directory, please do it manually and restart the script + + + + + + + + + + + + + + + + + + /WEB-INF/lib + + + + + + + + + + + + + + + + + + + + + + /WEB-INF/classes/* + + + + + + /WEB-INF/lib/from-classes.jar + + + + 0 + + + + + + + + + + + 1 + + + + + + + + + + 1 + + + + Zipping app classes + + + + + + + + /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/* + + + + + + + + + + + + /WEB-INF + + + + + + /META-INF/websocket + + + + + + + + + /websocket.info + + + + + &tjws_wskt_lib; + + &fast_scan_lib; + + maven:javax.websocket:javax.websocket-api:1.1 + + + Processing server endpoints + + + + + + + + + /META-INF/jsp-classes + + + + + + Compiling JSP + + -classpath + + -webapp + + -d + + -compile + + + Exception at jsp pre-compile + + + + + + + + + + /WEB-INF/lib/jsp-classes.jar + + + + + + + + + + /org + + + + + + + + + + + /* + + + Zipping JSP classes + + + + + + + + No JSP + + + + + + + /WEB-INF/lib + + + + + + /* + + + + + + + + + + /WEB-INF/lib-dex + + + + + + + + + + true + + + + + + + + --dex + + + --output= + + + + + + + + .jar + + + + + + + + + + + + /* + + + + + + + + + + Couldn't remove original jars from web-inf/lib, restart script with recover option : bee -Drecover=true -- <war file> [other used params] + + + + + + + /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .war + + + + + + + + /* + + + + + + + Completed. + + + diff --git a/Atjeews/bee-sign.xml b/Atjeews/bee-sign.xml new file mode 100755 index 0000000..71f3a13 --- /dev/null +++ b/Atjeews/bee-sign.xml @@ -0,0 +1,116 @@ + + + + + + + +]> + + + + + + apk_temp + + + + + + 0 + + + + + + / + + + + .apk + + + + + + + + + + + /*/*/*/*/*/*/*/*/*/*/*/*/*/* + + + + + + + + + + + + + /META-INF/services + + + + + + + + &tjws_src;/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator + + + + + + + + + + /* + + + + + + + + -verbose + -sigalg + SHA1withRSA + -digestalg + SHA1 + -keystore + &keystore; + + &alias; + + + + + .align + + + + -v + 4 + + + + + + + + + + + Done. + + + \ No newline at end of file diff --git a/Atjeews/default.properties b/Atjeews/default.properties new file mode 100755 index 0000000..51bdc29 --- /dev/null +++ b/Atjeews/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=Google Inc.:Google APIs:7 diff --git a/Atjeews/doc/Creation web application for Atrjeews.docx b/Atjeews/doc/Creation web application for Atrjeews.docx new file mode 100755 index 0000000..160a115 Binary files /dev/null and b/Atjeews/doc/Creation web application for Atrjeews.docx differ diff --git a/Atjeews/doc/atjeews_main.png b/Atjeews/doc/atjeews_main.png new file mode 100755 index 0000000..fa64c84 Binary files /dev/null and b/Atjeews/doc/atjeews_main.png differ diff --git a/Atjeews/doc/atjeews_manage.png b/Atjeews/doc/atjeews_manage.png new file mode 100755 index 0000000..3912627 Binary files /dev/null and b/Atjeews/doc/atjeews_manage.png differ diff --git a/Atjeews/doc/atjeews_settings.png b/Atjeews/doc/atjeews_settings.png new file mode 100755 index 0000000..46fcf36 Binary files /dev/null and b/Atjeews/doc/atjeews_settings.png differ diff --git a/Atjeews/doc/feauture_graphics.png b/Atjeews/doc/feauture_graphics.png new file mode 100755 index 0000000..7b11da3 Binary files /dev/null and b/Atjeews/doc/feauture_graphics.png differ diff --git a/Atjeews/doc/future b/Atjeews/doc/future new file mode 100755 index 0000000..afaf690 --- /dev/null +++ b/Atjeews/doc/future @@ -0,0 +1,2 @@ +1. catching unhandled exception +2. power lock \ No newline at end of file diff --git a/Atjeews/doc/hires_app_icon.png b/Atjeews/doc/hires_app_icon.png new file mode 100755 index 0000000..4544268 Binary files /dev/null and b/Atjeews/doc/hires_app_icon.png differ diff --git a/Atjeews/doc/promo.png b/Atjeews/doc/promo.png new file mode 100755 index 0000000..1fd693f Binary files /dev/null and b/Atjeews/doc/promo.png differ diff --git a/Atjeews/libs/jasper-7.0.27.1.jar b/Atjeews/libs/jasper-7.0.27.1.jar new file mode 100755 index 0000000..7fa2bba Binary files /dev/null and b/Atjeews/libs/jasper-7.0.27.1.jar differ diff --git a/Atjeews/libs/javax.websocket-api-1.0-rc5.jar b/Atjeews/libs/javax.websocket-api-1.0-rc5.jar new file mode 100755 index 0000000..6889a79 Binary files /dev/null and b/Atjeews/libs/javax.websocket-api-1.0-rc5.jar differ diff --git a/Atjeews/libs/javax.websocket-client-api-1.0-rc5.jar b/Atjeews/libs/javax.websocket-client-api-1.0-rc5.jar new file mode 100755 index 0000000..e1dfee7 Binary files /dev/null and b/Atjeews/libs/javax.websocket-client-api-1.0-rc5.jar differ diff --git a/Atjeews/libs/servlet-2-3.jar b/Atjeews/libs/servlet-2-3.jar new file mode 100755 index 0000000..9cccc09 Binary files /dev/null and b/Atjeews/libs/servlet-2-3.jar differ diff --git a/Atjeews/libs/war.jar b/Atjeews/libs/war.jar new file mode 100755 index 0000000..753032e Binary files /dev/null and b/Atjeews/libs/war.jar differ diff --git a/Atjeews/libs/webserver.jar b/Atjeews/libs/webserver.jar new file mode 100755 index 0000000..3b0ddda Binary files /dev/null and b/Atjeews/libs/webserver.jar differ diff --git a/Atjeews/lint.xml b/Atjeews/lint.xml new file mode 100755 index 0000000..ee0eead --- /dev/null +++ b/Atjeews/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Atjeews/proguard.cfg b/Atjeews/proguard.cfg new file mode 100755 index 0000000..6389a00 --- /dev/null +++ b/Atjeews/proguard.cfg @@ -0,0 +1,4 @@ +-keepclassmembers class fqcn.of.javascript.interface.for.webview { + public *; +} +-keepclasseswithmembers rogatkin.wskt.** \ No newline at end of file diff --git a/Atjeews/project.properties b/Atjeews/project.properties new file mode 100755 index 0000000..a73ee58 --- /dev/null +++ b/Atjeews/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard.cfg + +# Project target. +target=android-22 diff --git a/Atjeews/res/drawable-hdpi/browser.png b/Atjeews/res/drawable-hdpi/browser.png new file mode 100755 index 0000000..9b8324c Binary files /dev/null and b/Atjeews/res/drawable-hdpi/browser.png differ diff --git a/Atjeews/res/drawable-hdpi/icon.png b/Atjeews/res/drawable-hdpi/icon.png new file mode 100755 index 0000000..d376c81 Binary files /dev/null and b/Atjeews/res/drawable-hdpi/icon.png differ diff --git a/Atjeews/res/drawable-hdpi/info.png b/Atjeews/res/drawable-hdpi/info.png new file mode 100755 index 0000000..3ad57a2 Binary files /dev/null and b/Atjeews/res/drawable-hdpi/info.png differ diff --git a/Atjeews/res/drawable-hdpi/l_loaded.png b/Atjeews/res/drawable-hdpi/l_loaded.png new file mode 100755 index 0000000..7190748 Binary files /dev/null and b/Atjeews/res/drawable-hdpi/l_loaded.png differ diff --git a/Atjeews/res/drawable-hdpi/l_running.png b/Atjeews/res/drawable-hdpi/l_running.png new file mode 100755 index 0000000..9cd247b Binary files /dev/null and b/Atjeews/res/drawable-hdpi/l_running.png differ diff --git a/Atjeews/res/drawable-hdpi/l_stopped.png b/Atjeews/res/drawable-hdpi/l_stopped.png new file mode 100755 index 0000000..e5fb79c Binary files /dev/null and b/Atjeews/res/drawable-hdpi/l_stopped.png differ diff --git a/Atjeews/res/drawable-hdpi/reload.png b/Atjeews/res/drawable-hdpi/reload.png new file mode 100755 index 0000000..634c76e Binary files /dev/null and b/Atjeews/res/drawable-hdpi/reload.png differ diff --git a/Atjeews/res/drawable-hdpi/remove.png b/Atjeews/res/drawable-hdpi/remove.png new file mode 100755 index 0000000..efb7629 Binary files /dev/null and b/Atjeews/res/drawable-hdpi/remove.png differ diff --git a/Atjeews/res/drawable-hdpi/stop.png b/Atjeews/res/drawable-hdpi/stop.png new file mode 100755 index 0000000..fba8fa0 Binary files /dev/null and b/Atjeews/res/drawable-hdpi/stop.png differ diff --git a/Atjeews/res/drawable-ldpi/browser.png b/Atjeews/res/drawable-ldpi/browser.png new file mode 100755 index 0000000..d95c56f Binary files /dev/null and b/Atjeews/res/drawable-ldpi/browser.png differ diff --git a/Atjeews/res/drawable-ldpi/icon.png b/Atjeews/res/drawable-ldpi/icon.png new file mode 100755 index 0000000..d598369 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/icon.png differ diff --git a/Atjeews/res/drawable-ldpi/info.png b/Atjeews/res/drawable-ldpi/info.png new file mode 100755 index 0000000..f2418d5 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/info.png differ diff --git a/Atjeews/res/drawable-ldpi/l_loaded.png b/Atjeews/res/drawable-ldpi/l_loaded.png new file mode 100755 index 0000000..0e676f1 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/l_loaded.png differ diff --git a/Atjeews/res/drawable-ldpi/l_running.png b/Atjeews/res/drawable-ldpi/l_running.png new file mode 100755 index 0000000..6509987 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/l_running.png differ diff --git a/Atjeews/res/drawable-ldpi/l_stopped.png b/Atjeews/res/drawable-ldpi/l_stopped.png new file mode 100755 index 0000000..0b941f1 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/l_stopped.png differ diff --git a/Atjeews/res/drawable-ldpi/reload.png b/Atjeews/res/drawable-ldpi/reload.png new file mode 100755 index 0000000..cb36189 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/reload.png differ diff --git a/Atjeews/res/drawable-ldpi/remove.png b/Atjeews/res/drawable-ldpi/remove.png new file mode 100755 index 0000000..d292db8 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/remove.png differ diff --git a/Atjeews/res/drawable-ldpi/stop.png b/Atjeews/res/drawable-ldpi/stop.png new file mode 100755 index 0000000..5ce6cf8 Binary files /dev/null and b/Atjeews/res/drawable-ldpi/stop.png differ diff --git a/Atjeews/res/drawable-mdpi/browser.png b/Atjeews/res/drawable-mdpi/browser.png new file mode 100755 index 0000000..780e0f5 Binary files /dev/null and b/Atjeews/res/drawable-mdpi/browser.png differ diff --git a/Atjeews/res/drawable-mdpi/icon.png b/Atjeews/res/drawable-mdpi/icon.png new file mode 100755 index 0000000..e48b7e0 Binary files /dev/null and b/Atjeews/res/drawable-mdpi/icon.png differ diff --git a/Atjeews/res/drawable-mdpi/info.png b/Atjeews/res/drawable-mdpi/info.png new file mode 100755 index 0000000..2d1656a Binary files /dev/null and b/Atjeews/res/drawable-mdpi/info.png differ diff --git a/Atjeews/res/drawable-mdpi/l_loaded.png b/Atjeews/res/drawable-mdpi/l_loaded.png new file mode 100755 index 0000000..06f5565 Binary files /dev/null and b/Atjeews/res/drawable-mdpi/l_loaded.png differ diff --git a/Atjeews/res/drawable-mdpi/l_running.png b/Atjeews/res/drawable-mdpi/l_running.png new file mode 100755 index 0000000..4b4e1a0 Binary files /dev/null and b/Atjeews/res/drawable-mdpi/l_running.png differ diff --git a/Atjeews/res/drawable-mdpi/l_stopped.png b/Atjeews/res/drawable-mdpi/l_stopped.png new file mode 100755 index 0000000..186a61e Binary files /dev/null and b/Atjeews/res/drawable-mdpi/l_stopped.png differ diff --git a/Atjeews/res/drawable-mdpi/reload.png b/Atjeews/res/drawable-mdpi/reload.png new file mode 100755 index 0000000..74ac074 Binary files /dev/null and b/Atjeews/res/drawable-mdpi/reload.png differ diff --git a/Atjeews/res/drawable-mdpi/remove.png b/Atjeews/res/drawable-mdpi/remove.png new file mode 100755 index 0000000..3812f3e Binary files /dev/null and b/Atjeews/res/drawable-mdpi/remove.png differ diff --git a/Atjeews/res/drawable-mdpi/stop.png b/Atjeews/res/drawable-mdpi/stop.png new file mode 100755 index 0000000..c77e428 Binary files /dev/null and b/Atjeews/res/drawable-mdpi/stop.png differ diff --git a/Atjeews/res/layout/main.xml b/Atjeews/res/layout/main.xml new file mode 100755 index 0000000..7b663f3 --- /dev/null +++ b/Atjeews/res/layout/main.xml @@ -0,0 +1,36 @@ + + + + + + + + " + + + + + + + + + + + + + + + + + + + + diff --git a/Atjeews/res/menu/app_ops.xml b/Atjeews/res/menu/app_ops.xml new file mode 100755 index 0000000..b86c07a --- /dev/null +++ b/Atjeews/res/menu/app_ops.xml @@ -0,0 +1,989 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Atjeews/res/values/strings.xml b/Atjeews/res/values/strings.xml new file mode 100755 index 0000000..ed0cb15 --- /dev/null +++ b/Atjeews/res/values/strings.xml @@ -0,0 +1,26 @@ + + + Atjeews + Atjeews - Web Container for Android + Enable Server + Deploying Web application URL + http:// + Deploy + Deployed web apps + 1.10 + Redeploy + Remove + Stop + Info + Open + Atjeews is stopped, launch it first + Info + Warning + Rescan Apps + Error + Problem happened %s + Enable logging + 1.01 + SSL + © + diff --git a/Atjeews/src/rogatkin/mobile/web/AndroidClassLoader.java b/Atjeews/src/rogatkin/mobile/web/AndroidClassLoader.java new file mode 100755 index 0000000..2f13f06 --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/AndroidClassLoader.java @@ -0,0 +1,63 @@ +/** Copyright 2011 Dmitriy Rogatkin, All rights reserved. + * $Id: AndroidClassLoader.java,v 1.6 2012/05/23 05:08:15 dmitriy Exp $ + */ +package rogatkin.mobile.web; + +import java.io.File; +import java.net.URL; +import java.util.Arrays; + +import android.util.Log; +import dalvik.system.DexClassLoader; + +public class AndroidClassLoader extends DexClassLoader { + + ClassLoader parent; + + public AndroidClassLoader(URL[] classPath, ClassLoader parent) { + super(convertFilePaths(classPath), assureClassStorage(classPath), null, parent); + this.parent = parent; + } + + private static String convertFilePaths(URL[] urls) { + String result = ""; + String sep = System.getProperty("path.separator"); + for (URL url : urls) { + result += url.getPath(); + result += sep; + } + // possibly trim last sep char + if (Main.DEBUG) + Log.d(Main.APP_NAME, "Class path:" + result); + return result; + } + + private static String assureClassStorage(URL[] classPath) { + for (URL url : classPath) { + String file = url.getFile(); + int wip = file.indexOf("WEB-INF"); + if (wip >= 0) { + File dex_dir = new File(file.substring(0, wip) + + "META-INF/DEX/"+TJWSServ.SERVICE_NAME); + //Log.d(Main.APP_NAME, "Dex dir:"+dex_dir+" "+file); + if (dex_dir.exists() == false) { + dex_dir.mkdirs(); + } + if (dex_dir.exists() && dex_dir.isDirectory()) + return dex_dir.getPath(); + } + } + throw new RuntimeException("Can't create dex temporary storage of "+Arrays.toString(classPath)); + } + + @Override + protected URL findResource(String name) { + // Log.d(Main.APP_NAME, "Request for resource:"+name); + try { + return super.findResource(name); + } catch (Exception e) { + + } + return parent.getResource(name); + } +} diff --git a/Atjeews/src/rogatkin/mobile/web/Config.java b/Atjeews/src/rogatkin/mobile/web/Config.java new file mode 100755 index 0000000..954e81e --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/Config.java @@ -0,0 +1,89 @@ +/** Copyright 2012 Dmitriy Rogatkin, All rights reserved. + * + */ +package rogatkin.mobile.web; + +import java.net.InetAddress; + +import android.content.Context; +import android.content.SharedPreferences; + +public class Config { + + public static final String APP_HOME = "atjeews.home"; + static final String P_PORT = "port"; + static final String P_SSL = "ssl"; + static final String P_ROOTAPP = "root_app"; + static final String P_PASSWRD = "password"; + static final String P_WEBROOT = "wwwroor"; + static final String P_VIRTUAL = "virtual"; + static final String P_BINDADDR = "bind_addr"; + static final String P_HOMEDIR = "home_dir"; + static final String P_APPLOCK = "applock"; + static final String P_WEBSOCKET = "websocket"; + static final String P_BACKLOG = "backlog"; + + public InetAddress iadr; + public int port; + public boolean ssl; + public boolean webSocketEnabled; + public boolean app_deploy_lock; + public boolean logEnabled; + public boolean virtualHost; + public boolean useSD = true; + public String rootApp; + public String wwwFolder; + public String password; // admin password + public String bindAddr; + public int backlog; + + protected void store(Context context) { + SharedPreferences prefs = context.getSharedPreferences(Main.APP_NAME, Context.MODE_WORLD_READABLE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("log_enable", logEnabled); + editor.putBoolean(P_SSL, ssl); + editor.putInt(P_PORT, port <= 0 ? 8080 : port); + editor.putInt(P_BACKLOG, backlog <= 0 ? 60 : backlog); + editor.putString(P_PASSWRD, password); + editor.putBoolean(P_APPLOCK, app_deploy_lock); + editor.putBoolean(P_WEBSOCKET, webSocketEnabled); + if (System.getProperty(APP_HOME) != null) + editor.putString(P_HOMEDIR, System.getProperty(APP_HOME)); + else + editor.remove(P_HOMEDIR); + if (bindAddr == null) + editor.remove(P_BINDADDR); + else + editor.putString(P_BINDADDR, bindAddr); + editor.putString(P_WEBROOT, wwwFolder); + if (rootApp == null) + editor.remove(P_ROOTAPP); + else + editor.putString(P_ROOTAPP, rootApp); + editor.putBoolean(P_VIRTUAL, virtualHost); + editor.commit(); + } + + protected void load(Context context) { + SharedPreferences prefs = context.getSharedPreferences(Main.APP_NAME, Context.MODE_WORLD_READABLE); + port = prefs.getInt(P_PORT, 8080); + ssl = prefs.getBoolean(P_SSL, false); + backlog = prefs.getInt(P_BACKLOG, 60); + logEnabled = prefs.getBoolean("log_enable", false); + bindAddr = prefs.getString(P_BINDADDR, null); + virtualHost = prefs.getBoolean(P_VIRTUAL, false); + webSocketEnabled = prefs.getBoolean(P_WEBSOCKET, false); + app_deploy_lock = prefs.getBoolean(P_APPLOCK, false); + String home = prefs.getString(P_HOMEDIR, null); + if (home != null) { + System.setProperty(APP_HOME, home); + useSD = false; + } else { + System.getProperties().remove(APP_HOME); + useSD = true; + } + rootApp = prefs.getString(P_ROOTAPP, null); + wwwFolder = prefs.getString(P_WEBROOT, "/"); + password = prefs.getString(P_PASSWRD, null); + } +} diff --git a/Atjeews/src/rogatkin/mobile/web/Main.java b/Atjeews/src/rogatkin/mobile/web/Main.java new file mode 100755 index 0000000..a74f44c --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/Main.java @@ -0,0 +1,457 @@ +/** Copyright 2011 Dmitriy Rogatkin, All rights reserved. + * $Id: Main.java,v 1.48 2012/09/15 17:47:27 dmitriy Exp $ + */ +package rogatkin.mobile.web; + +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.List; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.HeaderViewListAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +/** + * Atjeews Android launcher of TJWS with administration support + * + * @author Dmitriy Rogatkin + * + */ +public class Main extends Activity { + public static final String APP_NAME = "Atjeews"; + + public static final int APP_VER_MN = 5; + + public static final int APP_VER_MJ = 1; + + public static final boolean DEBUG = false; + + protected Config config; + protected ArrayList servletsList; + protected String hostName; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + // getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + loadConfig(); + servletsList = new ArrayList(); + // getWindow().setSoftInputMode( + // WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + + // list deployed apps + final ListView listView = (ListView) findViewById(R.id.listView1); + TextView header = new TextView(this); + header.setText(R.string.list_deployed); + listView.addHeaderView(header); + + // process deployment request + Button button = (Button) findViewById(R.id.button1); + button.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + final EditText surl = (EditText) findViewById(R.id.editText1); + String userInput = surl.getText().toString(); + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(surl.getWindowToken(), 0); + if (userInput.length() <= "http://".length()) { + Toast.makeText(Main.this, "Please specify location URL of .war", Toast.LENGTH_SHORT).show(); + return; + } + if (config.app_deploy_lock) { + Toast.makeText(Main.this, "Deploying new apps is locked", Toast.LENGTH_SHORT).show(); + return; + } + new AsyncTask() { + private String lastError; + ProgressDialog dialog; + + @Override + protected void onPostExecute(Void result) { + dialog.dismiss(); + RCServ servCtrl = ((TJWSApp) getApplication()) + .getServiceControl(); + if (lastError != null) { + AlertDialog.Builder builder = new AlertDialog.Builder( + Main.this); + builder.setMessage(String.format(getResources() + .getString(R.string.alrt_problem), + lastError)); + builder.setIcon(R.drawable.stop); + builder.setTitle(R.string.t_error); + builder.create().show(); + } else { + if (lastError == null) { + surl.setText("http://"); + try { + fillServlets(servCtrl.getApps()); + } catch (Exception e) { + reportProblem(e); + } + } + } + super.onPostExecute(result); + } + + @Override + protected void onPreExecute() { + dialog = ProgressDialog.show(Main.this, "Deploying", + "Please wait for few seconds..", true); + super.onPreExecute(); + } + + @Override + protected Void doInBackground(String... urls) { + RCServ servCtrl = ((TJWSApp) getApplication()) + .getServiceControl(); + try { + lastError = servCtrl.deployApp(urls[0]); + } catch (NullPointerException npe) { + } catch (RemoteException e) { + reportProblem(e); + } + return null; + } + + }.execute(userInput); + } + }); + // process rescan request + button = (Button) findViewById(R.id.button2); + button.setOnClickListener(new OnClickListener() { + + public void onClick(View view) { + RCServ servCtrl = ((TJWSApp) getApplication()) + .getServiceControl(); + try { + if (servCtrl != null) + fillServlets(servCtrl.rescanApps()); + else + reportProblem(new Exception( + "Can't obtain service control - null")); + } catch (Exception e) { + reportProblem(e); + } // TODO consider AsyncTask + } + }); + + listView.setAdapter(new ArrayAdapter(this, + android.R.layout.simple_list_item_1, servletsList)); + registerForContextMenu(listView); + + CheckBox checkbox = (CheckBox) findViewById(R.id.checkStrt); + checkbox.requestFocus(); + checkbox.setOnClickListener(new OnClickListener() { + + public void onClick(View view) { + if (((CheckBox) view).isChecked()) + start(); + else + stop(); + } + }); + + ((CheckBox) findViewById(R.id.checkBox2)) + .setOnClickListener(new OnClickListener() { + + public void onClick(View view) { + RCServ servCtrl = ((TJWSApp) getApplication()) + .getServiceControl(); + try { + servCtrl.logging(((CheckBox) view).isChecked()); + } catch (Exception e) { + reportProblem(e); + } + } + }); + //updateUI(); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + @Override + protected void onStop() { + try { + storeConfig(); + } catch (Exception e) { + reportProblem(e); + } + super.onStop(); + } + + @Override + protected void onResume() { + super.onResume(); + updateUI(); + } + + private void updateUI() { + if (DEBUG) + Log.d(APP_NAME, "UI updated called"); + RCServ servCtrl = ((TJWSApp) getApplication()).getServiceControl(); + if (servCtrl != null) { + updateStatus(servCtrl); + try { + updateAppsList(servCtrl.getApps(), true); + } catch (RemoteException e) { + if (DEBUG) + Log.e(APP_NAME, "Updating apps list failed", e); + } + // Log.d(APP_NAME, "UPADTING =====>"+hostName, new + // Exception()); + } else if (DEBUG) + Log.d(APP_NAME, "service not started"); + updateTitle(); + } + + private void updateStatus(RCServ servCtrl) { + try { + CheckBox startBtn = (CheckBox) findViewById(R.id.checkStrt); + boolean stopped = servCtrl.getStatus() != TJWSServ.ST_RUN; + if (DEBUG) + Log.d(APP_NAME, "run "+stopped+", checking run "+startBtn.isChecked()); + //startBtn.setChecked(!stopped); + if (stopped == false && hostName == null) + start(servCtrl); + } catch (Exception e) { + reportProblem(e); + } + } + + void storeConfig() { + config.load(this); + config.logEnabled = ((CheckBox) findViewById(R.id.checkBox2)) + .isChecked(); + try { + int port = Integer + .parseInt(((EditText) findViewById(R.id.editPort)) + .getText().toString()); + if (port > 65536) + throw new IllegalArgumentException("Port value " + port + + " is out of allowed range"); + else if (port < 1024) { + try { + ServerSocket ss = new ServerSocket(port); + ss.close(); + } catch (Exception e) { + throw new IllegalArgumentException("Port value " + port + + " is out of allowed range", e); + } + } + config.port = port; + } catch (Exception e) { + throw new IllegalArgumentException("" + e, e); + } + config.ssl = ((CheckBox) findViewById(R.id.checkSSL)).isChecked(); + config.store(this); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + if (info.position <= 0) + return; + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.app_ops, menu); + ListView listView = (ListView) findViewById(R.id.listView1); + String appName = (String) listView.getAdapter().getItem(info.position); + if (appName != null) + menu.setHeaderTitle(appName); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + ListView listView = (ListView) findViewById(R.id.listView1); + String appName = (String) listView.getAdapter().getItem(info.position); + RCServ servCtrl = ((TJWSApp) getApplication()).getServiceControl(); + if (appName == null || servCtrl == null) + return super.onContextItemSelected(item); + try { + switch (item.getItemId()) { + case R.id.app_redeploy: + fillServlets(servCtrl.redeployApp(appName)); + return true; + case R.id.app_info: + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(servCtrl.getAppInfo(appName)); + builder.setCancelable(true); + builder.setTitle(R.string.t_info); + builder.setIcon(R.drawable.info); + AlertDialog alert = builder.create(); + alert.show(); + return true; + case R.id.app_open: + if (servCtrl.getStatus() != TJWSServ.ST_RUN || hostName == null) { + builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.alrt_noserver); + builder.setIcon(R.drawable.stop); + builder.setTitle(R.string.t_warning); + builder.create().show(); + return true; + } + boolean ipv6 = !(hostName.indexOf(':') < 0); + Intent browserIntent; + if ("/settings".equals(appName)) + browserIntent = new Intent(Intent.ACTION_VIEW, + Uri.parse("http" + (config.ssl ? "s" : "") + "://" + + (ipv6 ? "[" : "") + hostName + + (ipv6 ? "]" : "") + ":" + config.port + + "/settings")); + else + browserIntent = new Intent(Intent.ACTION_VIEW, + Uri.parse("http" + + (config.ssl ? "s" : "") + + "://" + + (ipv6 ? "[" : "") + + hostName + + (ipv6 ? "]" : "") + + ":" + + config.port + + (appName.endsWith("/*") ? appName + .substring(0, appName.length() - 2) + : appName))); + startActivity(browserIntent); + return true; + case R.id.app_remove: + servCtrl.removeApp(appName); + // coming through to stop + case R.id.app_stop: + fillServlets(servCtrl.stopApp(appName)); + return true; + default: + return super.onContextItemSelected(item); + } + } catch (RemoteException e) { + reportProblem(e); + } + return false; + } + + protected void loadConfig() { + if (config == null) + config = new Config(); + config.load(this); + ((EditText) findViewById(R.id.editPort)).setText("" + config.port); + ((CheckBox) findViewById(R.id.checkSSL)).setChecked(config.ssl); + ((CheckBox) findViewById(R.id.checkBox2)).setChecked(config.logEnabled); + } + + protected void fillServlets(List newList) { + updateAppsList(newList, true); + } + + private void updateAppsList(List newList, boolean notify) { + servletsList.clear(); + if (newList == null) { + if (DEBUG) + Log.e(APP_NAME, "Error happened at retrieving apps list"); + return; + } + for (String servName : newList) + servletsList.add(servName); + if (notify) { + ListView listView = (ListView) findViewById(R.id.listView1); + ((BaseAdapter) ((HeaderViewListAdapter) listView.getAdapter()) + .getWrappedAdapter()).notifyDataSetChanged(); + } + } + + void updateTitle() { + boolean running = hostName != null; + ((CheckBox) findViewById(R.id.checkSSL)).setEnabled(running == false); + ((EditText) findViewById(R.id.editPort)).setEnabled(running == false); + if (running) { + setTitle(APP_NAME + " [" + hostName + "]:" + config.port + " @" + + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "m"); + ((CheckBox) findViewById(R.id.checkStrt)).setChecked(true); + } else { + setTitle(APP_NAME); + ((CheckBox) findViewById(R.id.checkStrt)).setChecked(false); + } + } + + private void start() { + storeConfig(); + start(((TJWSApp) getApplication()).getServiceControl()); + } + + private void start(RCServ serv) { + new AsyncTask() { + + @Override + protected void onPostExecute(String host) { + hostName = host; + updateTitle(); + } + + @Override + protected String doInBackground(RCServ... sc) { + try { + return sc[0].start(); + } catch (Exception e) { + reportProblem(e); + } + return null; + } + }.execute(serv); + } + + private void stop() { + RCServ servCtrl = ((TJWSApp) getApplication()).getServiceControl(); + if (servCtrl != null) { + try { + servCtrl.stop(); + } catch (RemoteException e) { + reportProblem(e); + } + hostName = null; + } + updateTitle(); + } + + private void reportProblem(Throwable problem) { + if (problem instanceof NullPointerException == false) + if (DEBUG) + Log.e(APP_NAME, "Unexpected problem:" + problem, problem); + Toast.makeText(this, "" + problem, Toast.LENGTH_LONG).show(); + } + +} \ No newline at end of file diff --git a/Atjeews/src/rogatkin/mobile/web/MultipartParser.java b/Atjeews/src/rogatkin/mobile/web/MultipartParser.java new file mode 100755 index 0000000..468efec --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/MultipartParser.java @@ -0,0 +1,275 @@ +package rogatkin.mobile.web; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class MultipartParser { + public static final String MULTIPARTDATA = "multipart/form-data"; + + public static final String BOUNDARY_EQ = "boundary="; + + public static final String BOUNDARY_END_SFX = "--"; + + public static final String CONTENT_DISP = "Content-Disposition"; + + public static final String FORM_DATA = "form-data"; + + public static final String FILENAME_EQ_QT = "filename=\""; + + public static final String NAME_EQ_QT = "name=\""; + + public static final String FILENAME = "filename"; + + public static final String CONTENT_TYPE = "Content-Type"; + + protected HashMap multipartData; + + public MultipartParser(ServletRequest req, ServletResponse response) throws IOException { + String contentType = req.getContentType(); + ServletInputStream sis = null; + try { + sis = req.getInputStream(); + } catch (IllegalStateException ise) { + throw new IOException("Input stream is unaccessible"); + } + int bp = contentType.indexOf(BOUNDARY_EQ); + if (bp < 0) { + return; + } + + String boundary = contentType.substring(bp + BOUNDARY_EQ.length()); // it + // can be not last attribute + int boundaryLength = boundary.length(); + // TODO can be -1, it is normal + int contentLength = req.getContentLength(); + if (contentLength <= 0) { + return; + } + + int maxReqLength = 30 * 1024 * 1024; + if (contentLength > maxReqLength) { + sis.skip(contentLength); + return; + } + multipartData = new HashMap(); + // TODO: do not allocate buffer for all content length, just keep + // reading + byte[] buffer = new byte[contentLength]; + int contentRead = 0; + main_loop: + do { + if (contentRead > contentLength) { + break main_loop; + } + + // read --------------boundary + int ec = sis.readLine(buffer, contentRead, contentLength - contentRead); + if (ec < 0) { + break main_loop; + } + + String s = new String(buffer, contentRead, ec, "UTF-8"); + contentRead += ec; + int p = s.indexOf(boundary); + if (p >= 0) { + if (s.regionMatches(p + boundaryLength, BOUNDARY_END_SFX, 0, BOUNDARY_END_SFX.length())) { + // it shouldn't happen here, but it's Ok + break; + } + // skip the boundary, if it happens, because it's first + ec = sis.readLine(buffer, contentRead, contentLength - contentRead); + s = new String(buffer, contentRead, ec, "UTF-8"); + contentRead += ec; + } + + // s contains here first line of a part + int dp, ep; + String header, name = null, filename = null, token, partContentType = null; + do { + dp = s.indexOf(':'); + if (dp < 0) { // throw new IOException( .. + break main_loop; + } + + header = s.substring(0, dp); + s = s.substring(dp + 2); + if (CONTENT_DISP.equalsIgnoreCase(header)) { + StringTokenizer ast = new StringTokenizer(s, ";"); + if (ast.hasMoreTokens()) { + token = ast.nextToken(); + if (token.indexOf(FORM_DATA) < 0) { + break main_loop; // throw new IOException( .. + } + + while (ast.hasMoreTokens()) { + token = ast.nextToken(); + dp = token.indexOf(FILENAME_EQ_QT); + if (dp >= 0) { + ep = token.indexOf('"', dp + FILENAME_EQ_QT.length()); + if (ep < 0 || filename != null) { + break main_loop; + } + filename = token.substring(dp + FILENAME_EQ_QT.length(), ep); + continue; + } + dp = token.indexOf(NAME_EQ_QT); + if (dp >= 0) { + ep = token.indexOf('"', dp + NAME_EQ_QT.length()); + if (ep < 0 || ep == dp + NAME_EQ_QT.length() || name != null) { + break main_loop; // throw new + } + // IOException( .. + name = token.substring(dp + NAME_EQ_QT.length(), ep); + continue; + } + } + } + if (filename != null) + addPart(name + '+' + FILENAME, filename); + } else if (CONTENT_TYPE.equalsIgnoreCase(header)) { + partContentType = s; + } + ec = sis.readLine(buffer, contentRead, contentLength - contentRead); + if (ec < 0) + break main_loop; // throw new IOException( .. + if (ec == 2 && buffer[contentRead] == 0x0D && buffer[contentRead + 1] == 0x0A) { + contentRead += ec; + break; // empty line read, skip it + } + s = new String(buffer, contentRead, ec, "UTF-8"); + } while (true); + if (name == null) + break main_loop; // throw new IOException( .. + int marker = contentRead; + if (partContentType == null || partContentType.indexOf("text/") >= 0 || partContentType.indexOf("application/") >= 0 || partContentType.indexOf("message/") >= 0 || partContentType.indexOf("unknown") >= 0) { // read + // everything + do { + ec = sis.readLine(buffer, contentRead, contentLength - contentRead); + if (ec < 0) + break main_loop; + s = new String(buffer, contentRead, ec, "UTF-8"); + p = s.indexOf(boundary); + if (p >= 0) { // we met a boundry + // finish current part + if (contentRead - marker <= 2) { + // no file content in the stream, probably it's a + // remote file + try { + URLConnection uc = new URL(filename).openConnection(); + if (uc.getContentType().indexOf("image/") >= 0) { // support + int cl = uc.getContentLength(); + if (cl > 0 && cl < maxReqLength) { + InputStream uis = uc.getInputStream(); + if (uis != null) { + byte[] im = new byte[cl]; + cl = 0; + int rc; + do { + rc = uis.read(im, cl, im.length - cl); + if (rc < 0) + break; + cl += rc; + } while (rc > 0); + uis.close(); + addPart(name, im); + } + } else { // length unknown but we can try + InputStream uis = uc.getInputStream(); + if (uis != null) { + byte[] buf = new byte[2048]; + byte[] im = new byte[0]; + try { + do { + cl = uis.read(buf); + if (cl < 0) + break; + byte[] wa = new byte[im.length + cl]; + System.arraycopy(im, 0, wa, 0, im.length); + System.arraycopy(buf, 0, wa, im.length, cl); + im = wa; + } while (true); + } finally { + uis.close(); + } + addPart(name, im); + } + } + } + } catch (MalformedURLException mfe) { + } + } else { + if (partContentType != null && partContentType.indexOf("application/") >= 0) { + byte[] im = new byte[contentRead - marker - 2]; + System.arraycopy(buffer, marker, im, 0, contentRead - marker - 2/* crlf */); + addPart(name, im); + } else { + addPart(name, new String(buffer, marker, contentRead - marker - 2/* crlf */, "UTF-8")); + } + } + if (s.regionMatches(p + boundaryLength, BOUNDARY_END_SFX, 0, BOUNDARY_END_SFX.length())) + break main_loop; // it shouldn't happen here, but + // it's Ok + contentRead += ec; + break; + } + contentRead += ec; + } while (true); + } else if (partContentType.indexOf("image/") >= 0 || partContentType.indexOf("audio/") >= 0) { + do { + ec = sis.readLine(buffer, contentRead, contentLength - contentRead); + if (ec < 0) + throw new IOException("Premature ending of input stream"); + + s = new String(buffer, contentRead, ec, "UTF-8"); + p = s.indexOf(boundary); + if (p >= 0) { // we met a bounder + byte[] im = new byte[contentRead - marker - 2]; + System.arraycopy(buffer, marker, im, 0, contentRead - marker - 2); + addPart(name, im); + if (s.regionMatches(p + boundaryLength, BOUNDARY_END_SFX, 0, BOUNDARY_END_SFX.length())) + break main_loop; // it shouldn't happen here, but + // it's Ok + contentRead += ec; + break; + } + contentRead += ec; + } while (true); + } else { + throw new IOException("Unsupported content type '" + partContentType + '\''); + } + } while (true); + } + + protected void addPart(String name, Object data) { + Object[] curData = multipartData.get(name); + if (curData == null) { + curData = new Object[1]; + curData[0] = data; + } else { + Object[] newdata = new Object[curData.length + 1]; + System.arraycopy(curData, 0, newdata, 0, curData.length); + newdata[curData.length] = data; + curData = newdata; + } + multipartData.put(name, curData); + } + + public Object getParameter(String name) { + if (multipartData == null) + return null; + Object[] curData = multipartData.get(name); + if (curData == null) + return null; + return curData[0]; + + } +} diff --git a/Atjeews/src/rogatkin/mobile/web/RCServ.aidl b/Atjeews/src/rogatkin/mobile/web/RCServ.aidl new file mode 100755 index 0000000..8215c06 --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/RCServ.aidl @@ -0,0 +1,27 @@ +package rogatkin.mobile.web; + +interface RCServ { + + String start(); + + void stop(); + + int getStatus(); + + void logging(boolean on); + + List getApps(); + + List rescanApps(); + + String deployApp(String url); + + String getAppInfo(String name); + + List stopApp(String name); + + List redeployApp(String name); + + void removeApp(String name); + +} \ No newline at end of file diff --git a/Atjeews/src/rogatkin/mobile/web/Settings.java b/Atjeews/src/rogatkin/mobile/web/Settings.java new file mode 100755 index 0000000..31fcbcd --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/Settings.java @@ -0,0 +1,251 @@ +/** Copyright 2011 Dmitriy Rogatkin, All rights reserved. + * $Id: Settings.java,v 1.10 2012/04/03 06:13:58 dmitriy Exp $ + */ +package rogatkin.mobile.web; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import Acme.Utils; +import Acme.Serve.Serve; + +/** + * manages Atjeews settings + * + * @author drogatki + * + */ +public class Settings extends HttpServlet { + + private static final String SET_PASSWORD = "*******"; + private TJWSServ atjeews; + + public Settings(TJWSServ server) { + atjeews = server; + } + + @Override + public String getServletInfo() { + return Serve.Identification.serverName + " " + Serve.Identification.serverVersion; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.setHeader("Cache-Control", "no-cache"); + resp.setDateHeader("Expires", 0); + PrintWriter pw = resp.getWriter(); + printHtmlHead(pw); + pw.print("
"); + pw.print(""); + pw.print(""); + String password = atjeews.config.password != null ? SET_PASSWORD : ""; + + pw.print(""); + pw.print(""); + pw.print(""); + pw.print(""); + pw.print(""); + pw.print("
ROOT(/) web app
Serviced folder
Virt host
Admin password
Binding addr
WebSocket        No new app  "); + // TODO add backlog + pw.print("
Home dir
"); + pw.print("
Upload web application (.war) or keystore
"); + pw.print("
"); + printFooter(pw); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String message = "Okay"; + PrintWriter pw = resp.getWriter(); + printHtmlHead(pw); + String contentType = req.getContentType(); + if (contentType != null && contentType.toLowerCase().indexOf("multipart/form-data") >= 0) { + MultipartParser mpp = new MultipartParser(req, resp); + String fileName = (String) mpp.getParameter("app_file+" + MultipartParser.FILENAME); + message = "Nothing uploaded"; + if (atjeews.config.app_deploy_lock) { + message = "Deploying new apps is not allowed"; + fileName = null; + } + if (fileName != null) { + int sp = fileName.lastIndexOf('\\'); + if (sp >= 0) { + fileName = fileName.substring(sp + 1); + } + sp = fileName.lastIndexOf('/'); + if (sp >= 0) { + fileName = fileName.substring(sp + 1); + } + + Object data = mpp.getParameter("app_file"); + if (data instanceof byte[]) { + FileOutputStream fos = null; + if (fileName.toLowerCase().endsWith(".war")) { + fos = new FileOutputStream(new File(atjeews.deployDir, fileName)); + } else if (TJWSServ.KEYSTORE.equals(fileName)) { + fos = new FileOutputStream(new File(atjeews.getKeyDir(), TJWSServ.KEYSTORE)); + } else { + message = fileName + " isn't supported type"; + } + if (fos != null) { + fos.write((byte[]) data); + fos.close(); + message = fileName + " stored"; + } + } + } + } else { + // update data + String val = req.getParameter("root_app"); + if ("-".equals(val)) { + atjeews.config.rootApp = null; + } else { + atjeews.config.rootApp = val; + } + + atjeews.config.wwwFolder = req.getParameter("webroot"); + File wwwFolder = new File(atjeews.config.wwwFolder); + if (wwwFolder.exists() == false || wwwFolder.isDirectory() == false) { + atjeews.config.wwwFolder = null; + message = "Invalid web folder"; + } else { + atjeews.updateWWWServlet(); + } + val = req.getParameter("password"); + if (SET_PASSWORD.equals(val) == false) { + if (val.length() > 0) { + if (val.equals(req.getParameter("password2"))) { + atjeews.config.password = val; + } else { + message = "Passwords are not match"; + } + } else if (atjeews.config.password != null) { + atjeews.config.password = null; + } + atjeews.updateRealm(); + } + + val = req.getParameter("bind_addr"); + if (val.length() > 0) { + atjeews.config.bindAddr = val; + } else { + atjeews.config.bindAddr = null; + } + atjeews.config.virtualHost = Boolean.TRUE.toString().equals(req.getParameter("virt_host")); + val = req.getParameter("home_dir"); + if (val != null && val.length() > 0) { + System.setProperty(Config.APP_HOME, val); + } else { + System.getProperties().remove(Config.APP_HOME); + } + atjeews.config.app_deploy_lock = Boolean.TRUE.toString().equals(req.getParameter("lock_app")); + atjeews.config.webSocketEnabled = Boolean.TRUE.toString().equals(req.getParameter("webSocketEnabled")); + atjeews.deployDir = null; + atjeews.initDeployDirectory(); + atjeews.storeConfig(); + } + pw.print("
" + message + ".

Go back to settings"); + printFooter(pw); + } + + @Override + protected long getLastModified(HttpServletRequest req) { + return -1; + } + + private void printHtmlHead(PrintWriter pw) { + pw.print("Settings - "); + pw.print(Main.APP_NAME); + pw.print(""); + pw.print(""); + pw.print(""); + } + + private void printFooter(PrintWriter pw) { + pw.print("
"); + pw.print(Serve.Identification.serverIdHtml); + pw.print("
Privacy Policy
"); + } +} diff --git a/Atjeews/src/rogatkin/mobile/web/TJWSApp.java b/Atjeews/src/rogatkin/mobile/web/TJWSApp.java new file mode 100755 index 0000000..a411c58 --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/TJWSApp.java @@ -0,0 +1,71 @@ +/** Copyright 2012 Dmitriy Rogatkin, All rights reserved. + * $Id: TJWSApp.java,v 1.3 2012/09/15 17:47:27 dmitriy Exp $ + */ +package rogatkin.mobile.web; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.Application; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; +import java.lang.Thread.UncaughtExceptionHandler; + +public class TJWSApp extends Application { + protected RCServ servCtrl; + + @Override + public void onCreate() { + super.onCreate(); + if (Thread.getDefaultUncaughtExceptionHandler() == null) + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { + + public void uncaughtException(Thread thread, Throwable ex) { + if (Main.DEBUG) + Log.e(Main.APP_NAME, "Unhandled exception " + ex + + " in the thread: " + thread, ex); + } + }); + startServe(); + } + + RCServ getServiceControl() { + return servCtrl; + } + + void startServe() { + if (servCtrl != null) // sanity + return; + Intent serv = new Intent(this, TJWSServ.class); + if (!isMyServiceRunning(TJWSServ.class)) + startService(serv); + bindService(serv, new ServiceConnection() { + + public void onServiceConnected(ComponentName name, IBinder service) { + servCtrl = RCServ.Stub.asInterface(service); + // can send notification to activities here + } + + public void onServiceDisconnected(ComponentName name) { + if (Main.DEBUG) + Log.d(Main.APP_NAME, "Disconnected " + name); + servCtrl = null; + } + }, BIND_AUTO_CREATE); + } + + private boolean isMyServiceRunning(Class serviceClass) { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager + .getRunningServices(Integer.MAX_VALUE)) { + if (serviceClass.getName().equals(service.service.getClassName())) { + return true; + } + } + return false; + } +} diff --git a/Atjeews/src/rogatkin/mobile/web/TJWSServ.java b/Atjeews/src/rogatkin/mobile/web/TJWSServ.java new file mode 100755 index 0000000..2804b75 --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/TJWSServ.java @@ -0,0 +1,699 @@ +/** Copyright 2011 Dmitriy Rogatkin, All rights reserved. + * $Id: TJWSServ.java,v 1.15 2012/09/15 17:47:27 dmitriy Exp $ + */ +package rogatkin.mobile.web; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; + +import javax.servlet.Servlet; + +import org.apache.http.conn.util.InetAddressUtils; + +import rogatkin.web.WarRoller; +import rogatkin.web.WebApp; +import rogatkin.web.WebAppServlet; +import Acme.Utils; +import Acme.Serve.FileServlet; +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.os.Environment; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +/** + * Android TJWS server service + * + * @author drogatki + * + */ +public class TJWSServ extends Service { + public enum OperCode { + info, + stop, + remove, + deploy + } + + static final String SERVICE_NAME = "TJWS"; + public static final String DEPLOYMENTDIR = "atjeews/webapps"; + public static final String LOGDIR = "atjeews/log"; + public static final String KEYSTORE_DIR = "key"; + public static final String KEYSTORE = "keystore"; + + public static final int ST_RUN = 1; + public static final int ST_STOP = 0; + public static final int ST_ERR = -1; + + protected AndroidServer srv; + protected Config config; + + protected ArrayList servletsList; + protected PrintStream logStream; + public File deployDir; + + private int status; + + WifiLock wifiLock; + + public boolean protectedFS = android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1; + + @Override + public IBinder onBind(Intent intent) { + if (Main.DEBUG) + Log.d(SERVICE_NAME, "Binding from " + intent.getClass().getName()); + initServ(); + + return mBinder; + } + + private final RCServ.Stub mBinder = new RCServ.Stub() { + + public String start() throws RemoteException { + String result = updateNetworkSettings(); + startServ(); + return result; + } + + public void stop() throws RemoteException { + stopServ(); + } + + public int getStatus() throws RemoteException { + return status; + } + + public void logging(boolean enable) throws RemoteException { + srv.setAccessLogged(enable); + } + + public List getApps() throws RemoteException { + return servletsList; + } + + public String deployApp(String url) throws RemoteException { + return deployAppFrom(url); + } + + public List rescanApps() throws RemoteException { + scanDeployments(); + updateServletsList(); + return servletsList; + } + + public String getAppInfo(String name) throws RemoteException { + return (String) doAppOper(OperCode.info, name); + } + + public List stopApp(String name) throws RemoteException { + return (List) doAppOper(OperCode.stop, name); + } + + public void removeApp(String name) throws RemoteException { + doAppOper(OperCode.remove, name); + } + + public List redeployApp(String name) throws RemoteException { + return (List) doAppOper(OperCode.deploy, name); + } + }; + + @Override + public void onDestroy() { + // srv.log("Destroy commande received"); + stopServ(); // just in case + srv.destroyAllServlets(); + if (logStream != System.out && logStream != null) + logStream.close(); + super.onDestroy(); + } + + private void stopServ() { + // srv.log(new Exception("stop"), "stop"); + if (status != ST_STOP) + srv.notifyStop(); + } + + private void startServ() { + if (status != ST_RUN) { + new Thread() { + @Override + public void run() { + status = ST_RUN; + int code = 0; + if (wifiLock == null) { + WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + wifiLock = wifiManager.createWifiLock(SERVICE_NAME); + } + try { + wifiLock.acquire(); + code = srv.serve(); + if (Main.DEBUG) { + Log.d(SERVICE_NAME, "Serve terminated with :" + code); + srv.log("Serve terminated with :" + code); + } + } finally { + if (wifiLock != null && wifiLock.isHeld()) + wifiLock.release(); + status = code == 0 ? ST_STOP : ST_ERR; + // TODO find out how notify client + } + } + }.start(); + } + } + + protected void initServ() { + if (srv != null) { + if (Main.DEBUG) + Log.d(SERVICE_NAME, "Serve is already initialized"); + return; + } + if (config == null) + config = new Config(); + config.load(this); + initLogging(); + // setting properties for the server, and exchangeable Acceptors + Properties properties = new Properties(); + properties.setProperty(Acme.Serve.Serve.ARG_NOHUP, "nohup"); + // properties.put(Acme.Serve.Serve.ARG_KEEPALIVE, Boolean.FALSE); + // log properties + properties.setProperty(Acme.Serve.Serve.ARG_ACCESS_LOG_FMT, "{0} {2} [{3,date,dd/MMM/yy:HH:mm:ss Z}] \"{4} {5} {6}\" {7,number,#}"); + // //// JSP ///// + properties.setProperty(Acme.Serve.Serve.ARG_JSP, "org.apache.jasper.servlet.JspServlet"); + properties.setProperty("org.apache.jasper.servlet.JspServlet.classpath", "%classpath%"); + properties.setProperty("org.apache.jasper.servlet.JspServlet.scratchdir", "%deploydir%/META-INF/jsp-classes"); + // ////////// + srv = new AndroidServ(properties, logStream, (Object) this); + // add settings servlet + srv.addServlet("/settings", new Settings(this)); + System.setProperty(WebAppServlet.WAR_NAME_AS_CONTEXTPATH, "yes"); + // set dex class loader + System.setProperty(WebApp.DEF_WEBAPP_CLASSLOADER, AndroidClassLoader.class.getName()); // "rogatkin.mobile.web.AndroidClassLoader" + initDeployDirectory(); + resetServ(); + } + + @SuppressLint("NewApi") + protected void initLogging() { + if (logStream != null) + return; + File logDir = new File(protectedFS ? getExternalCacheDir() : Environment.getExternalStorageDirectory(), LOGDIR); + if (Main.DEBUG) + Log.d(SERVICE_NAME, "Open log " + logDir); + if (logDir.exists() && logDir.isDirectory() || logDir.mkdirs()) { + try { + logStream = new PrintStream(new File(logDir, "access-" + System.currentTimeMillis() + ".log"), "UTF-8"); + } catch (Exception e) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Can't create log file", e); + } + } + if (logStream == null) + logStream = System.out; + else + System.setErr(logStream); + } + + protected void initDeployDirectory() { + if (Main.DEBUG) + Log.d(SERVICE_NAME, "deploy dir:" + deployDir + ", for app:" + getFilesDir()); + if (deployDir != null && deployDir.exists()) + return; + if (Main.DEBUG) + Log.d(SERVICE_NAME, "use sd:" + config.useSD + ", deployed to:" + deployDir); + config.useSD = !protectedFS; + if (config.useSD) { + deployDir = new File(Environment.getExternalStorageDirectory(), DEPLOYMENTDIR); + if (deployDir.exists() || deployDir.mkdirs()) + System.setProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR, deployDir.getPath()); + else + config.useSD = false; + } + if (config.useSD == false) { + // deployDir = new File(System.getProperty(Config.APP_HOME), + // DEPLOYMENTDIR); + deployDir = new File(getFilesDir(), DEPLOYMENTDIR); + if (deployDir.exists() == false && deployDir.mkdirs() == false) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Can't establish web apps deployment directory:" + deployDir); + deployDir = new File("/sdcard", DEPLOYMENTDIR); + } + System.setProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR, deployDir.getPath()); + } + if (Main.DEBUG) + Log.d(SERVICE_NAME, "deploy dir " + deployDir + " is " + deployDir.exists()); + } + + protected void updateWWWServlet() { + Servlet rootServlet = srv.getServlet("/*"); + if (Main.DEBUG) + Log.d(SERVICE_NAME, "Root app :" + config.rootApp + ", servlet / " + rootServlet); + if ("/".equals(config.rootApp)) { + + Acme.Serve.Serve.PathTreeDictionary aliases = new Acme.Serve.Serve.PathTreeDictionary(); + aliases.put("/*", new File(config.wwwFolder)); + srv.setMappingTable(aliases); + if (rootServlet instanceof FileServlet == false) { + if (rootServlet != null) + srv.unloadServlet(rootServlet); + srv.addDefaultServlets(null); // optional file servlet + } + } else { + if (rootServlet != null) { + srv.unloadServlet(rootServlet); + rootServlet.destroy(); + srv.unloadSessions(rootServlet.getServletConfig().getServletContext()); + } + if (config.rootApp != null) { + System.setProperty(WebAppServlet.WAR_DEPLOY_IN_ROOT, config.rootApp.substring(1)); + } else { + System.getProperties().remove(WebAppServlet.WAR_DEPLOY_IN_ROOT); + } + } + } + + protected void updateRealm() { + Acme.Serve.Serve.PathTreeDictionary realms = new Acme.Serve.Serve.PathTreeDictionary(); + if (config.password != null && config.password.length() > 0) { + Acme.Serve.Serve.BasicAuthRealm realm; + realms.put("/settings", realm = new Acme.Serve.Serve.BasicAuthRealm(Main.APP_NAME)); + realm.put("", config.password); + } + srv.setRealms(realms); + } + + protected File getKeyDir() { + File result = new File(deployDir, "../" + KEYSTORE_DIR); + if (!result.exists()) + result.mkdirs(); + return result; + } + + void storeConfig() { + config.store(this); + } + + public InetAddress getLocalIpAddress() { + try { + if (config.bindAddr != null) + return InetAddress.getByName(config.bindAddr); + } catch (UnknownHostException e) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Can't resolve :" + config.bindAddr + " " + e.toString()); + return null; + } + return getLookbackAddress(); + // return getNonLookupAddress(); + } + + public static InetAddress getLookbackAddress() { + InetAddress result = null; + try { + for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { + NetworkInterface intf = en.nextElement(); + for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if (inetAddress.isLoopbackAddress()) { + if (InetAddressUtils.isIPv4Address(inetAddress.getHostAddress())) + return inetAddress; + result = inetAddress; + // if (Main.DEBUG) + // Log.e(SERVICE_NAME, "processed addr:"+result); + } + } + } + } catch (SocketException ex) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, ex.toString()); + } + return result; + } + + public static InetAddress getNonLookupAddress(boolean any) { + InetAddress result = null; + try { + for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { + NetworkInterface intf = en.nextElement(); + for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if (!inetAddress.isLoopbackAddress()) { + if ((inetAddress.isSiteLocalAddress() == false || any) && InetAddressUtils.isIPv4Address(inetAddress.getHostAddress())) + return inetAddress; + result = inetAddress; + } + } + } + } catch (SocketException ex) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, ex.toString()); + } + return result; + } + + String updateNetworkSettings() { + config.load(this); + // port + srv.arguments.put(Acme.Serve.Serve.ARG_PORT, config.port); + // SSL + if (config.ssl) { + srv.arguments.put(Acme.Serve.Serve.ARG_ACCEPTOR_CLASS, config.webSocketEnabled ? "rogatkin.wskt.SSLSelectorAcceptor" : "Acme.Serve.SSLAcceptor"); + srv.arguments.put(Acme.Serve.SSLAcceptor.ARG_KEYSTOREFILE, new File(getKeyDir(), KEYSTORE).getPath()); + srv.arguments.put(Acme.Serve.SSLAcceptor.ARG_KEYSTOREPASS, config.password == null || "".equals(config.password) ? "changeme" : config.password); + srv.arguments.put(Acme.Serve.SSLAcceptor.ARG_KEYSTORETYPE, "BKS"); + if (Main.DEBUG) + srv.log("SSL configured as:" + srv.arguments); + } else if (config.webSocketEnabled) + srv.arguments.put(Acme.Serve.Serve.ARG_ACCEPTOR_CLASS, "Acme.Serve.SelectorAcceptor"); + else + srv.arguments.remove(Acme.Serve.Serve.ARG_ACCEPTOR_CLASS); + srv.setAccessLogged(config.logEnabled); + + // bind address + if (Main.DEBUG) + Log.d(SERVICE_NAME, "bind to " + config.bindAddr + ",use sd:" + config.useSD + ", deployed to:" + deployDir); + resetServ(); + /* + * if (config.bindAddr == null) { + * srv.arguments.put(Acme.Serve.Serve.ARG_BINDADDRESS, "127:0:0:1"); + * return "localhost"; } + */ + InetAddress iadr = getLocalIpAddress(); + if (iadr != null) { + String canonicalAddr = iadr.getCanonicalHostName(); + if (canonicalAddr != null && "null".equals(canonicalAddr) == false) { // Android + // bug + if (iadr.isAnyLocalAddress() == false) { + srv.arguments.put(Acme.Serve.Serve.ARG_BINDADDRESS, iadr.getHostAddress()); + if (Main.DEBUG) + Log.e(SERVICE_NAME, "bound:" + canonicalAddr); + return canonicalAddr; + } else { + srv.arguments.remove(Acme.Serve.Serve.ARG_BINDADDRESS); + iadr = getNonLookupAddress(false); + if (iadr != null && InetAddressUtils.isIPv4Address(iadr.getHostAddress())) + return iadr.getHostAddress(); + // else + } + } + } + srv.arguments.remove(Acme.Serve.Serve.ARG_BINDADDRESS); + if (Main.DEBUG) + Log.e(SERVICE_NAME, "No address bound"); + // return "127:0:0:1"; + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + return "127:0:0:1"; // "::" + } + } + + void resetServ() { + updateRealm(); + updateWWWServlet(); + srv.addWebsocketProvider(null); + srv.deployApps(); + updateServletsList(); + } + + protected String deployAppFrom(String u) { + FileOutputStream fos = null; + InputStream cis = null; + try { + // TODO consider using DownloadManager + URL url = new URL(u); + String appFile = url.getFile(); + int sp = appFile.lastIndexOf('/'); + if (sp >= 0) + appFile = appFile.substring(sp + 1); + File warFile; + URLConnection ucon = url.openConnection(); + ucon.setConnectTimeout(30 * 1000); + Utils.copyStream(cis = ucon.getInputStream(), fos = new FileOutputStream(warFile = new File(deployDir, appFile)), 1024 * 1024 * 512); + if (appFile.endsWith(WarRoller.DEPLOY_ARCH_EXT) == false || appFile.length() <= WarRoller.DEPLOY_ARCH_EXT.length()) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, " Invalid extension for web archive file: " + appFile + ", it is stored but not deployed"); + return "Invalid extension for web archive file: " + appFile; + } + redeploy(appFile.substring(0, appFile.length() - WarRoller.DEPLOY_ARCH_EXT.length())); + if (Main.DEBUG) + Log.d(SERVICE_NAME, appFile + " has been deployed"); + // update list + updateServletsList(); + } catch (IOException ioe) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Could't deploy " + u, ioe); + return "" + ioe; + } finally { + if (fos != null) + try { + fos.close(); + } catch (IOException e) { + } + if (cis != null) + try { + cis.close(); + } catch (IOException e) { + } + } + return null; + } + + void scanDeployments() { + deployDir.listFiles(new FileFilter() { + public boolean accept(File pathname) { + String fileName = pathname.getName(); + String appName = pathname.isFile() && fileName.toLowerCase().endsWith(WarRoller.DEPLOY_ARCH_EXT) ? fileName.substring(0, fileName.length() - WarRoller.DEPLOY_ARCH_EXT.length()) : null; + if (appName != null && findServlet("/" + appName + "/*") == false) { + srv.getDeployer().deployWar(pathname, new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET)); + if (Main.DEBUG) + Log.d(SERVICE_NAME, "Found a not deployed app " + appName); + return true; + } + return false; + } + }); + // scan for already deployed but not launched + File[] deployedFiles = new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET).listFiles(); + if (deployedFiles == null) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Invaid deploy directory: " + new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET)); + return; + } + + for (File deployedFile : deployedFiles) { + if (deployedFile.isDirectory() && findServlet("/" + deployedFile.getName() + "/*") == false) { + if (Main.DEBUG) + Log.d(SERVICE_NAME, "Found not deployed app " + deployedFile); + srv.deployApp(deployedFile.getName()); + } + } + } + + protected Object doAppOper(OperCode oc, String appName) { + Servlet servlet = srv.getServlet(appName); + if (servlet == null) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "No servlet found for " + appName); + return null; + } + WebAppServlet appServlet = servlet instanceof WebAppServlet ? (WebAppServlet) servlet : null; + switch (oc) { + case info: + return servlet.getServletInfo(); + case deploy: + if (appServlet != null) { + redeploy(appName.substring(0, appName.length() - "/*".length())); + updateServletsList(); + } + return servletsList; + case remove: + if (appServlet != null) { + if (appName.endsWith("/*")) + appName = appName.substring(1, appName.length() - 2); + else if (appName.endsWith("/")) + appName = appName.substring(1, appName.length() - 1); + File appWar = new File(deployDir, appName + WarRoller.DEPLOY_ARCH_EXT); + if (appWar.delete() == false) + if (Main.DEBUG) + Log.e(SERVICE_NAME, "File can't be deleted " + appWar); + else { + File appFile = new File(new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET), appName); + if (deleteRecursively(appFile) == false) { + if (Main.DEBUG) + Log.e(SERVICE_NAME, "File can't be deleted " + appFile); + } + } + } else if (Main.DEBUG) + Log.e(SERVICE_NAME, "Can't find app " + appName + " to remove"); + return null; + case stop: + servlet = srv.unloadServlet(servlet); + if (servlet != null) { + servlet.destroy(); + srv.unloadSessions(servlet.getServletConfig().getServletContext()); + } else if (Main.DEBUG) + Log.e(SERVICE_NAME, "Couldn't unload servlet for " + appName); + updateServletsList(); + return servletsList; + } + return null; + } + + protected void redeploy(String appName) { + Servlet servlet = srv.getServlet(appName + "/*"); + // TODO use this code for context menu reload to avoid crash + if (servlet != null) { + servlet = srv.unloadServlet(servlet); + if (servlet != null && servlet instanceof WebAppServlet) { + servlet.destroy(); + srv.unloadSessions(servlet.getServletConfig().getServletContext()); + File dexCacheDir = new File(new File(new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET), appName), "META-INF/DEX/" + SERVICE_NAME); + // Log.d(APP_NAME, ""+dexCacheDir); + if (dexCacheDir.exists() && dexCacheDir.isAbsolute()) { + deleteRecursively(dexCacheDir); + } + } + } + srv.getDeployer().deployWar(new File(deployDir, appName + WarRoller.DEPLOY_ARCH_EXT), new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET)); + srv.deployApp(appName); + } + + private boolean deleteRecursively(final File file) { + for (File curf : file.listFiles()) { + if (curf.isFile()) { + if (curf.delete() == false) { + return false; + } + } else if (curf.isDirectory()) { + if (deleteRecursively(curf) == false) { + return false; + } + } else { + return false; + } + } + + return file.delete(); + } + + private void updateServletsList() { + if (servletsList == null){ + servletsList = new ArrayList(); + } + else { + servletsList.clear(); + } + Enumeration servlets = srv.getServletNames(); + while (servlets.hasMoreElements()) { + servletsList.add((String) servlets.nextElement()); + } + } + + /** + * + * @param servletName + * @return + */ + private boolean findServlet(String servletName) { + for (String curName : servletsList) { + if (curName.equals(servletName)) { + return true; + } + } + return false; + } + + class AndroidServer extends Acme.Serve.Serve { + /** deployer */ + private WarRoller deployer; + + public AndroidServ(Properties arguments, PrintStream logStream, Object runtime) { + super(arguments, logStream); + // provide servlet context Android environment access + WebAppServlet.setRuntimeEnv(runtime); + // addWebsocketProvider(WSProvider.class.toString()); + } + + @Override + protected void addWebsocketProvider(String provider) { + if (config.webSocketEnabled) { + websocketProvider = new WSProvider(); + websocketProvider.init(this); + websocketProvider.deploy(this, null); + } else { + websocketProvider = null; + } + } + + // Overriding method for public access + @Override + public void setMappingTable(PathTreeDictionary mappingtable) { + super.setMappingTable(mappingtable); + } + + @Override + protected void setRealms(PathTreeDictionary realms) { + super.setRealms(realms); + } + + public synchronized void deployApps() { + if (deployer == null) + deployer = new WarRoller(); + try { + deployer.deploy(this); + } catch (Throwable t) { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Unexpected problem in deploying apps", t); + } + } + + public synchronized boolean deployApp(String appName) { + // deployer must be not null + try { + WebAppServlet webAppServlet = WebAppServlet.create(new File(new File(deployDir, WarRoller.DEPLOYMENT_DIR_TARGET), appName), appName, this, null); + addServlet(webAppServlet.getContextPath() + "/*", webAppServlet, null); + return true; + } catch (Throwable t) { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + if (Main.DEBUG) + Log.e(SERVICE_NAME, "Problem in deployment " + appName, t); + } + return false; + } + + WarRoller getDeployer() { + return deployer; + } + + protected void setAccessLogged(boolean on) { + if (on) + arguments.put(ARG_LOG_OPTIONS, "L"); + else + arguments.remove(ARG_LOG_OPTIONS); + setAccessLogged(); + } + } +} diff --git a/Atjeews/src/rogatkin/mobile/web/WSProvider.java b/Atjeews/src/rogatkin/mobile/web/WSProvider.java new file mode 100755 index 0000000..b38b0f9 --- /dev/null +++ b/Atjeews/src/rogatkin/mobile/web/WSProvider.java @@ -0,0 +1,115 @@ +/** Copyright 2015 Dmitriy Rogatkin, All rights reserved. + * $Id: WSProvider.java,v 1.3 2012/09/15 17:47:27 dmitriy Exp $ + */package rogatkin.mobile.web; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; + +import javax.servlet.ServletContext; +import javax.websocket.DeploymentException; +import javax.websocket.Endpoint; +import javax.websocket.server.ServerApplicationConfig; +import javax.websocket.server.ServerEndpointConfig; + +import rogatkin.web.WebAppServlet; +import rogatkin.wskt.SimpleProvider; +import rogatkin.wskt.SimpleServerContainer; + +public class WSProvider extends SimpleProvider { + + public WSProvider() { + // TODO Auto-generated constructor stub + } + + @Override + public void deploy(ServletContext servCtx, List cp) { + SimpleServerContainer ssc = new SimpleServerContainer(this); + HashSet appCfgs = new HashSet(); + HashSet> annSeps = new HashSet>(); + HashSet> endps = new HashSet>(); + if (servCtx instanceof WebAppServlet) { + WebAppServlet webApp = (WebAppServlet)servCtx; + File wsInfo = new File(webApp.getDeploymentDir(), "META-INF/websocket/websocket.info"); + if (wsInfo.exists()) { + BufferedReader fr = null; + try { + fr = new BufferedReader(new FileReader(wsInfo)); + String s = + fr.readLine(); + while(s != null) { + if (s.startsWith("ServerEndpoint ")) { + try { + annSeps.add(Class.forName(s.substring("ServerEndpoint ".length()), true, webApp.getClassLoader())); + } catch (ClassNotFoundException e) { + serve.log(e, "Server Endpoint not found"); + } + } else if (s.startsWith("ServerApplicationConfig ")) { + try { + appCfgs.add((ServerApplicationConfig) Class.forName(s.substring("ServerApplicationConfig ".length()), true, webApp.getClassLoader()).newInstance()); + } catch (InstantiationException e) { + serve.log(e, "Error at deployment"); + } catch (IllegalAccessException e) { + serve.log(e, "Error at deployment"); + } catch (ClassNotFoundException e) { + serve.log(e, "Endpoint config not found"); + } + } else if (s.startsWith("Endpoint ")) { + try { + endps.add((Class) Class.forName(s.substring("Endpoint ".length()), true, webApp.getClassLoader())); + } catch (ClassNotFoundException e) { + serve.log(e, "Endpoint not found"); + } + } + s = fr.readLine(); + } + } catch(IOException e) { + + } finally { + if (fr != null) + try { + fr.close(); + } catch(Exception e) { + + } + } + } + } + if (appCfgs.size() > 0) { + for (ServerApplicationConfig sac : appCfgs) { + for (Class se : sac.getAnnotatedEndpointClasses(annSeps)) + try { + ssc.addEndpoint(se); + serve.log("Deployed ServerEndpoint " + se); + } catch (DeploymentException de) { + + } + for (ServerEndpointConfig epc : sac.getEndpointConfigs(endps)) + try { + ssc.addEndpoint(epc); + serve.log("Deployed ServerEndpointConfig " + epc); + } catch (DeploymentException de) { + + } + } + } else { + for (Class se : annSeps) + try { + ssc.addEndpoint(se); + serve.log("Deployed ServerEndpoint " + se); + } catch (DeploymentException de) { + + } + } + servCtx.setAttribute("javax.websocket.server.ServerContainer", ssc); + try { + servCtx.addListener(ssc); + } catch (Error e) { + // serve is still on old servlet spec + } + } + +} diff --git a/1.x/src/jasper/BeeCompiler.java b/BeeCompiler/jasper/BeeCompiler.java old mode 100644 new mode 100755 similarity index 76% rename from 1.x/src/jasper/BeeCompiler.java rename to BeeCompiler/jasper/BeeCompiler.java index 5d4c9f0..0b442d9 --- a/1.x/src/jasper/BeeCompiler.java +++ b/BeeCompiler/jasper/BeeCompiler.java @@ -1,12 +1,9 @@ /* * Copyright 1999,2004 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -35,68 +32,68 @@ * @author Dmitriy Rogatkin */ public class BeeCompiler extends Compiler { - + static { System.setErr(new SystemLogHandler(System.err)); } - + /** * Compile the servlet from .java file to .class file */ protected void generateClass(String[] smap) throws FileNotFoundException, JasperException, Exception { - + long t1 = 0; - if (log.isDebugEnabled()) { + if(log.isDebugEnabled()) { t1 = System.currentTimeMillis(); } - + List parameters = new ArrayList(20); parameters.add("-encoding"); parameters.add(ctxt.getOptions().getJavaEncoding()); - + String javaFileName = new File(ctxt.getServletJavaFileName()).getPath(); String classpath = ctxt.getClassPath(); - + String sep = File.pathSeparator; // System.getProperty("path.separator"); - + StringBuffer errorReport = new StringBuffer(); - + StringBuffer info = new StringBuffer(); info.append("Compile: javaFileName=" + javaFileName + "\n"); - + // Start capturing the System.err output for this thread SystemLogHandler.setThread(); - + // Initializing classpath String path = System.getProperty("java.class.path"); info.append(" cmd cp=" + path + "\n"); info.append(" ctx cp=" + classpath + "\n"); path += sep; path += classpath; - - if (log.isDebugEnabled()) + + if(log.isDebugEnabled()) log.debug("Using classpath: " + path); - + parameters.add("-classpath"); parameters.add(path); - + // Initializing sourcepath parameters.add("-sourcepath"); parameters.add(options.getScratchDir().getPath()); - + info.append(" work dir=" + options.getScratchDir() + "\n"); - + // Initialize and set java extensions String extdirs = System.getProperty("java.ext.dirs"); - if (extdirs != null) { + if(extdirs != null) { parameters.add("-extdirs"); parameters.add(extdirs); info.append(" extension dir=" + extdirs + "\n"); } - - if (ctxt.getOptions().getFork()) { + + if(ctxt.getOptions().getFork()) { String endorsed = System.getProperty("java.endorsed.dirs"); - if (endorsed != null) { + if(endorsed != null) { parameters.add("-endorseddirs"); // "-J-Djava.endorsed.dirs="+endorsed parameters.add(endorsed); info.append(" endorsed dir=" + endorsed + "\n"); @@ -104,96 +101,95 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper info.append(" no endorsed dirs specified\n"); } } - - if (ctxt.getOptions().getClassDebugInfo()) + + if(ctxt.getOptions().getClassDebugInfo()) parameters.add("-g"); - + // Set the Java compiler to use String compiler = options.getCompiler(); - if (compiler == null) { + if(compiler == null) { compiler = "com.sun.tools.javac.Main"; } info.append(" compiler=" + compiler + "\n"); - - if (options.getCompilerTargetVM() != null) { + + if(options.getCompilerTargetVM() != null) { parameters.add("-target"); parameters.add(options.getCompilerTargetVM()); info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n"); } - - if (options.getCompilerSourceVM() != null) { + + if(options.getCompilerSourceVM() != null) { parameters.add("-source"); parameters.add(options.getCompilerSourceVM()); info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n"); } - + info.append(" JavaPath=" + ctxt.getJavaPath() + "\n"); - + parameters.add(javaFileName); - + boolean compilationErrors = false; Exception ie = null; try { Integer success; Method cm = Class.forName(compiler).getMethod("compile", new Class[] { String[].class }); - if (ctxt.getOptions().getFork()) { - success = (Integer)cm.invoke(null, new Object[] {parameters.toArray(new String[parameters.size()])}); + if(ctxt.getOptions().getFork()) { + success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters.size()]) }); } else { - synchronized (javacLock) { - success = (Integer) cm.invoke(null, new Object[] {parameters.toArray(new String[parameters.size()])}); + synchronized(javacLock) { + success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters.size()]) }); } } - if (success.intValue() != 0) + if(success.intValue() != 0) compilationErrors = true; - } catch (Throwable t) { - if (t instanceof InvocationTargetException) + } catch(Throwable t) { + if(t instanceof InvocationTargetException) t = t.getCause(); - if (t instanceof Exception) - ie = (Exception)t; + if(t instanceof Exception) + ie = (Exception) t; else ie = new Exception(t); log.error("Javac exception ", t); log.error("Env: " + info.toString()); } - + // Stop capturing the System.err output for this thread String errorCapture = SystemLogHandler.unsetThread(); - if (compilationErrors && errorCapture != null) { + if(compilationErrors && errorCapture != null) { errorReport.append(System.getProperty("line.separator")); errorReport.append(errorCapture); } - - if (!ctxt.keepGenerated()) { + + if(!ctxt.keepGenerated()) { File javaFile = new File(javaFileName); javaFile.delete(); } - - if (compilationErrors || ie != null) { + + if(compilationErrors || ie != null) { String errorReportString = errorReport.toString(); log.error("Error compiling file: " + javaFileName + " " + errorReportString); - JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(errorReportString, javaFileName, - pageNodes); - if (javacErrors != null) { + JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(errorReportString, javaFileName, pageNodes); + if(javacErrors != null) { errDispatcher.javacError(javacErrors); } else { errDispatcher.javacError(errorReportString, ie); } } - - if (log.isDebugEnabled()) { + + if(log.isDebugEnabled()) { long t2 = System.currentTimeMillis(); log.debug("Compiled " + ctxt.getServletJavaFileName() + " " + (t2 - t1) + "ms"); } - - if (ctxt.isPrototypeMode()) { + + if(ctxt.isPrototypeMode()) { return; } - + // JSR45 Support - if (!options.isSmapSuppressed()) { - log.debug("Install Smap " + (smap==null?"null":Arrays.toString(smap))); + if(!options.isSmapSuppressed()) { + log.debug("Install Smap " + (smap == null ? "null" : Arrays.toString(smap))); SmapUtil.installSmap(smap); } } - + } diff --git a/BeeCompiler/jasper/JspC.java b/BeeCompiler/jasper/JspC.java new file mode 100755 index 0000000..2056bc3 --- /dev/null +++ b/BeeCompiler/jasper/JspC.java @@ -0,0 +1,1351 @@ +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.Options; +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.servlet.JspCServletContext; + +import Acme.IOHelper; + +/** + * Shell for the jspc compiler. Handles all options associated with the + * command line and creates compilation contexts which it then compiles + * according to the specified options. + * + * This version can process files from a _single_ webapp at once, i.e. + * a single docbase can be specified. + * + * It can be used as an Ant task using: + * + *
+ *   <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
+ *      <classpath>
+ *          <pathelement location="${java.home}/../lib/tools.jar"/>
+ *          <fileset dir="${ENV.CATALINA_HOME}/server/lib">
+ *              <include name="*.jar"/>
+ *          </fileset>
+ *          <fileset dir="${ENV.CATALINA_HOME}/common/lib">
+ *              <include name="*.jar"/>
+ *          </fileset>
+ *          <path refid="myjars"/>
+ *       </classpath>
+ *  </taskdef>
+ *
+ *  <jasper2 verbose="0"
+ *           package="my.package"
+ *           uriroot="${webapps.dir}/${webapp.name}"
+ *           webXmlFragment="${build.dir}/generated_web.xml"
+ *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
+ * 
+ * + * @author Danno Ferrin + * @author Pierre Delisle + * @author Costin Manolache + * @author Yoav Shapira + */ +public class JspC implements Options { + + public static final String DEFAULT_IE_CLASS_ID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + // Logger + private static Log log = LogFactory.getLog(JspC.class); + + private static final String SWITCH_VERBOSE = "-v"; + private static final String SWITCH_HELP = "-help"; + private static final String SWITCH_QUIET = "-q"; + private static final String SWITCH_OUTPUT_DIR = "-d"; + private static final String SWITCH_IE_CLASS_ID = "-ieplugin"; + private static final String SWITCH_PACKAGE_NAME = "-p"; + private static final String SWITCH_CACHE = "-cache"; + private static final String SWITCH_CLASS_NAME = "-c"; + private static final String SWITCH_FULL_STOP = "--"; + private static final String SWITCH_COMPILE = "-compile"; + private static final String SWITCH_SOURCE = "-source"; + private static final String SWITCH_TARGET = "-target"; + private static final String SWITCH_URI_BASE = "-uribase"; + private static final String SWITCH_URI_ROOT = "-uriroot"; + private static final String SWITCH_FILE_WEBAPP = "-webapp"; + private static final String SWITCH_WEBAPP_INC = "-webinc"; + private static final String SWITCH_WEBAPP_XML = "-webxml"; + private static final String SWITCH_MAPPED = "-mapped"; + private static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; + private static final String SWITCH_TRIM_SPACES = "-trimSpaces"; + private static final String SWITCH_CLASSPATH = "-classpath"; + private static final String SWITCH_DIE = "-die"; + private static final String SWITCH_POOLING = "-poolingEnabled"; + private static final String SWITCH_ENCODING = "-javaEncoding"; + private static final String SWITCH_SMAP = "-smap"; + private static final String SWITCH_DUMP_SMAP = "-dumpsmap"; + + private static final String SHOW_SUCCESS = "-s"; + private static final String LIST_ERRORS = "-l"; + private static final int NO_WEBXML = 0; + private static final int INC_WEBXML = 10; + private static final int ALL_WEBXML = 20; + private static final int DEFAULT_DIE_LEVEL = 1; + private static final int NO_DIE_LEVEL = 0; + + private static final String[] insertBefore = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }; + + private static int die; + private String classPath = null; + private URLClassLoader loader = null; + private boolean trimSpaces = false; + private boolean genStringAsCharArray = false; + private boolean xpoweredBy; + private boolean mappedFile = false; + private boolean poolingEnabled = true; + private File scratchDir; + private String ieClassId = DEFAULT_IE_CLASS_ID; + private String targetPackage; + private String targetClassName; + private String uriBase; + private String uriRoot; + private int dieLevel; + private boolean helpNeeded = false; + private boolean compile = false; + private boolean smapSuppressed = true; + private boolean smapDumped = false; + private boolean caching = true; + private Map cache = new HashMap(); + + private String compiler = null; + + private String compilerTargetVM = "1.4"; + private String compilerSourceVM = "1.4"; + + private boolean classDebugInfo = true; + + /** + * Throw an exception if there's a compilation error, or swallow it. + * Default is true to preserve old behavior. + */ + private boolean failOnError = true; + + /** + * The file extensions to be handled as JSP files. + * Default list is .jsp and .jspx. + */ + private List extensions; + + /** + * The pages. + */ + private List pages = new Vector(); + + /** + * Needs better documentation, this data member does. + * True by default. + */ + private boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * The java file encoding. Default + * is UTF-8. Added per bugzilla 19622. + */ + private String javaEncoding = IOHelper.UTF_8; + + // Generation of web.xml fragments + private String webxmlFile; + private int webxmlLevel; + private boolean addWebXmlMappings = false; + + private Writer mapout; + private CharArrayWriter servletout; + private CharArrayWriter mappingout; + + /** + * The servlet context. + */ + private JspCServletContext context; + + /** + * The runtime context. + * Maintain a dummy JspRuntimeContext for compiling tag files. + */ + private JspRuntimeContext rctxt; + + /** + * Cache for the TLD locations + */ + private TldLocationsCache tldLocationsCache = null; + + private JspConfig jspConfig = null; + private TagPluginManager tagPluginManager = null; + + private boolean verbose = false; + private boolean listErrors = false; + private boolean showSuccess = false; + private int argPos; + private boolean fullstop = false; + private String args[]; + + public static void main(String arg[]) { + if (arg.length == 0) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + try { + JspC jspc = new JspC(); + jspc.setArgs(arg); + if (jspc.helpNeeded) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + jspc.execute(); + } + } catch (JasperException je) { + System.err.println(je); + // System.err.println(je.getMessage()); + if (die != NO_DIE_LEVEL) { + System.exit(die); + } + } + } + } + + public void setArgs(String[] arg) throws JasperException { + args = arg; + String tok; + + dieLevel = NO_DIE_LEVEL; + die = dieLevel; + + while ((tok = nextArg()) != null) { + if (tok.equals(SWITCH_VERBOSE)) { + verbose = true; + showSuccess = true; + listErrors = true; + } else if (tok.equals(SWITCH_OUTPUT_DIR)) { + tok = nextArg(); + setOutputDir(tok); + } else if (tok.equals(SWITCH_PACKAGE_NAME)) { + targetPackage = nextArg(); + } else if (tok.equals(SWITCH_COMPILE)) { + compile = true; + } else if (tok.equals(SWITCH_CLASS_NAME)) { + targetClassName = nextArg(); + } else if (tok.equals(SWITCH_URI_BASE)) { + uriBase = nextArg(); + } else if (tok.equals(SWITCH_URI_ROOT)) { + setUriroot(nextArg()); + } else if (tok.equals(SWITCH_FILE_WEBAPP)) { + setUriroot(nextArg()); + } else if (tok.equals(SHOW_SUCCESS)) { + showSuccess = true; + } else if (tok.equals(LIST_ERRORS)) { + listErrors = true; + } else if (tok.equals(SWITCH_WEBAPP_INC)) { + webxmlFile = nextArg(); + if (webxmlFile != null) { + webxmlLevel = INC_WEBXML; + } + } else if (tok.equals(SWITCH_WEBAPP_XML)) { + webxmlFile = nextArg(); + if (webxmlFile != null) { + webxmlLevel = ALL_WEBXML; + } + } else if (tok.equals(SWITCH_MAPPED)) { + mappedFile = true; + } else if (tok.equals(SWITCH_XPOWERED_BY)) { + xpoweredBy = true; + } else if (tok.equals(SWITCH_TRIM_SPACES)) { + setTrimSpaces(true); + } else if (tok.equals(SWITCH_CACHE)) { + tok = nextArg(); + if ("false".equals(tok)) { + caching = false; + } else { + caching = true; + } + } else if (tok.equals(SWITCH_CLASSPATH)) { + setClassPath(nextArg()); + } else if (tok.startsWith(SWITCH_DIE)) { + try { + dieLevel = Integer.parseInt(tok.substring(SWITCH_DIE.length())); + } catch (NumberFormatException nfe) { + dieLevel = DEFAULT_DIE_LEVEL; + } + die = dieLevel; + } else if (tok.equals(SWITCH_HELP)) { + helpNeeded = true; + } else if (tok.equals(SWITCH_POOLING)) { + tok = nextArg(); + if ("false".equals(tok)) { + poolingEnabled = false; + } else { + poolingEnabled = true; + } + } else if (tok.equals(SWITCH_ENCODING)) { + setJavaEncoding(nextArg()); + } else if (tok.equals(SWITCH_SOURCE)) { + setCompilerSourceVM(nextArg()); + } else if (tok.equals(SWITCH_TARGET)) { + setCompilerTargetVM(nextArg()); + } else if (tok.equals(SWITCH_SMAP)) { + smapSuppressed = false; + } else if (tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; + } else { + if (tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + ". Use -help for help."); + } + if (!fullstop) { + argPos--; + } + // Start treating the rest as JSP Pages + break; + } + } + + // Add all extra arguments to the list of files + while (true) { + String file = nextFile(); + if (file == null) { + break; + } + pages.add(file); + } + } + + public boolean getKeepGenerated() { + // isn't this why we are running jspc? + return true; + } + + public boolean getTrimSpaces() { + return trimSpaces; + } + + public void setTrimSpaces(boolean ts) { + this.trimSpaces = ts; + } + + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + public boolean isXpoweredBy() { + return xpoweredBy; + } + + public void setXpoweredBy(boolean xpoweredBy) { + this.xpoweredBy = xpoweredBy; + } + + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + public int getTagPoolSize() { + return Constants.MAX_POOL_SIZE; + } + + /** + * Are we supporting HTML mapped servlets? + */ + public boolean getMappedFile() { + return mappedFile; + } + + // Off-line compiler, no need for security manager + public Object getProtectionDomain() { + return null; + } + + public boolean getSendErrorToClient() { + // implied send to System.err + return true; + } + + public void setClassDebugInfo(boolean b) { + classDebugInfo = b; + } + + public boolean getClassDebugInfo() { + // compile with debug info + return classDebugInfo; + } + + /** + * @see Options#isCaching() + */ + public boolean isCaching() { + return caching; + } + + /** + * @see Options#isCaching() + */ + public void setCaching(boolean caching) { + this.caching = caching; + } + + /** + * @see Options#getCache() + */ + public Map getCache() { + return cache; + } + + /** + * Background compilation check intervals in seconds + */ + public int getCheckInterval() { + return 0; + } + + /** + * Modification test interval. + */ + public int getModificationTestInterval() { + return 0; + } + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment() { + return false; + } + + /** + * Is the generation of SMAP info for JSR45 debuggin suppressed? + */ + public boolean isSmapSuppressed() { + return smapSuppressed; + } + + /** + * Set smapSuppressed flag. + */ + public void setSmapSuppressed(boolean smapSuppressed) { + this.smapSuppressed = smapSuppressed; + } + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + public boolean isSmapDumped() { + return smapDumped; + } + + /** + * Set smapSuppressed flag. + */ + public void setSmapDumped(boolean smapDumped) { + this.smapDumped = smapDumped; + } + + /** + * Determines whether text strings are to be generated as char arrays, + * which improves performance in some cases. + * + * @param genStringAsCharArray + * true if text strings are to be generated as + * char arrays, false otherwise + */ + public void setGenStringAsCharArray(boolean genStringAsCharArray) { + this.genStringAsCharArray = genStringAsCharArray; + } + + /** + * Indicates whether text strings are to be generated as char arrays. + * + * @return true if text strings are to be generated as char arrays, false + * otherwise + */ + public boolean genStringAsCharArray() { + return genStringAsCharArray; + } + + /** + * Sets the class-id value to be sent to Internet Explorer when using + * tags. + * + * @param ieClassId + * Class-id value + */ + public void setIeClassId(String ieClassId) { + this.ieClassId = ieClassId; + } + + /** + * Gets the class-id value that is sent to Internet Explorer when using + * tags. + * + * @return Class-id value + */ + public String getIeClassId() { + return ieClassId; + } + + public File getScratchDir() { + return scratchDir; + } + + public Class getJspCompilerPlugin() { + // we don't compile, so this is meanlingless + return null; + } + + public String getJspCompilerPath() { + // we don't compile, so this is meanlingless + return null; + } + + /** + * Compiler to use. + */ + public String getCompiler() { + return compiler; + } + + public void setCompiler(String c) { + compiler = c; + } + + /** + * @see Options#getCompilerTargetVM + */ + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + public void setCompilerTargetVM(String vm) { + compilerTargetVM = vm; + } + + /** + * @see Options#getCompilerSourceVM() + */ + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * @see Options#getCompilerSourceVM() + */ + public void setCompilerSourceVM(String vm) { + compilerSourceVM = vm; + } + + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + /** + * Returns the encoding to use for + * java files. The default is UTF-8. + * + * @return String The encoding + */ + public String getJavaEncoding() { + return javaEncoding; + } + + /** + * Sets the encoding to use for + * java files. + * + * @param encodingName + * The name, e.g. "UTF-8" + */ + public void setJavaEncoding(String encodingName) { + javaEncoding = encodingName; + } + + public boolean getFork() { + return false; + } + + /** + * + * @return + * @see org.apache.jasper.Options#getClassPath() + */ + public String getClassPath() { + return (classPath != null ? classPath : System.getProperty("java.class.path"); + } + + /** + * + * @param s + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * Returns the list of file extensions + * that are treated as JSP files. + * + * @return The list of extensions + */ + public List getExtensions() { + return extensions; + } + + /** + * Adds the given file extension to the + * list of extensions handled as JSP files. + * + * @param extension + * The extension to add, e.g. "myjsp" + */ + protected void addExtension(final String extension) { + if (extension != null) { + if (extensions == null) { + extensions = new Vector(); + } + + extensions.add(extension); + } + } + + /** + * Base dir for the webapp. Used to generate class names and resolve + * includes + */ + public void setUriroot(String s) { + if (s == null) { + uriRoot = s; + return; + } + try { + uriRoot = resolveFile(s).getCanonicalPath(); + } catch (Exception ex) { + uriRoot = s; + } + } + + /** + * Parses comma-separated list of JSP files to be processed. If the argument + * is null, nothing is done. + * + *

+ * Each file is interpreted relative to uriroot, unless it is absolute, + * in which case it must start with uriroot. + *

+ * + * @param jspFiles + * Comma-separated list of JSP files to be processed + */ + public void setJspFiles(final String jspFiles) { + if (jspFiles == null) { + return; + } + + StringTokenizer tok = new StringTokenizer(jspFiles, ","); + while (tok.hasMoreTokens()) { + pages.add(tok.nextToken()); + } + } + + /** + * Sets the compile flag. + * + * @param b + * Flag value + */ + public void setCompile(final boolean b) { + compile = b; + } + + /** + * Sets the verbosity level. The actual number doesn't + * matter: if it's greater than zero, the verbose flag will + * be true. + * + * @param level + * Positive means verbose + */ + public void setVerbose(final int level) { + if (level > 0) { + verbose = true; + showSuccess = true; + listErrors = true; + } + } + + public void setValidateXml(boolean b) { + org.apache.jasper.xmlparser.ParserUtils.validating = b; + } + + public void setListErrors(boolean b) { + listErrors = b; + } + + public void setOutputDir(String s) { + if (s != null) { + scratchDir = resolveFile(s).getAbsoluteFile(); + } else { + scratchDir = null; + } + } + + public void setPackage(String p) { + targetPackage = p; + } + + /** + * Class name of the generated file ( without package ). + * Can only be used if a single file is converted. + * XXX Do we need this feature ? + */ + public void setClassName(String p) { + targetClassName = p; + } + + /** + * File where we generate a web.xml fragment with the class definitions. + */ + public void setWebXmlFragment(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = INC_WEBXML; + } + + /** + * File where we generate a complete web.xml with the class definitions. + */ + public void setWebXml(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = ALL_WEBXML; + } + + public void setAddWebXmlMappings(boolean b) { + addWebXmlMappings = b; + } + + /** + * Set the option that throws an exception in case of a compilation error. + */ + public void setFailOnError(final boolean b) { + failOnError = b; + } + + public boolean getFailOnError() { + return failOnError; + } + + /** + * Obtain JSP configuration informantion specified in web.xml. + */ + public JspConfig getJspConfig() { + return jspConfig; + } + + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + public void generateWebMapping(String file, JspCompilationContext clctxt) throws IOException { + String className = clctxt.getServletClassName(); + String packageName = clctxt.getServletPackageName(); + + String thisServletName; + if ("".equals(packageName)) { + thisServletName = className; + } else { + thisServletName = packageName + '.' + className; + } + + if (servletout != null) { + servletout.write("\n \n "); + servletout.write(thisServletName); + servletout.write("\n "); + servletout.write(thisServletName); + servletout.write("\n \n"); + } + if (mappingout != null) { + mappingout.write("\n \n "); + mappingout.write(thisServletName); + mappingout.write("\n "); + mappingout.write(file.replace('\\', '/')); + mappingout.write("\n \n"); + + } + } + + /** + * Include the generated web.xml inside the webapp's web.xml. + */ + protected void mergeIntoWebXml() throws IOException { + + File webappBase = new File(uriRoot); + File webXml = new File(webappBase, "WEB-INF/web.xml"); + File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); + String insertStartMarker = Localizer.getMessage("jspc.webinc.insertStart"); + String insertEndMarker = Localizer.getMessage("jspc.webinc.insertEnd"); + + BufferedReader reader = new BufferedReader(new FileReader(webXml)); + BufferedReader fragmentReader = new BufferedReader(new FileReader(webxmlFile)); + PrintWriter writer = new PrintWriter(new FileWriter(webXml2)); + + // Insert the and declarations + int pos = -1; + String line = null; + while (true) { + line = reader.readLine(); + if (line == null) { + break; + } + // Skip anything previously generated by JSPC + if (line.indexOf(insertStartMarker) >= 0) { + while (true) { + line = reader.readLine(); + if (line == null) { + return; + } + if (line.indexOf(insertEndMarker) >= 0) { + line = reader.readLine(); + line = reader.readLine(); + if (line == null) { + return; + } + break; + } + } + } + for (int i = 0; i < insertBefore.length; i++) { + pos = line.indexOf(insertBefore[i]); + if (pos >= 0) + break; + } + if (pos >= 0) { + writer.print(line.substring(0, pos)); + break; + } else { + writer.println(line); + } + } + + writer.println(insertStartMarker); + while (true) { + String line2 = fragmentReader.readLine(); + if (line2 == null) { + writer.println(); + break; + } + writer.println(line2); + } + writer.println(insertEndMarker); + writer.println(); + + for (int i = 0; i < pos; i++) { + writer.print(" "); + } + writer.println(line.substring(pos)); + + while (true) { + line = reader.readLine(); + if (line == null) { + break; + } + writer.println(line); + } + writer.close(); + + reader.close(); + fragmentReader.close(); + + FileInputStream fis = new FileInputStream(webXml2); + FileOutputStream fos = new FileOutputStream(webXml); + + byte buf[] = new byte[512]; + while (true) { + int n = fis.read(buf); + if (n < 0) { + break; + } + fos.write(buf, 0, n); + } + + fis.close(); + fos.close(); + + webXml2.delete(); + (new File(webxmlFile)).delete(); + + } + + private void processFile(String file) throws JasperException { + ClassLoader originalClassLoader = null; + + try { + // set up a scratch/output dir if none is provided + if (scratchDir == null) { + String temp = System.getProperty("java.io.tmpdir"); + if (temp == null) { + temp = ""; + } + scratchDir = new File(new File(temp).getAbsolutePath()); + } + + String jspUri = file.replace('\\', '/'); + JspCompilationContext clctxt = new JspCompilationContext(jspUri, false, this, context, null, rctxt); + + /* Override the defaults */ + if ((targetClassName != null) && (targetClassName.length() > 0)) { + clctxt.setServletClassName(targetClassName); + targetClassName = null; + } + if (targetPackage != null) { + clctxt.setServletPackageName(targetPackage); + } + + originalClassLoader = Thread.currentThread().getContextClassLoader(); + if (loader == null) { + initClassLoader(clctxt); + } + Thread.currentThread().setContextClassLoader(loader); + + clctxt.setClassLoader(loader); + clctxt.setClassPath(classPath); + + Compiler clc = clctxt.createCompiler(); + + // If compile is set, generate both .java and .class, if + // .jsp file is newer than .class file; + // Otherwise only generate .java, if .jsp file is newer than + // the .java file + if (clc.isOutDated(compile)) { + clc.compile(compile, true); + } + + // Generate mapping + generateWebMapping(file, clctxt); + if (showSuccess) { + log.info("Built File: " + file); + } + + } catch (JasperException je) { + Throwable rootCause = je; + while (rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if (rootCause != je) { + log.error(Localizer.getMessage("jspc.error.generalException", file), rootCause); + } + + // Bugzilla 35114. + if (getFailOnError()) { + throw je; + } else { + log.error(je.getMessage()); + } + + } catch (Exception e) { + if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", e.getMessage())); + } + throw new JasperException(e); + } finally { + if (originalClassLoader != null) { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + + /** + * Locate all jsp files in the webapp. Used if no explicit + * jsps are specified. + */ + public void scanFiles(File base) throws JasperException { + Stack dirs = new Stack(); + dirs.push(base); + + // Make sure default extensions are always included + if ((getExtensions() == null) || (getExtensions().size() < 2)) { + addExtension("jsp"); + addExtension("jspx"); + } + + while (!dirs.isEmpty()) { + String s = dirs.pop().toString(); + File f = new File(s); + if (f.exists() && f.isDirectory()) { + String[] files = f.list(); + String ext; + for (int i = 0; (files != null) && i < files.length; i++) { + File f2 = new File(s, files[i]); + if (f2.isDirectory()) { + dirs.push(f2.getPath()); + } else { + String path = f2.getPath(); + String uri = path.substring(uriRoot.length()); + ext = files[i].substring(files[i].lastIndexOf('.') + 1); + if (getExtensions().contains(ext) || jspConfig.isJspPage(uri)) { + pages.add(path); + } + } + } + } + } + } + + /** + * Executes the compilation. + * + * @throws JasperException + * If an error occurs + */ + public void execute() throws JasperException { + if (log.isDebugEnabled()) { + log.debug("execute() starting for " + pages.size() + " pages."); + } + + try { + if (uriRoot == null) { + if (pages.size() == 0) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget")); + } + String firstJsp = (String) pages.get(0); + File firstJspF = new File(firstJsp); + if (!firstJspF.exists()) { + throw new JasperException(Localizer.getMessage("jspc.error.fileDoesNotExist", firstJsp)); + } + locateUriRoot(firstJspF); + } + + if (uriRoot == null) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot")); + } + + if (context == null) { + initServletContext(); + } + + // No explicit pages, we'll process all .jsp in the webapp + if (pages.size() == 0) { + scanFiles(new File(uriRoot)); + } + + File uriRootF = new File(uriRoot); + if (!uriRootF.exists() || !uriRootF.isDirectory()) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); + } + + initWebXml(); + + Iterator iter = pages.iterator(); + while (iter.hasNext()) { + String nextjsp = iter.next().toString(); + File fjsp = new File(nextjsp); + if (!fjsp.isAbsolute()) { + fjsp = new File(uriRootF, nextjsp); + } + if (!fjsp.exists()) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", fjsp.toString())); + } + continue; + } + String s = fjsp.getAbsolutePath(); + if (s.startsWith(uriRoot)) { + nextjsp = s.substring(uriRoot.length()); + } + if (nextjsp.startsWith("." + File.separatorChar)) { + nextjsp = nextjsp.substring(2); + } + processFile(nextjsp); + } + + completeWebXml(); + + if (addWebXmlMappings) { + mergeIntoWebXml(); + } + + } catch (IOException ioe) { + throw new JasperException(ioe); + + } catch (JasperException je) { + Throwable rootCause = je; + while (rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if (rootCause != je) { + rootCause.printStackTrace(); + } + throw je; + } finally { + if (loader != null) { + LogFactory.release(loader); + } + } + } + + // ==================== Private utility methods ==================== + + private String nextArg() { + if ((argPos >= args.length) || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { + return null; + } else { + return args[argPos++]; + } + } + + private String nextFile() { + if (fullstop) + argPos++; + if (argPos >= args.length) { + return null; + } else { + return args[argPos++]; + } + } + + private void initWebXml() { + try { + if (webxmlLevel >= INC_WEBXML) { + File fmapings = new File(webxmlFile); + mapout = new FileWriter(fmapings); + servletout = new CharArrayWriter(); + mappingout = new CharArrayWriter(); + } else { + mapout = null; + servletout = null; + mappingout = null; + } + if (webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.header")); + mapout.flush(); + } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.header")); + mapout.flush(); + } + } catch (IOException ioe) { + mapout = null; + servletout = null; + mappingout = null; + } + } + + private void completeWebXml() { + if (mapout != null) { + try { + servletout.writeTo(mapout); + mappingout.writeTo(mapout); + if (webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.footer")); + } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.footer")); + } + mapout.close(); + } catch (IOException ioe) { + // noting to do if it fails since we are done with it + } + } + } + + private void initServletContext() { + try { + context = new JspCServletContext(new PrintWriter(System.out), new URL("file:" + uriRoot.replace('\\', '/') + '/')); + tldLocationsCache = new TldLocationsCache(context, true); + } catch (MalformedURLException me) { + System.out.println("**" + me); + } + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); + } + + /** + * Initializes the classloader as/if needed for the given + * compilation context. + * + * @param clctxt + * The compilation context + * @throws IOException + * If an error occurs + */ + private void initClassLoader(JspCompilationContext clctxt) throws IOException { + + classPath = getClassPath(); + + ClassLoader jspcLoader = getClass().getClassLoader(); + + // Turn the classPath into URLs + ArrayList urls = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); + while (tokenizer.hasMoreTokens()) { + String path = tokenizer.nextToken(); + try { + File libFile = new File(path); + urls.add(libFile.toURL()); + } catch (IOException ioe) { + // Failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak uot + throw new RuntimeException(ioe.toString()); + } + } + + File webappBase = new File(uriRoot); + if (webappBase.exists()) { + File classes = new File(webappBase, "/WEB-INF/classes"); + try { + if (classes.exists()) { + classPath = classPath + File.pathSeparator + classes.getCanonicalPath(); + urls.add(classes.getCanonicalFile().toURL()); + } + } catch (IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + File lib = new File(webappBase, "/WEB-INF/lib"); + if (lib.exists() && lib.isDirectory()) { + String[] libs = lib.list(); + for (int i = 0; i < libs.length; i++) { + if (libs[i].length() < 5) + continue; + String ext = libs[i].substring(libs[i].length() - 4); + if (!".jar".equalsIgnoreCase(ext)) { + if (".tld".equalsIgnoreCase(ext)) { + log.warn("TLD files should not be placed in " + "/WEB-INF/lib"); + } + continue; + } + try { + File libFile = new File(lib, libs[i]); + classPath = classPath + File.pathSeparator + libFile.getAbsolutePath(); + urls.add(libFile.getAbsoluteFile().toURL()); + } catch (IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + } + } + } + + // What is this ?? + urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL()); + + URL urlsA[] = new URL[urls.size()]; + urls.toArray(urlsA); + loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); + + } + + /** + * Find the WEB-INF dir by looking up in the directory tree. + * This is used if no explicit docbase is set, but only files. + * XXX Maybe we should require the docbase. + */ + private void locateUriRoot(File f) { + String tUriBase = uriBase; + if (tUriBase == null) { + tUriBase = "/"; + } + try { + if (f.exists()) { + f = new File(f.getAbsolutePath()); + while (f != null) { + File g = new File(f, "WEB-INF"); + if (g.exists() && g.isDirectory()) { + uriRoot = f.getCanonicalPath(); + uriBase = tUriBase; + if (log.isInfoEnabled()) { + log.info(Localizer.getMessage("jspc.implicit.uriRoot", uriRoot)); + } + break; + } + if (f.exists() && f.isDirectory()) { + tUriBase = "/" + f.getName() + "/" + tUriBase; + } + + String fParent = f.getParent(); + if (fParent == null) { + break; + } else { + f = new File(fParent); + } + + // If there is no acceptible candidate, uriRoot will + // remain null to indicate to the CompilerContext to + // use the current working/user dir. + } + + if (uriRoot != null) { + File froot = new File(uriRoot); + uriRoot = froot.getCanonicalPath(); + } + } + } catch (IOException ioe) { + // since this is an optional default and a null value + // for uriRoot has a non-error meaning, we can just + // pass straight through + } + } + + /** + * Resolves the relative or absolute pathname correctly + * in both Ant and command-line situations. If Ant launched + * us, we should use the basedir of the current project + * to resolve relative paths. + * + * See Bugzilla 35571. + * + * @param s + * The file + * @return The file resolved + */ + protected File resolveFile(final String s) { + return new File(s); + } +} diff --git a/BeeCompiler/jasper/JspCompilationContext.java b/BeeCompiler/jasper/JspCompilationContext.java new file mode 100755 index 0000000..0229ca4 --- /dev/null +++ b/BeeCompiler/jasper/JspCompilationContext.java @@ -0,0 +1,668 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Hashtable; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagInfo; + +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.Options; +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.JspUtil; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.ServletWriter; +import org.apache.jasper.servlet.JasperLoader; +import org.apache.jasper.servlet.JspServletWrapper; + +/** + * A place holder for various things that are used through out the JSP + * engine. This is a per-request/per-context data structure. Some of + * the instance variables are set at different points. + * + * Most of the path-related stuff is here - mangling names, versions, dirs, + * loading resources and dealing with uris. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Pierre Delisle + * @author Costin Manolache + * @author Kin-man Chung + */ +public class JspCompilationContext { + + protected org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class); + + private Hashtable tagFileJarUrls; + private boolean isPackagedTagFile; + + private String className; + private String jspUri; + private boolean isErrPage; + private String basePackageName; + private String derivedPackageName; + private String servletJavaFileName; + private String javaPath; + private String classFileName; + private String contentType; + private ServletWriter writer; + private Options options; + private JspServletWrapper jsw; + private Compiler jspCompiler; + private String classPath; + + private String baseURI; + private String baseOutputDir; + private String outputDir; + private ServletContext context; + private URLClassLoader loader; + + private JspRuntimeContext rctxt; + + private int removed = 0; + + private URLClassLoader jspLoader; + private URL baseUrl; + private Class servletClass; + + private boolean isTagFile; + private boolean protoTypeMode; + private TagInfo tagInfo; + private URL tagFileJarUrl; + + // jspURI _must_ be relative to the context + public JspCompilationContext(String jspUri, boolean isErrPage, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt) { + + this.jspUri = canonicalURI(jspUri); + this.isErrPage = isErrPage; + this.options = options; + this.jsw = jsw; + this.context = context; + + this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); + // hack fix for resolveRelativeURI + if(baseURI == null) { + baseURI = "/"; + } else if(baseURI.charAt(0) != '/') { + // strip the basde slash since it will be combined with the + // uriBase to generate a file + baseURI = "/" + baseURI; + } + if(baseURI.charAt(baseURI.length() - 1) != '/') { + baseURI += '/'; + } + + this.rctxt = rctxt; + this.tagFileJarUrls = new Hashtable(); + this.basePackageName = Constants.JSP_PACKAGE_NAME; + } + + public JspCompilationContext(String tagfile, TagInfo tagInfo, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt, URL tagFileJarUrl) { + this(tagfile, false, options, context, jsw, rctxt); + this.isTagFile = true; + this.tagInfo = tagInfo; + this.tagFileJarUrl = tagFileJarUrl; + if(tagFileJarUrl != null) { + isPackagedTagFile = true; + } + } + + /* ==================== Methods to override ==================== */ + + /** ---------- Class path and loader ---------- */ + + /** + * The classpath that is passed off to the Java compiler. + */ + public String getClassPath() { + if(classPath != null) + return classPath; + return rctxt.getClassPath(); + } + + /** + * The classpath that is passed off to the Java compiler. + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * What class loader to use for loading classes while compiling + * this JSP? + */ + public ClassLoader getClassLoader() { + if(loader != null) + return loader; + return rctxt.getParentClassLoader(); + } + + public void setClassLoader(URLClassLoader loader) { + this.loader = loader; + } + + public ClassLoader getJspLoader() { + if(jspLoader == null) { + jspLoader = new JasperLoader(new URL[] { baseUrl }, getClassLoader(), rctxt.getPermissionCollection(), rctxt.getCodeSource()); + } + return jspLoader; + } + + /** ---------- Input/Output ---------- */ + + /** + * The output directory to generate code into. The output directory + * is make up of the scratch directory, which is provide in Options, + * plus the directory derived from the package name. + */ + public String getOutputDir() { + if(outputDir == null) { + createOutputDir(); + } + + return outputDir; + } + + /** + * Create a "Compiler" object based on some init param data. This + * is not done yet. Right now we're just hardcoding the actual + * compilers that are created. + */ + public Compiler createCompiler() throws JasperException { + if(jspCompiler != null) { + return jspCompiler; + } + jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); + if(jspCompiler == null) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); + } + jspCompiler.init(this, jsw); + return jspCompiler; + } + + private Compiler createCompiler(String className) { + Compiler compiler = null; + try { + compiler = (Compiler) Class.forName(className).newInstance(); + } catch(Throwable t) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), t); + } + } + return compiler; + } + + public Compiler getCompiler() { + return jspCompiler; + } + + /** ---------- Access resources in the webapp ---------- */ + + /** + * Get the full value of a URI relative to this compilations context + * uses current file as the base. + */ + public String resolveRelativeUri(String uri) { + // sometimes we get uri's massaged from File(String), so check for + // a root directory deperator char + if(uri.startsWith("/") || uri.startsWith(File.separator)) { + return uri; + } else { + return baseURI + uri; + } + } + + /** + * Gets a resource as a stream, relative to the meanings of this + * context's implementation. + * + * @return a null if the resource cannot be found or represented + * as an InputStream. + */ + public java.io.InputStream getResourceAsStream(String res) { + return context.getResourceAsStream(canonicalURI(res)); + } + + public URL getResource(String res) throws MalformedURLException { + return context.getResource(canonicalURI(res)); + } + + public Set getResourcePaths(String path) { + return context.getResourcePaths(canonicalURI(path)); + } + + /** + * Gets the actual path of a URI relative to the context of + * the compilation. + */ + public String getRealPath(String path) { + if(context != null) { + return context.getRealPath(path); + } + return path; + } + + /** + * Returns the tag-file-name-to-JAR-file map of this compilation unit, + * which maps tag file names to the JAR files in which the tag files are + * packaged. + * + * The map is populated when parsing the tag-file elements of the TLDs + * of any imported taglibs. + */ + public Hashtable getTagFileJarUrls() { + return this.tagFileJarUrls; + } + + /** + * Returns the JAR file in which the tag file for which this + * JspCompilationContext was created is packaged, or null if this + * JspCompilationContext does not correspond to a tag file, or if the + * corresponding tag file is not packaged in a JAR. + */ + public URL getTagFileJarUrl() { + return this.tagFileJarUrl; + } + + /* ==================== Common implementation ==================== */ + + /** + * Just the class name (does not include package name) of the + * generated class. + */ + public String getServletClassName() { + + if(className != null) { + return className; + } + + if(isTagFile) { + className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + if(lastIndex != -1) { + className = className.substring(lastIndex + 1); + } + } else { + int iSep = jspUri.lastIndexOf('/') + 1; + className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); + } + return className; + } + + public void setServletClassName(String className) { + this.className = className; + } + + /** + * Path of the JSP URI. Note that this is not a file name. This is + * the context rooted URI of the JSP file. + */ + public String getJspFile() { + return jspUri; + } + + /** + * Are we processing something that has been declared as an + * errorpage? + */ + public boolean isErrorPage() { + return isErrPage; + } + + public void setErrorPage(boolean isErrPage) { + this.isErrPage = isErrPage; + } + + public boolean isTagFile() { + return isTagFile; + } + + public TagInfo getTagInfo() { + return tagInfo; + } + + public void setTagInfo(TagInfo tagi) { + tagInfo = tagi; + } + + /** + * True if we are compiling a tag file in prototype mode. + * ie we only generate codes with class for the tag handler with empty + * method bodies. + */ + public boolean isPrototypeMode() { + return protoTypeMode; + } + + public void setPrototypeMode(boolean pm) { + protoTypeMode = pm; + } + + /** + * Package name for the generated class is make up of the base package + * name, which is user settable, and the derived package name. The + * derived package name directly mirrors the file heirachy of the JSP page. + */ + public String getServletPackageName() { + if(isTagFile()) { + String className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + String pkgName = ""; + if(lastIndex != -1) { + pkgName = className.substring(0, lastIndex); + } + return pkgName; + } else { + String dPackageName = getDerivedPackageName(); + if(dPackageName.length() == 0) { + return basePackageName; + } + return basePackageName + '.' + getDerivedPackageName(); + } + } + + private String getDerivedPackageName() { + if(derivedPackageName == null) { + int iSep = jspUri.lastIndexOf('/'); + derivedPackageName = (iSep > 0) ? JspUtil.makeJavaPackage(jspUri.substring(1, iSep)) : ""; + } + return derivedPackageName; + } + + /** + * The package name into which the servlet class is generated. + */ + public void setServletPackageName(String servletPackageName) { + this.basePackageName = servletPackageName; + } + + /** + * Full path name of the Java file into which the servlet is being + * generated. + */ + public String getServletJavaFileName() { + + if(servletJavaFileName == null) { + servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; + } else { + // Make sure output dir exists + makeOutputDir(); + } + return servletJavaFileName; + } + + public void setServletJavaFileName(String servletJavaFileName) { + this.servletJavaFileName = servletJavaFileName; + } + + /** + * Get hold of the Options object for this context. + */ + public Options getOptions() { + return options; + } + + public ServletContext getServletContext() { + return context; + } + + public JspRuntimeContext getRuntimeContext() { + return rctxt; + } + + /** + * Path of the Java file relative to the work directory. + */ + public String getJavaPath() { + + if(javaPath != null) { + return javaPath; + } + + if(isTagFile()) { + String tagName = tagInfo.getTagClassName(); + javaPath = tagName.replace('.', '/') + ".java"; + } else { + javaPath = getServletPackageName().replace('.', '/') + '/' + getServletClassName() + ".java"; + } + return javaPath; + } + + public String getClassFileName() { + + if(classFileName == null) { + classFileName = getOutputDir() + getServletClassName() + ".class"; + } else { + // Make sure output dir exists + makeOutputDir(); + } + return classFileName; + } + + /** + * Get the content type of this JSP. + * + * Content type includes content type and encoding. + */ + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + /** + * Where is the servlet being generated? + */ + public ServletWriter getWriter() { + return writer; + } + + public void setWriter(ServletWriter writer) { + this.writer = writer; + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, + * then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the given uri is not associated with any tag + * library + * 'exposed' in the web application. + */ + public String[] getTldLocation(String uri) throws JasperException { + String[] location = getOptions().getTldLocationsCache().getLocation(uri); + return location; + } + + /** + * Are we keeping generated code around? + */ + public boolean keepGenerated() { + return getOptions().getKeepGenerated(); + } + + // ==================== Removal ==================== + + public void incrementRemoved() { + if(removed > 1) { + jspCompiler.removeGeneratedFiles(); + if(rctxt != null) + rctxt.removeWrapper(jspUri); + } + removed++; + } + + public boolean isRemoved() { + if(removed > 1) { + return true; + } + return false; + } + + // ==================== Compile and reload ==================== + + public void compile() throws JasperException, FileNotFoundException { + createCompiler(); + if(isPackagedTagFile || jspCompiler.isOutDated()) { + try { + jspLoader = null; + jspCompiler.compile(); + jsw.setReload(true); + jsw.setCompilationException(null); + } catch(JasperException ex) { + // Cache compilation exception + jsw.setCompilationException(ex); + throw ex; + } catch(Exception ex) { + ex.printStackTrace(); + JasperException je = new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + // Cache compilation exception + jsw.setCompilationException(je); + throw je; + } + } + } + + // ==================== Manipulating the class ==================== + + public Class load() throws JasperException, FileNotFoundException { + try { + getJspLoader(); + + String name; + if(isTagFile()) { + name = tagInfo.getTagClassName(); + } else { + name = getServletPackageName() + "." + getServletClassName(); + } + servletClass = jspLoader.loadClass(name); + } catch(ClassNotFoundException cex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), cex); + } catch(Exception ex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + } + removed = 0; + return servletClass; + } + + // ==================== Private methods ==================== + + static Object outputDirLock = new Object(); + + private void makeOutputDir() { + synchronized(outputDirLock) { + File outDirFile = new File(outputDir); + outDirFile.mkdirs(); + } + } + + private void createOutputDir() { + String path = null; + if(isTagFile()) { + String tagName = tagInfo.getTagClassName(); + path = tagName.replace('.', '/'); + path = path.substring(0, path.lastIndexOf('/')); + } else { + path = getServletPackageName().replace('.', '/'); + } + + try { + // Append servlet or tag handler path to scratch dir + baseUrl = options.getScratchDir().toURL(); + String outUrlString = baseUrl.toString() + '/' + path; + URL outUrl = new URL(outUrlString); + outputDir = outUrl.getFile() + File.separator; + makeOutputDir(); + } catch(Exception e) { + throw new IllegalStateException("No output directory: " + e.getMessage()); + } + } + + private static final boolean isPathSeparator(char c) { + return (c == '/' || c == '\\'); + } + + private static final String canonicalURI(String s) { + if(s == null) + return null; + StringBuffer result = new StringBuffer(); + final int len = s.length(); + int pos = 0; + while(pos < len) { + char c = s.charAt(pos); + if(isPathSeparator(c)) { + /* + * multiple path separators. + * 'foo///bar' -> 'foo/bar' + */ + while(pos + 1 < len && isPathSeparator(s.charAt(pos + 1))) { + ++pos; + } + + if(pos + 1 < len && s.charAt(pos + 1) == '.') { + /* + * a single dot at the end of the path - we are done. + */ + if(pos + 2 >= len) + break; + + switch(s.charAt(pos + 2)) { + /* + * self directory in path + * foo/./bar -> foo/bar + */ + case '/': + case '\\': + pos += 2; + continue; + + /* + * two dots in a path: go back one hierarchy. + * foo/bar/../baz -> foo/baz + */ + case '.': + // only if we have exactly _two_ dots. + if(pos + 3 < len && isPathSeparator(s.charAt(pos + 3))) { + pos += 3; + int separatorPos = result.length() - 1; + while(separatorPos >= 0 && !isPathSeparator(result.charAt(separatorPos))) { + --separatorPos; + } + if(separatorPos >= 0) + result.setLength(separatorPos); + continue; + } + } + } + } + result.append(c); + ++pos; + } + return result.toString(); + } +} diff --git a/BeeCompiler/jasper/TldLocationsCache.java b/BeeCompiler/jasper/TldLocationsCache.java new file mode 100755 index 0000000..ca4b9a2 --- /dev/null +++ b/BeeCompiler/jasper/TldLocationsCache.java @@ -0,0 +1,540 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.InputStream; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import org.xml.sax.InputSource; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.xmlparser.ParserUtils; +import org.apache.jasper.xmlparser.TreeNode; + +/** + * A container for all tag libraries that are defined "globally" + * for the web application. + * + * Tag Libraries can be defined globally in one of two ways: + * 1. Via elements in web.xml: + * the uri and location of the tag-library are specified in + * the element. + * 2. Via packaged jar files that contain .tld files + * within the META-INF directory, or some subdirectory + * of it. The taglib is 'global' if it has the + * element defined. + * + * A mapping between the taglib URI and its associated TaglibraryInfoImpl + * is maintained in this container. + * Actually, that's what we'd like to do. However, because of the + * way the classes TagLibraryInfo and TagInfo have been defined, + * it is not currently possible to share an instance of TagLibraryInfo + * across page invocations. A bug has been submitted to the spec lead. + * In the mean time, all we do is save the 'location' where the + * TLD associated with a taglib URI can be found. + * + * When a JSP page has a taglib directive, the mappings in this container + * are first searched (see method getLocation()). + * If a mapping is found, then the location of the TLD is returned. + * If no mapping is found, then the uri specified + * in the taglib directive is to be interpreted as the location for + * the TLD of this tag library. + * + * @author Pierre Delisle + * @author Jan Luehe + */ + +public class TldLocationsCache { + + // Logger + private Log log = LogFactory.getLog(TldLocationsCache.class); + + /** + * The types of URI one may specify for a tag library + */ + public static final int ABS_URI = 0; + public static final int ROOT_REL_URI = 1; + public static final int NOROOT_REL_URI = 2; + + private static final String WEB_XML = "/WEB-INF/web.xml"; + private static final String FILE_PROTOCOL = "file:"; + private static final String JAR_FILE_SUFFIX = ".jar"; + + // Names of JARs that are known not to contain any TLDs + private static HashSet noTldJars; + + /** + * The mapping of the 'global' tag library URI to the location (resource + * path) of the TLD associated with that tag library. The location is + * returned as a String array: + * [0] The location + * [1] If the location is a jar file, this is the location of the tld. + */ + private Hashtable mappings; + + private boolean initialized; + private ServletContext ctxt; + private boolean redeployMode; + + // ********************************************************************* + // Constructor and Initilizations + + /* + * Initializes the set of JARs that are known not to contain any TLDs + */ + static { + noTldJars = new HashSet(); + noTldJars.add("ant.jar"); + noTldJars.add("catalina.jar"); + noTldJars.add("catalina-ant.jar"); + noTldJars.add("catalina-cluster.jar"); + noTldJars.add("catalina-optional.jar"); + noTldJars.add("catalina-i18n-fr.jar"); + noTldJars.add("catalina-i18n-ja.jar"); + noTldJars.add("catalina-i18n-es.jar"); + noTldJars.add("commons-dbcp.jar"); + noTldJars.add("commons-modeler.jar"); + noTldJars.add("commons-logging-api.jar"); + noTldJars.add("commons-beanutils.jar"); + noTldJars.add("commons-fileupload-1.0.jar"); + noTldJars.add("commons-pool.jar"); + noTldJars.add("commons-digester.jar"); + noTldJars.add("commons-logging.jar"); + noTldJars.add("commons-collections.jar"); + noTldJars.add("commons-el.jar"); + noTldJars.add("jakarta-regexp-1.2.jar"); + noTldJars.add("jasper-compiler.jar"); + noTldJars.add("jasper-runtime.jar"); + noTldJars.add("jmx.jar"); + noTldJars.add("jmx-tools.jar"); + noTldJars.add("jsp-api.jar"); + noTldJars.add("jkshm.jar"); + noTldJars.add("jkconfig.jar"); + noTldJars.add("naming-common.jar"); + noTldJars.add("naming-resources.jar"); + noTldJars.add("naming-factory.jar"); + noTldJars.add("naming-java.jar"); + noTldJars.add("servlet-api.jar"); + noTldJars.add("servlets-default.jar"); + noTldJars.add("servlets-invoker.jar"); + noTldJars.add("servlets-common.jar"); + noTldJars.add("servlets-webdav.jar"); + noTldJars.add("tomcat-util.jar"); + noTldJars.add("tomcat-http11.jar"); + noTldJars.add("tomcat-jni.jar"); + noTldJars.add("tomcat-jk.jar"); + noTldJars.add("tomcat-jk2.jar"); + noTldJars.add("tomcat-coyote.jar"); + noTldJars.add("xercesImpl.jar"); + noTldJars.add("xmlParserAPIs.jar"); + noTldJars.add("xml-apis.jar"); + // JARs from J2SE runtime + noTldJars.add("sunjce_provider.jar"); + noTldJars.add("ldapsec.jar"); + noTldJars.add("localedata.jar"); + noTldJars.add("dnsns.jar"); + } + + public TldLocationsCache(ServletContext ctxt) { + this(ctxt, true); + } + + /** + * Constructor. + * + * @param ctxt the servlet context of the web application in which Jasper + * is running + * @param redeployMode if true, then the compiler will allow redeploying + * a tag library from the same jar, at the expense of slowing + * down the + * server a bit. Note that this may only work on JDK 1.3.1_01a + * and later, + * because of JDK bug 4211817 fixed in this release. + * If redeployMode is false, a faster but less capable mode will + * be used. + */ + public TldLocationsCache(ServletContext ctxt, boolean redeployMode) { + this.ctxt = ctxt; + this.redeployMode = redeployMode; + mappings = new Hashtable(); + initialized = false; + } + + /** + * Sets the list of JARs that are known not to contain any TLDs. + * + * @param jarNames List of comma-separated names of JAR files that are + * known not to contain any TLDs + */ + public static void setNoTldJars(String jarNames) { + if(jarNames != null) { + noTldJars.clear(); + StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); + while(tokenizer.hasMoreElements()) { + noTldJars.add(tokenizer.nextToken()); + } + } + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * Returns null if the uri is not associated with any tag library 'exposed' + * in the web application. A tag library is 'exposed' either explicitly in + * web.xml or implicitly via the uri tag in the TLD of a taglib deployed + * in a jar file (WEB-INF/lib). + * + * @param uri The taglib uri + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, + * then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the uri is not associated with any tag library + * 'exposed' + * in the web application. + */ + public String[] getLocation(String uri) throws JasperException { + if(!initialized) { + init(); + } + return (String[]) mappings.get(uri); + } + + /** + * Returns the type of a URI: + * ABS_URI + * ROOT_REL_URI + * NOROOT_REL_URI + */ + public static int uriType(String uri) { + if(uri.indexOf(':') != -1) { + return ABS_URI; + } else if(uri.startsWith("/")) { + return ROOT_REL_URI; + } else { + return NOROOT_REL_URI; + } + } + + private void init() throws JasperException { + if(initialized) + return; + try { + processWebDotXml(); + scanJars(); + processTldsInFileSystem("/WEB-INF/"); + initialized = true; + } catch(Exception ex) { + throw new JasperException(Localizer.getMessage("jsp.error.internal.tldinit", ex.getMessage()), ex); + } + } + + /* + * Populates taglib map described in web.xml. + */ + private void processWebDotXml() throws Exception { + + InputStream is = null; + + try { + // Acquire input stream to web application deployment descriptor + String altDDName = (String) ctxt.getAttribute(Constants.ALT_DD_ATTR); + URL uri = null; + if(altDDName != null) { + try { + uri = new URL(FILE_PROTOCOL + altDDName.replace('\\', '/')); + } catch(MalformedURLException e) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.error.internal.filenotfound", altDDName)); + } + } + } else { + uri = ctxt.getResource(WEB_XML); + if(uri == null && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.error.internal.filenotfound", WEB_XML)); + } + } + + if(uri == null) { + return; + } + is = uri.openStream(); + InputSource ip = new InputSource(is); + ip.setSystemId(uri.toExternalForm()); + + // Parse the web application deployment descriptor + TreeNode webtld = null; + // altDDName is the absolute path of the DD + if(altDDName != null) { + webtld = new ParserUtils().parseXMLDocument(altDDName, ip); + } else { + webtld = new ParserUtils().parseXMLDocument(WEB_XML, ip); + } + + // Allow taglib to be an element of the root or jsp-config (JSP2.0) + TreeNode jspConfig = webtld.findChild("jsp-config"); + if(jspConfig != null) { + webtld = jspConfig; + } + Iterator taglibs = webtld.findChildren("taglib"); + while(taglibs.hasNext()) { + + // Parse the next element + TreeNode taglib = (TreeNode) taglibs.next(); + String tagUri = null; + String tagLoc = null; + TreeNode child = taglib.findChild("taglib-uri"); + if(child != null) + tagUri = child.getBody(); + child = taglib.findChild("taglib-location"); + if(child != null) + tagLoc = child.getBody(); + + // Save this location if appropriate + if(tagLoc == null) + continue; + if(uriType(tagLoc) == NOROOT_REL_URI) + tagLoc = "/WEB-INF/" + tagLoc; + String tagLoc2 = null; + if(tagLoc.endsWith(JAR_FILE_SUFFIX)) { + tagLoc = ctxt.getResource(tagLoc).toString(); + tagLoc2 = "META-INF/taglib.tld"; + } + mappings.put(tagUri, new String[] { tagLoc, tagLoc2 }); + } + } finally { + if(is != null) { + try { + is.close(); + } catch(Throwable t) { + } + } + } + } + + /** + * Scans the given JarURLConnection for TLD files located in META-INF + * (or a subdirectory of it), adding an implicit map entry to the taglib + * map for any TLD that has a element. + * + * @param conn The JarURLConnection to the JAR file to scan + * @param ignore true if any exceptions raised when processing the given + * JAR should be ignored, false otherwise + */ + private void scanJar(JarURLConnection conn, boolean ignore) throws JasperException { + + JarFile jarFile = null; + String resourcePath = conn.getJarFileURL().toString(); + try { + if(redeployMode) { + conn.setUseCaches(false); + } + jarFile = conn.getJarFile(); + Enumeration entries = jarFile.entries(); + while(entries.hasMoreElements()) { + JarEntry entry = (JarEntry) entries.nextElement(); + String name = entry.getName(); + if(!name.startsWith("META-INF/")) + continue; + if(!name.endsWith(".tld")) + continue; + InputStream stream = jarFile.getInputStream(entry); + try { + String uri = getUriFromTld(resourcePath, stream); + // Add implicit map entry only if its uri is not already + // present in the map + if(uri != null && mappings.get(uri) == null) { + mappings.put(uri, new String[] { resourcePath, name }); + } + } finally { + if(stream != null) { + try { + stream.close(); + } catch(Throwable t) { + // do nothing + } + } + } + } + } catch(Exception ex) { + if(!redeployMode) { + // if not in redeploy mode, close the jar in case of an error + if(jarFile != null) { + try { + jarFile.close(); + } catch(Throwable t) { + // ignore + } + } + } + if(!ignore) { + throw new JasperException(ex); + } + } finally { + if(redeployMode) { + // if in redeploy mode, always close the jar + if(jarFile != null) { + try { + jarFile.close(); + } catch(Throwable t) { + // ignore + } + } + } + } + } + + /* + * Searches the filesystem under /WEB-INF for any TLD files, and adds + * an implicit map entry to the taglib map for any TLD that has a + * element. + */ + private void processTldsInFileSystem(String startPath) throws Exception { + + Set dirList = ctxt.getResourcePaths(startPath); + if(dirList != null) { + Iterator it = dirList.iterator(); + while(it.hasNext()) { + String path = (String) it.next(); + if(path.endsWith("/")) { + processTldsInFileSystem(path); + } + if(!path.endsWith(".tld")) { + continue; + } + InputStream stream = ctxt.getResourceAsStream(path); + String uri = null; + try { + uri = getUriFromTld(path, stream); + } finally { + if(stream != null) { + try { + stream.close(); + } catch(Throwable t) { + // do nothing + } + } + } + // Add implicit map entry only if its uri is not already + // present in the map + if(uri != null && mappings.get(uri) == null) { + mappings.put(uri, new String[] { path, null }); + } + } + } + } + + /* + * Returns the value of the uri element of the given TLD, or null if the + * given TLD does not contain any such element. + */ + private String getUriFromTld(String resourcePath, InputStream in) throws JasperException { + // Parse the tag library descriptor at the specified resource path + TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in); + TreeNode uri = tld.findChild("uri"); + if(uri != null) { + String body = uri.getBody(); + if(body != null) + return body; + } + + return null; + } + + /* + * Scans all JARs accessible to the webapp's classloader and its + * parent classloaders for TLDs. + * The list of JARs always includes the JARs under WEB-INF/lib, as well as + * all shared JARs in the classloader delegation chain of the webapp's + * classloader. + * Considering JARs in the classloader delegation chain constitutes a + * Tomcat-specific extension to the TLD search + * order defined in the JSP spec. It allows tag libraries packaged as JAR + * files to be shared by web applications by simply dropping them in a + * location that all web applications have access to (e.g., + * /common/lib). + * The set of shared JARs to be scanned for TLDs is narrowed down by + * the noTldJars class variable, which contains the names of JARs + * that are known not to contain any TLDs. + */ + private void scanJars() throws Exception { + + ClassLoader webappLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader loader = webappLoader; + + while(loader != null) { + if(loader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) loader).getURLs(); + for(int i = 0; i < urls.length; i++) { + URLConnection conn = urls[i].openConnection(); + if(conn instanceof JarURLConnection) { + if(needScanJar(loader, webappLoader, ((JarURLConnection) conn).getJarFile().getName())) { + scanJar((JarURLConnection) conn, true); + } + } else { + String urlStr = urls[i].toString(); + if(urlStr.startsWith(FILE_PROTOCOL) && urlStr.endsWith(JAR_FILE_SUFFIX) && needScanJar(loader, webappLoader, urlStr)) { + URL jarURL = new URL("jar:" + urlStr + "!/"); + scanJar((JarURLConnection) jarURL.openConnection(), true); + } + } + } + } + + loader = loader.getParent(); + } + } + + /* + * Determines if the JAR file with the given jarPath needs to be + * scanned for TLDs. + * @param loader The current classloader in the parent chain + * @param webappLoader The webapp classloader + * @param jarPath The JAR file path + * @return TRUE if the JAR file identified by jarPath needs to be + * scanned for TLDs, FALSE otherwise + */ + private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader, String jarPath) { + if(loader == webappLoader) { + // JARs under WEB-INF/lib must be scanned unconditionally according + // to the spec. + return true; + } else { + String jarName = jarPath; + int slash = jarPath.lastIndexOf('/'); + if(slash >= 0) { + jarName = jarPath.substring(slash + 1); + } + return (!noTldJars.contains(jarName)); + } + } +} diff --git a/BeeCompiler/jasper/bee-jasper.xml b/BeeCompiler/jasper/bee-jasper.xml new file mode 100755 index 0000000..8ef55a3 --- /dev/null +++ b/BeeCompiler/jasper/bee-jasper.xml @@ -0,0 +1,494 @@ + + + + + + + + + + + ]> + + + + &env; + + + + + /bin/javac + + + + + + + /bin/javadoc + + + + + + ******** &project; + Build Process ******** + ********* Available targets: ************************************* + * compile - do Java compilation * + * jar - build &build_file; + file * + * run - run application &main_class; + * + ******************************************************************* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /&build_directory; + + + + + + + + + + + + + + + + + + Compiling javax... + + + + + + + + + + + > + + + + + + 0 + + + + Error(s) at compilation of javax + + + + + + + + + Exception at compilation of javax + + + + + + + + + + + + + + + + + + + + + + Compiling... &project; + + + + + + + + + + + > + + + + + + 0 + + + + Error(s) + at compilation of &project; + + + + + + + + + Exception + at compilation of &project; + + + + + + + + + + &manifestf; + + + + + true + + + + -d + + -sourcepath + + -classpath + + &domain; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &source_directory;/javax/servlet/jsp/resources/jsp*.dtd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/jsp*.xsd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/web-jsp*.dtd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/web-jsp*.xsd + + &build_directory;/javax/servlet/jsp/resources + + + &source_directory;/javax/servlet/resources/j2ee*.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/j2ee*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/javaee_*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/web-app*.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/web-*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/datatypes.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/xml.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/XMLSchema.dtd + + &build_directory;/javax/servlet/resources + + + + + + + + + + + + + + Jarring... + + + + + + + + + + + + + + + + + + + + + + + + + + -cf + + + + -cmf + + + + + + + + + + + + + + + java + org/apache/jasper/resources + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + Exception at jarring + + + + + + + + + + + + + y + + + + + + + + + Cleaning... + + + + + + + + + + + /&build_directory;/&build_file; + + + + + /lib/tools.jar + + + + + Running... + + + + -classpath + + + + + + diff --git a/BeeCompiler/jasper/env.xml b/BeeCompiler/jasper/env.xml new file mode 100755 index 0000000..b658951 --- /dev/null +++ b/BeeCompiler/jasper/env.xml @@ -0,0 +1,48 @@ + + + + +. + + + + + + + / + + + + + + + + + /jre + + + + + + + + + + +maven:javax.servlet:javax.servlet-api:3.1.0 + +1.6 + + + + \\jre + + + + + + + + + diff --git a/BeeCompiler/jasper6/BeeCompiler.java b/BeeCompiler/jasper6/BeeCompiler.java new file mode 100755 index 0000000..c950f9f --- /dev/null +++ b/BeeCompiler/jasper6/BeeCompiler.java @@ -0,0 +1,421 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.util.StringTokenizer; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLClassLoader; + +import org.apache.jasper.JasperException; + +/** + * Main JSP compiler class. This class uses 7Bee for compiling. + * + * @author Dmitriy Rogatkin + */ +public class BeeCompiler extends Compiler { + + protected static Object javacLock = new Object(); + + private Class javaCompiler; + + static { + System.setErr(new SystemLogHandler(System.err)); + } + + /** + * Compile the servlet from .java file to .class file + */ + protected void generateClass(String[] smap) throws FileNotFoundException, JasperException, Exception { + + long t1 = 0; + if(log.isDebugEnabled()) + t1 = System.currentTimeMillis(); + + List parameters = new ArrayList(20); + parameters.add("-encoding"); + parameters.add(ctxt.getOptions().getJavaEncoding()); + + String javaFileName = new File(ctxt.getServletJavaFileName()).getPath(); + String classpath = ctxt.getClassPath(); + + String sep = File.pathSeparator; // System.getProperty("path.separator"); + + StringBuffer errorReport = new StringBuffer(); + + StringBuffer info = new StringBuffer(); + info.append("Compile: javaFileName=" + javaFileName + "\n"); + + // Start capturing the System.err output for this thread + SystemLogHandler.setThread(); + + // Initializing classpath + String path = System.getProperty("java.class.path"); + info.append(" cmd cp=" + path + "\n"); + info.append(" ctx cp=" + classpath + "\n"); + path += sep; + path += classpath; + + if(log.isDebugEnabled()) + log.debug("Using classpath: " + path); + + parameters.add("-classpath"); + parameters.add(path); + + // Initializing sourcepath + parameters.add("-sourcepath"); + parameters.add(options.getScratchDir().getPath()); + + info.append(" work dir=" + options.getScratchDir() + "\n"); + + // Initialize and set java extensions + String extdirs = System.getProperty("java.ext.dirs"); + if(extdirs != null) { + parameters.add("-extdirs"); + parameters.add(extdirs); + info.append(" extension dir=" + extdirs + "\n"); + } + + if(ctxt.getOptions().getFork()) { + String endorsed = System.getProperty("java.endorsed.dirs"); + if(endorsed != null) { + parameters.add("-endorseddirs"); // "-J-Djava.endorsed.dirs="+endorsed + parameters.add(endorsed); + info.append(" endorsed dir=" + endorsed + "\n"); + } else { + info.append(" no endorsed dirs specified\n"); + } + } + + if(ctxt.getOptions().getClassDebugInfo()) + parameters.add("-g"); + + Exception ie = null; + + // Set the Java compiler to use + if(javaCompiler == null) { + // assumption, there is no dynamic changing Java compiler + String compiler = options.getCompiler(); + if(compiler == null) + compiler = "com.sun.tools.javac.Main"; + // verify compiler + try { + javaCompiler = Class.forName(compiler); + } catch(ClassNotFoundException cnfe) { + // try to figure out class path to compiler + String compileClassPath = System.getProperty("java.home"); + if(compileClassPath == null) + try { + compileClassPath = System.getenv("JAVA_HOME"); + if(compileClassPath == null) + compileClassPath = System.getenv("java_home"); + } catch(SecurityException se) { + + } + + if(compileClassPath != null) { + // HACK for now + compileClassPath = compileClassPath.replace("jre", "jdk"); + compileClassPath += "/lib/tools.jar"; + info.append(" checking default compiler in " + compileClassPath + "\n"); + try { + javaCompiler = Class.forName(compiler, true, new URLClassLoader(new URL[] { new URL("file", "localhost", compileClassPath) })); + } catch(Error er) { + log.error("Setting up Java compiler error ", er); + } catch(Exception ex) { + log.error("Setting up Java compiler exception ", ex); + } + } else + info.append(" no Java home path specified\n"); + } + info.append(" compiler=" + compiler + "\n"); + } + + if(options.getCompilerTargetVM() != null) { + parameters.add("-target"); + parameters.add(options.getCompilerTargetVM()); + info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n"); + } + + if(options.getCompilerSourceVM() != null) { + parameters.add("-source"); + parameters.add(options.getCompilerSourceVM()); + info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n"); + } + + info.append(" JavaPath=" + ctxt.getJavaPath() + "\n"); + + parameters.add(javaFileName); + + boolean compilationErrors = false; + String errorCapture = null; + if(javaCompiler != null) + try { + Integer success; + Method cm = javaCompiler.getMethod("compile", new Class[] { String[].class }); + if(ctxt.getOptions().getFork()) { + success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters.size()]) }); + } else { + synchronized(javacLock) { + success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters.size()]) }); + } + } + if(success.intValue() != 0) + compilationErrors = true; + } catch(Throwable t) { + if(t instanceof ThreadDeath) + throw (ThreadDeath) t; + if(t instanceof InvocationTargetException) + t = t.getCause(); + if(t instanceof Exception) + ie = (Exception) t; + else + ie = new Exception(t); + log.error("Javac exception ", t); + log.error("Env: " + info.toString()); + } finally { + // Stop capturing the System.err output for this thread + errorCapture = SystemLogHandler.unsetThread(); + } + if(compilationErrors && errorCapture != null) { + errorReport.append(System.getProperty("line.separator")); + errorReport.append(errorCapture); + } + + if(!ctxt.keepGenerated()) { + if(new File(javaFileName).delete() == false) + log.error("Couldn't delete source: " + javaFileName); + } + + if(compilationErrors || ie != null) { + String errorReportString = errorReport.toString(); + log.error("Error compiling file: " + javaFileName + " " + errorReportString); + JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(errorReportString, javaFileName, pageNodes); + if(javacErrors != null) { + errDispatcher.javacError(javacErrors); + } else { + errDispatcher.javacError(errorReportString, ie); + } + } + + if(log.isDebugEnabled()) { + long t2 = System.currentTimeMillis(); + log.debug("Compiled " + ctxt.getServletJavaFileName() + " " + (t2 - t1) + "ms"); + } + + if(ctxt.isPrototypeMode()) { + return; + } + + // JSR45 Support + if(!options.isSmapSuppressed()) { + log.debug("Install Smap " + (smap == null ? "null" : Arrays.toString(smap))); + SmapUtil.installSmap(smap); + } + } + + protected static class SystemLogHandler extends PrintStream { + + // ----------------------------------------------------------- + // Constructors + + /** + * Construct the handler to capture the output of the given steam. + */ + public SystemLogHandler(PrintStream wrapped) { + super(wrapped); + this.wrapped = wrapped; + } + + // ----------------------------------------------------- Instance + // Variables + + /** + * Wrapped PrintStream. + */ + protected PrintStream wrapped = null; + + /** + * Thread <-> PrintStream associations. + */ + protected static ThreadLocal streams = new ThreadLocal(); + + /** + * Thread <-> ByteArrayOutputStream associations. + */ + protected static ThreadLocal data = new ThreadLocal(); + + // --------------------------------------------------------- Public + // Methods + + public PrintStream getWrapped() { + return wrapped; + } + + /** + * Start capturing thread's output. + */ + public static void setThread() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + data.set(baos); + streams.set(new PrintStream(baos)); + } + + /** + * Stop capturing thread's output and return captured data as a String. + */ + public static String unsetThread() { + ByteArrayOutputStream baos = (ByteArrayOutputStream) data.get(); + if(baos == null) { + return null; + } + streams.set(null); + data.set(null); + return baos.toString(); + } + + // ------------------------------------------------------ Protected + // Methods + + /** + * Find PrintStream to which the output must be written to. + */ + protected PrintStream findStream() { + PrintStream ps = (PrintStream) streams.get(); + if(ps == null) { + ps = wrapped; + } + return ps; + } + + // ---------------------------------------------------- PrintStream + // Methods + + public void flush() { + findStream().flush(); + } + + public void close() { + findStream().close(); + } + + public boolean checkError() { + return findStream().checkError(); + } + + protected void setError() { + // findStream().setError(); + } + + public void write(int b) { + findStream().write(b); + } + + public void write(byte[] b) throws IOException { + findStream().write(b); + } + + public void write(byte[] buf, int off, int len) { + findStream().write(buf, off, len); + } + + public void print(boolean b) { + findStream().print(b); + } + + public void print(char c) { + findStream().print(c); + } + + public void print(int i) { + findStream().print(i); + } + + public void print(long l) { + findStream().print(l); + } + + public void print(float f) { + findStream().print(f); + } + + public void print(double d) { + findStream().print(d); + } + + public void print(char[] s) { + findStream().print(s); + } + + public void print(String s) { + findStream().print(s); + } + + public void print(Object obj) { + findStream().print(obj); + } + + public void println() { + findStream().println(); + } + + public void println(boolean x) { + findStream().println(x); + } + + public void println(char x) { + findStream().println(x); + } + + public void println(int x) { + findStream().println(x); + } + + public void println(long x) { + findStream().println(x); + } + + public void println(float x) { + findStream().println(x); + } + + public void println(double x) { + findStream().println(x); + } + + public void println(char[] x) { + findStream().println(x); + } + + public void println(String x) { + findStream().println(x); + } + + public void println(Object x) { + findStream().println(x); + } + + } + +} diff --git a/BeeCompiler/jasper6/JspC.java b/BeeCompiler/jasper6/JspC.java new file mode 100755 index 0000000..66ffadd --- /dev/null +++ b/BeeCompiler/jasper6/JspC.java @@ -0,0 +1,1552 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.servlet.JspCServletContext; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * Shell for the jspc compiler. Handles all options associated with the + * command line and creates compilation contexts which it then compiles + * according to the specified options. + * + * This version can process files from a _single_ webapp at once, i.e. + * a single docbase can be specified. + * + * It can be used as an Ant task using: + * + *
+ *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
+ *      <classpath>
+ *          <pathelement location="${java.home}/../lib/tools.jar"/>
+ *          <fileset dir="${ENV.CATALINA_HOME}/lib">
+ *              <include name="*.jar"/>
+ *          </fileset>
+ *          <path refid="myjars"/>
+ *       </classpath>
+ *  </taskdef>
+ *
+ *  <jasper verbose="0"
+ *           package="my.package"
+ *           uriroot="${webapps.dir}/${webapp.name}"
+ *           webXmlFragment="${build.dir}/generated_web.xml"
+ *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
+ * 
+ * + * @author Danno Ferrin + * @author Pierre Delisle + * @author Costin Manolache + * @author Yoav Shapira + */ +public class JspC implements Options { + + public static final String DEFAULT_IE_CLASS_ID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + // Logger + protected static Log log = LogFactory.getLog(JspC.class); + + protected static final String SWITCH_VERBOSE = "-v"; + protected static final String SWITCH_HELP = "-help"; + protected static final String SWITCH_OUTPUT_DIR = "-d"; + protected static final String SWITCH_PACKAGE_NAME = "-p"; + protected static final String SWITCH_CACHE = "-cache"; + protected static final String SWITCH_CLASS_NAME = "-c"; + protected static final String SWITCH_FULL_STOP = "--"; + protected static final String SWITCH_COMPILE = "-compile"; + protected static final String SWITCH_SOURCE = "-source"; + protected static final String SWITCH_TARGET = "-target"; + protected static final String SWITCH_URI_BASE = "-uribase"; + protected static final String SWITCH_URI_ROOT = "-uriroot"; + protected static final String SWITCH_FILE_WEBAPP = "-webapp"; + protected static final String SWITCH_WEBAPP_INC = "-webinc"; + protected static final String SWITCH_WEBAPP_XML = "-webxml"; + protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; + protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; + protected static final String SWITCH_MAPPED = "-mapped"; + protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; + protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; + protected static final String SWITCH_CLASSPATH = "-classpath"; + protected static final String SWITCH_DIE = "-die"; + protected static final String SWITCH_POOLING = "-poolingEnabled"; + protected static final String SWITCH_ENCODING = "-javaEncoding"; + protected static final String SWITCH_SMAP = "-smap"; + protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; + + protected static final String SHOW_SUCCESS = "-s"; + protected static final String LIST_ERRORS = "-l"; + protected static final int INC_WEBXML = 10; + protected static final int ALL_WEBXML = 20; + protected static final int DEFAULT_DIE_LEVEL = 1; + protected static final int NO_DIE_LEVEL = 0; + + protected static final String[] insertBefore = { "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "" }; + + protected static int die; + protected String classPath = null; + protected URLClassLoader loader = null; + protected boolean trimSpaces = false; + protected boolean genStringAsCharArray = false; + protected boolean xpoweredBy; + protected boolean mappedFile = false; + protected boolean poolingEnabled = true; + protected File scratchDir; + protected String ieClassId = DEFAULT_IE_CLASS_ID; + protected String targetPackage; + protected String targetClassName; + protected String uriBase; + protected String uriRoot; + protected int dieLevel; + protected boolean helpNeeded = false; + protected boolean compile = false; + protected boolean smapSuppressed = true; + protected boolean smapDumped = false; + protected boolean caching = true; + protected Map cache = new HashMap(); + + protected String compiler = null; + + protected String compilerTargetVM = "1.5"; + protected String compilerSourceVM = "1.5"; + + protected boolean classDebugInfo = true; + + /** + * Throw an exception if there's a compilation error, or swallow it. + * Default is true to preserve old behavior. + */ + protected boolean failOnError = true; + + /** + * The file extensions to be handled as JSP files. + * Default list is .jsp and .jspx. + */ + protected List extensions; + + /** + * The pages. + */ + protected List pages = new Vector(); + + /** + * Needs better documentation, this data member does. + * True by default. + */ + protected boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * The java file encoding. Default + * is UTF-8. Added per bugzilla 19622. + */ + protected String javaEncoding = "UTF-8"; + + // Generation of web.xml fragments + protected String webxmlFile; + protected int webxmlLevel; + protected String webxmlEncoding; + protected boolean addWebXmlMappings = false; + + protected Writer mapout; + protected CharArrayWriter servletout; + protected CharArrayWriter mappingout; + + /** + * The servlet context. + */ + protected JspCServletContext context; + + /** + * The runtime context. + * Maintain a dummy JspRuntimeContext for compiling tag files. + */ + protected JspRuntimeContext rctxt; + + /** + * Cache for the TLD locations + */ + protected TldLocationsCache tldLocationsCache = null; + + protected JspConfig jspConfig = null; + protected TagPluginManager tagPluginManager = null; + + protected boolean verbose = false; + protected boolean listErrors = false; + protected boolean showSuccess = false; + protected int argPos; + protected boolean fullstop = false; + protected String args[]; + + public static void main(String arg[]) { + if(arg.length == 0) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + try { + JspC jspc = new JspC(); + jspc.setArgs(arg); + if(jspc.helpNeeded) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + jspc.execute(); + } + } catch(JasperException je) { + System.err.println(je); + if(die != NO_DIE_LEVEL) { + System.exit(die); + } + } + } + } + + /** + * Apply command-line arguments. + * + * @param arg + * The arguments + */ + public void setArgs(String[] arg) throws JasperException { + args = arg; + String tok; + + dieLevel = NO_DIE_LEVEL; + die = dieLevel; + + while((tok = nextArg()) != null) { + if(tok.equals(SWITCH_VERBOSE)) { + verbose = true; + showSuccess = true; + listErrors = true; + } else if(tok.equals(SWITCH_OUTPUT_DIR)) { + tok = nextArg(); + setOutputDir(tok); + } else if(tok.equals(SWITCH_PACKAGE_NAME)) { + targetPackage = nextArg(); + } else if(tok.equals(SWITCH_COMPILE)) { + compile = true; + } else if(tok.equals(SWITCH_CLASS_NAME)) { + targetClassName = nextArg(); + } else if(tok.equals(SWITCH_URI_BASE)) { + uriBase = nextArg(); + } else if(tok.equals(SWITCH_URI_ROOT)) { + setUriroot(nextArg()); + } else if(tok.equals(SWITCH_FILE_WEBAPP)) { + setUriroot(nextArg()); + } else if(tok.equals(SHOW_SUCCESS)) { + showSuccess = true; + } else if(tok.equals(LIST_ERRORS)) { + listErrors = true; + } else if(tok.equals(SWITCH_WEBAPP_INC)) { + webxmlFile = nextArg(); + if(webxmlFile != null) { + webxmlLevel = INC_WEBXML; + } + } else if(tok.equals(SWITCH_WEBAPP_XML)) { + webxmlFile = nextArg(); + if(webxmlFile != null) { + webxmlLevel = ALL_WEBXML; + } + } else if(tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { + setWebXmlEncoding(nextArg()); + } else if(tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { + setAddWebXmlMappings(true); + } else if(tok.equals(SWITCH_MAPPED)) { + mappedFile = true; + } else if(tok.equals(SWITCH_XPOWERED_BY)) { + xpoweredBy = true; + } else if(tok.equals(SWITCH_TRIM_SPACES)) { + setTrimSpaces(true); + } else if(tok.equals(SWITCH_CACHE)) { + tok = nextArg(); + if("false".equals(tok)) { + caching = false; + } else { + caching = true; + } + } else if(tok.equals(SWITCH_CLASSPATH)) { + setClassPath(nextArg()); + } else if(tok.startsWith(SWITCH_DIE)) { + try { + dieLevel = Integer.parseInt(tok.substring(SWITCH_DIE.length())); + } catch(NumberFormatException nfe) { + dieLevel = DEFAULT_DIE_LEVEL; + } + die = dieLevel; + } else if(tok.equals(SWITCH_HELP)) { + helpNeeded = true; + } else if(tok.equals(SWITCH_POOLING)) { + tok = nextArg(); + if("false".equals(tok)) { + poolingEnabled = false; + } else { + poolingEnabled = true; + } + } else if(tok.equals(SWITCH_ENCODING)) { + setJavaEncoding(nextArg()); + } else if(tok.equals(SWITCH_SOURCE)) { + setCompilerSourceVM(nextArg()); + } else if(tok.equals(SWITCH_TARGET)) { + setCompilerTargetVM(nextArg()); + } else if(tok.equals(SWITCH_SMAP)) { + smapSuppressed = false; + } else if(tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; + } else { + if(tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + ". Use -help for help."); + } + if(!fullstop) { + argPos--; + } + // Start treating the rest as JSP Pages + break; + } + } + + // Add all extra arguments to the list of files + while(true) { + String file = nextFile(); + if(file == null) { + break; + } + pages.add(file); + } + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + public boolean getKeepGenerated() { + // isn't this why we are running jspc? + return true; + } + + /** + * {@inheritDoc} + */ + public boolean getTrimSpaces() { + return trimSpaces; + } + + /** + * Sets the option to trim white spaces between directives or actions. + */ + public void setTrimSpaces(boolean ts) { + this.trimSpaces = ts; + } + + /** + * {@inheritDoc} + */ + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + /** + * Sets the option to enable the tag handler pooling. + */ + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + /** + * {@inheritDoc} + */ + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Sets the option to enable generation of X-Powered-By response header. + */ + public void setXpoweredBy(boolean xpoweredBy) { + this.xpoweredBy = xpoweredBy; + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + public boolean getDisplaySourceFragment() { + return true; + } + + /** + * {@inheritDoc} + */ + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + /** + * Sets the option to issue a compilation error if the class attribute + * specified in useBean action is invalid. + */ + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + /** + * @deprecated Removed in Tomcat 7 + */ + @Deprecated + public int getTagPoolSize() { + return Constants.MAX_POOL_SIZE; + } + + /** + * {@inheritDoc} + */ + public boolean getMappedFile() { + return mappedFile; + } + + /** + * @deprecated Removed in Tomcat 7 + */ + @Deprecated + public Object getProtectionDomain() { + // Off-line compiler, no need for security manager + return null; + } + + /** + * @deprecated + */ + @Deprecated + public boolean getSendErrorToClient() { + return true; + } + + /** + * Sets the option to include debug information in compiled class. + */ + public void setClassDebugInfo(boolean b) { + classDebugInfo = b; + } + + /** + * {@inheritDoc} + */ + public boolean getClassDebugInfo() { + // compile with debug info + return classDebugInfo; + } + + /** + * {@inheritDoc} + */ + public boolean isCaching() { + return caching; + } + + /** + * Sets the option to enable caching. + * + * @see Options#isCaching() + */ + public void setCaching(boolean caching) { + this.caching = caching; + } + + /** + * {@inheritDoc} + */ + public Map getCache() { + return cache; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + public int getCheckInterval() { + return 0; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + public int getModificationTestInterval() { + return 0; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + public boolean getRecompileOnFail() { + return false; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + public boolean getDevelopment() { + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isSmapSuppressed() { + return smapSuppressed; + } + + /** + * Sets smapSuppressed flag. + */ + public void setSmapSuppressed(boolean smapSuppressed) { + this.smapSuppressed = smapSuppressed; + } + + /** + * {@inheritDoc} + */ + public boolean isSmapDumped() { + return smapDumped; + } + + /** + * Sets smapDumped flag. + * + * @see Options#isSmapDumped() + */ + public void setSmapDumped(boolean smapDumped) { + this.smapDumped = smapDumped; + } + + /** + * Determines whether text strings are to be generated as char arrays, + * which improves performance in some cases. + * + * @param genStringAsCharArray true if text strings are to be generated as + * char arrays, false otherwise + */ + public void setGenStringAsCharArray(boolean genStringAsCharArray) { + this.genStringAsCharArray = genStringAsCharArray; + } + + /** + * {@inheritDoc} + */ + public boolean genStringAsCharArray() { + return genStringAsCharArray; + } + + /** + * Sets the class-id value to be sent to Internet Explorer when using + * <jsp:plugin> tags. + * + * @param ieClassId + * Class-id value + */ + public void setIeClassId(String ieClassId) { + this.ieClassId = ieClassId; + } + + /** + * {@inheritDoc} + */ + public String getIeClassId() { + return ieClassId; + } + + /** + * {@inheritDoc} + */ + public File getScratchDir() { + return scratchDir; + } + + /** + * @deprecated Removed in Tomcat 7 + */ + @Deprecated + public Class getJspCompilerPlugin() { + // we don't compile, so this is meanlingless + return null; + } + + /** + * @deprecated Removed in Tomcat 7 + */ + @Deprecated + public String getJspCompilerPath() { + // we don't compile, so this is meanlingless + return null; + } + + /** + * {@inheritDoc} + */ + public String getCompiler() { + return compiler; + } + + /** + * Sets the option to determine what compiler to use. + * + * @see Options#getCompiler() + */ + public void setCompiler(String c) { + compiler = c; + } + + /** + * {@inheritDoc} + */ + public String getCompilerClassName() { + return null; + } + + /** + * {@inheritDoc} + */ + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * Sets the compiler target VM. + * + * @see Options#getCompilerTargetVM() + */ + public void setCompilerTargetVM(String vm) { + compilerTargetVM = vm; + } + + /** + * {@inheritDoc} + */ + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * Sets the compiler source VM. + * + * @see Options#getCompilerSourceVM() + */ + public void setCompilerSourceVM(String vm) { + compilerSourceVM = vm; + } + + /** + * {@inheritDoc} + */ + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + /** + * Returns the encoding to use for + * java files. The default is UTF-8. + * + * @return String The encoding + */ + public String getJavaEncoding() { + return javaEncoding; + } + + /** + * Sets the encoding to use for + * java files. + * + * @param encodingName The name, e.g. "UTF-8" + */ + public void setJavaEncoding(String encodingName) { + javaEncoding = encodingName; + } + + /** + * {@inheritDoc} + */ + public boolean getFork() { + return false; + } + + /** + * {@inheritDoc} + */ + public String getClassPath() { + if(classPath != null) + return classPath; + return System.getProperty("java.class.path"); + } + + /** + * Sets the classpath used while compiling the servlets generated from JSP + * files + */ + public void setClassPath(String s) { + classPath = s; + } + + /** + * Returns the list of file extensions + * that are treated as JSP files. + * + * @return The list of extensions + */ + public List getExtensions() { + return extensions; + } + + /** + * Adds the given file extension to the + * list of extensions handled as JSP files. + * + * @param extension The extension to add, e.g. "myjsp" + */ + protected void addExtension(final String extension) { + if(extension != null) { + if(extensions == null) { + extensions = new Vector(); + } + + extensions.add(extension); + } + } + + /** + * Base dir for the webapp. Used to generate class names and resolve + * includes. + */ + public void setUriroot(String s) { + if(s == null) { + uriRoot = s; + return; + } + try { + uriRoot = resolveFile(s).getCanonicalPath(); + } catch(Exception ex) { + uriRoot = s; + } + } + + /** + * Parses comma-separated list of JSP files to be processed. If the argument + * is null, nothing is done. + * + *

+ * Each file is interpreted relative to uriroot, unless it is absolute, + * in which case it must start with uriroot. + *

+ * + * @param jspFiles Comma-separated list of JSP files to be processed + */ + public void setJspFiles(final String jspFiles) { + if(jspFiles == null) { + return; + } + + StringTokenizer tok = new StringTokenizer(jspFiles, ","); + while(tok.hasMoreTokens()) { + pages.add(tok.nextToken()); + } + } + + /** + * Sets the compile flag. + * + * @param b Flag value + */ + public void setCompile(final boolean b) { + compile = b; + } + + /** + * Sets the verbosity level. The actual number doesn't + * matter: if it's greater than zero, the verbose flag will + * be true. + * + * @param level Positive means verbose + */ + public void setVerbose(final int level) { + if(level > 0) { + verbose = true; + showSuccess = true; + listErrors = true; + } + } + + public void setValidateXml(boolean b) { + org.apache.jasper.xmlparser.ParserUtils.validating = b; + } + + public void setListErrors(boolean b) { + listErrors = b; + } + + public void setOutputDir(String s) { + if(s != null) { + scratchDir = resolveFile(s).getAbsoluteFile(); + } else { + scratchDir = null; + } + } + + /** + * Sets the package name to be used for the generated servlet classes. + */ + public void setPackage(String p) { + targetPackage = p; + } + + /** + * Class name of the generated file ( without package ). + * Can only be used if a single file is converted. + * XXX Do we need this feature ? + */ + public void setClassName(String p) { + targetClassName = p; + } + + /** + * File where we generate a web.xml fragment with the class definitions. + */ + public void setWebXmlFragment(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = INC_WEBXML; + } + + /** + * File where we generate a complete web.xml with the class definitions. + */ + public void setWebXml(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = ALL_WEBXML; + } + + /** + * Sets the encoding to be used to read and write web.xml files. + * + *

+ * If not specified, defaults to the platform default encoding. + *

+ * + * @param encoding + * Encoding, e.g. "UTF-8". + */ + public void setWebXmlEncoding(String encoding) { + webxmlEncoding = encoding; + } + + /** + * Sets the option to merge generated web.xml fragment into the + * WEB-INF/web.xml file of the web application that we were processing. + * + * @param b + * true to merge the fragment into the existing + * web.xml file of the processed web application + * ({uriroot}/WEB-INF/web.xml), false to keep the + * generated web.xml fragment + */ + public void setAddWebXmlMappings(boolean b) { + addWebXmlMappings = b; + } + + /** + * Sets the option that throws an exception in case of a compilation error. + */ + public void setFailOnError(final boolean b) { + failOnError = b; + } + + /** + * Returns true if an exception will be thrown in case of a compilation + * error. + */ + public boolean getFailOnError() { + return failOnError; + } + + /** + * {@inheritDoc} + */ + public JspConfig getJspConfig() { + return jspConfig; + } + + /** + * {@inheritDoc} + */ + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + /** + * Adds servlet declaration and mapping for the JSP page servlet to the + * generated web.xml fragment. + * + * @param file + * Context-relative path to the JSP file, e.g. + * /index.jsp + * @param clctxt + * Compilation context of the servlet + */ + public void generateWebMapping(String file, JspCompilationContext clctxt) throws IOException { + if(log.isDebugEnabled()) { + log.debug("Generating web mapping for file " + file + " using compilation context " + clctxt); + } + + String className = clctxt.getServletClassName(); + String packageName = clctxt.getServletPackageName(); + + String thisServletName; + if("".equals(packageName)) { + thisServletName = className; + } else { + thisServletName = packageName + '.' + className; + } + + if(servletout != null) { + servletout.write("\n \n "); + servletout.write(thisServletName); + servletout.write("\n "); + servletout.write(thisServletName); + servletout.write("\n \n"); + } + if(mappingout != null) { + mappingout.write("\n \n "); + mappingout.write(thisServletName); + mappingout.write("\n "); + mappingout.write(file.replace('\\', '/')); + mappingout.write("\n \n"); + + } + } + + /** + * Include the generated web.xml inside the webapp's web.xml. + */ + protected void mergeIntoWebXml() throws IOException { + + File webappBase = new File(uriRoot); + File webXml = new File(webappBase, "WEB-INF/web.xml"); + File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); + String insertStartMarker = Localizer.getMessage("jspc.webinc.insertStart"); + String insertEndMarker = Localizer.getMessage("jspc.webinc.insertEnd"); + + BufferedReader reader = new BufferedReader(openWebxmlReader(webXml)); + BufferedReader fragmentReader = new BufferedReader(openWebxmlReader(new File(webxmlFile))); + PrintWriter writer = new PrintWriter(openWebxmlWriter(webXml2)); + + // Insert the and declarations + boolean inserted = false; + int current = reader.read(); + while(current > -1) { + if(current == '<') { + String element = getElement(reader); + boolean found = false; + if(!inserted) { + for(String before : insertBefore) { + if(element.equals(before)) { + found = true; + break; + } + } + } + if(found) { + // Insert generated content here + writer.println(insertStartMarker); + while(true) { + String line = fragmentReader.readLine(); + if(line == null) { + writer.println(); + break; + } + writer.println(line); + } + writer.println(insertEndMarker); + writer.println(); + writer.write(element); + inserted = true; + } else if(element.equals(insertStartMarker)) { + // Skip the previous auto-generated content + while(true) { + current = reader.read(); + if(current < 0) { + throw new EOFException(); + } + if(current == '<') { + element = getElement(reader); + if(element.equals(insertEndMarker)) { + break; + } + } + } + current = reader.read(); + while(current == '\n' || current == '\r') { + current = reader.read(); + } + continue; + } else { + writer.write(element); + } + } else { + writer.write(current); + } + current = reader.read(); + } + writer.close(); + + reader.close(); + fragmentReader.close(); + + FileInputStream fis = new FileInputStream(webXml2); + FileOutputStream fos = new FileOutputStream(webXml); + + byte buf[] = new byte[512]; + while(true) { + int n = fis.read(buf); + if(n < 0) { + break; + } + fos.write(buf, 0, n); + } + + fis.close(); + fos.close(); + + webXml2.delete(); + (new File(webxmlFile)).delete(); + + } + + /* + * Assumes valid xml + */ + private String getElement(Reader reader) throws IOException { + StringBuilder result = new StringBuilder(); + result.append('<'); + + boolean done = false; + + while(!done) { + int current = reader.read(); + while(current != '>') { + if(current < 0) { + throw new EOFException(); + } + result.append((char) current); + current = reader.read(); + } + result.append((char) current); + + int len = result.length(); + if(len > 4 && result.substring(0, 4).equals("")) { + done = true; + } + } else { + done = true; + } + } + + return result.toString(); + } + + protected void processFile(String file) throws JasperException { + if(log.isDebugEnabled()) { + log.debug("Processing file: " + file); + } + + ClassLoader originalClassLoader = null; + + try { + // set up a scratch/output dir if none is provided + if(scratchDir == null) { + String temp = System.getProperty("java.io.tmpdir"); + if(temp == null) { + temp = ""; + } + scratchDir = new File(new File(temp).getAbsolutePath()); + } + + String jspUri = file.replace('\\', '/'); + JspCompilationContext clctxt = new JspCompilationContext(jspUri, false, this, context, null, rctxt); + + /* Override the defaults */ + if((targetClassName != null) && (targetClassName.length() > 0)) { + clctxt.setServletClassName(targetClassName); + targetClassName = null; + } + if(targetPackage != null) { + clctxt.setServletPackageName(targetPackage); + } + + originalClassLoader = Thread.currentThread().getContextClassLoader(); + if(loader == null) { + initClassLoader(clctxt); + } + Thread.currentThread().setContextClassLoader(loader); + + clctxt.setClassLoader(loader); + clctxt.setClassPath(classPath); + + Compiler clc = clctxt.createCompiler(); + + // If compile is set, generate both .java and .class, if + // .jsp file is newer than .class file; + // Otherwise only generate .java, if .jsp file is newer than + // the .java file + if(clc.isOutDated(compile)) { + if(log.isDebugEnabled()) { + log.debug(jspUri + " is out dated, compiling..."); + } + + clc.compile(compile, true); + } + + // Generate mapping + generateWebMapping(file, clctxt); + if(showSuccess) { + log.info("Built File: " + file); + } + + } catch(JasperException je) { + Throwable rootCause = je; + while(rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if(rootCause != je) { + log.error(Localizer.getMessage("jspc.error.generalException", file), rootCause); + } + + // Bugzilla 35114. + if(getFailOnError()) { + throw je; + } else { + log.error(je.getMessage()); + } + + } catch(Exception e) { + if((e instanceof FileNotFoundException) && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", e.getMessage())); + } + throw new JasperException(e); + } finally { + if(originalClassLoader != null) { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + + /** + * Locate all jsp files in the webapp. Used if no explicit + * jsps are specified. + */ + public void scanFiles(File base) throws JasperException { + Stack dirs = new Stack(); + dirs.push(base.toString()); + + // Make sure default extensions are always included + if((getExtensions() == null) || (getExtensions().size() < 2)) { + addExtension("jsp"); + addExtension("jspx"); + } + + while(!dirs.isEmpty()) { + String s = dirs.pop(); + File f = new File(s); + if(f.exists() && f.isDirectory()) { + String[] files = f.list(); + String ext; + for(int i = 0; (files != null) && i < files.length; i++) { + File f2 = new File(s, files[i]); + if(f2.isDirectory()) { + dirs.push(f2.getPath()); + } else { + String path = f2.getPath(); + String uri = path.substring(uriRoot.length()); + ext = files[i].substring(files[i].lastIndexOf('.') + 1); + if(getExtensions().contains(ext) || jspConfig.isJspPage(uri)) { + pages.add(path); + } + } + } + } + } + } + + /** + * Executes the compilation. + * + * @throws JasperException If an error occurs + */ + public void execute() throws JasperException { + if(log.isDebugEnabled()) { + log.debug("execute() starting for " + pages.size() + " pages."); + } + + try { + if(uriRoot == null) { + if(pages.size() == 0) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget")); + } + String firstJsp = (String) pages.get(0); + File firstJspF = new File(firstJsp); + if(!firstJspF.exists()) { + throw new JasperException(Localizer.getMessage("jspc.error.fileDoesNotExist", firstJsp)); + } + locateUriRoot(firstJspF); + } + + if(uriRoot == null) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot")); + } + + if(context == null) { + initServletContext(); + } + + // No explicit pages, we'll process all .jsp in the webapp + if(pages.size() == 0) { + scanFiles(new File(uriRoot)); + } + + File uriRootF = new File(uriRoot); + if(!uriRootF.exists() || !uriRootF.isDirectory()) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); + } + + initWebXml(); + + Iterator iter = pages.iterator(); + while(iter.hasNext()) { + String nextjsp = iter.next().toString(); + File fjsp = new File(nextjsp); + if(!fjsp.isAbsolute()) { + fjsp = new File(uriRootF, nextjsp); + } + if(!fjsp.exists()) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", fjsp.toString())); + } + continue; + } + String s = fjsp.getAbsolutePath(); + if(s.startsWith(uriRoot)) { + nextjsp = s.substring(uriRoot.length()); + } + if(nextjsp.startsWith("." + File.separatorChar)) { + nextjsp = nextjsp.substring(2); + } + processFile(nextjsp); + } + + completeWebXml(); + + if(addWebXmlMappings) { + mergeIntoWebXml(); + } + + } catch(IOException ioe) { + throw new JasperException(ioe); + + } catch(JasperException je) { + Throwable rootCause = je; + while(rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if(rootCause != je) { + rootCause.printStackTrace(); + } + throw je; + } finally { + if(loader != null) { + LogFactory.release(loader); + } + } + } + + // ==================== protected utility methods ==================== + + protected String nextArg() { + if((argPos >= args.length) || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { + return null; + } else { + return args[argPos++]; + } + } + + protected String nextFile() { + if(fullstop) + argPos++; + if(argPos >= args.length) { + return null; + } else { + return args[argPos++]; + } + } + + protected void initWebXml() { + try { + if(webxmlLevel >= INC_WEBXML) { + mapout = openWebxmlWriter(new File(webxmlFile)); + servletout = new CharArrayWriter(); + mappingout = new CharArrayWriter(); + } else { + mapout = null; + servletout = null; + mappingout = null; + } + if(webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.header")); + mapout.flush(); + } else if((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.header")); + mapout.flush(); + } + } catch(IOException ioe) { + mapout = null; + servletout = null; + mappingout = null; + } + } + + protected void completeWebXml() { + if(mapout != null) { + try { + servletout.writeTo(mapout); + mappingout.writeTo(mapout); + if(webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.footer")); + } else if((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.footer")); + } + mapout.close(); + } catch(IOException ioe) { + // noting to do if it fails since we are done with it + } + } + } + + protected void initServletContext() { + try { + context = new JspCServletContext(new PrintWriter(System.out), new URL("file:" + uriRoot.replace('\\', '/') + '/')); + tldLocationsCache = new TldLocationsCache(context, true); + } catch(MalformedURLException me) { + System.out.println("**" + me); + } + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); + } + + /** + * Initializes the classloader as/if needed for the given + * compilation context. + * + * @param clctxt The compilation context + * @throws IOException If an error occurs + */ + protected void initClassLoader(JspCompilationContext clctxt) throws IOException { + + classPath = getClassPath(); + + ClassLoader jspcLoader = getClass().getClassLoader(); + + // TODO add 7Bee class loader + + // Turn the classPath into URLs + ArrayList urls = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); + while(tokenizer.hasMoreTokens()) { + String path = tokenizer.nextToken(); + try { + File libFile = new File(path); + urls.add(libFile.toURL()); + } catch(IOException ioe) { + // Failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak uot + throw new RuntimeException(ioe.toString()); + } + } + + File webappBase = new File(uriRoot); + if(webappBase.exists()) { + File classes = new File(webappBase, "/WEB-INF/classes"); + try { + if(classes.exists()) { + classPath = classPath + File.pathSeparator + classes.getCanonicalPath(); + urls.add(classes.getCanonicalFile().toURL()); + } + } catch(IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + File lib = new File(webappBase, "/WEB-INF/lib"); + if(lib.exists() && lib.isDirectory()) { + String[] libs = lib.list(); + for(int i = 0; i < libs.length; i++) { + if(libs[i].length() < 5) + continue; + String ext = libs[i].substring(libs[i].length() - 4); + if(!".jar".equalsIgnoreCase(ext)) { + if(".tld".equalsIgnoreCase(ext)) { + log.warn("TLD files should not be placed in " + "/WEB-INF/lib"); + } + continue; + } + try { + File libFile = new File(lib, libs[i]); + classPath = classPath + File.pathSeparator + libFile.getAbsolutePath(); + urls.add(libFile.getAbsoluteFile().toURL()); + } catch(IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + } + } + } + + // What is this ?? + urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL()); + + URL urlsA[] = new URL[urls.size()]; + urls.toArray(urlsA); + loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); + + } + + /** + * Find the WEB-INF dir by looking up in the directory tree. + * This is used if no explicit docbase is set, but only files. + * XXX Maybe we should require the docbase. + */ + protected void locateUriRoot(File f) { + String tUriBase = uriBase; + if(tUriBase == null) { + tUriBase = "/"; + } + try { + if(f.exists()) { + f = new File(f.getAbsolutePath()); + while(f != null) { + File g = new File(f, "WEB-INF"); + if(g.exists() && g.isDirectory()) { + uriRoot = f.getCanonicalPath(); + uriBase = tUriBase; + if(log.isInfoEnabled()) { + log.info(Localizer.getMessage("jspc.implicit.uriRoot", uriRoot)); + } + break; + } + if(f.exists() && f.isDirectory()) { + tUriBase = "/" + f.getName() + "/" + tUriBase; + } + + String fParent = f.getParent(); + if(fParent == null) { + break; + } else { + f = new File(fParent); + } + + // If there is no acceptible candidate, uriRoot will + // remain null to indicate to the CompilerContext to + // use the current working/user dir. + } + + if(uriRoot != null) { + File froot = new File(uriRoot); + uriRoot = froot.getCanonicalPath(); + } + } + } catch(IOException ioe) { + // since this is an optional default and a null value + // for uriRoot has a non-error meaning, we can just + // pass straight through + } + } + + /** + * Resolves the relative or absolute pathname correctly + * in both Ant and command-line situations. If Ant launched + * us, we should use the basedir of the current project + * to resolve relative paths. + * + * See Bugzilla 35571. + * + * @param s The file + * @return The file resolved + */ + protected File resolveFile(final String s) { + return new File(s); + } + + private Reader openWebxmlReader(File file) throws IOException { + FileInputStream fis = new FileInputStream(file); + try { + return webxmlEncoding != null ? new InputStreamReader(fis, webxmlEncoding) : new InputStreamReader(fis); + } catch(IOException ex) { + fis.close(); + throw ex; + } + } + + private Writer openWebxmlWriter(File file) throws IOException { + FileOutputStream fos = new FileOutputStream(file); + try { + return webxmlEncoding != null ? new OutputStreamWriter(fos, webxmlEncoding) : new OutputStreamWriter(fos); + } catch(IOException ex) { + fos.close(); + throw ex; + } + } +} diff --git a/BeeCompiler/jasper6/JspCompilationContext.java b/BeeCompiler/jasper6/JspCompilationContext.java new file mode 100755 index 0000000..a6bc078 --- /dev/null +++ b/BeeCompiler/jasper6/JspCompilationContext.java @@ -0,0 +1,677 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.JspUtil; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.ServletWriter; +import org.apache.jasper.servlet.JasperLoader; +import org.apache.jasper.servlet.JspServletWrapper; + +/** + * A place holder for various things that are used through out the JSP + * engine. This is a per-request/per-context data structure. Some of + * the instance variables are set at different points. + * + * Most of the path-related stuff is here - mangling names, versions, dirs, + * loading resources and dealing with uris. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Pierre Delisle + * @author Costin Manolache + * @author Kin-man Chung + */ +public class JspCompilationContext { + + protected org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(JspCompilationContext.class); + + protected Map tagFileJarUrls; + protected boolean isPackagedTagFile; + + protected String className; + protected String jspUri; + protected boolean isErrPage; + protected String basePackageName; + protected String derivedPackageName; + protected String servletJavaFileName; + protected String javaPath; + protected String classFileName; + protected String contentType; + protected ServletWriter writer; + protected Options options; + protected JspServletWrapper jsw; + protected Compiler jspCompiler; + protected String classPath; + + protected String baseURI; + protected String outputDir; + protected ServletContext context; + protected URLClassLoader loader; + + protected JspRuntimeContext rctxt; + + protected int removed = 0; + + protected URLClassLoader jspLoader; + protected URL baseUrl; + protected Class servletClass; + + protected boolean isTagFile; + protected boolean protoTypeMode; + protected TagInfo tagInfo; + protected URL tagFileJarUrl; + + // jspURI _must_ be relative to the context + public JspCompilationContext(String jspUri, boolean isErrPage, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt) { + + this.jspUri = canonicalURI(jspUri); + this.isErrPage = isErrPage; + this.options = options; + this.jsw = jsw; + this.context = context; + + this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); + // hack fix for resolveRelativeURI + if(baseURI == null) { + baseURI = "/"; + } else if(baseURI.charAt(0) != '/') { + // strip the basde slash since it will be combined with the + // uriBase to generate a file + baseURI = "/" + baseURI; + } + if(baseURI.charAt(baseURI.length() - 1) != '/') { + baseURI += '/'; + } + + this.rctxt = rctxt; + this.tagFileJarUrls = new HashMap(); + this.basePackageName = Constants.JSP_PACKAGE_NAME; + } + + public JspCompilationContext(String tagfile, TagInfo tagInfo, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt, URL tagFileJarUrl) { + this(tagfile, false, options, context, jsw, rctxt); + this.isTagFile = true; + this.tagInfo = tagInfo; + this.tagFileJarUrl = tagFileJarUrl; + if(tagFileJarUrl != null) { + isPackagedTagFile = true; + } + } + + /* ==================== Methods to override ==================== */ + + /** ---------- Class path and loader ---------- */ + + /** + * The classpath that is passed off to the Java compiler. + */ + public String getClassPath() { + if(classPath != null) + return classPath; + return rctxt.getClassPath(); + } + + /** + * The classpath that is passed off to the Java compiler. + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * What class loader to use for loading classes while compiling + * this JSP? + */ + public ClassLoader getClassLoader() { + if(loader != null) + return loader; + return rctxt.getParentClassLoader(); + } + + public void setClassLoader(URLClassLoader loader) { + this.loader = loader; + } + + public ClassLoader getJspLoader() { + if(jspLoader == null) { + jspLoader = new JasperLoader(new URL[] { baseUrl }, getClassLoader(), rctxt.getPermissionCollection(), rctxt.getCodeSource()); + } + return jspLoader; + } + + /** ---------- Input/Output ---------- */ + + /** + * The output directory to generate code into. The output directory + * is make up of the scratch directory, which is provide in Options, + * plus the directory derived from the package name. + */ + public String getOutputDir() { + if(outputDir == null) { + createOutputDir(); + } + + return outputDir; + } + + /** + * Create a "Compiler" object based on some init param data. This + * is not done yet. Right now we're just hardcoding the actual + * compilers that are created. + */ + public Compiler createCompiler() throws JasperException { + if(jspCompiler != null) { + return jspCompiler; + } + jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); + if(jspCompiler == null) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); + } + jspCompiler.init(this, jsw); + return jspCompiler; + } + + protected Compiler createCompiler(String className) { + Compiler compiler = null; + try { + compiler = (Compiler) Class.forName(className).newInstance(); + } catch(InstantiationException e) { + log.warn(Localizer.getMessage("jsp.error.compiler"), e); + } catch(IllegalAccessException e) { + log.warn(Localizer.getMessage("jsp.error.compiler"), e); + } catch(NoClassDefFoundError e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), e); + } + } catch(ClassNotFoundException e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), e); + } + } + return compiler; + } + + public Compiler getCompiler() { + return jspCompiler; + } + + /** ---------- Access resources in the webapp ---------- */ + + /** + * Get the full value of a URI relative to this compilations context + * uses current file as the base. + */ + public String resolveRelativeUri(String uri) { + // sometimes we get uri's massaged from File(String), so check for + // a root directory deperator char + if(uri.startsWith("/") || uri.startsWith(File.separator)) { + return uri; + } else { + return baseURI + uri; + } + } + + /** + * Gets a resource as a stream, relative to the meanings of this + * context's implementation. + * + * @return a null if the resource cannot be found or represented + * as an InputStream. + */ + public java.io.InputStream getResourceAsStream(String res) { + return context.getResourceAsStream(canonicalURI(res)); + } + + public URL getResource(String res) throws MalformedURLException { + return context.getResource(canonicalURI(res)); + } + + public Set getResourcePaths(String path) { + return context.getResourcePaths(canonicalURI(path)); + } + + /** + * Gets the actual path of a URI relative to the context of + * the compilation. + */ + public String getRealPath(String path) { + if(context != null) { + return context.getRealPath(path); + } + return path; + } + + /** + * Returns the tag-file-name-to-JAR-file map of this compilation unit, + * which maps tag file names to the JAR files in which the tag files are + * packaged. + * + * The map is populated when parsing the tag-file elements of the TLDs + * of any imported taglibs. + */ + public URL getTagFileJarUrl(String tagFile) { + return this.tagFileJarUrls.get(tagFile); + } + + public void setTagFileJarUrl(String tagFile, URL tagFileURL) { + this.tagFileJarUrls.put(tagFile, tagFileURL); + } + + /** + * Returns the JAR file in which the tag file for which this + * JspCompilationContext was created is packaged, or null if this + * JspCompilationContext does not correspond to a tag file, or if the + * corresponding tag file is not packaged in a JAR. + */ + public URL getTagFileJarUrl() { + return this.tagFileJarUrl; + } + + /* ==================== Common implementation ==================== */ + + /** + * Just the class name (does not include package name) of the + * generated class. + */ + public String getServletClassName() { + + if(className != null) { + return className; + } + + if(isTagFile) { + className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + if(lastIndex != -1) { + className = className.substring(lastIndex + 1); + } + } else { + int iSep = jspUri.lastIndexOf('/') + 1; + className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); + } + return className; + } + + public void setServletClassName(String className) { + this.className = className; + } + + /** + * Path of the JSP URI. Note that this is not a file name. This is + * the context rooted URI of the JSP file. + */ + public String getJspFile() { + return jspUri; + } + + /** + * Are we processing something that has been declared as an + * errorpage? + */ + public boolean isErrorPage() { + return isErrPage; + } + + public void setErrorPage(boolean isErrPage) { + this.isErrPage = isErrPage; + } + + public boolean isTagFile() { + return isTagFile; + } + + public TagInfo getTagInfo() { + return tagInfo; + } + + public void setTagInfo(TagInfo tagi) { + tagInfo = tagi; + } + + /** + * True if we are compiling a tag file in prototype mode. + * ie we only generate codes with class for the tag handler with empty + * method bodies. + */ + public boolean isPrototypeMode() { + return protoTypeMode; + } + + public void setPrototypeMode(boolean pm) { + protoTypeMode = pm; + } + + /** + * Package name for the generated class is make up of the base package + * name, which is user settable, and the derived package name. The + * derived package name directly mirrors the file heirachy of the JSP page. + */ + public String getServletPackageName() { + if(isTagFile()) { + String className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + String pkgName = ""; + if(lastIndex != -1) { + pkgName = className.substring(0, lastIndex); + } + return pkgName; + } else { + String dPackageName = getDerivedPackageName(); + if(dPackageName.length() == 0) { + return basePackageName; + } + return basePackageName + '.' + getDerivedPackageName(); + } + } + + protected String getDerivedPackageName() { + if(derivedPackageName == null) { + int iSep = jspUri.lastIndexOf('/'); + derivedPackageName = (iSep > 0) ? JspUtil.makeJavaPackage(jspUri.substring(1, iSep)) : ""; + } + return derivedPackageName; + } + + /** + * The package name into which the servlet class is generated. + */ + public void setServletPackageName(String servletPackageName) { + this.basePackageName = servletPackageName; + } + + /** + * Full path name of the Java file into which the servlet is being + * generated. + */ + public String getServletJavaFileName() { + if(servletJavaFileName == null) { + servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; + } + return servletJavaFileName; + } + + /** + * Get hold of the Options object for this context. + */ + public Options getOptions() { + return options; + } + + public ServletContext getServletContext() { + return context; + } + + public JspRuntimeContext getRuntimeContext() { + return rctxt; + } + + /** + * Path of the Java file relative to the work directory. + */ + public String getJavaPath() { + + if(javaPath != null) { + return javaPath; + } + + if(isTagFile()) { + String tagName = tagInfo.getTagClassName(); + javaPath = tagName.replace('.', '/') + ".java"; + } else { + javaPath = getServletPackageName().replace('.', '/') + '/' + getServletClassName() + ".java"; + } + return javaPath; + } + + public String getClassFileName() { + if(classFileName == null) { + classFileName = getOutputDir() + getServletClassName() + ".class"; + } + return classFileName; + } + + /** + * Get the content type of this JSP. + * + * Content type includes content type and encoding. + */ + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + /** + * Where is the servlet being generated? + */ + public ServletWriter getWriter() { + return writer; + } + + public void setWriter(ServletWriter writer) { + this.writer = writer; + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, + * then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the given uri is not associated with any tag + * library + * 'exposed' in the web application. + */ + public String[] getTldLocation(String uri) throws JasperException { + String[] location = getOptions().getTldLocationsCache().getLocation(uri); + return location; + } + + /** + * Are we keeping generated code around? + */ + public boolean keepGenerated() { + return getOptions().getKeepGenerated(); + } + + // ==================== Removal ==================== + + public void incrementRemoved() { + if(removed == 0 && rctxt != null) { + rctxt.removeWrapper(jspUri); + } + removed++; + } + + public boolean isRemoved() { + if(removed > 1) { + return true; + } + return false; + } + + // ==================== Compile and reload ==================== + + public void compile() throws JasperException, FileNotFoundException { + createCompiler(); + if(isPackagedTagFile || jspCompiler.isOutDated()) { + try { + jspCompiler.removeGeneratedFiles(); + jspLoader = null; + jspCompiler.compile(); + jsw.setReload(true); + jsw.setCompilationException(null); + } catch(JasperException ex) { + // Cache compilation exception + jsw.setCompilationException(ex); + throw ex; + } catch(Exception ex) { + JasperException je = new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + // Cache compilation exception + jsw.setCompilationException(je); + throw je; + } + } + } + + // ==================== Manipulating the class ==================== + + public Class load() throws JasperException, FileNotFoundException { + try { + getJspLoader(); + + String name; + if(isTagFile()) { + name = tagInfo.getTagClassName(); + } else { + name = getServletPackageName() + "." + getServletClassName(); + } + servletClass = jspLoader.loadClass(name); + } catch(ClassNotFoundException cex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), cex); + } catch(Exception ex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + } + removed = 0; + return servletClass; + } + + // ==================== protected methods ==================== + + static Object outputDirLock = new Object(); + + public void checkOutputDir() { + if(outputDir != null) { + if(!(new File(outputDir)).exists()) { + makeOutputDir(); + } + } else { + createOutputDir(); + } + } + + protected boolean makeOutputDir() { + synchronized(outputDirLock) { + File outDirFile = new File(outputDir); + return (outDirFile.exists() || outDirFile.mkdirs()); + } + } + + protected void createOutputDir() { + String path = null; + if(isTagFile()) { + String tagName = tagInfo.getTagClassName(); + path = tagName.replace('.', '/'); + path = path.substring(0, path.lastIndexOf('/')); + } else { + path = getServletPackageName().replace('.', '/'); + } + + // Append servlet or tag handler path to scratch dir + try { + baseUrl = options.getScratchDir().toURL(); + String outUrlString = baseUrl.toString() + '/' + path; + URL outUrl = new URL(outUrlString); + outputDir = outUrl.getFile() + File.separator; + if(!makeOutputDir()) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); + } + } catch(MalformedURLException e) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); + } + } + + protected static final boolean isPathSeparator(char c) { + return (c == '/' || c == '\\'); + } + + protected static final String canonicalURI(String s) { + if(s == null) + return null; + StringBuffer result = new StringBuffer(); + final int len = s.length(); + int pos = 0; + while(pos < len) { + char c = s.charAt(pos); + if(isPathSeparator(c)) { + /* + * multiple path separators. + * 'foo///bar' -> 'foo/bar' + */ + while(pos + 1 < len && isPathSeparator(s.charAt(pos + 1))) { + ++pos; + } + + if(pos + 1 < len && s.charAt(pos + 1) == '.') { + /* + * a single dot at the end of the path - we are done. + */ + if(pos + 2 >= len) + break; + + switch(s.charAt(pos + 2)) { + /* + * self directory in path + * foo/./bar -> foo/bar + */ + case '/': + case '\\': + pos += 2; + continue; + + /* + * two dots in a path: go back one hierarchy. + * foo/bar/../baz -> foo/baz + */ + case '.': + // only if we have exactly _two_ dots. + if(pos + 3 < len && isPathSeparator(s.charAt(pos + 3))) { + pos += 3; + int separatorPos = result.length() - 1; + while(separatorPos >= 0 && !isPathSeparator(result.charAt(separatorPos))) { + --separatorPos; + } + if(separatorPos >= 0) + result.setLength(separatorPos); + continue; + } + } + } + } + result.append(c); + ++pos; + } + return result.toString(); + } +} diff --git a/BeeCompiler/jasper6/bee-jasper.xml b/BeeCompiler/jasper6/bee-jasper.xml new file mode 100755 index 0000000..6203ed0 --- /dev/null +++ b/BeeCompiler/jasper6/bee-jasper.xml @@ -0,0 +1,444 @@ + + + + + + + + + + + ]> + + + + &env; + + + + + /bin/javac + + + + + + + /bin/javadoc + + + + + + ******** &project; + Build Process ******** + ********* Available targets: ************************************* + * compile - do Java compilation * + * jar - build &build_file; + file * + * run - run application &main_class; + * + ******************************************************************* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /&build_directory; + + + + + + + + + + + + + + + + + + Compiling javax... + + + + + + + + + + + > + + + + + + 0 + + + + Error(s) at compilation of javax + + + + + + + + + Exception at compilation of javax + + + + + + + + + + + + + + + + + + + + + + Compiling... &project; + + + + + + + + + + + > + + + + + + 0 + + + + Error(s) + at compilation of &project; + + + + + + + + + Exception + at compilation of &project; + + + + + + + + + + &manifestf; + + + + + true + + + + -d + + -sourcepath + + -classpath + + &domain; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &source_directory;/javax/servlet/jsp/resources/jsp*.dtd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/jsp*.xsd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/web-jsp*.dtd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/web-jsp*.xsd + + &build_directory;/javax/servlet/jsp/resources + + + &source_directory;/javax/servlet/resources/j2ee*.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/j2ee*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/web-app*.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/web-app*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/datatypes.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/xml.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/XMLSchema.dtd + + &build_directory;/javax/servlet/resources + + + + + + + + + + + + + + Jarring... + + + + + + + + + + + + + + + + + + + + + + + + + + -cf + + + + -cmf + + + + + + + + + + + + + + + java + org/apache/jasper/resources + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + Exception at jarring + + + + + + + + + + + + + y + + + + + + + + + Cleaning... + + + + + + + + + + + /&build_directory;/&build_file; + + + + + /lib/tools.jar + + + + + Running... + + + + -classpath + + + + + + diff --git a/BeeCompiler/jasper6/env.xml b/BeeCompiler/jasper6/env.xml new file mode 100755 index 0000000..626954b --- /dev/null +++ b/BeeCompiler/jasper6/env.xml @@ -0,0 +1,49 @@ + + + + +. + + + + + + + / + + + + + + + + + /jre + + + + + + + + + + +/home/dmitriy/libs/javax. + +1.5 + + + + \\jre + + + + + + + + servlet.jar + + diff --git a/BeeCompiler/jasper7-6x/EmbeddedServletOptions.java b/BeeCompiler/jasper7-6x/EmbeddedServletOptions.java new file mode 100755 index 0000000..3fe1fea --- /dev/null +++ b/BeeCompiler/jasper7-6x/EmbeddedServletOptions.java @@ -0,0 +1,749 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.util.Enumeration; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagLibraryInfo; + +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * A class to hold all init parameters specific to the JSP engine. + * + * @author Anil K. Vijendran + * @author Hans Bergsten + * @author Pierre Delisle + */ +public final class EmbeddedServletOptions implements Options { + + // Logger + private final Log log = LogFactory.getLog(EmbeddedServletOptions.class); + + private Properties settings = new Properties(); + + /** + * Is Jasper being used in development mode? + */ + private boolean development = true; + + /** + * Should Ant fork its java compiles of JSP pages. + */ + public boolean fork = true; + + /** + * Do you want to keep the generated Java files around? + */ + private boolean keepGenerated = true; + + /** + * Should white spaces between directives or actions be trimmed? + */ + private boolean trimSpaces = false; + + /** + * Determines whether tag handler pooling is enabled. + */ + private boolean isPoolingEnabled = true; + + /** + * Do you want support for "mapped" files? This will generate + * servlet that has a print statement per line of the JSP file. + * This seems like a really nice feature to have for debugging. + */ + private boolean mappedFile = true; + + /** + * Do we want to include debugging information in the class file? + */ + private boolean classDebugInfo = true; + + /** + * Background compile thread check interval in seconds. + */ + private int checkInterval = 0; + + /** + * Is the generation of SMAP info for JSR45 debugging suppressed? + */ + private boolean isSmapSuppressed = false; + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + private boolean isSmapDumped = false; + + /** + * Are Text strings to be generated as char arrays? + */ + private boolean genStringAsCharArray = false; + + private boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * I want to see my generated servlets. Which directory are they + * in? + */ + private File scratchDir; + + /** + * Need to have this as is for versions 4 and 5 of IE. Can be set from + * the initParams so if it changes in the future all that is needed is + * to have a jsp initParam of type ieClassId="" + */ + private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + /** + * What classpath should I use while compiling generated servlets? + */ + private String classpath = null; + + /** + * Compiler to use. + */ + private String compiler = null; + + /** + * Compiler target VM. + */ + private String compilerTargetVM = "1.6"; + + /** + * The compiler source VM. + */ + private String compilerSourceVM = "1.6"; + + /** + * The compiler class name. + */ + private String compilerClassName = null; + + /** + * Cache for the TLD locations + */ + private TldLocationsCache tldLocationsCache = null; + + /** + * Jsp config information + */ + private JspConfig jspConfig = null; + + /** + * TagPluginManager + */ + private TagPluginManager tagPluginManager = null; + + /** + * Java platform encoding to generate the JSP + * page servlet. + */ + private String javaEncoding = "UTF8"; + + /** + * Modification test interval. + */ + private int modificationTestInterval = 4; + + /** + * Is re-compilation attempted immediately after a failure? + */ + private boolean recompileOnFail = false; + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + private boolean xpoweredBy; + + /** + * Should we include a source fragment in exception messages, which could be + * displayed + * to the developer ? + */ + private boolean displaySourceFragment = true; + + /** + * The maximum number of loaded jsps per web-application. If there are more + * jsps loaded, they will be unloaded. + */ + private int maxLoadedJsps = -1; + + /** + * The idle time in seconds after which a JSP is unloaded. + * If unset or less or equal than 0, no jsps are unloaded. + */ + private int jspIdleTimeout = -1; + + public String getProperty(String name) { + return settings.getProperty(name); + } + + public void setProperty(String name, String value) { + if(name != null && value != null) { + settings.setProperty(name, value); + } + } + + /** + * Are we keeping generated code around? + */ + @Override + public boolean getKeepGenerated() { + return keepGenerated; + } + + /** + * Should white spaces between directives or actions be trimmed? + */ + @Override + public boolean getTrimSpaces() { + return trimSpaces; + } + + @Override + public boolean isPoolingEnabled() { + return isPoolingEnabled; + } + + /** + * Are we supporting HTML mapped servlets? + */ + @Override + public boolean getMappedFile() { + return mappedFile; + } + + /** + * Should class files be compiled with debug information? + */ + @Override + public boolean getClassDebugInfo() { + return classDebugInfo; + } + + /** + * Background JSP compile thread check interval + */ + @Override + public int getCheckInterval() { + return checkInterval; + } + + /** + * Modification test interval. + */ + @Override + public int getModificationTestInterval() { + return modificationTestInterval; + } + + /** + * Re-compile on failure. + */ + @Override + public boolean getRecompileOnFail() { + return recompileOnFail; + } + + /** + * Is Jasper being used in development mode? + */ + @Override + public boolean getDevelopment() { + return development; + } + + /** + * Is the generation of SMAP info for JSR45 debugging suppressed? + */ + @Override + public boolean isSmapSuppressed() { + return isSmapSuppressed; + } + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + @Override + public boolean isSmapDumped() { + return isSmapDumped; + } + + /** + * Are Text strings to be generated as char arrays? + */ + @Override + public boolean genStringAsCharArray() { + return this.genStringAsCharArray; + } + + /** + * Class ID for use in the plugin tag when the browser is IE. + */ + @Override + public String getIeClassId() { + return ieClassId; + } + + /** + * What is my scratch dir? + */ + @Override + public File getScratchDir() { + return scratchDir; + } + + /** + * What classpath should I use while compiling the servlets + * generated from JSP files? + */ + @Override + public String getClassPath() { + return classpath; + } + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + @Override + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Compiler to use. + */ + @Override + public String getCompiler() { + return compiler; + } + + /** + * @see Options#getCompilerTargetVM + */ + @Override + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * @see Options#getCompilerSourceVM + */ + @Override + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * Java compiler class to use. + */ + @Override + public String getCompilerClassName() { + return compilerClassName; + } + + @Override + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + @Override + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + public void setTldLocationsCache(TldLocationsCache tldC) { + tldLocationsCache = tldC; + } + + @Override + public String getJavaEncoding() { + return javaEncoding; + } + + @Override + public boolean getFork() { + return fork; + } + + @Override + public JspConfig getJspConfig() { + return jspConfig; + } + + @Override + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + @Override + public boolean isCaching() { + return false; + } + + @Override + public Map getCache() { + return null; + } + + /** + * Should we include a source fragment in exception messages, which could be + * displayed + * to the developer ? + */ + @Override + public boolean getDisplaySourceFragment() { + return displaySourceFragment; + } + + /** + * Should jsps be unloaded if to many are loaded? + * If set to a value greater than 0 eviction of jsps is started. Default: -1 + */ + @Override + public int getMaxLoadedJsps() { + return maxLoadedJsps; + } + + /** + * Should any jsps be unloaded when being idle for this time in seconds? + * If set to a value greater than 0 eviction of jsps is started. Default: -1 + */ + @Override + public int getJspIdleTimeout() { + return jspIdleTimeout; + } + + /** + * Create an EmbeddedServletOptions object using data available from + * ServletConfig and ServletContext. + */ + public EmbeddedServletOptions(ServletConfig config, ServletContext context) { + + Enumeration enumeration = config.getInitParameterNames(); + while(enumeration.hasMoreElements()) { + String k = enumeration.nextElement(); + String v = config.getInitParameter(k); + setProperty(k, v); + } + + String keepgen = config.getInitParameter("keepgenerated"); + if(keepgen != null) { + if(keepgen.equalsIgnoreCase("true")) { + this.keepGenerated = true; + } else if(keepgen.equalsIgnoreCase("false")) { + this.keepGenerated = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.keepgen")); + } + } + } + + String trimsp = config.getInitParameter("trimSpaces"); + if(trimsp != null) { + if(trimsp.equalsIgnoreCase("true")) { + trimSpaces = true; + } else if(trimsp.equalsIgnoreCase("false")) { + trimSpaces = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.trimspaces")); + } + } + } + + this.isPoolingEnabled = true; + String poolingEnabledParam = config.getInitParameter("enablePooling"); + if(poolingEnabledParam != null && !poolingEnabledParam.equalsIgnoreCase("true")) { + if(poolingEnabledParam.equalsIgnoreCase("false")) { + this.isPoolingEnabled = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.enablePooling")); + } + } + } + + String mapFile = config.getInitParameter("mappedfile"); + if(mapFile != null) { + if(mapFile.equalsIgnoreCase("true")) { + this.mappedFile = true; + } else if(mapFile.equalsIgnoreCase("false")) { + this.mappedFile = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.mappedFile")); + } + } + } + + String debugInfo = config.getInitParameter("classdebuginfo"); + if(debugInfo != null) { + if(debugInfo.equalsIgnoreCase("true")) { + this.classDebugInfo = true; + } else if(debugInfo.equalsIgnoreCase("false")) { + this.classDebugInfo = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.classDebugInfo")); + } + } + } + + String checkInterval = config.getInitParameter("checkInterval"); + if(checkInterval != null) { + try { + this.checkInterval = Integer.parseInt(checkInterval); + } catch(NumberFormatException ex) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.checkInterval")); + } + } + } + + String modificationTestInterval = config.getInitParameter("modificationTestInterval"); + if(modificationTestInterval != null) { + try { + this.modificationTestInterval = Integer.parseInt(modificationTestInterval); + } catch(NumberFormatException ex) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval")); + } + } + } + + String recompileOnFail = config.getInitParameter("recompileOnFail"); + if(recompileOnFail != null) { + if(recompileOnFail.equalsIgnoreCase("true")) { + this.recompileOnFail = true; + } else if(recompileOnFail.equalsIgnoreCase("false")) { + this.recompileOnFail = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.recompileOnFail")); + } + } + } + String development = config.getInitParameter("development"); + if(development != null) { + if(development.equalsIgnoreCase("true")) { + this.development = true; + } else if(development.equalsIgnoreCase("false")) { + this.development = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.development")); + } + } + } + + String suppressSmap = config.getInitParameter("suppressSmap"); + if(suppressSmap != null) { + if(suppressSmap.equalsIgnoreCase("true")) { + isSmapSuppressed = true; + } else if(suppressSmap.equalsIgnoreCase("false")) { + isSmapSuppressed = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.suppressSmap")); + } + } + } + + String dumpSmap = config.getInitParameter("dumpSmap"); + if(dumpSmap != null) { + if(dumpSmap.equalsIgnoreCase("true")) { + isSmapDumped = true; + } else if(dumpSmap.equalsIgnoreCase("false")) { + isSmapDumped = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.dumpSmap")); + } + } + } + + String genCharArray = config.getInitParameter("genStringAsCharArray"); + if(genCharArray != null) { + if(genCharArray.equalsIgnoreCase("true")) { + genStringAsCharArray = true; + } else if(genCharArray.equalsIgnoreCase("false")) { + genStringAsCharArray = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.genchararray")); + } + } + } + + String errBeanClass = config.getInitParameter("errorOnUseBeanInvalidClassAttribute"); + if(errBeanClass != null) { + if(errBeanClass.equalsIgnoreCase("true")) { + errorOnUseBeanInvalidClassAttribute = true; + } else if(errBeanClass.equalsIgnoreCase("false")) { + errorOnUseBeanInvalidClassAttribute = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.errBean")); + } + } + } + + String ieClassId = config.getInitParameter("ieClassId"); + if(ieClassId != null) + this.ieClassId = ieClassId; + + String classpath = config.getInitParameter("classpath"); + if(classpath != null) + this.classpath = classpath; + + /* + * scratchdir + */ + String dir = config.getInitParameter("scratchdir"); + if(dir != null) { + scratchDir = new File(dir); + } else { + // First try the Servlet 2.2 javax.servlet.context.tempdir property + scratchDir = (File) context.getAttribute(ServletContext.TEMPDIR); + if(scratchDir == null) { + // Not running in a Servlet 2.2 container. + // Try to get the JDK 1.2 java.io.tmpdir property + dir = System.getProperty("java.io.tmpdir"); + if(dir != null) + scratchDir = new File(dir); + } + } + if(this.scratchDir == null) { + log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir")); + return; + } + + if(!scratchDir.exists()) + scratchDir.mkdirs(); + if(!(scratchDir.exists() && scratchDir.canRead() && scratchDir.canWrite() && scratchDir.isDirectory())) + log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir", scratchDir.getAbsolutePath())); + + this.compiler = config.getInitParameter("compiler"); + + String compilerTargetVM = config.getInitParameter("compilerTargetVM"); + if(compilerTargetVM != null) { + this.compilerTargetVM = compilerTargetVM; + } + + String compilerSourceVM = config.getInitParameter("compilerSourceVM"); + if(compilerSourceVM != null) { + this.compilerSourceVM = compilerSourceVM; + } + + String javaEncoding = config.getInitParameter("javaEncoding"); + if(javaEncoding != null) { + this.javaEncoding = javaEncoding; + } + + String compilerClassName = config.getInitParameter("compilerClassName"); + if(compilerClassName != null) { + this.compilerClassName = compilerClassName; + } + + String fork = config.getInitParameter("fork"); + if(fork != null) { + if(fork.equalsIgnoreCase("true")) { + this.fork = true; + } else if(fork.equalsIgnoreCase("false")) { + this.fork = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.fork")); + } + } + } + + String xpoweredBy = config.getInitParameter("xpoweredBy"); + if(xpoweredBy != null) { + if(xpoweredBy.equalsIgnoreCase("true")) { + this.xpoweredBy = true; + } else if(xpoweredBy.equalsIgnoreCase("false")) { + this.xpoweredBy = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.xpoweredBy")); + } + } + } + + String displaySourceFragment = config.getInitParameter("displaySourceFragment"); + if(displaySourceFragment != null) { + if(displaySourceFragment.equalsIgnoreCase("true")) { + this.displaySourceFragment = true; + } else if(displaySourceFragment.equalsIgnoreCase("false")) { + this.displaySourceFragment = false; + } else { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.displaySourceFragment")); + } + } + } + + String maxLoadedJsps = config.getInitParameter("maxLoadedJsps"); + if(maxLoadedJsps != null) { + try { + this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps); + } catch(NumberFormatException ex) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps", "" + this.maxLoadedJsps)); + } + } + } + + String jspIdleTimeout = config.getInitParameter("jspIdleTimeout"); + if(jspIdleTimeout != null) { + try { + this.jspIdleTimeout = Integer.parseInt(jspIdleTimeout); + } catch(NumberFormatException ex) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.jspIdleTimeout", "" + this.jspIdleTimeout)); + } + } + } + + // Setup the global Tag Libraries location cache for this + // web-application. + tldLocationsCache = TldLocationsCache.getInstance(context); + + // Setup the jsp config info for this web app. + jspConfig = new JspConfig(context); + + // Create a Tag plugin instance + tagPluginManager = new TagPluginManager(context); + } + +} diff --git a/BeeCompiler/jasper7-6x/JspC.java b/BeeCompiler/jasper7-6x/JspC.java new file mode 100755 index 0000000..caf704d --- /dev/null +++ b/BeeCompiler/jasper7-6x/JspC.java @@ -0,0 +1,1601 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.jsp.tagext.TagLibraryInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.servlet.JspCServletContext; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * Shell for the jspc compiler. Handles all options associated with the + * command line and creates compilation contexts which it then compiles + * according to the specified options. + * + * This version can process files from a _single_ webapp at once, i.e. + * a single docbase can be specified. + * + * It can be used as an Ant task using: + * + *
+ *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
+ *      <classpath>
+ *          <pathelement location="${java.home}/../lib/tools.jar"/>
+ *          <fileset dir="${ENV.CATALINA_HOME}/lib">
+ *              <include name="*.jar"/>
+ *          </fileset>
+ *          <path refid="myjars"/>
+ *       </classpath>
+ *  </taskdef>
+ *
+ *  <jasper verbose="0"
+ *           package="my.package"
+ *           uriroot="${webapps.dir}/${webapp.name}"
+ *           webXmlFragment="${build.dir}/generated_web.xml"
+ *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
+ * 
+ * + * @author Danno Ferrin + * @author Pierre Delisle + * @author Costin Manolache + * @author Yoav Shapira + */ +public class JspC implements Options { + + public static final String DEFAULT_IE_CLASS_ID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + // Logger + private static final Log log = LogFactory.getLog(JspC.class); + + protected static final String SWITCH_VERBOSE = "-v"; + protected static final String SWITCH_HELP = "-help"; + protected static final String SWITCH_OUTPUT_DIR = "-d"; + protected static final String SWITCH_PACKAGE_NAME = "-p"; + protected static final String SWITCH_CACHE = "-cache"; + protected static final String SWITCH_CLASS_NAME = "-c"; + protected static final String SWITCH_FULL_STOP = "--"; + protected static final String SWITCH_COMPILE = "-compile"; + protected static final String SWITCH_SOURCE = "-source"; + protected static final String SWITCH_TARGET = "-target"; + protected static final String SWITCH_URI_BASE = "-uribase"; + protected static final String SWITCH_URI_ROOT = "-uriroot"; + protected static final String SWITCH_FILE_WEBAPP = "-webapp"; + protected static final String SWITCH_WEBAPP_INC = "-webinc"; + protected static final String SWITCH_WEBAPP_XML = "-webxml"; + protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; + protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; + protected static final String SWITCH_MAPPED = "-mapped"; + protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; + protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; + protected static final String SWITCH_CLASSPATH = "-classpath"; + protected static final String SWITCH_DIE = "-die"; + protected static final String SWITCH_POOLING = "-poolingEnabled"; + protected static final String SWITCH_ENCODING = "-javaEncoding"; + protected static final String SWITCH_SMAP = "-smap"; + protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; + protected static final String SWITCH_VALIDATE_TLD = "-validateTld"; + protected static final String SWITCH_VALIDATE_XML = "-validateXml"; + protected static final String SWITCH_BLOCK_EXTERNAL = "-blockExternal"; + protected static final String SWITCH_NO_BLOCK_EXTERNAL = "-no-blockExternal"; + protected static final String SHOW_SUCCESS = "-s"; + protected static final String LIST_ERRORS = "-l"; + protected static final int INC_WEBXML = 10; + protected static final int ALL_WEBXML = 20; + protected static final int DEFAULT_DIE_LEVEL = 1; + protected static final int NO_DIE_LEVEL = 0; + protected static final Set insertBefore = new HashSet(); + + static { + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + } + + protected String classPath = null; + protected ClassLoader loader = null; + protected boolean trimSpaces = false; + protected boolean genStringAsCharArray = false; + protected boolean validateTld; + protected boolean validateXml; + protected boolean blockExternal = true; + protected boolean xpoweredBy; + protected boolean mappedFile = false; + protected boolean poolingEnabled = true; + protected File scratchDir; + protected String ieClassId = DEFAULT_IE_CLASS_ID; + protected String targetPackage; + protected String targetClassName; + protected String uriBase; + protected String uriRoot; + protected int dieLevel; + protected boolean helpNeeded = false; + protected boolean compile = false; + protected boolean smapSuppressed = true; + protected boolean smapDumped = false; + protected boolean caching = true; + protected final Map cache = new HashMap(); + + protected String compiler = null; + + protected String compilerTargetVM = "1.6"; + protected String compilerSourceVM = "1.6"; + + protected boolean classDebugInfo = true; + + /** + * Throw an exception if there's a compilation error, or swallow it. + * Default is true to preserve old behavior. + */ + protected boolean failOnError = true; + + /** + * The file extensions to be handled as JSP files. + * Default list is .jsp and .jspx. + */ + protected List extensions; + + /** + * The pages. + */ + protected final List pages = new Vector(); + + /** + * Needs better documentation, this data member does. + * True by default. + */ + protected boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * The java file encoding. Default + * is UTF-8. Added per bugzilla 19622. + */ + protected String javaEncoding = "UTF-8"; + + // Generation of web.xml fragments + protected String webxmlFile; + protected int webxmlLevel; + protected String webxmlEncoding; + protected boolean addWebXmlMappings = false; + + protected Writer mapout; + protected CharArrayWriter servletout; + protected CharArrayWriter mappingout; + + /** + * The servlet context. + */ + protected JspCServletContext context; + + /** + * The runtime context. + * Maintain a dummy JspRuntimeContext for compiling tag files. + */ + protected JspRuntimeContext rctxt; + + /** + * Cache for the TLD locations + */ + protected TldLocationsCache tldLocationsCache = null; + + protected JspConfig jspConfig = null; + protected TagPluginManager tagPluginManager = null; + + protected boolean verbose = false; + protected boolean listErrors = false; + protected boolean showSuccess = false; + protected int argPos; + protected boolean fullstop = false; + protected String args[]; + + public static void main(String arg[]) { + if(arg.length == 0) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + JspC jspc = new JspC(); + try { + jspc.setArgs(arg); + if(jspc.helpNeeded) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + jspc.execute(); + } + } catch(JasperException je) { + System.err.println(je); + if(jspc.dieLevel != NO_DIE_LEVEL) { + System.exit(jspc.dieLevel); + } + } catch(RuntimeException je) { + System.err.println(je); + if(jspc.dieLevel != NO_DIE_LEVEL) { + System.exit(jspc.dieLevel); + } + } + } + } + + /** + * Apply command-line arguments. + * + * @param arg + * The arguments + */ + public void setArgs(String[] arg) throws JasperException { + args = arg; + String tok; + + dieLevel = NO_DIE_LEVEL; + + while((tok = nextArg()) != null) { + if(tok.equals(SWITCH_VERBOSE)) { + verbose = true; + showSuccess = true; + listErrors = true; + } else if(tok.equals(SWITCH_OUTPUT_DIR)) { + tok = nextArg(); + setOutputDir(tok); + } else if(tok.equals(SWITCH_PACKAGE_NAME)) { + targetPackage = nextArg(); + } else if(tok.equals(SWITCH_COMPILE)) { + compile = true; + } else if(tok.equals(SWITCH_CLASS_NAME)) { + targetClassName = nextArg(); + } else if(tok.equals(SWITCH_URI_BASE)) { + uriBase = nextArg(); + } else if(tok.equals(SWITCH_URI_ROOT)) { + setUriroot(nextArg()); + } else if(tok.equals(SWITCH_FILE_WEBAPP)) { + setUriroot(nextArg()); + } else if(tok.equals(SHOW_SUCCESS)) { + showSuccess = true; + } else if(tok.equals(LIST_ERRORS)) { + listErrors = true; + } else if(tok.equals(SWITCH_WEBAPP_INC)) { + webxmlFile = nextArg(); + if(webxmlFile != null) { + webxmlLevel = INC_WEBXML; + } + } else if(tok.equals(SWITCH_WEBAPP_XML)) { + webxmlFile = nextArg(); + if(webxmlFile != null) { + webxmlLevel = ALL_WEBXML; + } + } else if(tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { + setWebXmlEncoding(nextArg()); + } else if(tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { + setAddWebXmlMappings(true); + } else if(tok.equals(SWITCH_MAPPED)) { + mappedFile = true; + } else if(tok.equals(SWITCH_XPOWERED_BY)) { + xpoweredBy = true; + } else if(tok.equals(SWITCH_TRIM_SPACES)) { + setTrimSpaces(true); + } else if(tok.equals(SWITCH_CACHE)) { + tok = nextArg(); + if("false".equals(tok)) { + caching = false; + } else { + caching = true; + } + } else if(tok.equals(SWITCH_CLASSPATH)) { + setClassPath(nextArg()); + } else if(tok.startsWith(SWITCH_DIE)) { + try { + dieLevel = Integer.parseInt(tok.substring(SWITCH_DIE.length())); + } catch(NumberFormatException nfe) { + dieLevel = DEFAULT_DIE_LEVEL; + } + } else if(tok.equals(SWITCH_HELP)) { + helpNeeded = true; + } else if(tok.equals(SWITCH_POOLING)) { + tok = nextArg(); + if("false".equals(tok)) { + poolingEnabled = false; + } else { + poolingEnabled = true; + } + } else if(tok.equals(SWITCH_ENCODING)) { + setJavaEncoding(nextArg()); + } else if(tok.equals(SWITCH_SOURCE)) { + setCompilerSourceVM(nextArg()); + } else if(tok.equals(SWITCH_TARGET)) { + setCompilerTargetVM(nextArg()); + } else if(tok.equals(SWITCH_SMAP)) { + smapSuppressed = false; + } else if(tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; + } else if(tok.equals(SWITCH_VALIDATE_TLD)) { + setValidateTld(true); + } else if(tok.equals(SWITCH_VALIDATE_XML)) { + setValidateXml(true); + } else if(tok.equals(SWITCH_BLOCK_EXTERNAL)) { + setBlockExternal(true); + } else if(tok.equals(SWITCH_NO_BLOCK_EXTERNAL)) { + setBlockExternal(false); + } else { + if(tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + ". Use -help for help."); + } + if(!fullstop) { + argPos--; + } + // Start treating the rest as JSP Pages + break; + } + } + + // Add all extra arguments to the list of files + while(true) { + String file = nextFile(); + if(file == null) { + break; + } + pages.add(file); + } + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + @Override + public boolean getKeepGenerated() { + // isn't this why we are running jspc? + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getTrimSpaces() { + return trimSpaces; + } + + /** + * Sets the option to trim white spaces between directives or actions. + */ + public void setTrimSpaces(boolean ts) { + this.trimSpaces = ts; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + /** + * Sets the option to enable the tag handler pooling. + */ + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Sets the option to enable generation of X-Powered-By response header. + */ + public void setXpoweredBy(boolean xpoweredBy) { + this.xpoweredBy = xpoweredBy; + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + @Override + public boolean getDisplaySourceFragment() { + return true; + } + + @Override + public int getMaxLoadedJsps() { + return -1; + } + + @Override + public int getJspIdleTimeout() { + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + /** + * Sets the option to issue a compilation error if the class attribute + * specified in useBean action is invalid. + */ + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getMappedFile() { + return mappedFile; + } + + public void setMappedFile(boolean b) { + mappedFile = b; + } + + /** + * Sets the option to include debug information in compiled class. + */ + public void setClassDebugInfo(boolean b) { + classDebugInfo = b; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getClassDebugInfo() { + // compile with debug info + return classDebugInfo; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isCaching() { + return caching; + } + + /** + * Sets the option to enable caching. + * + * @see Options#isCaching() + */ + public void setCaching(boolean caching) { + this.caching = caching; + } + + /** + * {@inheritDoc} + */ + @Override + public Map getCache() { + return cache; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + @Override + public int getCheckInterval() { + return 0; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + @Override + public int getModificationTestInterval() { + return 0; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + @Override + public boolean getRecompileOnFail() { + return false; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + @Override + public boolean getDevelopment() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSmapSuppressed() { + return smapSuppressed; + } + + /** + * Sets smapSuppressed flag. + */ + public void setSmapSuppressed(boolean smapSuppressed) { + this.smapSuppressed = smapSuppressed; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSmapDumped() { + return smapDumped; + } + + /** + * Sets smapDumped flag. + * + * @see Options#isSmapDumped() + */ + public void setSmapDumped(boolean smapDumped) { + this.smapDumped = smapDumped; + } + + /** + * Determines whether text strings are to be generated as char arrays, + * which improves performance in some cases. + * + * @param genStringAsCharArray true if text strings are to be generated as + * char arrays, false otherwise + */ + public void setGenStringAsCharArray(boolean genStringAsCharArray) { + this.genStringAsCharArray = genStringAsCharArray; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean genStringAsCharArray() { + return genStringAsCharArray; + } + + /** + * Sets the class-id value to be sent to Internet Explorer when using + * <jsp:plugin> tags. + * + * @param ieClassId + * Class-id value + */ + public void setIeClassId(String ieClassId) { + this.ieClassId = ieClassId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getIeClassId() { + return ieClassId; + } + + /** + * {@inheritDoc} + */ + @Override + public File getScratchDir() { + return scratchDir; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompiler() { + return compiler; + } + + /** + * Sets the option to determine what compiler to use. + * + * @see Options#getCompiler() + */ + public void setCompiler(String c) { + compiler = c; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerClassName() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * Sets the compiler target VM. + * + * @see Options#getCompilerTargetVM() + */ + public void setCompilerTargetVM(String vm) { + compilerTargetVM = vm; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * Sets the compiler source VM. + * + * @see Options#getCompilerSourceVM() + */ + public void setCompilerSourceVM(String vm) { + compilerSourceVM = vm; + } + + /** + * {@inheritDoc} + */ + @Override + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + /** + * Returns the encoding to use for + * java files. The default is UTF-8. + * + * @return String The encoding + */ + @Override + public String getJavaEncoding() { + return javaEncoding; + } + + /** + * Sets the encoding to use for + * java files. + * + * @param encodingName The name, e.g. "UTF-8" + */ + public void setJavaEncoding(String encodingName) { + javaEncoding = encodingName; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getFork() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public String getClassPath() { + if(classPath != null) + return classPath; + return System.getProperty("java.class.path"); + } + + /** + * Sets the classpath used while compiling the servlets generated from JSP + * files + */ + public void setClassPath(String s) { + classPath = s; + } + + /** + * Returns the list of file extensions + * that are treated as JSP files. + * + * @return The list of extensions + */ + public List getExtensions() { + return extensions; + } + + /** + * Adds the given file extension to the + * list of extensions handled as JSP files. + * + * @param extension The extension to add, e.g. "myjsp" + */ + protected void addExtension(final String extension) { + if(extension != null) { + if(extensions == null) { + extensions = new Vector(); + } + + extensions.add(extension); + } + } + + /** + * Base dir for the webapp. Used to generate class names and resolve + * includes. + */ + public void setUriroot(String s) { + if(s == null) { + uriRoot = null; + return; + } + try { + uriRoot = resolveFile(s).getCanonicalPath(); + } catch(Exception ex) { + uriRoot = s; + } + } + + /** + * Parses comma-separated list of JSP files to be processed. If the argument + * is null, nothing is done. + * + *

+ * Each file is interpreted relative to uriroot, unless it is absolute, + * in which case it must start with uriroot. + *

+ * + * @param jspFiles Comma-separated list of JSP files to be processed + */ + public void setJspFiles(final String jspFiles) { + if(jspFiles == null) { + return; + } + + StringTokenizer tok = new StringTokenizer(jspFiles, ","); + while(tok.hasMoreTokens()) { + pages.add(tok.nextToken()); + } + } + + /** + * Sets the compile flag. + * + * @param b Flag value + */ + public void setCompile(final boolean b) { + compile = b; + } + + /** + * Sets the verbosity level. The actual number doesn't + * matter: if it's greater than zero, the verbose flag will + * be true. + * + * @param level Positive means verbose + */ + public void setVerbose(final int level) { + if(level > 0) { + verbose = true; + showSuccess = true; + listErrors = true; + } + } + + public void setValidateTld(boolean b) { + this.validateTld = b; + } + + public boolean isValidateTld() { + return validateTld; + } + + public void setValidateXml(boolean b) { + this.validateXml = b; + } + + public boolean isValidateXml() { + return validateXml; + } + + public void setBlockExternal(boolean b) { + this.blockExternal = b; + } + + public boolean isBlockExternal() { + return blockExternal; + } + + public void setListErrors(boolean b) { + listErrors = b; + } + + public void setOutputDir(String s) { + if(s != null) { + scratchDir = resolveFile(s).getAbsoluteFile(); + } else { + scratchDir = null; + } + } + + /** + * Sets the package name to be used for the generated servlet classes. + */ + public void setPackage(String p) { + targetPackage = p; + } + + /** + * Class name of the generated file ( without package ). + * Can only be used if a single file is converted. + * XXX Do we need this feature ? + */ + public void setClassName(String p) { + targetClassName = p; + } + + /** + * File where we generate a web.xml fragment with the class definitions. + */ + public void setWebXmlFragment(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = INC_WEBXML; + } + + /** + * File where we generate a complete web.xml with the class definitions. + */ + public void setWebXml(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = ALL_WEBXML; + } + + /** + * Sets the encoding to be used to read and write web.xml files. + * + *

+ * If not specified, defaults to the platform default encoding. + *

+ * + * @param encoding + * Encoding, e.g. "UTF-8". + */ + public void setWebXmlEncoding(String encoding) { + webxmlEncoding = encoding; + } + + /** + * Sets the option to merge generated web.xml fragment into the + * WEB-INF/web.xml file of the web application that we were processing. + * + * @param b + * true to merge the fragment into the existing + * web.xml file of the processed web application + * ({uriroot}/WEB-INF/web.xml), false to keep the + * generated web.xml fragment + */ + public void setAddWebXmlMappings(boolean b) { + addWebXmlMappings = b; + } + + /** + * Sets the option that throws an exception in case of a compilation error. + */ + public void setFailOnError(final boolean b) { + failOnError = b; + } + + /** + * Returns true if an exception will be thrown in case of a compilation + * error. + */ + public boolean getFailOnError() { + return failOnError; + } + + /** + * {@inheritDoc} + */ + @Override + public JspConfig getJspConfig() { + return jspConfig; + } + + /** + * {@inheritDoc} + */ + @Override + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + /** + * Adds servlet declaration and mapping for the JSP page servlet to the + * generated web.xml fragment. + * + * @param file + * Context-relative path to the JSP file, e.g. + * /index.jsp + * @param clctxt + * Compilation context of the servlet + */ + public void generateWebMapping(String file, JspCompilationContext clctxt) throws IOException { + if(log.isDebugEnabled()) { + log.debug("Generating web mapping for file " + file + " using compilation context " + clctxt); + } + + String className = clctxt.getServletClassName(); + String packageName = clctxt.getServletPackageName(); + + String thisServletName; + if("".equals(packageName)) { + thisServletName = className; + } else { + thisServletName = packageName + '.' + className; + } + + if(servletout != null) { + servletout.write("\n \n "); + servletout.write(thisServletName); + servletout.write("\n "); + servletout.write(thisServletName); + servletout.write("\n \n"); + } + if(mappingout != null) { + mappingout.write("\n \n "); + mappingout.write(thisServletName); + mappingout.write("\n "); + mappingout.write(file.replace('\\', '/')); + mappingout.write("\n \n"); + + } + } + + /** + * Include the generated web.xml inside the webapp's web.xml. + */ + protected void mergeIntoWebXml() throws IOException { + + File webappBase = new File(uriRoot); + File webXml = new File(webappBase, "WEB-INF/web.xml"); + File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); + String insertStartMarker = Localizer.getMessage("jspc.webinc.insertStart"); + String insertEndMarker = Localizer.getMessage("jspc.webinc.insertEnd"); + + BufferedReader reader = new BufferedReader(openWebxmlReader(webXml)); + BufferedReader fragmentReader = new BufferedReader(openWebxmlReader(new File(webxmlFile))); + PrintWriter writer = new PrintWriter(openWebxmlWriter(webXml2)); + + // Insert the and declarations + boolean inserted = false; + int current = reader.read(); + while(current > -1) { + if(current == '<') { + String element = getElement(reader); + if(!inserted && insertBefore.contains(element)) { + // Insert generated content here + writer.println(insertStartMarker); + while(true) { + String line = fragmentReader.readLine(); + if(line == null) { + writer.println(); + break; + } + writer.println(line); + } + writer.println(insertEndMarker); + writer.println(); + writer.write(element); + inserted = true; + } else if(element.equals(insertStartMarker)) { + // Skip the previous auto-generated content + while(true) { + current = reader.read(); + if(current < 0) { + throw new EOFException(); + } + if(current == '<') { + element = getElement(reader); + if(element.equals(insertEndMarker)) { + break; + } + } + } + current = reader.read(); + while(current == '\n' || current == '\r') { + current = reader.read(); + } + continue; + } else { + writer.write(element); + } + } else { + writer.write(current); + } + current = reader.read(); + } + writer.close(); + + reader.close(); + fragmentReader.close(); + + FileInputStream fis = new FileInputStream(webXml2); + FileOutputStream fos = new FileOutputStream(webXml); + + byte buf[] = new byte[512]; + while(true) { + int n = fis.read(buf); + if(n < 0) { + break; + } + fos.write(buf, 0, n); + } + + fis.close(); + fos.close(); + + if(!webXml2.delete() && log.isDebugEnabled()) + log.debug(Localizer.getMessage("jspc.delete.fail", webXml2.toString())); + + if(!(new File(webxmlFile)).delete() && log.isDebugEnabled()) + log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile)); + + } + + /* + * Assumes valid xml + */ + private String getElement(Reader reader) throws IOException { + StringBuilder result = new StringBuilder(); + result.append('<'); + + boolean done = false; + + while(!done) { + int current = reader.read(); + while(current != '>') { + if(current < 0) { + throw new EOFException(); + } + result.append((char) current); + current = reader.read(); + } + result.append((char) current); + + int len = result.length(); + if(len > 4 && result.substring(0, 4).equals("")) { + done = true; + } + } else { + done = true; + } + } + + return result.toString(); + } + + protected void processFile(String file) throws JasperException { + if(log.isDebugEnabled()) { + log.debug("Processing file: " + file); + } + + ClassLoader originalClassLoader = null; + + try { + // set up a scratch/output dir if none is provided + if(scratchDir == null) { + String temp = System.getProperty("java.io.tmpdir"); + if(temp == null) { + temp = ""; + } + scratchDir = new File(new File(temp).getAbsolutePath()); + } + + String jspUri = file.replace('\\', '/'); + JspCompilationContext clctxt = new JspCompilationContext(jspUri, this, context, null, rctxt); + + /* Override the defaults */ + if((targetClassName != null) && (targetClassName.length() > 0)) { + clctxt.setServletClassName(targetClassName); + targetClassName = null; + } + if(targetPackage != null) { + clctxt.setServletPackageName(targetPackage); + } + + originalClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(loader); + + clctxt.setClassLoader(loader); + clctxt.setClassPath(classPath); + + Compiler clc = clctxt.createCompiler(); + + // If compile is set, generate both .java and .class, if + // .jsp file is newer than .class file; + // Otherwise only generate .java, if .jsp file is newer than + // the .java file + if(clc.isOutDated(compile)) { + if(log.isDebugEnabled()) { + log.debug(jspUri + " is out dated, compiling..."); + } + + clc.compile(compile, true); + } + + // Generate mapping + generateWebMapping(file, clctxt); + if(showSuccess) { + log.info("Built File: " + file); + } + + } catch(JasperException je) { + Throwable rootCause = je; + while(rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if(rootCause != je) { + log.error(Localizer.getMessage("jspc.error.generalException", file), rootCause); + } + + // Bugzilla 35114. + if(getFailOnError()) { + throw je; + } else { + log.error(je.getMessage()); + } + + } catch(Exception e) { + if((e instanceof FileNotFoundException) && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", e.getMessage())); + } + throw new JasperException(e); + } finally { + if(originalClassLoader != null) { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + + /** + * Locate all jsp files in the webapp. Used if no explicit + * jsps are specified. + */ + public void scanFiles(File base) throws JasperException { + Stack dirs = new Stack(); + dirs.push(base.toString()); + + // Make sure default extensions are always included + if((getExtensions() == null) || (getExtensions().size() < 2)) { + addExtension("jsp"); + addExtension("jspx"); + } + + while(!dirs.isEmpty()) { + String s = dirs.pop(); + File f = new File(s); + if(f.exists() && f.isDirectory()) { + String[] files = f.list(); + String ext; + for(int i = 0; (files != null) && i < files.length; i++) { + File f2 = new File(s, files[i]); + if(f2.isDirectory()) { + dirs.push(f2.getPath()); + } else { + String path = f2.getPath(); + String uri = path.substring(uriRoot.length()); + ext = files[i].substring(files[i].lastIndexOf('.') + 1); + if(getExtensions().contains(ext) || jspConfig.isJspPage(uri)) { + pages.add(path); + } + } + } + } + } + } + + /** + * Executes the compilation. + */ + public void execute() { + if(log.isDebugEnabled()) { + log.debug("execute() starting for " + pages.size() + " pages."); + } + + try { + if(uriRoot == null) { + if(pages.size() == 0) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget")); + } + String firstJsp = pages.get(0); + File firstJspF = new File(firstJsp); + if(!firstJspF.exists()) { + throw new JasperException(Localizer.getMessage("jspc.error.fileDoesNotExist", firstJsp)); + } + locateUriRoot(firstJspF); + } + + if(uriRoot == null) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot")); + } + + File uriRootF = new File(uriRoot); + if(!uriRootF.isDirectory()) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); + } + + if(loader == null) { + loader = initClassLoader(); + } + if(context == null) { + initServletContext(loader); + } + + // No explicit pages, we'll process all .jsp in the webapp + if(pages.size() == 0) { + scanFiles(uriRootF); + } + + initWebXml(); + + Iterator iter = pages.iterator(); + while(iter.hasNext()) { + String nextjsp = iter.next().toString(); + File fjsp = new File(nextjsp); + if(!fjsp.isAbsolute()) { + fjsp = new File(uriRootF, nextjsp); + } + if(!fjsp.exists()) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", fjsp.toString())); + } + continue; + } + String s = fjsp.getAbsolutePath(); + if(s.startsWith(uriRoot)) { + nextjsp = s.substring(uriRoot.length()); + } + if(nextjsp.startsWith("." + File.separatorChar)) { + nextjsp = nextjsp.substring(2); + } + processFile(nextjsp); + } + + completeWebXml(); + + if(addWebXmlMappings) { + mergeIntoWebXml(); + } + + } catch(IOException ioe) { + throw new RuntimeException(ioe); // TODO make it our own + + } catch(JasperException je) { + Throwable rootCause = je; + while(rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if(rootCause != je) { + rootCause.printStackTrace(); + } + throw new RuntimeException(je); // TODO make it our own + } finally { + if(loader != null) { + LogFactory.release(loader); + } + } + } + + // ==================== protected utility methods ==================== + + protected String nextArg() { + if((argPos >= args.length) || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { + return null; + } else { + return args[argPos++]; + } + } + + protected String nextFile() { + if(fullstop) + argPos++; + if(argPos >= args.length) { + return null; + } else { + return args[argPos++]; + } + } + + protected void initWebXml() { + try { + if(webxmlLevel >= INC_WEBXML) { + mapout = openWebxmlWriter(new File(webxmlFile)); + servletout = new CharArrayWriter(); + mappingout = new CharArrayWriter(); + } else { + mapout = null; + servletout = null; + mappingout = null; + } + if(webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.header")); + mapout.flush(); + } else if((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.header")); + mapout.flush(); + } + } catch(IOException ioe) { + mapout = null; + servletout = null; + mappingout = null; + } + } + + protected void completeWebXml() { + if(mapout != null) { + try { + servletout.writeTo(mapout); + mappingout.writeTo(mapout); + if(webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.footer")); + } else if((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.footer")); + } + mapout.close(); + } catch(IOException ioe) { + // noting to do if it fails since we are done with it + } + } + } + + protected void initServletContext(ClassLoader classLoader) throws IOException, JasperException { + // TODO: should we use the Ant Project's log? + PrintWriter log = new PrintWriter(System.out); + URL resourceBase = new File(uriRoot).getCanonicalFile().toURI().toURL(); + context = new JspCServletContext(log, resourceBase, classLoader); + if(isValidateTld()) { + context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true"); + } + if(isValidateXml()) { + context.setInitParameter(Constants.XML_VALIDATION_INIT_PARAM, "true"); + } + context.setInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM, String.valueOf(isBlockExternal())); + + tldLocationsCache = TldLocationsCache.getInstance(context); + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); + } + + /** + * Initializes the classloader as/if needed for the given + * compilation context. + * + * @throws IOException If an error occurs + */ + protected ClassLoader initClassLoader() throws IOException { + + classPath = getClassPath(); + + ClassLoader jspcLoader = getClass().getClassLoader(); + // TODO add check for 7Bee/TJWS class loader and extend CP as needed + + // Turn the classPath into URLs + ArrayList urls = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); + while(tokenizer.hasMoreTokens()) { + String path = tokenizer.nextToken(); + try { + File libFile = new File(path); + urls.add(libFile.toURI().toURL()); + } catch(IOException ioe) { + // Failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak uot + throw new RuntimeException(ioe.toString()); + } + } + + File webappBase = new File(uriRoot); + if(webappBase.exists()) { + File classes = new File(webappBase, "/WEB-INF/classes"); + try { + if(classes.exists()) { + classPath = classPath + File.pathSeparator + classes.getCanonicalPath(); + urls.add(classes.getCanonicalFile().toURI().toURL()); + } + } catch(IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + File lib = new File(webappBase, "/WEB-INF/lib"); + if(lib.exists() && lib.isDirectory()) { + String[] libs = lib.list(); + for(int i = 0; i < libs.length; i++) { + if(libs[i].length() < 5) + continue; + String ext = libs[i].substring(libs[i].length() - 4); + if(!".jar".equalsIgnoreCase(ext)) { + if(".tld".equalsIgnoreCase(ext)) { + log.warn("TLD files should not be placed in " + "/WEB-INF/lib"); + } + continue; + } + try { + File libFile = new File(lib, libs[i]); + classPath = classPath + File.pathSeparator + libFile.getAbsolutePath(); + urls.add(libFile.getAbsoluteFile().toURI().toURL()); + } catch(IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + } + } + } + + URL urlsA[] = new URL[urls.size()]; + urls.toArray(urlsA); + loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); + return loader; + } + + /** + * Find the WEB-INF dir by looking up in the directory tree. + * This is used if no explicit docbase is set, but only files. + * XXX Maybe we should require the docbase. + */ + protected void locateUriRoot(File f) { + String tUriBase = uriBase; + if(tUriBase == null) { + tUriBase = "/"; + } + try { + if(f.exists()) { + f = new File(f.getAbsolutePath()); + while(true) { + File g = new File(f, "WEB-INF"); + if(g.exists() && g.isDirectory()) { + uriRoot = f.getCanonicalPath(); + uriBase = tUriBase; + if(log.isInfoEnabled()) { + log.info(Localizer.getMessage("jspc.implicit.uriRoot", uriRoot)); + } + break; + } + if(f.exists() && f.isDirectory()) { + tUriBase = "/" + f.getName() + "/" + tUriBase; + } + + String fParent = f.getParent(); + if(fParent == null) { + break; + } else { + f = new File(fParent); + } + + // If there is no acceptable candidate, uriRoot will + // remain null to indicate to the CompilerContext to + // use the current working/user dir. + } + + if(uriRoot != null) { + File froot = new File(uriRoot); + uriRoot = froot.getCanonicalPath(); + } + } + } catch(IOException ioe) { + // since this is an optional default and a null value + // for uriRoot has a non-error meaning, we can just + // pass straight through + } + } + + /** + * Resolves the relative or absolute pathname correctly + * in both Ant and command-line situations. If Ant launched + * us, we should use the basedir of the current project + * to resolve relative paths. + * + * See Bugzilla 35571. + * + * @param s The file + * @return The file resolved + */ + protected File resolveFile(final String s) { + // TODO consider some massaging of s as relative path to project home + return new File(s); + } + + private Reader openWebxmlReader(File file) throws IOException { + FileInputStream fis = new FileInputStream(file); + try { + return webxmlEncoding != null ? new InputStreamReader(fis, webxmlEncoding) : new InputStreamReader(fis); + } catch(IOException ex) { + fis.close(); + throw ex; + } + } + + private Writer openWebxmlWriter(File file) throws IOException { + FileOutputStream fos = new FileOutputStream(file); + try { + return webxmlEncoding != null ? new OutputStreamWriter(fos, webxmlEncoding) : new OutputStreamWriter(fos); + } catch(IOException ex) { + fos.close(); + throw ex; + } + } +} diff --git a/BeeCompiler/jasper7-6x/JspCompilationContext.java b/BeeCompiler/jasper7-6x/JspCompilationContext.java new file mode 100755 index 0000000..c856465 --- /dev/null +++ b/BeeCompiler/jasper7-6x/JspCompilationContext.java @@ -0,0 +1,792 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JarResource; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.JspUtil; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.ServletWriter; +import org.apache.jasper.compiler.TldLocation; +import org.apache.jasper.servlet.JasperLoader; +import org.apache.jasper.servlet.JspServletWrapper; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * A place holder for various things that are used through out the JSP + * engine. This is a per-request/per-context data structure. Some of + * the instance variables are set at different points. + * + * Most of the path-related stuff is here - mangling names, versions, dirs, + * loading resources and dealing with uris. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Pierre Delisle + * @author Costin Manolache + * @author Kin-man Chung + */ +public class JspCompilationContext { + + // must not be static + private final Log log = LogFactory.getLog(JspCompilationContext.class); + + protected Map tagFileJarUrls; + + protected String className; + protected String jspUri; + protected String basePackageName; + protected String derivedPackageName; + protected String servletJavaFileName; + protected String javaPath; + protected String classFileName; + protected ServletWriter writer; + protected Options options; + protected JspServletWrapper jsw; + protected Compiler jspCompiler; + protected String classPath; + + protected String baseURI; + protected String outputDir; + protected ServletContext context; + protected ClassLoader loader; + + protected JspRuntimeContext rctxt; + + protected volatile int removed = 0; + + protected URLClassLoader jspLoader; + protected URL baseUrl; + protected Class servletClass; + + protected boolean isTagFile; + protected boolean protoTypeMode; + protected TagInfo tagInfo; + protected JarResource tagJarResource; + + // jspURI _must_ be relative to the context + public JspCompilationContext(String jspUri, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt) { + + this.jspUri = canonicalURI(jspUri); + this.options = options; + this.jsw = jsw; + this.context = context; + + this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); + // hack fix for resolveRelativeURI + if(baseURI == null) { + baseURI = "/"; + } else if(baseURI.charAt(0) != '/') { + // strip the base slash since it will be combined with the + // uriBase to generate a file + baseURI = "/" + baseURI; + } + if(baseURI.charAt(baseURI.length() - 1) != '/') { + baseURI += '/'; + } + + this.rctxt = rctxt; + this.tagFileJarUrls = new HashMap(); + this.basePackageName = Constants.JSP_PACKAGE_NAME; + } + + public JspCompilationContext(String tagfile, TagInfo tagInfo, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt, JarResource tagJarResource) { + this(tagfile, options, context, jsw, rctxt); + this.isTagFile = true; + this.tagInfo = tagInfo; + this.tagJarResource = tagJarResource; + } + + /* ==================== Methods to override ==================== */ + + /** ---------- Class path and loader ---------- */ + + /** + * The classpath that is passed off to the Java compiler. + */ + public String getClassPath() { + if(classPath != null) { + return classPath; + } + return rctxt.getClassPath(); + } + + /** + * The classpath that is passed off to the Java compiler. + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * What class loader to use for loading classes while compiling + * this JSP? + */ + public ClassLoader getClassLoader() { + if(loader != null) { + return loader; + } + return rctxt.getParentClassLoader(); + } + + public void setClassLoader(ClassLoader loader) { + this.loader = loader; + } + + public ClassLoader getJspLoader() { + if(jspLoader == null) { + jspLoader = new JasperLoader(new URL[] { baseUrl }, getClassLoader(), rctxt.getPermissionCollection()); + } + return jspLoader; + } + + public void clearJspLoader() { + jspLoader = null; + } + + /** ---------- Input/Output ---------- */ + + /** + * The output directory to generate code into. The output directory + * is make up of the scratch directory, which is provide in Options, + * plus the directory derived from the package name. + */ + public String getOutputDir() { + if(outputDir == null) { + createOutputDir(); + } + + return outputDir; + } + + /** + * Create a "Compiler" object based on some init param data. This + * is not done yet. Right now we're just hardcoding the actual + * compilers that are created. + */ + public Compiler createCompiler() { + if(jspCompiler != null) { + return jspCompiler; + } + jspCompiler = null; + jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); + if(jspCompiler == null) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); + } + jspCompiler.init(this, jsw); + return jspCompiler; + } + + protected Compiler createCompiler(String className) { + Compiler compiler = null; + try { + compiler = (Compiler) Class.forName(className).newInstance(); + } catch(InstantiationException e) { + log.warn(Localizer.getMessage("jsp.error.compiler"), e); + } catch(IllegalAccessException e) { + log.warn(Localizer.getMessage("jsp.error.compiler"), e); + } catch(NoClassDefFoundError e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), e); + } + } catch(ClassNotFoundException e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), e); + } + } + return compiler; + } + + public Compiler getCompiler() { + return jspCompiler; + } + + /** ---------- Access resources in the webapp ---------- */ + + /** + * Get the full value of a URI relative to this compilations context + * uses current file as the base. + */ + public String resolveRelativeUri(String uri) { + // sometimes we get uri's massaged from File(String), so check for + // a root directory separator char + if(uri.startsWith("/") || uri.startsWith(File.separator)) { + return uri; + } else { + return baseURI + uri; + } + } + + /** + * Gets a resource as a stream, relative to the meanings of this + * context's implementation. + * + * @return a null if the resource cannot be found or represented + * as an InputStream. + */ + public java.io.InputStream getResourceAsStream(String res) { + return context.getResourceAsStream(canonicalURI(res)); + } + + public URL getResource(String res) throws MalformedURLException { + URL result = null; + + if(res.startsWith("/META-INF/")) { + // This is a tag file packaged in a jar that is being compiled + JarResource jarResource = tagFileJarUrls.get(res); + if(jarResource == null) { + jarResource = tagJarResource; + } + if(jarResource != null) { + result = jarResource.getEntry(res.substring(1)); + } else { + // May not be in a JAR in some IDE environments + result = context.getResource(canonicalURI(res)); + } + } else if(res.startsWith("jar:jndi:")) { + // This is a tag file packaged in a jar that is being checked + // for a dependency + result = new URL(res); + + } else { + result = context.getResource(canonicalURI(res)); + } + return result; + } + + public Set getResourcePaths(String path) { + return context.getResourcePaths(canonicalURI(path)); + } + + /** + * Gets the actual path of a URI relative to the context of + * the compilation. + */ + public String getRealPath(String path) { + if(context != null) { + return context.getRealPath(path); + } + return path; + } + + /** + * Returns the tag-file-name-to-JAR-file map of this compilation unit, + * which maps tag file names to the JAR files in which the tag files are + * packaged. + * + * The map is populated when parsing the tag-file elements of the TLDs + * of any imported taglibs. + */ + public JarResource getTagFileJarResource(String tagFile) { + return this.tagFileJarUrls.get(tagFile); + } + + public void setTagFileJarResource(String tagFile, JarResource jarResource) { + this.tagFileJarUrls.put(tagFile, jarResource); + } + + /** + * Returns the JAR file in which the tag file for which this + * JspCompilationContext was created is packaged, or null if this + * JspCompilationContext does not correspond to a tag file, or if the + * corresponding tag file is not packaged in a JAR. + */ + public JarResource getTagFileJarResource() { + return this.tagJarResource; + } + + /* ==================== Common implementation ==================== */ + + /** + * Just the class name (does not include package name) of the + * generated class. + */ + public String getServletClassName() { + + if(className != null) { + return className; + } + + if(isTagFile) { + className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + if(lastIndex != -1) { + className = className.substring(lastIndex + 1); + } + } else { + int iSep = jspUri.lastIndexOf('/') + 1; + className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); + } + return className; + } + + public void setServletClassName(String className) { + this.className = className; + } + + /** + * Path of the JSP URI. Note that this is not a file name. This is + * the context rooted URI of the JSP file. + */ + public String getJspFile() { + return jspUri; + } + + /** + * @deprecated Will be removed in Tomcat 8.0.x. Use + * {@link #getLastModified(String)} instead. + */ + @Deprecated + public long getJspLastModified() { + long result = -1; + URLConnection uc = null; + try { + URL jspUrl = getResource(getJspFile()); + if(jspUrl == null) { + incrementRemoved(); + return result; + } + uc = jspUrl.openConnection(); + if(uc instanceof JarURLConnection) { + result = ((JarURLConnection) uc).getJarEntry().getTime(); + } else { + result = uc.getLastModified(); + } + } catch(IOException e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } finally { + if(uc != null) { + try { + uc.getInputStream().close(); + } catch(IOException e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } + } + } + return result; + } + + public Long getLastModified(String resource) { + long result = -1; + if(resource.startsWith("file:/")) { + File f; + try { + f = new File(new URI(resource)); + } catch(URISyntaxException e) { + return Long.valueOf(-1); + } + return Long.valueOf(f.lastModified()); + } + + URLConnection uc = null; + try { + URL jspUrl = getResource(resource); + if(jspUrl == null) { + incrementRemoved(); + return Long.valueOf(result); + } + File resFile = new File(jspUrl.getFile()); // TJWS on Android + if(resFile.exists()) { + result = resFile.lastModified(); + // System.err.printf("Android for %s is %d%n", jspUrl, result); + } else { + uc = jspUrl.openConnection(); + if(uc instanceof JarURLConnection) { + result = ((JarURLConnection) uc).getJarEntry().getTime(); + } else { + result = uc.getLastModified(); + } + } + } catch(IOException e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } finally { + if(uc != null) { + try { + uc.getInputStream().close(); + } catch(IOException e) { + if(log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } + } + } + return Long.valueOf(result); + } + + public boolean isTagFile() { + return isTagFile; + } + + public TagInfo getTagInfo() { + return tagInfo; + } + + public void setTagInfo(TagInfo tagi) { + tagInfo = tagi; + } + + /** + * True if we are compiling a tag file in prototype mode. + * ie we only generate codes with class for the tag handler with empty + * method bodies. + */ + public boolean isPrototypeMode() { + return protoTypeMode; + } + + public void setPrototypeMode(boolean pm) { + protoTypeMode = pm; + } + + /** + * Package name for the generated class is make up of the base package + * name, which is user settable, and the derived package name. The + * derived package name directly mirrors the file hierarchy of the JSP page. + */ + public String getServletPackageName() { + if(isTagFile()) { + String className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + String pkgName = ""; + if(lastIndex != -1) { + pkgName = className.substring(0, lastIndex); + } + return pkgName; + } else { + String dPackageName = getDerivedPackageName(); + if(dPackageName.length() == 0) { + return basePackageName; + } + return basePackageName + '.' + getDerivedPackageName(); + } + } + + protected String getDerivedPackageName() { + if(derivedPackageName == null) { + int iSep = jspUri.lastIndexOf('/'); + derivedPackageName = (iSep > 0) ? JspUtil.makeJavaPackage(jspUri.substring(1, iSep)) : ""; + } + return derivedPackageName; + } + + /** + * The package name into which the servlet class is generated. + */ + public void setServletPackageName(String servletPackageName) { + this.basePackageName = servletPackageName; + } + + /** + * Full path name of the Java file into which the servlet is being + * generated. + */ + public String getServletJavaFileName() { + if(servletJavaFileName == null) { + servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; + } + return servletJavaFileName; + } + + /** + * Get hold of the Options object for this context. + */ + public Options getOptions() { + return options; + } + + public ServletContext getServletContext() { + return context; + } + + public JspRuntimeContext getRuntimeContext() { + return rctxt; + } + + /** + * Path of the Java file relative to the work directory. + */ + public String getJavaPath() { + + if(javaPath != null) { + return javaPath; + } + + if(isTagFile()) { + String tagName = tagInfo.getTagClassName(); + javaPath = tagName.replace('.', '/') + ".java"; + } else { + javaPath = getServletPackageName().replace('.', '/') + '/' + getServletClassName() + ".java"; + } + return javaPath; + } + + public String getClassFileName() { + if(classFileName == null) { + classFileName = getOutputDir() + getServletClassName() + ".class"; + } + return classFileName; + } + + /** + * Where is the servlet being generated? + */ + public ServletWriter getWriter() { + return writer; + } + + public void setWriter(ServletWriter writer) { + this.writer = writer; + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, + * then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the given uri is not associated with any tag + * library + * 'exposed' in the web application. + */ + public TldLocation getTldLocation(String uri) throws JasperException { + TldLocation location = getOptions().getTldLocationsCache().getLocation(uri); + return location; + } + + /** + * Are we keeping generated code around? + */ + public boolean keepGenerated() { + return getOptions().getKeepGenerated(); + } + + // ==================== Removal ==================== + + public void incrementRemoved() { + if(removed == 0 && rctxt != null) { + rctxt.removeWrapper(jspUri); + } + removed++; + } + + public boolean isRemoved() { + if(removed > 0) { + return true; + } + return false; + } + + // ==================== Compile and reload ==================== + + public void compile() throws JasperException, FileNotFoundException { + createCompiler(); + if(jspCompiler.isOutDated()) { + if(isRemoved()) { + throw new FileNotFoundException(jspUri); + } + try { + jspCompiler.removeGeneratedFiles(); + jspLoader = null; + jspCompiler.compile(); + jsw.setReload(true); + jsw.setCompilationException(null); + } catch(JasperException ex) { + // Cache compilation exception + jsw.setCompilationException(ex); + if(options.getDevelopment() && options.getRecompileOnFail()) { + // Force a recompilation attempt on next access + jsw.setLastModificationTest(-1); + } + throw ex; + } catch(FileNotFoundException fnfe) { + // Re-throw to let caller handle this - will result in a 404 + throw fnfe; + } catch(Exception ex) { + JasperException je = new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + // Cache compilation exception + jsw.setCompilationException(je); + throw je; + } + } + } + + // ==================== Manipulating the class ==================== + + public Class load() throws JasperException { + try { + getJspLoader(); + + String name = getFQCN(); + servletClass = jspLoader.loadClass(name); + } catch(ClassNotFoundException cex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), cex); + } catch(Exception ex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + } + removed = 0; + return servletClass; + } + + public String getFQCN() { + String name; + if(isTagFile()) { + name = tagInfo.getTagClassName(); + } else { + name = getServletPackageName() + "." + getServletClassName(); + } + return name; + } + + // ==================== protected methods ==================== + + static Object outputDirLock = new Object(); + + public void checkOutputDir() { + if(outputDir != null) { + if(!(new File(outputDir)).exists()) { + makeOutputDir(); + } + } else { + createOutputDir(); + } + } + + protected boolean makeOutputDir() { + synchronized(outputDirLock) { + File outDirFile = new File(outputDir); + return (outDirFile.mkdirs() || outDirFile.isDirectory()); + } + } + + protected void createOutputDir() { + String path = null; + if(isTagFile()) { + String tagName = tagInfo.getTagClassName(); + path = tagName.replace('.', File.separatorChar); + path = path.substring(0, path.lastIndexOf(File.separatorChar)); + } else { + path = getServletPackageName().replace('.', File.separatorChar); + } + + // Append servlet or tag handler path to scratch dir + try { + File base = options.getScratchDir(); + baseUrl = base.toURI().toURL(); + outputDir = base.getAbsolutePath() + File.separator + path + File.separator; + if(!makeOutputDir()) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); + } + } catch(MalformedURLException e) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); + } + } + + protected static final boolean isPathSeparator(char c) { + return (c == '/' || c == '\\'); + } + + protected static final String canonicalURI(String s) { + if(s == null) { + return null; + } + StringBuilder result = new StringBuilder(); + final int len = s.length(); + int pos = 0; + while(pos < len) { + char c = s.charAt(pos); + if(isPathSeparator(c)) { + /* + * multiple path separators. + * 'foo///bar' -> 'foo/bar' + */ + while(pos + 1 < len && isPathSeparator(s.charAt(pos + 1))) { + ++pos; + } + + if(pos + 1 < len && s.charAt(pos + 1) == '.') { + /* + * a single dot at the end of the path - we are done. + */ + if(pos + 2 >= len) { + break; + } + + switch(s.charAt(pos + 2)) { + /* + * self directory in path + * foo/./bar -> foo/bar + */ + case '/': + case '\\': + pos += 2; + continue; + + /* + * two dots in a path: go back one hierarchy. + * foo/bar/../baz -> foo/baz + */ + case '.': + // only if we have exactly _two_ dots. + if(pos + 3 < len && isPathSeparator(s.charAt(pos + 3))) { + pos += 3; + int separatorPos = result.length() - 1; + while(separatorPos >= 0 && !isPathSeparator(result.charAt(separatorPos))) { + --separatorPos; + } + if(separatorPos >= 0) { + result.setLength(separatorPos); + } + continue; + } + } + } + } + result.append(c); + ++pos; + } + return result.toString(); + } +} diff --git a/BeeCompiler/jasper7-6x/SimpleInstanceManager.java b/BeeCompiler/jasper7-6x/SimpleInstanceManager.java new file mode 100755 index 0000000..39017b9 --- /dev/null +++ b/BeeCompiler/jasper7-6x/SimpleInstanceManager.java @@ -0,0 +1,37 @@ +package org.apache.jasper.tjws; + +import java.lang.reflect.InvocationTargetException; +import javax.naming.NamingException; +import org.apache.tomcat.InstanceManager; + +public class SimpleInstanceManager implements InstanceManager { + + public Object newInstance(Class clazz) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException { + return clazz.newInstance(); + } + + public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + return Class.forName(className).newInstance(); + } + + public Object newInstance(String fqcn, ClassLoader classLoader) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + // System.err.printf("Requested new instance as %s with loader %s and + // parent %s%n", fqcn, classLoader, classLoader.getParent()); + try { + return Class.forName(fqcn, true, classLoader).newInstance(); + } catch(ClassNotFoundException cnfe) { + // System.err.printf("Exceprion %s%n", cnfe); + // trying parent loader for Android + } + return Class.forName(fqcn, true, classLoader.getParent()).newInstance(); + } + + public void newInstance(Object o) throws IllegalAccessException, InvocationTargetException, NamingException { + // System.err.printf("New instance for object %s", o); + } + + public void destroyInstance(Object o) throws IllegalAccessException, InvocationTargetException { + // System.err.printf("Destroying object %s", o); + } + +} \ No newline at end of file diff --git a/BeeCompiler/jasper7-6x/bee-jasper.xml b/BeeCompiler/jasper7-6x/bee-jasper.xml new file mode 100755 index 0000000..8ef55a3 --- /dev/null +++ b/BeeCompiler/jasper7-6x/bee-jasper.xml @@ -0,0 +1,494 @@ + + + + + + + + + + + ]> + + + + &env; + + + + + /bin/javac + + + + + + + /bin/javadoc + + + + + + ******** &project; + Build Process ******** + ********* Available targets: ************************************* + * compile - do Java compilation * + * jar - build &build_file; + file * + * run - run application &main_class; + * + ******************************************************************* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /&build_directory; + + + + + + + + + + + + + + + + + + Compiling javax... + + + + + + + + + + + > + + + + + + 0 + + + + Error(s) at compilation of javax + + + + + + + + + Exception at compilation of javax + + + + + + + + + + + + + + + + + + + + + + Compiling... &project; + + + + + + + + + + + > + + + + + + 0 + + + + Error(s) + at compilation of &project; + + + + + + + + + Exception + at compilation of &project; + + + + + + + + + + &manifestf; + + + + + true + + + + -d + + -sourcepath + + -classpath + + &domain; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &source_directory;/javax/servlet/jsp/resources/jsp*.dtd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/jsp*.xsd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/web-jsp*.dtd + + &build_directory;/javax/servlet/jsp/resources + + &source_directory;/javax/servlet/jsp/resources/web-jsp*.xsd + + &build_directory;/javax/servlet/jsp/resources + + + &source_directory;/javax/servlet/resources/j2ee*.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/j2ee*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/javaee_*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/web-app*.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/web-*.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/datatypes.dtd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/xml.xsd + + &build_directory;/javax/servlet/resources + + &source_directory;/javax/servlet/resources/XMLSchema.dtd + + &build_directory;/javax/servlet/resources + + + + + + + + + + + + + + Jarring... + + + + + + + + + + + + + + + + + + + + + + + + + + -cf + + + + -cmf + + + + + + + + + + + + + + + java + org/apache/jasper/resources + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + + + -C + &source_directory; + + + + + + + + + + Exception at jarring + + + + + + + + + + + + + y + + + + + + + + + Cleaning... + + + + + + + + + + + /&build_directory;/&build_file; + + + + + /lib/tools.jar + + + + + Running... + + + + -classpath + + + + + + diff --git a/BeeCompiler/jasper7-6x/env.xml b/BeeCompiler/jasper7-6x/env.xml new file mode 100755 index 0000000..b658951 --- /dev/null +++ b/BeeCompiler/jasper7-6x/env.xml @@ -0,0 +1,48 @@ + + + + +. + + + + + + + / + + + + + + + + + /jre + + + + + + + + + + +maven:javax.servlet:javax.servlet-api:3.1.0 + +1.6 + + + + \\jre + + + + + + + + + diff --git a/1.x/src/jasper7/InstanceManagerFactory.java b/BeeCompiler/jasper7/InstanceManagerFactory.java old mode 100644 new mode 100755 similarity index 50% rename from 1.x/src/jasper7/InstanceManagerFactory.java rename to BeeCompiler/jasper7/InstanceManagerFactory.java index 5dd2c96..7e6f047 --- a/1.x/src/jasper7/InstanceManagerFactory.java +++ b/BeeCompiler/jasper7/InstanceManagerFactory.java @@ -1,13 +1,11 @@ /* * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with + * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,28 +20,29 @@ import org.apache.tomcat.InstanceManager; /** - * @version $Id: InstanceManagerFactory.java,v 1.1 2011/06/04 04:59:07 dmitriy Exp $ + * @version $Id: InstanceManagerFactory.java,v 1.1 2011/06/04 04:59:07 dmitriy + * Exp $ */ public class InstanceManagerFactory { - + static private InstanceManager cachedManager; // same for all apps for now - private InstanceManagerFactory() { - } - - public static InstanceManager getInstanceManager(ServletConfig config) { - InstanceManager instanceManager = - (InstanceManager) config.getServletContext().getAttribute(InstanceManager.class.getName()); - if (instanceManager == null) { - synchronized(InstanceManagerFactory.class) { - if (cachedManager == null) { - cachedManager = new SimpleInstanceManager(); - } - } - instanceManager = cachedManager; - //throw new IllegalStateException("No org.apache.tomcat.InstanceManager set in ServletContext"); - } - return instanceManager; - } - + private InstanceManagerFactory() { + } + + public static InstanceManager getInstanceManager(ServletConfig config) { + InstanceManager instanceManager = (InstanceManager) config.getServletContext().getAttribute(InstanceManager.class.getName()); + if(instanceManager == null) { + synchronized(InstanceManagerFactory.class) { + if(cachedManager == null) { + cachedManager = new SimpleInstanceManager(); + } + } + instanceManager = cachedManager; + // throw new IllegalStateException("No + // org.apache.tomcat.InstanceManager set in ServletContext"); + } + return instanceManager; + } + } diff --git a/BeeCompiler/jasper7/JspC.java b/BeeCompiler/jasper7/JspC.java new file mode 100755 index 0000000..087fd47 --- /dev/null +++ b/BeeCompiler/jasper7/JspC.java @@ -0,0 +1,1562 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.jsp.tagext.TagLibraryInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.servlet.JspCServletContext; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * Shell for the jspc compiler. Handles all options associated with the + * command line and creates compilation contexts which it then compiles + * according to the specified options. + * + * This version can process files from a _single_ webapp at once, i.e. + * a single docbase can be specified. + * + * It can be used as an Ant task using: + * + *
+ *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
+ *      <classpath>
+ *          <pathelement location="${java.home}/../lib/tools.jar"/>
+ *          <fileset dir="${ENV.CATALINA_HOME}/lib">
+ *              <include name="*.jar"/>
+ *          </fileset>
+ *          <path refid="myjars"/>
+ *       </classpath>
+ *  </taskdef>
+ *
+ *  <jasper verbose="0"
+ *           package="my.package"
+ *           uriroot="${webapps.dir}/${webapp.name}"
+ *           webXmlFragment="${build.dir}/generated_web.xml"
+ *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
+ * 
+ * + * @author Danno Ferrin + * @author Pierre Delisle + * @author Costin Manolache + * @author Yoav Shapira + */ +public class JspC implements Options { + + public static final String DEFAULT_IE_CLASS_ID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + // Logger + private static final Log log = LogFactory.getLog(JspC.class); + + protected static final String SWITCH_VERBOSE = "-v"; + protected static final String SWITCH_HELP = "-help"; + protected static final String SWITCH_OUTPUT_DIR = "-d"; + protected static final String SWITCH_PACKAGE_NAME = "-p"; + protected static final String SWITCH_CACHE = "-cache"; + protected static final String SWITCH_CLASS_NAME = "-c"; + protected static final String SWITCH_FULL_STOP = "--"; + protected static final String SWITCH_COMPILE = "-compile"; + protected static final String SWITCH_SOURCE = "-source"; + protected static final String SWITCH_TARGET = "-target"; + protected static final String SWITCH_URI_BASE = "-uribase"; + protected static final String SWITCH_URI_ROOT = "-uriroot"; + protected static final String SWITCH_FILE_WEBAPP = "-webapp"; + protected static final String SWITCH_WEBAPP_INC = "-webinc"; + protected static final String SWITCH_WEBAPP_XML = "-webxml"; + protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; + protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; + protected static final String SWITCH_MAPPED = "-mapped"; + protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; + protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; + protected static final String SWITCH_CLASSPATH = "-classpath"; + protected static final String SWITCH_DIE = "-die"; + protected static final String SWITCH_POOLING = "-poolingEnabled"; + protected static final String SWITCH_ENCODING = "-javaEncoding"; + protected static final String SWITCH_SMAP = "-smap"; + protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; + protected static final String SHOW_SUCCESS = "-s"; + protected static final String LIST_ERRORS = "-l"; + protected static final int INC_WEBXML = 10; + protected static final int ALL_WEBXML = 20; + protected static final int DEFAULT_DIE_LEVEL = 1; + protected static final int NO_DIE_LEVEL = 0; + protected static final Set insertBefore = new HashSet(); + + static { + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + } + + protected String classPath = null; + protected URLClassLoader loader = null; + protected boolean trimSpaces = false; + protected boolean genStringAsCharArray = false; + protected boolean xpoweredBy; + protected boolean mappedFile = false; + protected boolean poolingEnabled = true; + protected File scratchDir; + protected String ieClassId = DEFAULT_IE_CLASS_ID; + protected String targetPackage; + protected String targetClassName; + protected String uriBase; + protected String uriRoot; + protected int dieLevel; + protected boolean helpNeeded = false; + protected boolean compile = false; + protected boolean smapSuppressed = true; + protected boolean smapDumped = false; + protected boolean caching = true; + protected final Map cache = new HashMap(); + + protected String compiler = null; + + protected String compilerTargetVM = "1.6"; + protected String compilerSourceVM = "1.6"; + + protected boolean classDebugInfo = true; + + /** + * Throw an exception if there's a compilation error, or swallow it. + * Default is true to preserve old behavior. + */ + protected boolean failOnError = true; + + /** + * The file extensions to be handled as JSP files. + * Default list is .jsp and .jspx. + */ + protected List extensions; + + /** + * The pages. + */ + protected final List pages = new Vector(); + + /** + * Needs better documentation, this data member does. + * True by default. + */ + protected boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * The java file encoding. Default + * is UTF-8. Added per bugzilla 19622. + */ + protected String javaEncoding = "UTF-8"; + + // Generation of web.xml fragments + protected String webxmlFile; + protected int webxmlLevel; + protected String webxmlEncoding; + protected boolean addWebXmlMappings = false; + + protected Writer mapout; + protected CharArrayWriter servletout; + protected CharArrayWriter mappingout; + + /** + * The servlet context. + */ + protected JspCServletContext context; + + /** + * The runtime context. + * Maintain a dummy JspRuntimeContext for compiling tag files. + */ + protected JspRuntimeContext rctxt; + + /** + * Cache for the TLD locations + */ + protected TldLocationsCache tldLocationsCache = null; + + protected JspConfig jspConfig = null; + protected TagPluginManager tagPluginManager = null; + + protected boolean verbose = false; + protected boolean listErrors = false; + protected boolean showSuccess = false; + protected int argPos; + protected boolean fullstop = false; + protected String args[]; + + public static void main(String arg[]) { + if(arg.length == 0) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + JspC jspc = new JspC(); + try { + jspc.setArgs(arg); + if(jspc.helpNeeded) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + jspc.execute(); + } + } catch(JasperException je) { + System.err.println(je); + if(jspc.dieLevel != NO_DIE_LEVEL) { + System.exit(jspc.dieLevel); + } + } catch(Exception je) { + System.err.println(je); + if(jspc.dieLevel != NO_DIE_LEVEL) { + System.exit(jspc.dieLevel); + } + } + } + } + + /** + * Apply command-line arguments. + * + * @param arg + * The arguments + */ + public void setArgs(String[] arg) throws JasperException { + args = arg; + String tok; + + dieLevel = NO_DIE_LEVEL; + + while((tok = nextArg()) != null) { + if(tok.equals(SWITCH_VERBOSE)) { + verbose = true; + showSuccess = true; + listErrors = true; + } else if(tok.equals(SWITCH_OUTPUT_DIR)) { + tok = nextArg(); + setOutputDir(tok); + } else if(tok.equals(SWITCH_PACKAGE_NAME)) { + targetPackage = nextArg(); + } else if(tok.equals(SWITCH_COMPILE)) { + compile = true; + } else if(tok.equals(SWITCH_CLASS_NAME)) { + targetClassName = nextArg(); + } else if(tok.equals(SWITCH_URI_BASE)) { + uriBase = nextArg(); + } else if(tok.equals(SWITCH_URI_ROOT)) { + setUriroot(nextArg()); + } else if(tok.equals(SWITCH_FILE_WEBAPP)) { + setUriroot(nextArg()); + } else if(tok.equals(SHOW_SUCCESS)) { + showSuccess = true; + } else if(tok.equals(LIST_ERRORS)) { + listErrors = true; + } else if(tok.equals(SWITCH_WEBAPP_INC)) { + webxmlFile = nextArg(); + if(webxmlFile != null) { + webxmlLevel = INC_WEBXML; + } + } else if(tok.equals(SWITCH_WEBAPP_XML)) { + webxmlFile = nextArg(); + if(webxmlFile != null) { + webxmlLevel = ALL_WEBXML; + } + } else if(tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { + setWebXmlEncoding(nextArg()); + } else if(tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { + setAddWebXmlMappings(true); + } else if(tok.equals(SWITCH_MAPPED)) { + mappedFile = true; + } else if(tok.equals(SWITCH_XPOWERED_BY)) { + xpoweredBy = true; + } else if(tok.equals(SWITCH_TRIM_SPACES)) { + setTrimSpaces(true); + } else if(tok.equals(SWITCH_CACHE)) { + tok = nextArg(); + if("false".equals(tok)) { + caching = false; + } else { + caching = true; + } + } else if(tok.equals(SWITCH_CLASSPATH)) { + setClassPath(nextArg()); + } else if(tok.startsWith(SWITCH_DIE)) { + try { + dieLevel = Integer.parseInt(tok.substring(SWITCH_DIE.length())); + } catch(NumberFormatException nfe) { + dieLevel = DEFAULT_DIE_LEVEL; + } + } else if(tok.equals(SWITCH_HELP)) { + helpNeeded = true; + } else if(tok.equals(SWITCH_POOLING)) { + tok = nextArg(); + if("false".equals(tok)) { + poolingEnabled = false; + } else { + poolingEnabled = true; + } + } else if(tok.equals(SWITCH_ENCODING)) { + setJavaEncoding(nextArg()); + } else if(tok.equals(SWITCH_SOURCE)) { + setCompilerSourceVM(nextArg()); + } else if(tok.equals(SWITCH_TARGET)) { + setCompilerTargetVM(nextArg()); + } else if(tok.equals(SWITCH_SMAP)) { + smapSuppressed = false; + } else if(tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; + } else { + if(tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + ". Use -help for help."); + } + if(!fullstop) { + argPos--; + } + // Start treating the rest as JSP Pages + break; + } + } + + // Add all extra arguments to the list of files + while(true) { + String file = nextFile(); + if(file == null) { + break; + } + pages.add(file); + } + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + @Override + public boolean getKeepGenerated() { + // isn't this why we are running jspc? + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getTrimSpaces() { + return trimSpaces; + } + + /** + * Sets the option to trim white spaces between directives or actions. + */ + public void setTrimSpaces(boolean ts) { + this.trimSpaces = ts; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + /** + * Sets the option to enable the tag handler pooling. + */ + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Sets the option to enable generation of X-Powered-By response header. + */ + public void setXpoweredBy(boolean xpoweredBy) { + this.xpoweredBy = xpoweredBy; + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + @Override + public boolean getDisplaySourceFragment() { + return true; + } + + @Override + public int getMaxLoadedJsps() { + return -1; + } + + @Override + public int getJspIdleTimeout() { + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + /** + * Sets the option to issue a compilation error if the class attribute + * specified in useBean action is invalid. + */ + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getMappedFile() { + return mappedFile; + } + + /** + * Sets the option to include debug information in compiled class. + */ + public void setClassDebugInfo(boolean b) { + classDebugInfo = b; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getClassDebugInfo() { + // compile with debug info + return classDebugInfo; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isCaching() { + return caching; + } + + /** + * Sets the option to enable caching. + * + * @see Options#isCaching() + */ + public void setCaching(boolean caching) { + this.caching = caching; + } + + /** + * {@inheritDoc} + */ + @Override + public Map getCache() { + return cache; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + @Override + public int getCheckInterval() { + return 0; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + @Override + public int getModificationTestInterval() { + return 0; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + @Override + public boolean getRecompileOnFail() { + return false; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + @Override + public boolean getDevelopment() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSmapSuppressed() { + return smapSuppressed; + } + + /** + * Sets smapSuppressed flag. + */ + public void setSmapSuppressed(boolean smapSuppressed) { + this.smapSuppressed = smapSuppressed; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSmapDumped() { + return smapDumped; + } + + /** + * Sets smapDumped flag. + * + * @see Options#isSmapDumped() + */ + public void setSmapDumped(boolean smapDumped) { + this.smapDumped = smapDumped; + } + + /** + * Determines whether text strings are to be generated as char arrays, + * which improves performance in some cases. + * + * @param genStringAsCharArray true if text strings are to be generated as + * char arrays, false otherwise + */ + public void setGenStringAsCharArray(boolean genStringAsCharArray) { + this.genStringAsCharArray = genStringAsCharArray; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean genStringAsCharArray() { + return genStringAsCharArray; + } + + /** + * Sets the class-id value to be sent to Internet Explorer when using + * <jsp:plugin> tags. + * + * @param ieClassId + * Class-id value + */ + public void setIeClassId(String ieClassId) { + this.ieClassId = ieClassId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getIeClassId() { + return ieClassId; + } + + /** + * {@inheritDoc} + */ + @Override + public File getScratchDir() { + return scratchDir; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompiler() { + return compiler; + } + + /** + * Sets the option to determine what compiler to use. + * + * @see Options#getCompiler() + */ + public void setCompiler(String c) { + compiler = c; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerClassName() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * Sets the compiler target VM. + * + * @see Options#getCompilerTargetVM() + */ + public void setCompilerTargetVM(String vm) { + compilerTargetVM = vm; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * Sets the compiler source VM. + * + * @see Options#getCompilerSourceVM() + */ + public void setCompilerSourceVM(String vm) { + compilerSourceVM = vm; + } + + /** + * {@inheritDoc} + */ + @Override + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + /** + * Returns the encoding to use for + * java files. The default is UTF-8. + * + * @return String The encoding + */ + @Override + public String getJavaEncoding() { + return javaEncoding; + } + + /** + * Sets the encoding to use for + * java files. + * + * @param encodingName The name, e.g. "UTF-8" + */ + public void setJavaEncoding(String encodingName) { + javaEncoding = encodingName; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getFork() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public String getClassPath() { + if(classPath != null) + return classPath; + return System.getProperty("java.class.path"); + } + + /** + * Sets the classpath used while compiling the servlets generated from JSP + * files + */ + public void setClassPath(String s) { + classPath = s; + } + + /** + * Returns the list of file extensions + * that are treated as JSP files. + * + * @return The list of extensions + */ + public List getExtensions() { + return extensions; + } + + /** + * Adds the given file extension to the + * list of extensions handled as JSP files. + * + * @param extension The extension to add, e.g. "myjsp" + */ + protected void addExtension(final String extension) { + if(extension != null) { + if(extensions == null) { + extensions = new Vector(); + } + + extensions.add(extension); + } + } + + /** + * Base dir for the webapp. Used to generate class names and resolve + * includes. + */ + public void setUriroot(String s) { + if(s == null) { + uriRoot = null; + return; + } + try { + uriRoot = resolveFile(s).getCanonicalPath(); + } catch(Exception ex) { + uriRoot = s; + } + } + + /** + * Parses comma-separated list of JSP files to be processed. If the argument + * is null, nothing is done. + * + *

+ * Each file is interpreted relative to uriroot, unless it is absolute, + * in which case it must start with uriroot. + *

+ * + * @param jspFiles Comma-separated list of JSP files to be processed + */ + public void setJspFiles(final String jspFiles) { + if(jspFiles == null) { + return; + } + + StringTokenizer tok = new StringTokenizer(jspFiles, ","); + while(tok.hasMoreTokens()) { + pages.add(tok.nextToken()); + } + } + + /** + * Sets the compile flag. + * + * @param b Flag value + */ + public void setCompile(final boolean b) { + compile = b; + } + + /** + * Sets the verbosity level. The actual number doesn't + * matter: if it's greater than zero, the verbose flag will + * be true. + * + * @param level Positive means verbose + */ + public void setVerbose(final int level) { + if(level > 0) { + verbose = true; + showSuccess = true; + listErrors = true; + } + } + + public void setValidateXml(boolean b) { + org.apache.jasper.xmlparser.ParserUtils.validating = b; + } + + public void setListErrors(boolean b) { + listErrors = b; + } + + public void setOutputDir(String s) { + if(s != null) { + scratchDir = resolveFile(s).getAbsoluteFile(); + } else { + scratchDir = null; + } + } + + /** + * Sets the package name to be used for the generated servlet classes. + */ + public void setPackage(String p) { + targetPackage = p; + } + + /** + * Class name of the generated file ( without package ). + * Can only be used if a single file is converted. + * XXX Do we need this feature ? + */ + public void setClassName(String p) { + targetClassName = p; + } + + /** + * File where we generate a web.xml fragment with the class definitions. + */ + public void setWebXmlFragment(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = INC_WEBXML; + } + + /** + * File where we generate a complete web.xml with the class definitions. + */ + public void setWebXml(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = ALL_WEBXML; + } + + /** + * Sets the encoding to be used to read and write web.xml files. + * + *

+ * If not specified, defaults to the platform default encoding. + *

+ * + * @param encoding + * Encoding, e.g. "UTF-8". + */ + public void setWebXmlEncoding(String encoding) { + webxmlEncoding = encoding; + } + + /** + * Sets the option to merge generated web.xml fragment into the + * WEB-INF/web.xml file of the web application that we were processing. + * + * @param b + * true to merge the fragment into the existing + * web.xml file of the processed web application + * ({uriroot}/WEB-INF/web.xml), false to keep the + * generated web.xml fragment + */ + public void setAddWebXmlMappings(boolean b) { + addWebXmlMappings = b; + } + + /** + * Sets the option that throws an exception in case of a compilation error. + */ + public void setFailOnError(final boolean b) { + failOnError = b; + } + + /** + * Returns true if an exception will be thrown in case of a compilation + * error. + */ + public boolean getFailOnError() { + return failOnError; + } + + /** + * {@inheritDoc} + */ + @Override + public JspConfig getJspConfig() { + return jspConfig; + } + + /** + * {@inheritDoc} + */ + @Override + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + /** + * Adds servlet declaration and mapping for the JSP page servlet to the + * generated web.xml fragment. + * + * @param file + * Context-relative path to the JSP file, e.g. + * /index.jsp + * @param clctxt + * Compilation context of the servlet + */ + public void generateWebMapping(String file, JspCompilationContext clctxt) throws IOException { + if(log.isDebugEnabled()) { + log.debug("Generating web mapping for file " + file + " using compilation context " + clctxt); + } + + String className = clctxt.getServletClassName(); + String packageName = clctxt.getServletPackageName(); + + String thisServletName; + if("".equals(packageName)) { + thisServletName = className; + } else { + thisServletName = packageName + '.' + className; + } + + if(servletout != null) { + servletout.write("\n \n "); + servletout.write(thisServletName); + servletout.write("\n "); + servletout.write(thisServletName); + servletout.write("\n \n"); + } + if(mappingout != null) { + mappingout.write("\n \n "); + mappingout.write(thisServletName); + mappingout.write("\n "); + mappingout.write(file.replace('\\', '/')); + mappingout.write("\n \n"); + + } + } + + /** + * Include the generated web.xml inside the webapp's web.xml. + */ + protected void mergeIntoWebXml() throws IOException { + + File webappBase = new File(uriRoot); + File webXml = new File(webappBase, "WEB-INF/web.xml"); + File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); + String insertStartMarker = Localizer.getMessage("jspc.webinc.insertStart"); + String insertEndMarker = Localizer.getMessage("jspc.webinc.insertEnd"); + + BufferedReader reader = new BufferedReader(openWebxmlReader(webXml)); + BufferedReader fragmentReader = new BufferedReader(openWebxmlReader(new File(webxmlFile))); + PrintWriter writer = new PrintWriter(openWebxmlWriter(webXml2)); + + // Insert the and declarations + boolean inserted = false; + int current = reader.read(); + while(current > -1) { + if(current == '<') { + String element = getElement(reader); + if(!inserted && insertBefore.contains(element)) { + // Insert generated content here + writer.println(insertStartMarker); + while(true) { + String line = fragmentReader.readLine(); + if(line == null) { + writer.println(); + break; + } + writer.println(line); + } + writer.println(insertEndMarker); + writer.println(); + writer.write(element); + inserted = true; + } else if(element.equals(insertStartMarker)) { + // Skip the previous auto-generated content + while(true) { + current = reader.read(); + if(current < 0) { + throw new EOFException(); + } + if(current == '<') { + element = getElement(reader); + if(element.equals(insertEndMarker)) { + break; + } + } + } + current = reader.read(); + while(current == '\n' || current == '\r') { + current = reader.read(); + } + continue; + } else { + writer.write(element); + } + } else { + writer.write(current); + } + current = reader.read(); + } + writer.close(); + + reader.close(); + fragmentReader.close(); + + FileInputStream fis = new FileInputStream(webXml2); + FileOutputStream fos = new FileOutputStream(webXml); + + byte buf[] = new byte[512]; + while(true) { + int n = fis.read(buf); + if(n < 0) { + break; + } + fos.write(buf, 0, n); + } + + fis.close(); + fos.close(); + + if(!webXml2.delete() && log.isDebugEnabled()) + log.debug(Localizer.getMessage("jspc.delete.fail", webXml2.toString())); + + if(!(new File(webxmlFile)).delete() && log.isDebugEnabled()) + log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile)); + + } + + /* + * Assumes valid xml + */ + private String getElement(Reader reader) throws IOException { + StringBuilder result = new StringBuilder(); + result.append('<'); + + boolean done = false; + + while(!done) { + int current = reader.read(); + while(current != '>') { + if(current < 0) { + throw new EOFException(); + } + result.append((char) current); + current = reader.read(); + } + result.append((char) current); + + int len = result.length(); + if(len > 4 && result.substring(0, 4).equals("")) { + done = true; + } + } else { + done = true; + } + } + + return result.toString(); + } + + protected void processFile(String file) throws JasperException { + if(log.isDebugEnabled()) { + log.debug("Processing file: " + file); + } + + ClassLoader originalClassLoader = null; + + try { + // set up a scratch/output dir if none is provided + if(scratchDir == null) { + String temp = System.getProperty("java.io.tmpdir"); + if(temp == null) { + temp = ""; + } + scratchDir = new File(new File(temp).getAbsolutePath()); + } + + String jspUri = file.replace('\\', '/'); + JspCompilationContext clctxt = new JspCompilationContext(jspUri, this, context, null, rctxt); + + /* Override the defaults */ + if((targetClassName != null) && (targetClassName.length() > 0)) { + clctxt.setServletClassName(targetClassName); + targetClassName = null; + } + if(targetPackage != null) { + clctxt.setServletPackageName(targetPackage); + } + + originalClassLoader = Thread.currentThread().getContextClassLoader(); + if(loader == null) { + initClassLoader(clctxt); + } + Thread.currentThread().setContextClassLoader(loader); + + clctxt.setClassLoader(loader); + clctxt.setClassPath(classPath); + + Compiler clc = clctxt.createCompiler(); + + // If compile is set, generate both .java and .class, if + // .jsp file is newer than .class file; + // Otherwise only generate .java, if .jsp file is newer than + // the .java file + if(clc.isOutDated(compile)) { + if(log.isDebugEnabled()) { + log.debug(jspUri + " is out dated, compiling..."); + } + + clc.compile(compile, true); + } + + // Generate mapping + generateWebMapping(file, clctxt); + if(showSuccess) { + log.info("Built File: " + file); + } + + } catch(JasperException je) { + Throwable rootCause = je; + while(rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if(rootCause != je) { + log.error(Localizer.getMessage("jspc.error.generalException", file), rootCause); + } + + // Bugzilla 35114. + if(getFailOnError()) { + throw je; + } else { + log.error(je.getMessage()); + } + + } catch(Exception e) { + if((e instanceof FileNotFoundException) && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", e.getMessage())); + } + throw new JasperException(e); + } finally { + if(originalClassLoader != null) { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + + /** + * Locate all jsp files in the webapp. Used if no explicit + * jsps are specified. + */ + public void scanFiles(File base) throws JasperException { + Stack dirs = new Stack(); + dirs.push(base.toString()); + + // Make sure default extensions are always included + if((getExtensions() == null) || (getExtensions().size() < 2)) { + addExtension("jsp"); + addExtension("jspx"); + } + + while(!dirs.isEmpty()) { + String s = dirs.pop(); + File f = new File(s); + if(f.exists() && f.isDirectory()) { + String[] files = f.list(); + String ext; + for(int i = 0; (files != null) && i < files.length; i++) { + File f2 = new File(s, files[i]); + if(f2.isDirectory()) { + dirs.push(f2.getPath()); + } else { + String path = f2.getPath(); + String uri = path.substring(uriRoot.length()); + ext = files[i].substring(files[i].lastIndexOf('.') + 1); + if(getExtensions().contains(ext) || jspConfig.isJspPage(uri)) { + pages.add(path); + } + } + } + } + } + } + + /** + * Executes the compilation. + * + * @throws JasperException If an error occurs + */ + public void execute() { + if(log.isDebugEnabled()) { + log.debug("execute() starting for " + pages.size() + " pages."); + } + + try { + if(uriRoot == null) { + if(pages.size() == 0) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget")); + } + String firstJsp = pages.get(0); + File firstJspF = new File(firstJsp); + if(!firstJspF.exists()) { + throw new JasperException(Localizer.getMessage("jspc.error.fileDoesNotExist", firstJsp)); + } + locateUriRoot(firstJspF); + } + + if(uriRoot == null) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot")); + } + + File uriRootF = new File(uriRoot); + if(!uriRootF.isDirectory()) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); + } + + if(context == null) { + initServletContext(); + } + + // No explicit pages, we'll process all .jsp in the webapp + if(pages.size() == 0) { + scanFiles(uriRootF); + } + + initWebXml(); + + Iterator iter = pages.iterator(); + while(iter.hasNext()) { + String nextjsp = iter.next().toString(); + File fjsp = new File(nextjsp); + if(!fjsp.isAbsolute()) { + fjsp = new File(uriRootF, nextjsp); + } + if(!fjsp.exists()) { + if(log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", fjsp.toString())); + } + continue; + } + String s = fjsp.getAbsolutePath(); + if(s.startsWith(uriRoot)) { + nextjsp = s.substring(uriRoot.length()); + } + if(nextjsp.startsWith("." + File.separatorChar)) { + nextjsp = nextjsp.substring(2); + } + processFile(nextjsp); + } + + completeWebXml(); + + if(addWebXmlMappings) { + mergeIntoWebXml(); + } + + } catch(IOException ioe) { + throw new RuntimeException("Build - " + ioe, ioe); + + } catch(JasperException je) { + Throwable rootCause = je; + while(rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if(rootCause != je) { + rootCause.printStackTrace(); + } + throw new RuntimeException("Build - " + je, je); + } finally { + if(loader != null) { + LogFactory.release(loader); + } + } + } + + // ==================== protected utility methods ==================== + + protected String nextArg() { + if((argPos >= args.length) || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { + return null; + } else { + return args[argPos++]; + } + } + + protected String nextFile() { + if(fullstop) + argPos++; + if(argPos >= args.length) { + return null; + } else { + return args[argPos++]; + } + } + + protected void initWebXml() { + try { + if(webxmlLevel >= INC_WEBXML) { + mapout = openWebxmlWriter(new File(webxmlFile)); + servletout = new CharArrayWriter(); + mappingout = new CharArrayWriter(); + } else { + mapout = null; + servletout = null; + mappingout = null; + } + if(webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.header")); + mapout.flush(); + } else if((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.header")); + mapout.flush(); + } + } catch(IOException ioe) { + mapout = null; + servletout = null; + mappingout = null; + } + } + + protected void completeWebXml() { + if(mapout != null) { + try { + servletout.writeTo(mapout); + mappingout.writeTo(mapout); + if(webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.footer")); + } else if((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.footer")); + } + mapout.close(); + } catch(IOException ioe) { + // noting to do if it fails since we are done with it + } + } + } + + protected void initServletContext() { + try { + context = new JspCServletContext(new PrintWriter(System.out), new URL("file:" + uriRoot.replace('\\', '/') + '/')); + tldLocationsCache = TldLocationsCache.getInstance(context); + } catch(MalformedURLException me) { + System.out.println("**" + me); + } + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); + } + + /** + * Initializes the classloader as/if needed for the given + * compilation context. + * + * @param clctxt The compilation context + * @throws IOException If an error occurs + */ + protected void initClassLoader(JspCompilationContext clctxt) throws IOException { + + classPath = getClassPath(); + + ClassLoader jspcLoader = getClass().getClassLoader(); + // TODO add 7Bee class loader + // Turn the classPath into URLs + ArrayList urls = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); + while(tokenizer.hasMoreTokens()) { + String path = tokenizer.nextToken(); + try { + File libFile = new File(path); + urls.add(libFile.toURI().toURL()); + } catch(IOException ioe) { + // Failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak uot + throw new RuntimeException(ioe.toString()); + } + } + + File webappBase = new File(uriRoot); + if(webappBase.exists()) { + File classes = new File(webappBase, "/WEB-INF/classes"); + try { + if(classes.exists()) { + classPath = classPath + File.pathSeparator + classes.getCanonicalPath(); + urls.add(classes.getCanonicalFile().toURI().toURL()); + } + } catch(IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + File lib = new File(webappBase, "/WEB-INF/lib"); + if(lib.exists() && lib.isDirectory()) { + String[] libs = lib.list(); + for(int i = 0; i < libs.length; i++) { + if(libs[i].length() < 5) + continue; + String ext = libs[i].substring(libs[i].length() - 4); + if(!".jar".equalsIgnoreCase(ext)) { + if(".tld".equalsIgnoreCase(ext)) { + log.warn("TLD files should not be placed in " + "/WEB-INF/lib"); + } + continue; + } + try { + File libFile = new File(lib, libs[i]); + classPath = classPath + File.pathSeparator + libFile.getAbsolutePath(); + urls.add(libFile.getAbsoluteFile().toURI().toURL()); + } catch(IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + } + } + } + + // What is this ?? + urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURI().toURL()); + + URL urlsA[] = new URL[urls.size()]; + urls.toArray(urlsA); + loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); + context.setClassLoader(loader); + } + + /** + * Find the WEB-INF dir by looking up in the directory tree. + * This is used if no explicit docbase is set, but only files. + * XXX Maybe we should require the docbase. + */ + protected void locateUriRoot(File f) { + String tUriBase = uriBase; + if(tUriBase == null) { + tUriBase = "/"; + } + try { + if(f.exists()) { + f = new File(f.getAbsolutePath()); + while(true) { + File g = new File(f, "WEB-INF"); + if(g.exists() && g.isDirectory()) { + uriRoot = f.getCanonicalPath(); + uriBase = tUriBase; + if(log.isInfoEnabled()) { + log.info(Localizer.getMessage("jspc.implicit.uriRoot", uriRoot)); + } + break; + } + if(f.exists() && f.isDirectory()) { + tUriBase = "/" + f.getName() + "/" + tUriBase; + } + + String fParent = f.getParent(); + if(fParent == null) { + break; + } else { + f = new File(fParent); + } + + // If there is no acceptable candidate, uriRoot will + // remain null to indicate to the CompilerContext to + // use the current working/user dir. + } + + if(uriRoot != null) { + File froot = new File(uriRoot); + uriRoot = froot.getCanonicalPath(); + } + } + } catch(IOException ioe) { + // since this is an optional default and a null value + // for uriRoot has a non-error meaning, we can just + // pass straight through + } + } + + /** + * Resolves the relative or absolute pathname correctly + * in both Ant and command-line situations. If Ant launched + * us, we should use the basedir of the current project + * to resolve relative paths. + * + * See Bugzilla 35571. + * + * @param s The file + * @return The file resolved + */ + protected File resolveFile(final String s) { + // TODO consider some massaging of s as relative path to project home + return new File(s); + } + + private Reader openWebxmlReader(File file) throws IOException { + FileInputStream fis = new FileInputStream(file); + try { + return webxmlEncoding != null ? new InputStreamReader(fis, webxmlEncoding) : new InputStreamReader(fis); + } catch(IOException ex) { + fis.close(); + throw ex; + } + } + + private Writer openWebxmlWriter(File file) throws IOException { + FileOutputStream fos = new FileOutputStream(file); + try { + return webxmlEncoding != null ? new OutputStreamWriter(fos, webxmlEncoding) : new OutputStreamWriter(fos); + } catch(IOException ex) { + fos.close(); + throw ex; + } + } +} diff --git a/Jasper/org/apache/jasper/EmbeddedServletOptions.java b/Jasper/org/apache/jasper/EmbeddedServletOptions.java new file mode 100755 index 0000000..705d957 --- /dev/null +++ b/Jasper/org/apache/jasper/EmbeddedServletOptions.java @@ -0,0 +1,781 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.util.Enumeration; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagLibraryInfo; + +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * A class to hold all init parameters specific to the JSP engine. + * + * @author Anil K. Vijendran + * @author Hans Bergsten + * @author Pierre Delisle + */ +public final class EmbeddedServletOptions implements Options { + + // Logger + private final Log log = LogFactory.getLog(EmbeddedServletOptions.class); + + private Properties settings = new Properties(); + + /** + * Is Jasper being used in development mode? + */ + private boolean development = true; + + /** + * Should Ant fork its java compiles of JSP pages. + */ + public boolean fork = true; + + /** + * Do you want to keep the generated Java files around? + */ + private boolean keepGenerated = true; + + /** + * Should white spaces between directives or actions be trimmed? + */ + private boolean trimSpaces = false; + + /** + * Determines whether tag handler pooling is enabled. + */ + private boolean isPoolingEnabled = true; + + /** + * Do you want support for "mapped" files? This will generate + * servlet that has a print statement per line of the JSP file. + * This seems like a really nice feature to have for debugging. + */ + private boolean mappedFile = true; + + /** + * Do we want to include debugging information in the class file? + */ + private boolean classDebugInfo = true; + + /** + * Background compile thread check interval in seconds. + */ + private int checkInterval = 0; + + /** + * Is the generation of SMAP info for JSR45 debugging suppressed? + */ + private boolean isSmapSuppressed = false; + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + private boolean isSmapDumped = false; + + /** + * Are Text strings to be generated as char arrays? + */ + private boolean genStringAsCharArray = false; + + private boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * I want to see my generated servlets. Which directory are they + * in? + */ + private File scratchDir; + + /** + * Need to have this as is for versions 4 and 5 of IE. Can be set from + * the initParams so if it changes in the future all that is needed is + * to have a jsp initParam of type ieClassId="" + */ + private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + /** + * What classpath should I use while compiling generated servlets? + */ + private String classpath = null; + + /** + * Compiler to use. + */ + private String compiler = null; + + /** + * Compiler target VM. + */ + private String compilerTargetVM = "1.6"; + + /** + * The compiler source VM. + */ + private String compilerSourceVM = "1.6"; + + /** + * The compiler class name. + */ + private String compilerClassName = null; + + /** + * Cache for the TLD locations + */ + private TldLocationsCache tldLocationsCache = null; + + /** + * Jsp config information + */ + private JspConfig jspConfig = null; + + /** + * TagPluginManager + */ + private TagPluginManager tagPluginManager = null; + + /** + * Java platform encoding to generate the JSP + * page servlet. + */ + private String javaEncoding = "UTF8"; + + /** + * Modification test interval. + */ + private int modificationTestInterval = 4; + + /** + * Is re-compilation attempted immediately after a failure? + */ + private boolean recompileOnFail = false; + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + private boolean xpoweredBy; + + /** + * Should we include a source fragment in exception messages, which could be + * displayed + * to the developer ? + */ + private boolean displaySourceFragment = true; + + /** + * The maximum number of loaded jsps per web-application. If there are more + * jsps loaded, they will be unloaded. + */ + private int maxLoadedJsps = -1; + + /** + * The idle time in seconds after which a JSP is unloaded. + * If unset or less or equal than 0, no jsps are unloaded. + */ + private int jspIdleTimeout = -1; + + /** + * When EL is used in JSP attribute values, should the rules for quoting of + * attributes described in JSP.1.6 be applied to the expression? + */ + private boolean quoteAttributeEL = true; + + public String getProperty(String name) { + return settings.getProperty(name); + } + + public void setProperty(String name, String value) { + if (name != null && value != null) { + settings.setProperty(name, value); + } + } + + public void setQuoteAttributeEL(boolean b) { + this.quoteAttributeEL = b; + } + + // @Override + public boolean getQuoteAttributeEL() { + return quoteAttributeEL; + } + + /** + * Are we keeping generated code around? + */ + @Override + public boolean getKeepGenerated() { + return keepGenerated; + } + + /** + * Should white spaces between directives or actions be trimmed? + */ + @Override + public boolean getTrimSpaces() { + return trimSpaces; + } + + @Override + public boolean isPoolingEnabled() { + return isPoolingEnabled; + } + + /** + * Are we supporting HTML mapped servlets? + */ + @Override + public boolean getMappedFile() { + return mappedFile; + } + + /** + * Should class files be compiled with debug information? + */ + @Override + public boolean getClassDebugInfo() { + return classDebugInfo; + } + + /** + * Background JSP compile thread check interval + */ + @Override + public int getCheckInterval() { + return checkInterval; + } + + /** + * Modification test interval. + */ + @Override + public int getModificationTestInterval() { + return modificationTestInterval; + } + + /** + * Re-compile on failure. + */ + @Override + public boolean getRecompileOnFail() { + return recompileOnFail; + } + + /** + * Is Jasper being used in development mode? + */ + @Override + public boolean getDevelopment() { + return development; + } + + /** + * Is the generation of SMAP info for JSR45 debugging suppressed? + */ + @Override + public boolean isSmapSuppressed() { + return isSmapSuppressed; + } + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + @Override + public boolean isSmapDumped() { + return isSmapDumped; + } + + /** + * Are Text strings to be generated as char arrays? + */ + @Override + public boolean genStringAsCharArray() { + return this.genStringAsCharArray; + } + + /** + * Class ID for use in the plugin tag when the browser is IE. + */ + @Override + public String getIeClassId() { + return ieClassId; + } + + /** + * What is my scratch dir? + */ + @Override + public File getScratchDir() { + return scratchDir; + } + + /** + * What classpath should I use while compiling the servlets + * generated from JSP files? + */ + @Override + public String getClassPath() { + return classpath; + } + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + @Override + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Compiler to use. + */ + @Override + public String getCompiler() { + return compiler; + } + + /** + * @see Options#getCompilerTargetVM + */ + @Override + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * @see Options#getCompilerSourceVM + */ + @Override + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * Java compiler class to use. + */ + @Override + public String getCompilerClassName() { + return compilerClassName; + } + + @Override + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + @Override + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + public void setTldLocationsCache(TldLocationsCache tldC) { + tldLocationsCache = tldC; + } + + @Override + public String getJavaEncoding() { + return javaEncoding; + } + + @Override + public boolean getFork() { + return fork; + } + + @Override + public JspConfig getJspConfig() { + return jspConfig; + } + + @Override + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + @Override + public boolean isCaching() { + return false; + } + + @Override + public Map getCache() { + return null; + } + + /** + * Should we include a source fragment in exception messages, which could be + * displayed + * to the developer ? + */ + @Override + public boolean getDisplaySourceFragment() { + return displaySourceFragment; + } + + /** + * Should jsps be unloaded if to many are loaded? + * If set to a value greater than 0 eviction of jsps is started. Default: -1 + */ + @Override + public int getMaxLoadedJsps() { + return maxLoadedJsps; + } + + /** + * Should any jsps be unloaded when being idle for this time in seconds? + * If set to a value greater than 0 eviction of jsps is started. Default: -1 + */ + @Override + public int getJspIdleTimeout() { + return jspIdleTimeout; + } + + /** + * Create an EmbeddedServletOptions object using data available from + * ServletConfig and ServletContext. + */ + public EmbeddedServletOptions(ServletConfig config, ServletContext context) { + + Enumeration enumeration = config.getInitParameterNames(); + while (enumeration.hasMoreElements()) { + String k = enumeration.nextElement(); + String v = config.getInitParameter(k); + setProperty(k, v); + } + + String keepgen = config.getInitParameter("keepgenerated"); + if (keepgen != null) { + if (keepgen.equalsIgnoreCase("true")) { + this.keepGenerated = true; + } else if (keepgen.equalsIgnoreCase("false")) { + this.keepGenerated = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.keepgen")); + } + } + } + + String trimsp = config.getInitParameter("trimSpaces"); + if (trimsp != null) { + if (trimsp.equalsIgnoreCase("true")) { + trimSpaces = true; + } else if (trimsp.equalsIgnoreCase("false")) { + trimSpaces = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.trimspaces")); + } + } + } + + this.isPoolingEnabled = true; + String poolingEnabledParam = config.getInitParameter("enablePooling"); + if (poolingEnabledParam != null && !poolingEnabledParam.equalsIgnoreCase("true")) { + if (poolingEnabledParam.equalsIgnoreCase("false")) { + this.isPoolingEnabled = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.enablePooling")); + } + } + } + + String mapFile = config.getInitParameter("mappedfile"); + if (mapFile != null) { + if (mapFile.equalsIgnoreCase("true")) { + this.mappedFile = true; + } else if (mapFile.equalsIgnoreCase("false")) { + this.mappedFile = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.mappedFile")); + } + } + } + + String debugInfo = config.getInitParameter("classdebuginfo"); + if (debugInfo != null) { + if (debugInfo.equalsIgnoreCase("true")) { + this.classDebugInfo = true; + } else if (debugInfo.equalsIgnoreCase("false")) { + this.classDebugInfo = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.classDebugInfo")); + } + } + } + + String checkInterval = config.getInitParameter("checkInterval"); + if (checkInterval != null) { + try { + this.checkInterval = Integer.parseInt(checkInterval); + } catch (NumberFormatException ex) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.checkInterval")); + } + } + } + + String modificationTestInterval = config.getInitParameter("modificationTestInterval"); + if (modificationTestInterval != null) { + try { + this.modificationTestInterval = Integer.parseInt(modificationTestInterval); + } catch (NumberFormatException ex) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval")); + } + } + } + + String recompileOnFail = config.getInitParameter("recompileOnFail"); + if (recompileOnFail != null) { + if (recompileOnFail.equalsIgnoreCase("true")) { + this.recompileOnFail = true; + } else if (recompileOnFail.equalsIgnoreCase("false")) { + this.recompileOnFail = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.recompileOnFail")); + } + } + } + String development = config.getInitParameter("development"); + if (development != null) { + if (development.equalsIgnoreCase("true")) { + this.development = true; + } else if (development.equalsIgnoreCase("false")) { + this.development = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.development")); + } + } + } + + String suppressSmap = config.getInitParameter("suppressSmap"); + if (suppressSmap != null) { + if (suppressSmap.equalsIgnoreCase("true")) { + isSmapSuppressed = true; + } else if (suppressSmap.equalsIgnoreCase("false")) { + isSmapSuppressed = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.suppressSmap")); + } + } + } + + String dumpSmap = config.getInitParameter("dumpSmap"); + if (dumpSmap != null) { + if (dumpSmap.equalsIgnoreCase("true")) { + isSmapDumped = true; + } else if (dumpSmap.equalsIgnoreCase("false")) { + isSmapDumped = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.dumpSmap")); + } + } + } + + String genCharArray = config.getInitParameter("genStringAsCharArray"); + if (genCharArray != null) { + if (genCharArray.equalsIgnoreCase("true")) { + genStringAsCharArray = true; + } else if (genCharArray.equalsIgnoreCase("false")) { + genStringAsCharArray = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.genchararray")); + } + } + } + + String errBeanClass = config.getInitParameter("errorOnUseBeanInvalidClassAttribute"); + if (errBeanClass != null) { + if (errBeanClass.equalsIgnoreCase("true")) { + errorOnUseBeanInvalidClassAttribute = true; + } else if (errBeanClass.equalsIgnoreCase("false")) { + errorOnUseBeanInvalidClassAttribute = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.errBean")); + } + } + } + + String ieClassId = config.getInitParameter("ieClassId"); + if (ieClassId != null) + this.ieClassId = ieClassId; + + String classpath = config.getInitParameter("classpath"); + if (classpath != null) + this.classpath = classpath; + + /* + * scratchdir + */ + String dir = config.getInitParameter("scratchdir"); + if (dir != null && Constants.IS_SECURITY_ENABLED) { + log.info(Localizer.getMessage("jsp.info.ignoreSetting", "scratchdir", dir)); + dir = null; + } + if (dir != null) { + scratchDir = new File(dir); + } else { + // First try the Servlet 2.2 javax.servlet.context.tempdir property + /** TODO- FIX ME! - UNCOMMENT LATER */ + // scratchDir = (File) context.getAttribute(ServletContext.TEMPDIR); + if (scratchDir == null) { + // Not running in a Servlet 2.2 container. + // Try to get the JDK 1.2 java.io.tmpdir property + dir = System.getProperty("java.io.tmpdir"); + if (dir != null) + scratchDir = new File(dir); + } + } + if (this.scratchDir == null) { + log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir")); + return; + } + if (!scratchDir.exists()) // for TJWS force creation of scratchdir + scratchDir.mkdirs(); + if (!(scratchDir.exists() && scratchDir.canRead() && scratchDir.canWrite() && scratchDir.isDirectory())) + log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir", scratchDir.getAbsolutePath())); + + this.compiler = config.getInitParameter("compiler"); + + String compilerTargetVM = config.getInitParameter("compilerTargetVM"); + if (compilerTargetVM != null) { + this.compilerTargetVM = compilerTargetVM; + } + + String compilerSourceVM = config.getInitParameter("compilerSourceVM"); + if (compilerSourceVM != null) { + this.compilerSourceVM = compilerSourceVM; + } + + String javaEncoding = config.getInitParameter("javaEncoding"); + if (javaEncoding != null) { + this.javaEncoding = javaEncoding; + } + + String compilerClassName = config.getInitParameter("compilerClassName"); + if (compilerClassName != null) { + this.compilerClassName = compilerClassName; + } + + String fork = config.getInitParameter("fork"); + if (fork != null) { + if (fork.equalsIgnoreCase("true")) { + this.fork = true; + } else if (fork.equalsIgnoreCase("false")) { + this.fork = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.fork")); + } + } + } + + String xpoweredBy = config.getInitParameter("xpoweredBy"); + if (xpoweredBy != null) { + if (xpoweredBy.equalsIgnoreCase("true")) { + this.xpoweredBy = true; + } else if (xpoweredBy.equalsIgnoreCase("false")) { + this.xpoweredBy = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.xpoweredBy")); + } + } + } + + String displaySourceFragment = config.getInitParameter("displaySourceFragment"); + if (displaySourceFragment != null) { + if (displaySourceFragment.equalsIgnoreCase("true")) { + this.displaySourceFragment = true; + } else if (displaySourceFragment.equalsIgnoreCase("false")) { + this.displaySourceFragment = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.displaySourceFragment")); + } + } + } + + String maxLoadedJsps = config.getInitParameter("maxLoadedJsps"); + if (maxLoadedJsps != null) { + try { + this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps); + } catch (NumberFormatException ex) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps", "" + this.maxLoadedJsps)); + } + } + } + + String jspIdleTimeout = config.getInitParameter("jspIdleTimeout"); + if (jspIdleTimeout != null) { + try { + this.jspIdleTimeout = Integer.parseInt(jspIdleTimeout); + } catch (NumberFormatException ex) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.jspIdleTimeout", "" + this.jspIdleTimeout)); + } + } + } + + String quoteAttributeEL = config.getInitParameter("quoteAttributeEL"); + if (quoteAttributeEL != null) { + if (quoteAttributeEL.equalsIgnoreCase("true")) { + this.quoteAttributeEL = true; + } else if (quoteAttributeEL.equalsIgnoreCase("false")) { + this.quoteAttributeEL = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.quoteAttributeEL")); + } + } + } + + // Setup the global Tag Libraries location cache for this + // web-application. + tldLocationsCache = TldLocationsCache.getInstance(context); + + // Setup the jsp config info for this web app. + jspConfig = new JspConfig(context); + + // Create a Tag plugin instance + tagPluginManager = new TagPluginManager(context); + } + +} diff --git a/Jasper/org/apache/jasper/JspC.java b/Jasper/org/apache/jasper/JspC.java new file mode 100755 index 0000000..6df4141 --- /dev/null +++ b/Jasper/org/apache/jasper/JspC.java @@ -0,0 +1,1656 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.jsp.tagext.TagLibraryInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.servlet.JspCServletContext; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * Shell for the jspc compiler. Handles all options associated with the + * command line and creates compilation contexts which it then compiles + * according to the specified options. + * + * This version can process files from a _single_ webapp at once, i.e. + * a single docbase can be specified. + * + * It can be used as an Ant task using: + * + *
+ *   <taskdef classname="org.apache.jasper.JspC" name="jasper" >
+ *      <classpath>
+ *          <pathelement location="${java.home}/../lib/tools.jar"/>
+ *          <fileset dir="${ENV.CATALINA_HOME}/lib">
+ *              <include name="*.jar"/>
+ *          </fileset>
+ *          <path refid="myjars"/>
+ *       </classpath>
+ *  </taskdef>
+ *
+ *  <jasper verbose="0"
+ *           package="my.package"
+ *           uriroot="${webapps.dir}/${webapp.name}"
+ *           webXmlFragment="${build.dir}/generated_web.xml"
+ *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
+ * 
+ * + * @author Danno Ferrin + * @author Pierre Delisle + * @author Costin Manolache + * @author Yoav Shapira + */ +public class JspC implements Options { + + public static final String DEFAULT_IE_CLASS_ID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + // Logger + private static final Log log = LogFactory.getLog(JspC.class); + + protected static final String SWITCH_VERBOSE = "-v"; + protected static final String SWITCH_HELP = "-help"; + protected static final String SWITCH_OUTPUT_DIR = "-d"; + protected static final String SWITCH_PACKAGE_NAME = "-p"; + protected static final String SWITCH_CACHE = "-cache"; + protected static final String SWITCH_CLASS_NAME = "-c"; + protected static final String SWITCH_FULL_STOP = "--"; + protected static final String SWITCH_COMPILE = "-compile"; + protected static final String SWITCH_SOURCE = "-source"; + protected static final String SWITCH_TARGET = "-target"; + protected static final String SWITCH_URI_BASE = "-uribase"; + protected static final String SWITCH_URI_ROOT = "-uriroot"; + protected static final String SWITCH_FILE_WEBAPP = "-webapp"; + protected static final String SWITCH_WEBAPP_INC = "-webinc"; + protected static final String SWITCH_WEBAPP_XML = "-webxml"; + protected static final String SWITCH_WEBAPP_XML_ENCODING = "-webxmlencoding"; + protected static final String SWITCH_ADD_WEBAPP_XML_MAPPINGS = "-addwebxmlmappings"; + protected static final String SWITCH_MAPPED = "-mapped"; + protected static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; + protected static final String SWITCH_TRIM_SPACES = "-trimSpaces"; + protected static final String SWITCH_CLASSPATH = "-classpath"; + protected static final String SWITCH_DIE = "-die"; + protected static final String SWITCH_POOLING = "-poolingEnabled"; + protected static final String SWITCH_ENCODING = "-javaEncoding"; + protected static final String SWITCH_SMAP = "-smap"; + protected static final String SWITCH_DUMP_SMAP = "-dumpsmap"; + protected static final String SWITCH_VALIDATE_TLD = "-validateTld"; + protected static final String SWITCH_VALIDATE_XML = "-validateXml"; + protected static final String SWITCH_BLOCK_EXTERNAL = "-blockExternal"; + protected static final String SWITCH_NO_BLOCK_EXTERNAL = "-no-blockExternal"; + protected static final String SWITCH_QUOTE_ATTRIBUTE_EL = "-quoteAttributeEL"; + protected static final String SWITCH_NO_QUOTE_ATTRIBUTE_EL = "-no-quoteAttributeEL"; + protected static final String SHOW_SUCCESS = "-s"; + protected static final String LIST_ERRORS = "-l"; + protected static final int INC_WEBXML = 10; + protected static final int ALL_WEBXML = 20; + protected static final int DEFAULT_DIE_LEVEL = 1; + protected static final int NO_DIE_LEVEL = 0; + protected static final Set insertBefore = new HashSet(); + + static { + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + insertBefore.add(""); + } + + protected String classPath = null; + protected ClassLoader loader = null; + protected boolean trimSpaces = false; + protected boolean genStringAsCharArray = false; + protected boolean validateTld; + protected boolean validateXml; + protected boolean blockExternal = true; + protected boolean quoteAttributeEL = true; + protected boolean xpoweredBy; + protected boolean mappedFile = false; + protected boolean poolingEnabled = true; + protected File scratchDir; + protected String ieClassId = DEFAULT_IE_CLASS_ID; + protected String targetPackage; + protected String targetClassName; + protected String uriBase; + protected String uriRoot; + protected int dieLevel; + protected boolean helpNeeded = false; + protected boolean compile = false; + protected boolean smapSuppressed = true; + protected boolean smapDumped = false; + protected boolean caching = true; + protected final Map cache = new HashMap(); + + protected String compiler = null; + + protected String compilerTargetVM = "1.6"; + protected String compilerSourceVM = "1.6"; + + protected boolean classDebugInfo = true; + + /** + * Throw an exception if there's a compilation error, or swallow it. + * Default is true to preserve old behavior. + */ + protected boolean failOnError = true; + + /** + * The file extensions to be handled as JSP files. + * Default list is .jsp and .jspx. + */ + protected List extensions; + + /** + * The pages. + */ + protected final List pages = new Vector(); + + /** + * Needs better documentation, this data member does. + * True by default. + */ + protected boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * The java file encoding. Default + * is UTF-8. Added per bugzilla 19622. + */ + protected String javaEncoding = "UTF-8"; + + // Generation of web.xml fragments + protected String webxmlFile; + protected int webxmlLevel; + protected String webxmlEncoding; + protected boolean addWebXmlMappings = false; + + protected Writer mapout; + protected CharArrayWriter servletout; + protected CharArrayWriter mappingout; + + /** + * The servlet context. + */ + protected JspCServletContext context; + + /** + * The runtime context. + * Maintain a dummy JspRuntimeContext for compiling tag files. + */ + protected JspRuntimeContext rctxt; + + /** + * Cache for the TLD locations + */ + protected TldLocationsCache tldLocationsCache = null; + + protected JspConfig jspConfig = null; + protected TagPluginManager tagPluginManager = null; + + protected boolean verbose = false; + protected boolean listErrors = false; + protected boolean showSuccess = false; + protected int argPos; + protected boolean fullstop = false; + protected String args[]; + + public static void main(String arg[]) { + if (arg.length == 0) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + JspC jspc = new JspC(); + try { + jspc.setArgs(arg); + if (jspc.helpNeeded) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + jspc.execute(); + } + } catch (JasperException je) { + System.err.println(je); + if (jspc.dieLevel != NO_DIE_LEVEL) { + System.exit(jspc.dieLevel); + } + } catch (RuntimeException je) { + System.err.println(je); + if (jspc.dieLevel != NO_DIE_LEVEL) { + System.exit(jspc.dieLevel); + } + } + } + } + + /** + * Apply command-line arguments. + * + * @param arg + * The arguments + */ + public void setArgs(String[] arg) throws JasperException { + args = arg; + String tok; + + dieLevel = NO_DIE_LEVEL; + + while ((tok = nextArg()) != null) { + if (tok.equals(SWITCH_VERBOSE)) { + verbose = true; + showSuccess = true; + listErrors = true; + } else if (tok.equals(SWITCH_OUTPUT_DIR)) { + tok = nextArg(); + setOutputDir(tok); + } else if (tok.equals(SWITCH_PACKAGE_NAME)) { + targetPackage = nextArg(); + } else if (tok.equals(SWITCH_COMPILE)) { + compile = true; + } else if (tok.equals(SWITCH_CLASS_NAME)) { + targetClassName = nextArg(); + } else if (tok.equals(SWITCH_URI_BASE)) { + uriBase = nextArg(); + } else if (tok.equals(SWITCH_URI_ROOT)) { + setUriroot(nextArg()); + } else if (tok.equals(SWITCH_FILE_WEBAPP)) { + setUriroot(nextArg()); + } else if (tok.equals(SHOW_SUCCESS)) { + showSuccess = true; + } else if (tok.equals(LIST_ERRORS)) { + listErrors = true; + } else if (tok.equals(SWITCH_WEBAPP_INC)) { + webxmlFile = nextArg(); + if (webxmlFile != null) { + webxmlLevel = INC_WEBXML; + } + } else if (tok.equals(SWITCH_WEBAPP_XML)) { + webxmlFile = nextArg(); + if (webxmlFile != null) { + webxmlLevel = ALL_WEBXML; + } + } else if (tok.equals(SWITCH_WEBAPP_XML_ENCODING)) { + setWebXmlEncoding(nextArg()); + } else if (tok.equals(SWITCH_ADD_WEBAPP_XML_MAPPINGS)) { + setAddWebXmlMappings(true); + } else if (tok.equals(SWITCH_MAPPED)) { + mappedFile = true; + } else if (tok.equals(SWITCH_XPOWERED_BY)) { + xpoweredBy = true; + } else if (tok.equals(SWITCH_TRIM_SPACES)) { + setTrimSpaces(true); + } else if (tok.equals(SWITCH_CACHE)) { + tok = nextArg(); + if ("false".equals(tok)) { + caching = false; + } else { + caching = true; + } + } else if (tok.equals(SWITCH_CLASSPATH)) { + setClassPath(nextArg()); + } else if (tok.startsWith(SWITCH_DIE)) { + try { + dieLevel = Integer.parseInt(tok.substring(SWITCH_DIE.length())); + } catch (NumberFormatException nfe) { + dieLevel = DEFAULT_DIE_LEVEL; + } + } else if (tok.equals(SWITCH_HELP)) { + helpNeeded = true; + } else if (tok.equals(SWITCH_POOLING)) { + tok = nextArg(); + if ("false".equals(tok)) { + poolingEnabled = false; + } else { + poolingEnabled = true; + } + } else if (tok.equals(SWITCH_ENCODING)) { + setJavaEncoding(nextArg()); + } else if (tok.equals(SWITCH_SOURCE)) { + setCompilerSourceVM(nextArg()); + } else if (tok.equals(SWITCH_TARGET)) { + setCompilerTargetVM(nextArg()); + } else if (tok.equals(SWITCH_SMAP)) { + smapSuppressed = false; + } else if (tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; + } else if (tok.equals(SWITCH_VALIDATE_TLD)) { + setValidateTld(true); + } else if (tok.equals(SWITCH_VALIDATE_XML)) { + setValidateXml(true); + } else if (tok.equals(SWITCH_BLOCK_EXTERNAL)) { + setBlockExternal(true); + } else if (tok.equals(SWITCH_NO_BLOCK_EXTERNAL)) { + setBlockExternal(false); + } else if (tok.equals(SWITCH_QUOTE_ATTRIBUTE_EL)) { + setQuoteAttributeEL(true); + } else if (tok.equals(SWITCH_NO_QUOTE_ATTRIBUTE_EL)) { + setQuoteAttributeEL(false); + } else { + if (tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + ". Use -help for help."); + } + if (!fullstop) { + argPos--; + } + // Start treating the rest as JSP Pages + break; + } + } + + // Add all extra arguments to the list of files + while (true) { + String file = nextFile(); + if (file == null) { + break; + } + pages.add(file); + } + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + @Override + public boolean getKeepGenerated() { + // isn't this why we are running jspc? + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getTrimSpaces() { + return trimSpaces; + } + + /** + * Sets the option to trim white spaces between directives or actions. + */ + public void setTrimSpaces(boolean ts) { + this.trimSpaces = ts; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + /** + * Sets the option to enable the tag handler pooling. + */ + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Sets the option to enable generation of X-Powered-By response header. + */ + public void setXpoweredBy(boolean xpoweredBy) { + this.xpoweredBy = xpoweredBy; + } + + /** + * In JspC this always returns true. + * {@inheritDoc} + */ + @Override + public boolean getDisplaySourceFragment() { + return true; + } + + @Override + public int getMaxLoadedJsps() { + return -1; + } + + @Override + public int getJspIdleTimeout() { + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + /** + * Sets the option to issue a compilation error if the class attribute + * specified in useBean action is invalid. + */ + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getMappedFile() { + return mappedFile; + } + + public void setMappedFile(boolean b) { + mappedFile = b; + } + + /** + * Sets the option to include debug information in compiled class. + */ + public void setClassDebugInfo(boolean b) { + classDebugInfo = b; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getClassDebugInfo() { + // compile with debug info + return classDebugInfo; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isCaching() { + return caching; + } + + /** + * Sets the option to enable caching. + * + * @see Options#isCaching() + */ + public void setCaching(boolean caching) { + this.caching = caching; + } + + /** + * {@inheritDoc} + */ + @Override + public Map getCache() { + return cache; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + @Override + public int getCheckInterval() { + return 0; + } + + /** + * In JspC this always returns 0. + * {@inheritDoc} + */ + @Override + public int getModificationTestInterval() { + return 0; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + @Override + public boolean getRecompileOnFail() { + return false; + } + + /** + * In JspC this always returns false. + * {@inheritDoc} + */ + @Override + public boolean getDevelopment() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSmapSuppressed() { + return smapSuppressed; + } + + /** + * Sets smapSuppressed flag. + */ + public void setSmapSuppressed(boolean smapSuppressed) { + this.smapSuppressed = smapSuppressed; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSmapDumped() { + return smapDumped; + } + + /** + * Sets smapDumped flag. + * + * @see Options#isSmapDumped() + */ + public void setSmapDumped(boolean smapDumped) { + this.smapDumped = smapDumped; + } + + /** + * Determines whether text strings are to be generated as char arrays, + * which improves performance in some cases. + * + * @param genStringAsCharArray true if text strings are to be generated as + * char arrays, false otherwise + */ + public void setGenStringAsCharArray(boolean genStringAsCharArray) { + this.genStringAsCharArray = genStringAsCharArray; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean genStringAsCharArray() { + return genStringAsCharArray; + } + + /** + * Sets the class-id value to be sent to Internet Explorer when using + * <jsp:plugin> tags. + * + * @param ieClassId + * Class-id value + */ + public void setIeClassId(String ieClassId) { + this.ieClassId = ieClassId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getIeClassId() { + return ieClassId; + } + + /** + * {@inheritDoc} + */ + @Override + public File getScratchDir() { + return scratchDir; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompiler() { + return compiler; + } + + /** + * Sets the option to determine what compiler to use. + * + * @see Options#getCompiler() + */ + public void setCompiler(String c) { + compiler = c; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerClassName() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * Sets the compiler target VM. + * + * @see Options#getCompilerTargetVM() + */ + public void setCompilerTargetVM(String vm) { + compilerTargetVM = vm; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * Sets the compiler source VM. + * + * @see Options#getCompilerSourceVM() + */ + public void setCompilerSourceVM(String vm) { + compilerSourceVM = vm; + } + + /** + * {@inheritDoc} + */ + @Override + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + /** + * Returns the encoding to use for + * java files. The default is UTF-8. + * + * @return String The encoding + */ + @Override + public String getJavaEncoding() { + return javaEncoding; + } + + /** + * Sets the encoding to use for + * java files. + * + * @param encodingName The name, e.g. "UTF-8" + */ + public void setJavaEncoding(String encodingName) { + javaEncoding = encodingName; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getFork() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public String getClassPath() { + if (classPath != null) + return classPath; + return System.getProperty("java.class.path"); + } + + /** + * Sets the classpath used while compiling the servlets generated from JSP + * files + */ + public void setClassPath(String s) { + classPath = s; + } + + /** + * Returns the list of file extensions + * that are treated as JSP files. + * + * @return The list of extensions + */ + public List getExtensions() { + return extensions; + } + + /** + * Adds the given file extension to the + * list of extensions handled as JSP files. + * + * @param extension The extension to add, e.g. "myjsp" + */ + protected void addExtension(final String extension) { + if (extension != null) { + if (extensions == null) { + extensions = new Vector(); + } + + extensions.add(extension); + } + } + + /** + * Base dir for the webapp. Used to generate class names and resolve + * includes. + */ + public void setUriroot(String s) { + if (s == null) { + uriRoot = null; + return; + } + try { + uriRoot = resolveFile(s).getCanonicalPath(); + } catch (Exception ex) { + uriRoot = s; + } + } + + /** + * Parses comma-separated list of JSP files to be processed. If the argument + * is null, nothing is done. + * + *

+ * Each file is interpreted relative to uriroot, unless it is absolute, + * in which case it must start with uriroot. + *

+ * + * @param jspFiles Comma-separated list of JSP files to be processed + */ + public void setJspFiles(final String jspFiles) { + if (jspFiles == null) { + return; + } + + StringTokenizer tok = new StringTokenizer(jspFiles, ","); + while (tok.hasMoreTokens()) { + pages.add(tok.nextToken()); + } + } + + /** + * Sets the compile flag. + * + * @param b Flag value + */ + public void setCompile(final boolean b) { + compile = b; + } + + /** + * Sets the verbosity level. The actual number doesn't + * matter: if it's greater than zero, the verbose flag will + * be true. + * + * @param level Positive means verbose + */ + public void setVerbose(final int level) { + if (level > 0) { + verbose = true; + showSuccess = true; + listErrors = true; + } + } + + public void setValidateTld(boolean b) { + this.validateTld = b; + } + + public boolean isValidateTld() { + return validateTld; + } + + public void setValidateXml(boolean b) { + this.validateXml = b; + } + + public boolean isValidateXml() { + return validateXml; + } + + public void setBlockExternal(boolean b) { + this.blockExternal = b; + } + + public boolean isBlockExternal() { + return blockExternal; + } + + public void setQuoteAttributeEL(boolean b) { + quoteAttributeEL = b; + } + + // @Override + public boolean getQuoteAttributeEL() { + return quoteAttributeEL; + } + + public void setListErrors(boolean b) { + listErrors = b; + } + + public void setOutputDir(String s) { + if (s != null) { + scratchDir = resolveFile(s).getAbsoluteFile(); + } else { + scratchDir = null; + } + } + + /** + * Sets the package name to be used for the generated servlet classes. + */ + public void setPackage(String p) { + targetPackage = p; + } + + /** + * Class name of the generated file ( without package ). + * Can only be used if a single file is converted. + * XXX Do we need this feature ? + */ + public void setClassName(String p) { + targetClassName = p; + } + + /** + * File where we generate a web.xml fragment with the class definitions. + */ + public void setWebXmlFragment(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = INC_WEBXML; + } + + /** + * File where we generate a complete web.xml with the class definitions. + */ + public void setWebXml(String s) { + webxmlFile = resolveFile(s).getAbsolutePath(); + webxmlLevel = ALL_WEBXML; + } + + /** + * Sets the encoding to be used to read and write web.xml files. + * + *

+ * If not specified, defaults to the platform default encoding. + *

+ * + * @param encoding + * Encoding, e.g. "UTF-8". + */ + public void setWebXmlEncoding(String encoding) { + webxmlEncoding = encoding; + } + + /** + * Sets the option to merge generated web.xml fragment into the + * WEB-INF/web.xml file of the web application that we were processing. + * + * @param b + * true to merge the fragment into the existing + * web.xml file of the processed web application + * ({uriroot}/WEB-INF/web.xml), false to keep the + * generated web.xml fragment + */ + public void setAddWebXmlMappings(boolean b) { + addWebXmlMappings = b; + } + + /** + * Sets the option that throws an exception in case of a compilation error. + */ + public void setFailOnError(final boolean b) { + failOnError = b; + } + + /** + * Returns true if an exception will be thrown in case of a compilation + * error. + */ + public boolean getFailOnError() { + return failOnError; + } + + /** + * {@inheritDoc} + */ + @Override + public JspConfig getJspConfig() { + return jspConfig; + } + + /** + * {@inheritDoc} + */ + @Override + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + /** + * Adds servlet declaration and mapping for the JSP page servlet to the + * generated web.xml fragment. + * + * @param file + * Context-relative path to the JSP file, e.g. + * /index.jsp + * @param clctxt + * Compilation context of the servlet + */ + public void generateWebMapping(String file, JspCompilationContext clctxt) throws IOException { + if (log.isDebugEnabled()) { + log.debug("Generating web mapping for file " + file + " using compilation context " + clctxt); + } + + String className = clctxt.getServletClassName(); + String packageName = clctxt.getServletPackageName(); + + String thisServletName; + if ("".equals(packageName)) { + thisServletName = className; + } else { + thisServletName = packageName + '.' + className; + } + + if (servletout != null) { + servletout.write("\n \n "); + servletout.write(thisServletName); + servletout.write("\n "); + servletout.write(thisServletName); + servletout.write("\n \n"); + } + if (mappingout != null) { + mappingout.write("\n \n "); + mappingout.write(thisServletName); + mappingout.write("\n "); + mappingout.write(file.replace('\\', '/')); + mappingout.write("\n \n"); + + } + } + + /** + * Include the generated web.xml inside the webapp's web.xml. + */ + protected void mergeIntoWebXml() throws IOException { + + File webappBase = new File(uriRoot); + File webXml = new File(webappBase, "WEB-INF/web.xml"); + File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); + String insertStartMarker = Localizer.getMessage("jspc.webinc.insertStart"); + String insertEndMarker = Localizer.getMessage("jspc.webinc.insertEnd"); + + BufferedReader reader = null; + BufferedReader fragmentReader = null; + PrintWriter writer = null; + try { + reader = new BufferedReader(openWebxmlReader(webXml)); + fragmentReader = new BufferedReader(openWebxmlReader(new File(webxmlFile))); + writer = new PrintWriter(openWebxmlWriter(webXml2)); + // Insert the and declarations + boolean inserted = false; + int current = reader.read(); + while (current > -1) { + if (current == '<') { + String element = getElement(reader); + if (!inserted && insertBefore.contains(element)) { + // Insert generated content here + writer.println(insertStartMarker); + while (true) { + String line = fragmentReader.readLine(); + if (line == null) { + writer.println(); + break; + } + writer.println(line); + } + writer.println(insertEndMarker); + writer.println(); + writer.write(element); + inserted = true; + } else if (element.equals(insertStartMarker)) { + // Skip the previous auto-generated content + while (true) { + current = reader.read(); + if (current < 0) { + throw new EOFException(); + } + if (current == '<') { + element = getElement(reader); + if (element.equals(insertEndMarker)) { + break; + } + } + } + current = reader.read(); + while (current == '\n' || current == '\r') { + current = reader.read(); + } + continue; + } else { + writer.write(element); + } + } else { + writer.write(current); + } + current = reader.read(); + } + } finally { + if (writer != null) { + try { + writer.close(); + } catch (Exception e) { + } + } + if (reader != null) { + try { + reader.close(); + } catch (Exception e) { + } + } + if (fragmentReader != null) { + try { + fragmentReader.close(); + } catch (Exception e) { + } + } + } + + FileInputStream fis = null; + FileOutputStream fos = null; + try { + fis = new FileInputStream(webXml2); + fos = new FileOutputStream(webXml); + byte buf[] = new byte[512]; + while (true) { + int n = fis.read(buf); + if (n < 0) { + break; + } + fos.write(buf, 0, n); + } + } finally { + if (fis != null) { + try { + fis.close(); + } catch (Exception e) { + } + } + if (fos != null) { + try { + fos.close(); + } catch (Exception e) { + } + } + } + + if (!webXml2.delete() && log.isDebugEnabled()) + log.debug(Localizer.getMessage("jspc.delete.fail", webXml2.toString())); + + if (!(new File(webxmlFile)).delete() && log.isDebugEnabled()) + log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile)); + + } + + /* + * Assumes valid xml + */ + private String getElement(Reader reader) throws IOException { + StringBuilder result = new StringBuilder(); + result.append('<'); + + boolean done = false; + + while (!done) { + int current = reader.read(); + while (current != '>') { + if (current < 0) { + throw new EOFException(); + } + result.append((char) current); + current = reader.read(); + } + result.append((char) current); + + int len = result.length(); + if (len > 4 && result.substring(0, 4).equals("")) { + done = true; + } + } else { + done = true; + } + } + + return result.toString(); + } + + protected void processFile(String file) throws JasperException { + if (log.isDebugEnabled()) { + log.debug("Processing file: " + file); + } + + ClassLoader originalClassLoader = null; + + try { + // set up a scratch/output dir if none is provided + if (scratchDir == null) { + String temp = System.getProperty("java.io.tmpdir"); + if (temp == null) { + temp = ""; + } + scratchDir = new File(new File(temp).getAbsolutePath()); + } + + String jspUri = file.replace('\\', '/'); + JspCompilationContext clctxt = new JspCompilationContext(jspUri, this, context, null, rctxt); + + /* Override the defaults */ + if ((targetClassName != null) && (targetClassName.length() > 0)) { + clctxt.setServletClassName(targetClassName); + targetClassName = null; + } + if (targetPackage != null) { + clctxt.setServletPackageName(targetPackage); + } + + originalClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(loader); + + clctxt.setClassLoader(loader); + clctxt.setClassPath(classPath); + + Compiler clc = clctxt.createCompiler(); + + // If compile is set, generate both .java and .class, if + // .jsp file is newer than .class file; + // Otherwise only generate .java, if .jsp file is newer than + // the .java file + if (clc.isOutDated(compile)) { + if (log.isDebugEnabled()) { + log.debug(jspUri + " is out dated, compiling..."); + } + + clc.compile(compile, true); + } + + // Generate mapping + generateWebMapping(file, clctxt); + if (showSuccess) { + log.info("Built File: " + file); + } + + } catch (JasperException je) { + Throwable rootCause = je; + while (rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if (rootCause != je) { + log.error(Localizer.getMessage("jspc.error.generalException", file), rootCause); + } + + // Bugzilla 35114. + if (getFailOnError()) { + throw je; + } else { + log.error(je.getMessage()); + } + + } catch (Exception e) { + if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", e.getMessage())); + } + throw new JasperException(e); + } finally { + if (originalClassLoader != null) { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + + /** + * Locate all jsp files in the webapp. Used if no explicit + * jsps are specified. + */ + public void scanFiles(File base) throws JasperException { + Stack dirs = new Stack(); + dirs.push(base.toString()); + + // Make sure default extensions are always included + if ((getExtensions() == null) || (getExtensions().size() < 2)) { + addExtension("jsp"); + addExtension("jspx"); + } + + while (!dirs.isEmpty()) { + String s = dirs.pop(); + File f = new File(s); + if (f.exists() && f.isDirectory()) { + String[] files = f.list(); + String ext; + for (int i = 0; (files != null) && i < files.length; i++) { + File f2 = new File(s, files[i]); + if (f2.isDirectory()) { + dirs.push(f2.getPath()); + } else { + String path = f2.getPath(); + String uri = path.substring(uriRoot.length()); + ext = files[i].substring(files[i].lastIndexOf('.') + 1); + if (getExtensions().contains(ext) || jspConfig.isJspPage(uri)) { + pages.add(path); + } + } + } + } + } + } + + /** + * Executes the compilation. + */ + public void execute() { + if (log.isDebugEnabled()) { + log.debug("execute() starting for " + pages.size() + " pages."); + } + + try { + if (uriRoot == null) { + if (pages.size() == 0) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget")); + } + String firstJsp = pages.get(0); + File firstJspF = new File(firstJsp); + if (!firstJspF.exists()) { + throw new JasperException(Localizer.getMessage("jspc.error.fileDoesNotExist", firstJsp)); + } + locateUriRoot(firstJspF); + } + + if (uriRoot == null) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot")); + } + + File uriRootF = new File(uriRoot); + if (!uriRootF.isDirectory()) { + throw new JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); + } + + if (loader == null) { + loader = initClassLoader(); + } + if (context == null) { + initServletContext(loader); + } + + // No explicit pages, we'll process all .jsp in the webapp + if (pages.size() == 0) { + scanFiles(uriRootF); + } + + initWebXml(); + + Iterator iter = pages.iterator(); + while (iter.hasNext()) { + String nextjsp = iter.next(); + File fjsp = new File(nextjsp); + if (!fjsp.isAbsolute()) { + fjsp = new File(uriRootF, nextjsp); + } + if (!fjsp.exists()) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", fjsp.toString())); + } + continue; + } + String s = fjsp.getAbsolutePath(); + if (s.startsWith(uriRoot)) { + nextjsp = s.substring(uriRoot.length()); + } + if (nextjsp.startsWith("." + File.separatorChar)) { + nextjsp = nextjsp.substring(2); + } + processFile(nextjsp); + } + + completeWebXml(); + + if (addWebXmlMappings) { + mergeIntoWebXml(); + } + + } catch (IOException ioe) { + throw new RuntimeException(ioe); // TODO make it our own + + } catch (JasperException je) { + Throwable rootCause = je; + while (rootCause instanceof JasperException && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if (rootCause != je) { + rootCause.printStackTrace(); + } + throw new RuntimeException(je); // TODO make it our own + } finally { + if (loader != null) { + LogFactory.release(loader); + } + } + } + + // ==================== protected utility methods ==================== + + protected String nextArg() { + if ((argPos >= args.length) || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { + return null; + } else { + return args[argPos++]; + } + } + + protected String nextFile() { + if (fullstop) + argPos++; + if (argPos >= args.length) { + return null; + } else { + return args[argPos++]; + } + } + + protected void initWebXml() { + try { + if (webxmlLevel >= INC_WEBXML) { + mapout = openWebxmlWriter(new File(webxmlFile)); + servletout = new CharArrayWriter(); + mappingout = new CharArrayWriter(); + } else { + mapout = null; + servletout = null; + mappingout = null; + } + if (webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.header")); + mapout.flush(); + } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.header")); + mapout.flush(); + } + } catch (IOException ioe) { + mapout = null; + servletout = null; + mappingout = null; + } + } + + protected void completeWebXml() { + if (mapout != null) { + try { + servletout.writeTo(mapout); + mappingout.writeTo(mapout); + if (webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.footer")); + } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.footer")); + } + mapout.close(); + } catch (IOException ioe) { + // noting to do if it fails since we are done with it + } + } + } + + protected void initServletContext(ClassLoader classLoader) throws IOException, JasperException { + // TODO: should we use the Ant Project's log? + PrintWriter log = new PrintWriter(System.out); + URL resourceBase = new File(uriRoot).getCanonicalFile().toURI().toURL(); + context = new JspCServletContext(log, resourceBase, classLoader); + /** TODO - FIX ME - UNCOMMENT LATER */ + if (isValidateTld()) { + context.setInitParameter("XML_VALIDATION_TLD_INIT_PARAM", "true"); +// context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true"); + } + if (isValidateXml()) { + context.setInitParameter("XML_VALIDATION_INIT_PARAM", "true"); +// context.setInitParameter(Constants.XML_VALIDATION_INIT_PARAM, "true"); + } + context.setInitParameter("XML_BLOCK_EXTERNAL_INIT_PARAM", String.valueOf(isBlockExternal())); +// context.setInitParameter(Constants.XML_BLOCK_EXTERNAL_INIT_PARAM, String.valueOf(isBlockExternal())); + + tldLocationsCache = TldLocationsCache.getInstance(context); + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); + } + + /** + * Initializes the classloader as/if needed for the given + * compilation context. + * + * @throws IOException If an error occurs + */ + protected ClassLoader initClassLoader() throws IOException { + + classPath = getClassPath(); + + ClassLoader jspcLoader = getClass().getClassLoader(); + // TODO add check for 7Bee/TJWS class loader and extend CP as needed + + // Turn the classPath into URLs + ArrayList urls = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); + while (tokenizer.hasMoreTokens()) { + String path = tokenizer.nextToken(); + try { + File libFile = new File(path); + urls.add(libFile.toURI().toURL()); + } catch (IOException ioe) { + // Failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak uot + throw new RuntimeException(ioe.toString()); + } + } + + File webappBase = new File(uriRoot); + if (webappBase.exists()) { + File classes = new File(webappBase, "/WEB-INF/classes"); + try { + if (classes.exists()) { + classPath = classPath + File.pathSeparator + classes.getCanonicalPath(); + urls.add(classes.getCanonicalFile().toURI().toURL()); + } + } catch (IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + File lib = new File(webappBase, "/WEB-INF/lib"); + if (lib.exists() && lib.isDirectory()) { + String[] libs = lib.list(); + if (libs != null) { + for (int i = 0; i < libs.length; i++) { + if (libs[i].length() < 5) + continue; + String ext = libs[i].substring(libs[i].length() - 4); + if (!".jar".equalsIgnoreCase(ext)) { + if (".tld".equalsIgnoreCase(ext)) { + log.warn("TLD files should not be placed in " + "/WEB-INF/lib"); + } + continue; + } + try { + File libFile = new File(lib, libs[i]); + classPath = classPath + File.pathSeparator + libFile.getAbsolutePath(); + urls.add(libFile.getAbsoluteFile().toURI().toURL()); + } catch (IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + } + } + } + } + + URL urlsA[] = new URL[urls.size()]; + urls.toArray(urlsA); + loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); + return loader; + } + + /** + * Find the WEB-INF dir by looking up in the directory tree. + * This is used if no explicit docbase is set, but only files. + * XXX Maybe we should require the docbase. + */ + protected void locateUriRoot(File f) { + String tUriBase = uriBase; + if (tUriBase == null) { + tUriBase = "/"; + } + try { + if (f.exists()) { + f = new File(f.getAbsolutePath()); + while (true) { + File g = new File(f, "WEB-INF"); + if (g.exists() && g.isDirectory()) { + uriRoot = f.getCanonicalPath(); + uriBase = tUriBase; + if (log.isInfoEnabled()) { + log.info(Localizer.getMessage("jspc.implicit.uriRoot", uriRoot)); + } + break; + } + if (f.exists() && f.isDirectory()) { + tUriBase = "/" + f.getName() + "/" + tUriBase; + } + + String fParent = f.getParent(); + if (fParent == null) { + break; + } else { + f = new File(fParent); + } + + // If there is no acceptable candidate, uriRoot will + // remain null to indicate to the CompilerContext to + // use the current working/user dir. + } + + if (uriRoot != null) { + File froot = new File(uriRoot); + uriRoot = froot.getCanonicalPath(); + } + } + } catch (IOException ioe) { + // since this is an optional default and a null value + // for uriRoot has a non-error meaning, we can just + // pass straight through + } + } + + /** + * Resolves the relative or absolute pathname correctly + * in both Ant and command-line situations. If Ant launched + * us, we should use the basedir of the current project + * to resolve relative paths. + * + * See Bugzilla 35571. + * + * @param s The file + * @return The file resolved + */ + protected File resolveFile(final String s) { + // TODO consider some massaging of s as relative path to project home + // for TJWS + return new File(s); + } + + private Reader openWebxmlReader(File file) throws IOException { + FileInputStream fis = new FileInputStream(file); + try { + return webxmlEncoding != null ? new InputStreamReader(fis, webxmlEncoding) : new InputStreamReader(fis); + } catch (IOException ex) { + fis.close(); + throw ex; + } + } + + private Writer openWebxmlWriter(File file) throws IOException { + FileOutputStream fos = new FileOutputStream(file); + try { + return webxmlEncoding != null ? new OutputStreamWriter(fos, webxmlEncoding) : new OutputStreamWriter(fos); + } catch (IOException ex) { + fos.close(); + throw ex; + } + } +} diff --git a/Jasper/org/apache/jasper/JspCompilationContext.java b/Jasper/org/apache/jasper/JspCompilationContext.java new file mode 100755 index 0000000..3286ce6 --- /dev/null +++ b/Jasper/org/apache/jasper/JspCompilationContext.java @@ -0,0 +1,768 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JarResource; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.JspUtil; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.ServletWriter; +import org.apache.jasper.compiler.TldLocation; +import org.apache.jasper.servlet.JasperLoader; +import org.apache.jasper.servlet.JspServletWrapper; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * A place holder for various things that are used through out the JSP + * engine. This is a per-request/per-context data structure. Some of + * the instance variables are set at different points. + * + * Most of the path-related stuff is here - mangling names, versions, dirs, + * loading resources and dealing with uris. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Pierre Delisle + * @author Costin Manolache + * @author Kin-man Chung + */ +public class JspCompilationContext { + + // must not be static + private final Log log = LogFactory.getLog(JspCompilationContext.class); + + protected Map tagFileJarUrls; + + protected String className; + protected String jspUri; + protected String basePackageName; + protected String derivedPackageName; + protected String servletJavaFileName; + protected String javaPath; + protected String classFileName; + protected ServletWriter writer; + protected Options options; + protected JspServletWrapper jsw; + protected Compiler jspCompiler; + protected String classPath; + + protected String baseURI; + protected String outputDir; + protected ServletContext context; + protected ClassLoader loader; + + protected JspRuntimeContext rctxt; + + protected volatile int removed = 0; + + protected URLClassLoader jspLoader; + protected URL baseUrl; + protected Class servletClass; + + protected boolean isTagFile; + protected boolean protoTypeMode; + protected TagInfo tagInfo; + protected JarResource tagJarResource; + + // jspURI _must_ be relative to the context + public JspCompilationContext(String jspUri, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt) { + + this.jspUri = canonicalURI(jspUri); + this.options = options; + this.jsw = jsw; + this.context = context; + + this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); + // hack fix for resolveRelativeURI + if (baseURI == null) { + baseURI = "/"; + } else if (baseURI.charAt(0) != '/') { + // strip the base slash since it will be combined with the + // uriBase to generate a file + baseURI = "/" + baseURI; + } + if (baseURI.charAt(baseURI.length() - 1) != '/') { + baseURI += '/'; + } + + this.rctxt = rctxt; + this.tagFileJarUrls = new HashMap(); + this.basePackageName = Constants.JSP_PACKAGE_NAME; + } + + public JspCompilationContext(String tagfile, TagInfo tagInfo, Options options, ServletContext context, JspServletWrapper jsw, JspRuntimeContext rctxt, JarResource tagJarResource) { + this(tagfile, options, context, jsw, rctxt); + this.isTagFile = true; + this.tagInfo = tagInfo; + this.tagJarResource = tagJarResource; + } + + /* ==================== Methods to override ==================== */ + + /** ---------- Class path and loader ---------- */ + + /** + * The classpath that is passed off to the Java compiler. + */ + public String getClassPath() { + if (classPath != null) + return classPath; + return rctxt.getClassPath(); + } + + /** + * The classpath that is passed off to the Java compiler. + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * What class loader to use for loading classes while compiling + * this JSP? + */ + public ClassLoader getClassLoader() { + if (loader != null) + return loader; + return rctxt.getParentClassLoader(); + } + + public void setClassLoader(ClassLoader loader) { + this.loader = loader; + } + + public ClassLoader getJspLoader() { + if (jspLoader == null) { + jspLoader = new JasperLoader(new URL[] { baseUrl }, getClassLoader(), rctxt.getPermissionCollection()); + } + return jspLoader; + } + + /** ---------- Input/Output ---------- */ + + /** + * The output directory to generate code into. The output directory + * is make up of the scratch directory, which is provide in Options, + * plus the directory derived from the package name. + */ + public String getOutputDir() { + if (outputDir == null) { + createOutputDir(); + } + + return outputDir; + } + + /** + * Create a "Compiler" object based on some init param data. This + * is not done yet. Right now we're just hardcoding the actual + * compilers that are created. + */ + public Compiler createCompiler() { + if (jspCompiler != null) { + return jspCompiler; + } + jspCompiler = createCompiler("org.apache.jasper.compiler.BeeCompiler"); + if (jspCompiler == null) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); + } + jspCompiler.init(this, jsw); + return jspCompiler; + } + + protected Compiler createCompiler(String className) { + Compiler compiler = null; + try { + compiler = (Compiler) Class.forName(className).newInstance(); + } catch (InstantiationException e) { + log.warn(Localizer.getMessage("jsp.error.compiler"), e); + } catch (IllegalAccessException e) { + log.warn(Localizer.getMessage("jsp.error.compiler"), e); + } catch (NoClassDefFoundError e) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), e); + } + } catch (ClassNotFoundException e) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), e); + } + } + return compiler; + } + + public Compiler getCompiler() { + return jspCompiler; + } + + /** ---------- Access resources in the webapp ---------- */ + + /** + * Get the full value of a URI relative to this compilations context + * uses current file as the base. + */ + public String resolveRelativeUri(String uri) { + // sometimes we get uri's massaged from File(String), so check for + // a root directory separator char + if (uri.startsWith("/") || uri.startsWith(File.separator)) { + return uri; + } else { + return baseURI + uri; + } + } + + /** + * Gets a resource as a stream, relative to the meanings of this + * context's implementation. + * + * @return a null if the resource cannot be found or represented + * as an InputStream. + */ + public java.io.InputStream getResourceAsStream(String res) { + return context.getResourceAsStream(canonicalURI(res)); + } + + public URL getResource(String res) throws MalformedURLException { + URL result = null; + + if (res.startsWith("/META-INF/")) { + // This is a tag file packaged in a jar that is being compiled + JarResource jarResource = tagFileJarUrls.get(res); + if (jarResource == null) { + jarResource = tagJarResource; + } + if (jarResource != null) { + result = jarResource.getEntry(res.substring(1)); + } else { + // May not be in a JAR in some IDE environments + result = context.getResource(canonicalURI(res)); + } + } else if (res.startsWith("jar:jndi:")) { + // This is a tag file packaged in a jar that is being checked + // for a dependency + result = new URL(res); + + } else { + result = context.getResource(canonicalURI(res)); + } + return result; + } + + public Set getResourcePaths(String path) { + return context.getResourcePaths(canonicalURI(path)); + } + + /** + * Gets the actual path of a URI relative to the context of + * the compilation. + */ + public String getRealPath(String path) { + if (context != null) { + return context.getRealPath(path); + } + return path; + } + + /** + * Returns the tag-file-name-to-JAR-file map of this compilation unit, + * which maps tag file names to the JAR files in which the tag files are + * packaged. + * + * The map is populated when parsing the tag-file elements of the TLDs + * of any imported taglibs. + */ + public JarResource getTagFileJarResource(String tagFile) { + return this.tagFileJarUrls.get(tagFile); + } + + public void setTagFileJarResource(String tagFile, JarResource jarResource) { + this.tagFileJarUrls.put(tagFile, jarResource); + } + + /** + * Returns the JAR file in which the tag file for which this + * JspCompilationContext was created is packaged, or null if this + * JspCompilationContext does not correspond to a tag file, or if the + * corresponding tag file is not packaged in a JAR. + */ + public JarResource getTagFileJarResource() { + return this.tagJarResource; + } + + /* ==================== Common implementation ==================== */ + + /** + * Just the class name (does not include package name) of the + * generated class. + */ + public String getServletClassName() { + + if (className != null) { + return className; + } + + if (isTagFile) { + className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + if (lastIndex != -1) { + className = className.substring(lastIndex + 1); + } + } else { + int iSep = jspUri.lastIndexOf('/') + 1; + className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); + } + return className; + } + + public void setServletClassName(String className) { + this.className = className; + } + + /** + * Path of the JSP URI. Note that this is not a file name. This is + * the context rooted URI of the JSP file. + */ + public String getJspFile() { + return jspUri; + } + + /** + * @deprecated Will be removed in Tomcat 8.0.x. Use + * {@link #getLastModified(String)} instead. + */ + @Deprecated + public long getJspLastModified() { + long result = -1; + URLConnection uc = null; + try { + URL jspUrl = getResource(getJspFile()); + if (jspUrl == null) { + incrementRemoved(); + return result; + } + uc = jspUrl.openConnection(); + if (uc instanceof JarURLConnection) { + result = ((JarURLConnection) uc).getJarEntry().getTime(); + } else { + result = uc.getLastModified(); + } + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } finally { + if (uc != null) { + try { + uc.getInputStream().close(); + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } + } + } + return result; + } + + public Long getLastModified(String resource) { + long result = -1; + URLConnection uc = null; + try { + URL jspUrl = getResource(resource); + if (jspUrl == null) { + incrementRemoved(); + return Long.valueOf(result); + } + File resFile = new File(jspUrl.getFile()); // TJWS on Android + if (resFile.exists()) { + result = resFile.lastModified(); + } else { + uc = jspUrl.openConnection(); + if (uc instanceof JarURLConnection) { + result = ((JarURLConnection) uc).getJarEntry().getTime(); + } else { + result = uc.getLastModified(); + } + } + // System.out.printf("Jasper ctx %s modified %d / %s%n", uc, result, + // resFile); + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } finally { + if (uc != null) { + try { + uc.getInputStream().close(); + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.lastModified", getJspFile()), e); + } + result = -1; + } + } + } + return Long.valueOf(result); + } + + public boolean isTagFile() { + return isTagFile; + } + + public TagInfo getTagInfo() { + return tagInfo; + } + + public void setTagInfo(TagInfo tagi) { + tagInfo = tagi; + } + + /** + * True if we are compiling a tag file in prototype mode. + * ie we only generate codes with class for the tag handler with empty + * method bodies. + */ + public boolean isPrototypeMode() { + return protoTypeMode; + } + + public void setPrototypeMode(boolean pm) { + protoTypeMode = pm; + } + + /** + * Package name for the generated class is make up of the base package + * name, which is user settable, and the derived package name. The + * derived package name directly mirrors the file hierarchy of the JSP page. + */ + public String getServletPackageName() { + if (isTagFile()) { + String className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + String pkgName = ""; + if (lastIndex != -1) { + pkgName = className.substring(0, lastIndex); + } + return pkgName; + } else { + String dPackageName = getDerivedPackageName(); + if (dPackageName.length() == 0) { + return basePackageName; + } + return basePackageName + '.' + getDerivedPackageName(); + } + } + + protected String getDerivedPackageName() { + if (derivedPackageName == null) { + int iSep = jspUri.lastIndexOf('/'); + derivedPackageName = (iSep > 0) ? JspUtil.makeJavaPackage(jspUri.substring(1, iSep)) : ""; + } + return derivedPackageName; + } + + /** + * The package name into which the servlet class is generated. + */ + public void setServletPackageName(String servletPackageName) { + this.basePackageName = servletPackageName; + } + + /** + * Full path name of the Java file into which the servlet is being + * generated. + */ + public String getServletJavaFileName() { + if (servletJavaFileName == null) { + servletJavaFileName = getOutputDir() + getServletClassName() + ".java"; + } + return servletJavaFileName; + } + + /** + * Get hold of the Options object for this context. + */ + public Options getOptions() { + return options; + } + + public ServletContext getServletContext() { + return context; + } + + public JspRuntimeContext getRuntimeContext() { + return rctxt; + } + + /** + * Path of the Java file relative to the work directory. + */ + public String getJavaPath() { + + if (javaPath != null) { + return javaPath; + } + + if (isTagFile()) { + String tagName = tagInfo.getTagClassName(); + javaPath = tagName.replace('.', '/') + ".java"; + } else { + javaPath = getServletPackageName().replace('.', '/') + '/' + getServletClassName() + ".java"; + } + return javaPath; + } + + public String getClassFileName() { + if (classFileName == null) { + classFileName = getOutputDir() + getServletClassName() + ".class"; + } + return classFileName; + } + + /** + * Where is the servlet being generated? + */ + public ServletWriter getWriter() { + return writer; + } + + public void setWriter(ServletWriter writer) { + this.writer = writer; + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, + * then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the given uri is not associated with any tag + * library + * 'exposed' in the web application. + */ + public TldLocation getTldLocation(String uri) throws JasperException { + TldLocation location = getOptions().getTldLocationsCache().getLocation(uri); + return location; + } + + /** + * Are we keeping generated code around? + */ + public boolean keepGenerated() { + return getOptions().getKeepGenerated(); + } + + // ==================== Removal ==================== + + public void incrementRemoved() { + if (removed == 0 && rctxt != null) { + rctxt.removeWrapper(jspUri); + } + removed++; + } + + public boolean isRemoved() { + if (removed > 0) { + return true; + } + return false; + } + + // ==================== Compile and reload ==================== + + public void compile() throws JasperException, FileNotFoundException { + createCompiler(); + if (jspCompiler.isOutDated()) { + if (isRemoved()) { + throw new FileNotFoundException(jspUri); + } + try { + jspCompiler.removeGeneratedFiles(); + jspLoader = null; + jspCompiler.compile(); + jsw.setReload(true); + jsw.setCompilationException(null); + } catch (JasperException ex) { + // Cache compilation exception + jsw.setCompilationException(ex); + if (options.getDevelopment() && options.getRecompileOnFail()) { + // Force a recompilation attempt on next access + jsw.setLastModificationTest(-1); + } + throw ex; + } catch (Exception ex) { + JasperException je = new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + // Cache compilation exception + jsw.setCompilationException(je); + throw je; + } + } + } + + // ==================== Manipulating the class ==================== + + public Class load() throws JasperException { + try { + getJspLoader(); + + String name = getFQCN(); + servletClass = jspLoader.loadClass(name); + } catch (ClassNotFoundException cex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), cex); + } catch (Exception ex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); + } + removed = 0; + return servletClass; + } + + public String getFQCN() { + String name; + if (isTagFile()) { + name = tagInfo.getTagClassName(); + } else { + name = getServletPackageName() + "." + getServletClassName(); + } + return name; + } + + // ==================== protected methods ==================== + + static Object outputDirLock = new Object(); + + public void checkOutputDir() { + if (outputDir != null) { + if (!(new File(outputDir)).exists()) { + makeOutputDir(); + } + } else { + createOutputDir(); + } + } + + protected boolean makeOutputDir() { + synchronized (outputDirLock) { + File outDirFile = new File(outputDir); + return (outDirFile.exists() || outDirFile.mkdirs()); + } + } + + protected void createOutputDir() { + String path = null; + if (isTagFile()) { + String tagName = tagInfo.getTagClassName(); + path = tagName.replace('.', File.separatorChar); + path = path.substring(0, path.lastIndexOf(File.separatorChar)); + } else { + path = getServletPackageName().replace('.', File.separatorChar); + } + + // Append servlet or tag handler path to scratch dir + try { + File base = options.getScratchDir(); + baseUrl = base.toURI().toURL(); + outputDir = base.getAbsolutePath() + File.separator + path + File.separator; + if (!makeOutputDir()) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); + } + } catch (MalformedURLException e) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); + } + } + + protected static final boolean isPathSeparator(char c) { + return (c == '/' || c == '\\'); + } + + protected static final String canonicalURI(String s) { + if (s == null) + return null; + StringBuilder result = new StringBuilder(); + final int len = s.length(); + int pos = 0; + while (pos < len) { + char c = s.charAt(pos); + if (isPathSeparator(c)) { + /* + * multiple path separators. + * 'foo///bar' -> 'foo/bar' + */ + while (pos + 1 < len && isPathSeparator(s.charAt(pos + 1))) { + ++pos; + } + + if (pos + 1 < len && s.charAt(pos + 1) == '.') { + /* + * a single dot at the end of the path - we are done. + */ + if (pos + 2 >= len) + break; + + switch (s.charAt(pos + 2)) { + /* + * self directory in path + * foo/./bar -> foo/bar + */ + case '/': + case '\\': + pos += 2; + continue; + + /* + * two dots in a path: go back one hierarchy. + * foo/bar/../baz -> foo/baz + */ + case '.': + // only if we have exactly _two_ dots. + if (pos + 3 < len && isPathSeparator(s.charAt(pos + 3))) { + pos += 3; + int separatorPos = result.length() - 1; + while (separatorPos >= 0 && !isPathSeparator(result.charAt(separatorPos))) { + --separatorPos; + } + if (separatorPos >= 0) + result.setLength(separatorPos); + continue; + } + } + } + } + result.append(c); + ++pos; + } + return result.toString(); + } +} diff --git a/1.x/src/jasper6/BeeCompiler.java b/Jasper/org/apache/jasper/compiler/BeeCompiler.java old mode 100644 new mode 100755 similarity index 56% rename from 1.x/src/jasper6/BeeCompiler.java rename to Jasper/org/apache/jasper/compiler/BeeCompiler.java index 9e85c29..3f40330 --- a/1.x/src/jasper6/BeeCompiler.java +++ b/Jasper/org/apache/jasper/compiler/BeeCompiler.java @@ -1,12 +1,9 @@ /* * Copyright 1999,2004 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,21 +13,22 @@ package org.apache.jasper.compiler; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; -import java.io.PrintStream; import java.io.IOException; -import java.io.ByteArrayOutputStream; -import java.util.StringTokenizer; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; -import java.lang.reflect.Method; +import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.jasper.JasperException; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; /** * Main JSP compiler class. This class uses 7Bee for compiling. @@ -38,60 +36,58 @@ * @author Dmitriy Rogatkin */ public class BeeCompiler extends Compiler { - + // must not be static + private final Log log = LogFactory.getLog(BeeCompiler.class); protected static Object javacLock = new Object(); - - private Class javaCompiler; - + private Class javaCompiler; + static { System.setErr(new SystemLogHandler(System.err)); } - + /** * Compile the servlet from .java file to .class file */ protected void generateClass(String[] smap) throws FileNotFoundException, JasperException, Exception { - + long t1 = 0; - if (log.isDebugEnabled()) + if (log.isDebugEnabled()) { t1 = System.currentTimeMillis(); - + } + List parameters = new ArrayList(20); parameters.add("-encoding"); parameters.add(ctxt.getOptions().getJavaEncoding()); - + String javaFileName = new File(ctxt.getServletJavaFileName()).getPath(); String classpath = ctxt.getClassPath(); - - String sep = File.pathSeparator; // System.getProperty("path.separator"); - + StringBuffer errorReport = new StringBuffer(); - StringBuffer info = new StringBuffer(); info.append("Compile: javaFileName=" + javaFileName + "\n"); - + // Start capturing the System.err output for this thread SystemLogHandler.setThread(); - + // Initializing classpath String path = System.getProperty("java.class.path"); info.append(" cmd cp=" + path + "\n"); info.append(" ctx cp=" + classpath + "\n"); - path += sep; + path += File.pathSeparator; path += classpath; - + if (log.isDebugEnabled()) log.debug("Using classpath: " + path); - + parameters.add("-classpath"); parameters.add(path); - + // Initializing sourcepath parameters.add("-sourcepath"); parameters.add(options.getScratchDir().getPath()); - + info.append(" work dir=" + options.getScratchDir() + "\n"); - + // Initialize and set java extensions String extdirs = System.getProperty("java.ext.dirs"); if (extdirs != null) { @@ -99,7 +95,7 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper parameters.add(extdirs); info.append(" extension dir=" + extdirs + "\n"); } - + if (ctxt.getOptions().getFork()) { String endorsed = System.getProperty("java.endorsed.dirs"); if (endorsed != null) { @@ -110,15 +106,15 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper info.append(" no endorsed dirs specified\n"); } } - + if (ctxt.getOptions().getClassDebugInfo()) parameters.add("-g"); - + Exception ie = null; - + // Set the Java compiler to use if (javaCompiler == null) { - // assumption, there is no dynamic changing Java compiler + // assumption, there is no dynamic changing Java compiler String compiler = options.getCompiler(); if (compiler == null) compiler = "com.sun.tools.javac.Main"; @@ -134,17 +130,16 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper if (compileClassPath == null) compileClassPath = System.getenv("java_home"); } catch (SecurityException se) { - + } - + if (compileClassPath != null) { // HACK for now compileClassPath = compileClassPath.replace("jre", "jdk"); compileClassPath += "/lib/tools.jar"; info.append(" checking default compiler in " + compileClassPath + "\n"); try { - javaCompiler = Class.forName(compiler, true, new URLClassLoader(new URL[] { new URL("file", - "localhost", compileClassPath) })); + javaCompiler = Class.forName(compiler, true, new URLClassLoader(new URL[] { new URL("file", "localhost", compileClassPath) })); } catch (Error er) { log.error("Setting up Java compiler error ", er); } catch (Exception ex) { @@ -155,23 +150,23 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper } info.append(" compiler=" + compiler + "\n"); } - + if (options.getCompilerTargetVM() != null) { parameters.add("-target"); parameters.add(options.getCompilerTargetVM()); info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n"); } - + if (options.getCompilerSourceVM() != null) { parameters.add("-source"); parameters.add(options.getCompilerSourceVM()); info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n"); } - + info.append(" JavaPath=" + ctxt.getJavaPath() + "\n"); - + parameters.add(javaFileName); - + boolean compilationErrors = false; String errorCapture = null; if (javaCompiler != null) @@ -179,12 +174,10 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper Integer success; Method cm = javaCompiler.getMethod("compile", new Class[] { String[].class }); if (ctxt.getOptions().getFork()) { - success = (Integer) cm.invoke(null, new Object[] { parameters - .toArray(new String[parameters.size()]) }); + success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters.size()]) }); } else { synchronized (javacLock) { - success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters - .size()]) }); + success = (Integer) cm.invoke(null, new Object[] { parameters.toArray(new String[parameters.size()]) }); } } if (success.intValue() != 0) @@ -208,231 +201,220 @@ protected void generateClass(String[] smap) throws FileNotFoundException, Jasper errorReport.append(System.getProperty("line.separator")); errorReport.append(errorCapture); } - + if (!ctxt.keepGenerated()) { if (new File(javaFileName).delete() == false) log.error("Couldn't delete source: " + javaFileName); } - + if (compilationErrors || ie != null) { String errorReportString = errorReport.toString(); log.error("Error compiling file: " + javaFileName + " " + errorReportString); - JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(errorReportString, javaFileName, - pageNodes); + JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(errorReportString, javaFileName, pageNodes); if (javacErrors != null) { errDispatcher.javacError(javacErrors); } else { errDispatcher.javacError(errorReportString, ie); } } - + if (log.isDebugEnabled()) { long t2 = System.currentTimeMillis(); log.debug("Compiled " + ctxt.getServletJavaFileName() + " " + (t2 - t1) + "ms"); } - + if (ctxt.isPrototypeMode()) { return; } - + // JSR45 Support if (!options.isSmapSuppressed()) { log.debug("Install Smap " + (smap == null ? "null" : Arrays.toString(smap))); SmapUtil.installSmap(smap); } } - - protected static class SystemLogHandler extends PrintStream { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct the handler to capture the output of the given steam. - */ - public SystemLogHandler(PrintStream wrapped) { - super(wrapped); - this.wrapped = wrapped; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped PrintStream. - */ - protected PrintStream wrapped = null; - - - /** - * Thread <-> PrintStream associations. - */ - protected static ThreadLocal streams = new ThreadLocal(); - - - /** - * Thread <-> ByteArrayOutputStream associations. - */ - protected static ThreadLocal data = new ThreadLocal(); - - - // --------------------------------------------------------- Public Methods - - - public PrintStream getWrapped() { - return wrapped; - } - - /** - * Start capturing thread's output. - */ - public static void setThread() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - data.set(baos); - streams.set(new PrintStream(baos)); - } - - - /** - * Stop capturing thread's output and return captured data as a String. - */ - public static String unsetThread() { - ByteArrayOutputStream baos = - (ByteArrayOutputStream) data.get(); - if (baos == null) { - return null; - } - streams.set(null); - data.set(null); - return baos.toString(); - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Find PrintStream to which the output must be written to. - */ - protected PrintStream findStream() { - PrintStream ps = (PrintStream) streams.get(); - if (ps == null) { - ps = wrapped; - } - return ps; - } - - - // ---------------------------------------------------- PrintStream Methods - - - public void flush() { - findStream().flush(); - } - - public void close() { - findStream().close(); - } - - public boolean checkError() { - return findStream().checkError(); - } - - protected void setError() { - //findStream().setError(); - } - - public void write(int b) { - findStream().write(b); - } - - public void write(byte[] b) - throws IOException { - findStream().write(b); - } - - public void write(byte[] buf, int off, int len) { - findStream().write(buf, off, len); - } - - public void print(boolean b) { - findStream().print(b); - } - - public void print(char c) { - findStream().print(c); - } - - public void print(int i) { - findStream().print(i); - } - - public void print(long l) { - findStream().print(l); - } - - public void print(float f) { - findStream().print(f); - } - - public void print(double d) { - findStream().print(d); - } - - public void print(char[] s) { - findStream().print(s); - } - - public void print(String s) { - findStream().print(s); - } - - public void print(Object obj) { - findStream().print(obj); - } - - public void println() { - findStream().println(); - } - - public void println(boolean x) { - findStream().println(x); - } - - public void println(char x) { - findStream().println(x); - } - - public void println(int x) { - findStream().println(x); - } - - public void println(long x) { - findStream().println(x); - } - - public void println(float x) { - findStream().println(x); - } - - public void println(double x) { - findStream().println(x); - } - - public void println(char[] x) { - findStream().println(x); - } - - public void println(String x) { - findStream().println(x); - } - - public void println(Object x) { - findStream().println(x); - } - - } - + + protected static class SystemLogHandler extends PrintStream { + + // ----------------------------------------------------------- + // Constructors + + /** + * Construct the handler to capture the output of the given steam. + */ + public SystemLogHandler(PrintStream wrapped) { + super(wrapped); + this.wrapped = wrapped; + } + + // ----------------------------------------------------- Instance + // Variables + + /** + * Wrapped PrintStream. + */ + protected PrintStream wrapped = null; + + /** + * Thread <-> PrintStream associations. + */ + protected static ThreadLocal streams = new ThreadLocal(); + + /** + * Thread <-> ByteArrayOutputStream associations. + */ + protected static ThreadLocal data = new ThreadLocal(); + + // --------------------------------------------------------- Public + // Methods + + public PrintStream getWrapped() { + return wrapped; + } + + /** + * Start capturing thread's output. + */ + public static void setThread() { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + data.set(outputStream); + streams.set(new PrintStream(outputStream)); + } + + /** + * Stop capturing thread's output and return captured data as a String. + */ + public static String unsetThread() { + ByteArrayOutputStream baos = (ByteArrayOutputStream) data.get(); + if (baos == null) { + return null; + } + streams.set(null); + data.set(null); + return baos.toString(); + } + + // ------------------------------------------------------ Protected + // Methods + + /** + * Find PrintStream to which the output must be written to. + */ + protected PrintStream findStream() { + PrintStream ps = (PrintStream) streams.get(); + if (ps == null) { + ps = wrapped; + } + return ps; + } + + // ---------------------------------------------------- PrintStream + // Methods + + public void flush() { + findStream().flush(); + } + + public void close() { + findStream().close(); + } + + public boolean checkError() { + return findStream().checkError(); + } + + protected void setError() { + // findStream().setError(); + } + + public void write(int b) { + findStream().write(b); + } + + public void write(byte[] b) throws IOException { + findStream().write(b); + } + + public void write(byte[] buf, int off, int len) { + findStream().write(buf, off, len); + } + + public void print(boolean b) { + findStream().print(b); + } + + public void print(char c) { + findStream().print(c); + } + + public void print(int i) { + findStream().print(i); + } + + public void print(long l) { + findStream().print(l); + } + + public void print(float f) { + findStream().print(f); + } + + public void print(double d) { + findStream().print(d); + } + + public void print(char[] s) { + findStream().print(s); + } + + public void print(String s) { + findStream().print(s); + } + + public void print(Object obj) { + findStream().print(obj); + } + + public void println() { + findStream().println(); + } + + public void println(boolean x) { + findStream().println(x); + } + + public void println(char x) { + findStream().println(x); + } + + public void println(int x) { + findStream().println(x); + } + + public void println(long x) { + findStream().println(x); + } + + public void println(float x) { + findStream().println(x); + } + + public void println(double x) { + findStream().println(x); + } + + public void println(char[] x) { + findStream().println(x); + } + + public void println(String x) { + findStream().println(x); + } + + public void println(Object x) { + findStream().println(x); + } + + } + } diff --git a/Jasper/org/apache/jasper/servlet/JspCServletContext.java b/Jasper/org/apache/jasper/servlet/JspCServletContext.java new file mode 100755 index 0000000..9cfdd3c --- /dev/null +++ b/Jasper/org/apache/jasper/servlet/JspCServletContext.java @@ -0,0 +1,588 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.servlet; + +import java.io.File; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.EnumSet; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; + +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.FilterRegistration.Dynamic; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; + +import org.apache.jasper.JasperException; +import org.apache.jasper.util.ExceptionUtils; + +/** + * Simple ServletContext implementation without + * HTTP-specific methods. + * + * @author Peter Rossbach (pr@webapp.de) + */ + +public class JspCServletContext implements ServletContext { + + // ----------------------------------------------------- Instance Variables + + /** + * Servlet context attributes. + */ + protected Hashtable myAttributes; + + /** + * Servlet context initialization parameters. + */ + private final ConcurrentHashMap myParameters; + + /** + * The log writer we will write log messages to. + */ + protected PrintWriter myLogWriter; + + /** + * The base URL (document root) for this context. + */ + protected URL myResourceBaseURL; + + /** + * Web application class loader. + */ + private final ClassLoader loader; + + // ----------------------------------------------------------- Constructors + + /** + * Create a new instance of this ServletContext implementation. + * + * @param aLogWriter PrintWriter which is used for log() calls + * @param aResourceBaseURL Resource base URL + */ + public JspCServletContext(PrintWriter aLogWriter, URL aResourceBaseURL, ClassLoader classLoader) throws JasperException { + + myAttributes = new Hashtable(); + myParameters = new ConcurrentHashMap(); + myLogWriter = aLogWriter; + myResourceBaseURL = aResourceBaseURL; + this.loader = classLoader; + + } + + // --------------------------------------------------------- Public Methods + + /** + * Return the specified context attribute, if any. + * + * @param name Name of the requested attribute + */ + @Override + public Object getAttribute(String name) { + + return (myAttributes.get(name)); + + } + + /** + * Return an enumeration of context attribute names. + */ + @Override + public Enumeration getAttributeNames() { + + return (myAttributes.keys()); + + } + + /** + * Return the servlet context for the specified path. + * + * @param uripath Server-relative path starting with '/' + */ + @Override + public ServletContext getContext(String uripath) { + + return (null); + + } + + /** + * Return the context path. + */ +// @Override + public String getContextPath() { + return (null); + } + + /** + * Return the specified context initialization parameter. + * + * @param name Name of the requested parameter + */ + @Override + public String getInitParameter(String name) { + return myParameters.get(name); + } + + /** + * Return an enumeration of the names of context initialization + * parameters. + */ + @Override + public Enumeration getInitParameterNames() { + return myParameters.keys(); + } + + /** + * Return the Servlet API major version number. + */ + @Override + public int getMajorVersion() { + + return (3); + + } + + /** + * Return the MIME type for the specified filename. + * + * @param file Filename whose MIME type is requested + */ + @Override + public String getMimeType(String file) { + + return (null); + + } + + /** + * Return the Servlet API minor version number. + */ + @Override + public int getMinorVersion() { + + return (0); + + } + + /** + * Return a request dispatcher for the specified servlet name. + * + * @param name Name of the requested servlet + */ + @Override + public RequestDispatcher getNamedDispatcher(String name) { + + return (null); + + } + + /** + * Return the real path for the specified context-relative + * virtual path. + * + * @param path The context-relative virtual path to resolve + */ + @Override + public String getRealPath(String path) { + + if (!myResourceBaseURL.getProtocol().equals("file")) + return null; + if (!path.startsWith("/")) + return null; + try { + File f = new File(getResource(path).toURI()); + return f.getAbsolutePath(); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + return null; + } + } + + /** + * Return a request dispatcher for the specified context-relative path. + * + * @param path Context-relative path for which to acquire a dispatcher + */ + @Override + public RequestDispatcher getRequestDispatcher(String path) { + + return (null); + + } + + /** + * Return a URL object of a resource that is mapped to the + * specified context-relative path. + * + * @param path Context-relative path of the desired resource + * + * @exception MalformedURLException if the resource path is + * not properly formed + */ + @Override + public URL getResource(String path) throws MalformedURLException { + + if (!path.startsWith("/")) + throw new MalformedURLException("Path '" + path + "' does not start with '/'"); + URL url = new URL(myResourceBaseURL, path.substring(1)); + InputStream is = null; + try { + is = url.openStream(); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + url = null; + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable t2) { + ExceptionUtils.handleThrowable(t2); + } + } + } + return url; + + } + + /** + * Return an InputStream allowing access to the resource at the + * specified context-relative path. + * + * @param path Context-relative path of the desired resource + */ + @Override + public InputStream getResourceAsStream(String path) { + + try { + return (getResource(path).openStream()); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + return (null); + } + + } + + /** + * Return the set of resource paths for the "directory" at the + * specified context path. + * + * @param path Context-relative base path + */ + @Override + public Set getResourcePaths(String path) { + + Set thePaths = new HashSet(); + if (!path.endsWith("/")) + path += "/"; + String basePath = getRealPath(path); + if (basePath == null) + return (thePaths); + File theBaseDir = new File(basePath); + if (!theBaseDir.exists() || !theBaseDir.isDirectory()) + return (thePaths); + String theFiles[] = theBaseDir.list(); + for (int i = 0; i < theFiles.length; i++) { + File testFile = new File(basePath + File.separator + theFiles[i]); + if (testFile.isFile()) + thePaths.add(path + theFiles[i]); + else if (testFile.isDirectory()) + thePaths.add(path + theFiles[i] + "/"); + } + return (thePaths); + + } + + /** + * Return descriptive information about this server. + */ + @Override + public String getServerInfo() { + + return ("JspCServletContext/1.0"); + + } + + /** + * Return a null reference for the specified servlet name. + * + * @param name Name of the requested servlet + * + * @deprecated This method has been deprecated with no replacement + */ + @Override + @Deprecated + public Servlet getServlet(String name) throws ServletException { + + return (null); + + } + + /** + * Return the name of this servlet context. + */ + @Override + public String getServletContextName() { + + return (getServerInfo()); + + } + + /** + * Return an empty enumeration of servlet names. + * + * @deprecated This method has been deprecated with no replacement + */ + @Override + @Deprecated + public Enumeration getServletNames() { + + return (new Vector().elements()); + + } + + /** + * Return an empty enumeration of servlets. + * + * @deprecated This method has been deprecated with no replacement + */ + @Override + @Deprecated + public Enumeration getServlets() { + + return (new Vector().elements()); + + } + + /** + * Log the specified message. + * + * @param message The message to be logged + */ + @Override + public void log(String message) { + + myLogWriter.println(message); + + } + + /** + * Log the specified message and exception. + * + * @param exception The exception to be logged + * @param message The message to be logged + * + * @deprecated Use log(String,Throwable) instead + */ + @Override + @Deprecated + public void log(Exception exception, String message) { + + log(message, exception); + + } + + /** + * Log the specified message and exception. + * + * @param message The message to be logged + * @param exception The exception to be logged + */ + @Override + public void log(String message, Throwable exception) { + + myLogWriter.println(message); + exception.printStackTrace(myLogWriter); + + } + + /** + * Remove the specified context attribute. + * + * @param name Name of the attribute to remove + */ + @Override + public void removeAttribute(String name) { + + myAttributes.remove(name); + + } + + /** + * Set or replace the specified context attribute. + * + * @param name Name of the context attribute to set + * @param value Corresponding attribute value + */ + @Override + public void setAttribute(String name, Object value) { + + myAttributes.put(name, value); + + } + +// @Override + public FilterRegistration.Dynamic addFilter(String filterName, String className) { + return null; + } + +// @Override + public ServletRegistration.Dynamic addServlet(String servletName, String className) { + return null; + } + +// @Override + public Set getDefaultSessionTrackingModes() { + return EnumSet.noneOf(SessionTrackingMode.class); + } + +// @Override + public Set getEffectiveSessionTrackingModes() { + return EnumSet.noneOf(SessionTrackingMode.class); + } + +// @Override + public SessionCookieConfig getSessionCookieConfig() { + return null; + } + +// @Override + public void setSessionTrackingModes(Set sessionTrackingModes) { + // Do nothing + } + +// @Override + public Dynamic addFilter(String filterName, Filter filter) { + return null; + } + +// @Override + public Dynamic addFilter(String filterName, Class filterClass) { + return null; + } + +// @Override + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { + return null; + } + +// @Override + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { + return null; + } + +// @Override + public T createFilter(Class c) throws ServletException { + return null; + } + +// @Override + public T createServlet(Class c) throws ServletException { + return null; + } + +// @Override + public FilterRegistration getFilterRegistration(String filterName) { + return null; + } + +// @Override + public ServletRegistration getServletRegistration(String servletName) { + return null; + } + +// @Override + public boolean setInitParameter(String name, String value) { + return myParameters.putIfAbsent(name, value) == null; + } + +// @Override + public void addListener(Class listenerClass) { + // NOOP + } + +// @Override + public void addListener(String className) { + // NOOP + } + +// @Override + public void addListener(T t) { + // NOOP + } + +// @Override + public T createListener(Class c) throws ServletException { + return null; + } + +// @Override + public void declareRoles(String... roleNames) { + // NOOP + } + +// @Override + public ClassLoader getClassLoader() { + return loader; + } + +// @Override + public int getEffectiveMajorVersion() { + return 3; + } + +// @Override + public int getEffectiveMinorVersion() { + return 0; + } + +// @Override + public Map getFilterRegistrations() { + return null; + } + +// @Override + public JspConfigDescriptor getJspConfigDescriptor() { + return null; + } + +// @Override + public Map getServletRegistrations() { + return null; + } + + // @Override + public String getVirtualServerName() { + throw new UnsupportedOperationException("TJWS will do it"); + } + +} diff --git a/Jasper/org/apache/jasper/tagplugins/jstl/Util.java b/Jasper/org/apache/jasper/tagplugins/jstl/Util.java new file mode 100755 index 0000000..d28ad59 --- /dev/null +++ b/Jasper/org/apache/jasper/tagplugins/jstl/Util.java @@ -0,0 +1,359 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.tagplugins.jstl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.util.Locale; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.PageContext; + +import org.apache.jasper.Constants; + +import Acme.IOHelper; + +/** + * Util contains some often used consts, static methods and embedded class + * to support the JSTL tag plugin. + */ + +public class Util { + + public static final String VALID_SCHEME_CHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-"; + + public static final String DEFAULT_ENCODING = "ISO-8859-1"; + + public static final int HIGHEST_SPECIAL = '>'; + + private static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][]; + + static { + specialCharactersRepresentation['&'] = "&".toCharArray(); + specialCharactersRepresentation['<'] = "<".toCharArray(); + specialCharactersRepresentation['>'] = ">".toCharArray(); + specialCharactersRepresentation['"'] = """.toCharArray(); + specialCharactersRepresentation['\''] = "'".toCharArray(); + } + + /** + * Converts the given string description of a scope to the corresponding + * PageContext constant. + * + * The validity of the given scope has already been checked by the + * appropriate TLV. + * + * @param scope + * String description of scope + * + * @return PageContext constant corresponding to given scope description + * + * taken from org.apache.taglibs.standard.tag.common.core.Util + */ + public static int getScope(String scope) { + int ret = PageContext.PAGE_SCOPE; + + if ("request".equalsIgnoreCase(scope)) { + ret = PageContext.REQUEST_SCOPE; + } else if ("session".equalsIgnoreCase(scope)) { + ret = PageContext.SESSION_SCOPE; + } else if ("application".equalsIgnoreCase(scope)) { + ret = PageContext.APPLICATION_SCOPE; + } + + return ret; + } + + /** + * Returns true if our current URL is absolute, + * false otherwise. + * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport + */ + public static boolean isAbsoluteUrl(String url) { + if (url == null) { + return false; + } + + int colonPos = url.indexOf(":"); + if (colonPos == -1) { + return false; + } + + for (int i = 0; i < colonPos; i++) { + if (VALID_SCHEME_CHAR.indexOf(url.charAt(i)) == -1) { + return false; + } + } + + return true; + } + + /** + * Get the value associated with a content-type attribute. + * Syntax defined in RFC 2045, section 5.1. + * taken from org.apache.taglibs.standard.tag.common.core.Util + */ + public static String getContentTypeAttribute(String input, String name) { + int begin; + int end; + int index = input.toUpperCase(Locale.ENGLISH).indexOf(name.toUpperCase(Locale.ENGLISH)); + if (index == -1) + return null; + index = index + name.length(); // positioned after the attribute name + index = input.indexOf('=', index); // positioned at the '=' + if (index == -1) + return null; + index += 1; // positioned after the '=' + input = input.substring(index).trim(); + + if (input.charAt(0) == '"') { + // attribute value is a quoted string + begin = 1; + end = input.indexOf('"', begin); + if (end == -1) + return null; + } else { + begin = 0; + end = input.indexOf(';'); + if (end == -1) + end = input.indexOf(' '); + if (end == -1) + end = input.length(); + } + return input.substring(begin, end).trim(); + } + + /** + * Strips a servlet session ID from url. The session ID + * is encoded as a URL "path parameter" beginning with "jsessionid=". + * We thus remove anything we find between ";jsessionid=" (inclusive) + * and either EOS or a subsequent ';' (exclusive). + * + * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport + */ + public static String stripSession(String url) { + StringBuilder u = new StringBuilder(url); + int sessionStart; + while ((sessionStart = u.toString().indexOf(";" + Constants.SESSION_PARAMETER_NAME + "=")) != -1) { + int sessionEnd = u.toString().indexOf(";", sessionStart + 1); + if (sessionEnd == -1) + sessionEnd = u.toString().indexOf("?", sessionStart + 1); + if (sessionEnd == -1) // still + sessionEnd = u.length(); + u.delete(sessionStart, sessionEnd); + } + return u.toString(); + } + + /** + * Performs the following substring replacements + * (to facilitate output to XML/HTML pages): + * + * & -> & + * < -> < + * > -> > + * " -> " + * ' -> ' + * + * See also OutSupport.writeEscapedXml(). + * + * taken from org.apache.taglibs.standard.tag.common.core.Util + */ + public static String escapeXml(String buffer) { + String result = escapeXml(buffer.toCharArray(), buffer.length()); + if (result == null) { + return buffer; + } else { + return result; + } + } + + @SuppressWarnings("null") // escapedBuffer cannot be null + public static String escapeXml(char[] arrayBuffer, int length) { + int start = 0; + StringBuilder escapedBuffer = null; + + for (int i = 0; i < length; i++) { + char c = arrayBuffer[i]; + if (c <= HIGHEST_SPECIAL) { + char[] escaped = specialCharactersRepresentation[c]; + if (escaped != null) { + // create StringBuilder to hold escaped xml string + if (start == 0) { + escapedBuffer = new StringBuilder(length + 5); + } + // add unescaped portion + if (start < i) { + escapedBuffer.append(arrayBuffer, start, i - start); + } + start = i + 1; + // add escaped xml + escapedBuffer.append(escaped); + } + } + } + // no xml escaping was necessary + if (start == 0) { + return null; + } + // add rest of unescaped portion + if (start < length) { + escapedBuffer.append(arrayBuffer, start, length - start); + } + return escapedBuffer.toString(); + } + + /** + * Utility methods + * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport + */ + public static String resolveUrl(String url, String context, PageContext pageContext) throws JspException { + // don't touch absolute URLs + if (isAbsoluteUrl(url)) + return url; + + // normalize relative URLs against a context root + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + if (context == null) { + if (url.startsWith("/")) + return (request.getContextPath() + url); + else + return url; + } else { + if (!context.startsWith("/") || !url.startsWith("/")) { + throw new JspTagException("In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\"."); + } + if (context.equals("/")) { + // Don't produce string starting with '//', many + // browsers interpret this as host name, not as + // path on same host. + return url; + } else { + return (context + url); + } + } + } + + /** + * Wraps responses to allow us to retrieve results as Strings. + * mainly taken from + * org.apache.taglibs.standard.tag.common.core.importSupport + */ + public static class ImportResponseWrapper extends HttpServletResponseWrapper { + + private StringWriter stringWriter = new StringWriter(); + private ByteArrayOutputStream bos = new ByteArrayOutputStream(); + private ServletOutputStream sos = new ServletOutputStream() { + @Override + public void write(int b) throws IOException { + bos.write(b); + } + + // // @Override + // public void setWriteListener(WriteListener writeListener) { + // // TODO implement it, or borrow from Tomcat 8 + // } + + // @Override + public boolean isReady() { + return true; + } + + }; + private boolean isWriterUsed; + private boolean isStreamUsed; + private int status = 200; + private String charEncoding; + + public ImportResponseWrapper(HttpServletResponse arg0) { + super(arg0); + } + + @Override + public PrintWriter getWriter() { + if (isStreamUsed) { + throw new IllegalStateException("Unexpected internal error during <import>: " + "Target servlet called getWriter(), then getOutputStream()"); + } + isWriterUsed = true; + return new PrintWriter(stringWriter); + } + + @Override + public ServletOutputStream getOutputStream() { + if (isWriterUsed) { + throw new IllegalStateException("Unexpected internal error during <import>: " + "Target servlet called getOutputStream(), then getWriter()"); + } + + isStreamUsed = true; + return sos; + } + + /** Has no effect. */ + @Override + public void setContentType(String x) { + // ignore + } + + /** Has no effect. */ + @Override + public void setLocale(Locale x) { + // ignore + } + + @Override + public void setStatus(int status) { + this.status = status; + } + + @Override + public int getStatus() { + return status; + } + + public String getCharEncoding() { + return this.charEncoding; + } + + public void setCharEncoding(String charEncoding) { + this.charEncoding = charEncoding; + } + + public String getString() throws UnsupportedEncodingException { + if (isWriterUsed) { + return stringWriter.toString(); + } else if (isStreamUsed) { + if (this.charEncoding != null && !this.charEncoding.equals("")) { + return bos.toString(charEncoding); + } else { + return bos.toString(IOHelper.ISO_8859_1); + } + } else { + // target didn't write anything + return ""; + } + } + + } + +} diff --git a/1.x/src/jasper7/SimpleInstanceManager.java b/Jasper/org/apache/jasper/tjws/SimpleInstanceManager.java old mode 100644 new mode 100755 similarity index 54% rename from 1.x/src/jasper7/SimpleInstanceManager.java rename to Jasper/org/apache/jasper/tjws/SimpleInstanceManager.java index 53fe6e1..defcb72 --- a/1.x/src/jasper7/SimpleInstanceManager.java +++ b/Jasper/org/apache/jasper/tjws/SimpleInstanceManager.java @@ -5,34 +5,29 @@ import org.apache.tomcat.InstanceManager; public class SimpleInstanceManager implements InstanceManager { - - public Object newInstance(String className) throws IllegalAccessException, - InvocationTargetException, NamingException, InstantiationException, - ClassNotFoundException { + + public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { return Class.forName(className).newInstance(); } - - public Object newInstance(String fqcn, ClassLoader classLoader) - throws IllegalAccessException, InvocationTargetException, - NamingException, InstantiationException, ClassNotFoundException { - //System.err.printf("Requested new instance as %s with loader %s and parent %s%n", fqcn, classLoader, classLoader.getParent()); + + public Object newInstance(String fqcn, ClassLoader classLoader) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + // System.err.printf("Requested new instance as %s with loader %s and + // parent %s%n", fqcn, classLoader, classLoader.getParent()); try { return Class.forName(fqcn, true, classLoader).newInstance(); } catch (ClassNotFoundException cnfe) { - //System.err.printf("Exceprion %s%n", cnfe); + // System.err.printf("Exceprion %s%n", cnfe); // trying parent loader for Android } return Class.forName(fqcn, true, classLoader.getParent()).newInstance(); } - - public void newInstance(Object o) throws IllegalAccessException, - InvocationTargetException, NamingException { - //System.err.printf("New instance for object %s", o); + + public void newInstance(Object o) throws IllegalAccessException, InvocationTargetException, NamingException { + // System.err.printf("New instance for object %s", o); } - - public void destroyInstance(Object o) throws IllegalAccessException, - InvocationTargetException { - //System.err.printf("Destroying object %s", o); + + public void destroyInstance(Object o) throws IllegalAccessException, InvocationTargetException { + // System.err.printf("Destroying object %s", o); } - + } \ No newline at end of file diff --git a/bee.xml b/bee.xml new file mode 100755 index 0000000..a69760b --- /dev/null +++ b/bee.xml @@ -0,0 +1,1671 @@ + + + + + + ]> + + + + + &env; + + + ================ ATTENTION ================== + Please make sure that below variables obtained correct values + in file env.xml for build correctness: + + SERVLET_LIB - fully qualified path to servlet.jar or other lib/directory + containing JSS 2.3 classes (this one is used for building base TJWS) + = + + + + SERVLET_LIB_30 - fully qualified path to javax.servlet.jar or other lib/directory + containing JSS 3.x classes (used for J2EE extension) + = + + + SERVLET_SRC - fully qualified path to sources of JSS classes, used only for + packaging + text resources in a launcher (optional) + = + + + + SERVLET_BUILD - fully qualified path to binaries of classes of JSS, used only for + packaging JSS in a launcher (correct version of JSS + has to be used for target applications (optional) + = + + + + JSP_LIB - fully qualified path to jsp.jar or other lib/directory containing + JSP API classes, unless JASPER library is defined (optional) + = + + + + JASPER (optional) + = + + + + ANDROID_RT (optional for android compilation) + = + + + WEBSOCKET_CLIENT_LIB, EBSOCKET_SERVER_LIB - websocket (JSR356) API libraries (optional) + = + + + + + WEBSOCKET_API - fully qualified path to websocket spec source api directory + (optional) + = + + + CLASS_SCAN_LIB, CLASS_SCAN_CLASSES - fully qualified paths to fast scan library and + classes tree (optional) + = + + + + ============================================= + + + + + + + + + /bin/javac + + + + + + + /bin/idlj + + + + + + + + + + + + + + + + + + + + + + + ./compatibility + + + + + + : + + + + bee + + + bee.bat + + + + + + + + + + + + + jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &build_directory; + + + + + + + + + + &build_directory; + + + + + + + + + + + + + + + + + + + + + //////////////////// TJWS Build Process ///////////////////////// + type: + bee -th + to get help on build targets + ///////////////////////////////////////////////////////////////// + + + + + + + + Compiling core... + + + + + + + + + + + + + yes + + + + + 1.8 + + + + + + + + + + + + + + + 1.8 + + + + + -bootclasspath + + + + + + + + + + + + + + + + + + + + + + src/Acme/Utils.java + + + + + + + + + + 0 + + + + Error(s) at compilation + + + + + + + + + + + + IDL compilation... + + + + + + + + + + + + + + + + + + + + + + + + 1.8 + + + + yes + + + + + + + + + + + + .*SysTrayControl\.java + + + + + + + + + + + + + + + + + + + + + Compiling J2EE... + + + + + + + + + + + + + + + 1.8 + + + + yes + + + + + + + + + yes + + + + + + + + + + + .*rogatkin[/|\\]?app.* + + + + + + + -bootclasspath + + + + + + + + + + + + + + + + + + + + + + src/rogatkin/web/WarRoller.java + + + + + + + + + + 0 + + + + Error(s) at compilation + + + + + + + + + + + + + + Compiling checker... + + + 1.8 + + 1.8 + + + + + + + + Jarring war... + + + + + + + + + + + + + + + + + + + Jarring wskt... + + + + + + + + + + + + + + + + + + + + + Jarring app... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jarring checker.... + + + + + + + + + + + + + + Jarring... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Converting resources + + src/rogatkin/resource/*.asis + + + + + /lib/tools.jar + + + + + + + + + + + src/rogatkin/resource + + + + + .properties + + + + + + + + + + + + + /javax/servlet/LocalStrings*.properties + + + + + + + /javax/servlet/http/LocalStrings*.properties + + + + + + + /javax/servlet/resources/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + src + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Acme/Resource/mime.properties + + + rogatkin/resource/tjws.gif + + + rogatkin/resource/splash.gif + + + + + + + + + + -C + + + + + + + + + + + + + -C + + + + + + + + + + + + + -C + + + + + + + + + + + + /client/lib + + + + + + + + + + /server/lib + + + + + + + + + + + + + + + + JASPER_BUILD + + + + Adding Jasper + + + + + + + + + + + + + + + org/apache/jasper/resources + + + javax/servlet/resources + + + + + Launcher's been built. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rogatkin/resource/tjws.gif + + + rogatkin/resource/splash.gif + + + Acme/Resource/mime.properties + + + + + + + + + + -C + + + + + + + + + + + + + -C + + + + + + + + + + + + + -C + + + + + + + + + + + + /client/lib + + + + + + + + + + /server/lib + + + + + + + + + + + + + + + + JASPER_BUILD + + + + Adding Jasper + + + + + + + + + + + + + + + org/apache/jasper/resources + + + + No JSP support added in the launcher + + + + App Server Launcher's been built. + + + + + + + + + Enter command line arguments for app [-nohup -p 8080]? + + -nohup -p 8080 + + + + + Enter application .war file location? + + + + + + Enter application icon (32x32 gif image file) + location[src/rogatkin/resource/tjws.gif]? + src/rogatkin/resource/tjws.gif + + + + + + Do you need tools.jar added (Java compiler for JSP) [n]? + + n + + + + + + + n + + + + Please precompile your JSP using a command similar to bellow + (Jasper): + bee -- -webapp <web app dir> -v -d <target dir> -compile + + + + rundescriptor + + + + + + + + + .war + + + + + rundescriptor + -C + + + + + + + + + + \..* + + + + + + + + + + + + .war + + + + + + + &build_directory;/ + + + + .jar + + + + rundescriptor + + + + + + + + + + + + + + + + Enter command line arguments for app server, use + -j org.apache.jasper.servlet.JspServlet + -org.apache.jasper.servlet.JspServlet.classpath %classpath% + -org.apache.jasper.servlet.JspServlet.scratchdir + %deploydir%/WEB-INF + for Jasper enabled application [-nohup -p 80 -dataSource + datasource.properties]? + + -nohup -p 80 -dataSource datasource.properties + + + + + + Enter application .war file location? + + + + + rundescriptor + + + + + + + + + .war + + + + + rundescriptor + -C + + + + + + + + + + \..* + + + + + + + + + + + + .war + + + + + + + &build_directory;/ + + + + .jar + + + + rundescriptor + + + + + + + + + + + + + + y + + + + + + + + + Cleaning... + + + + + + + + + + + + + + + + Generation SSL certificate + + + + + + + /.keystore + + + + + Keystore path[~/.keystore]? + + + + + + Keystore password[changeme]? + changeme + + + + + Keystore provider (use default for BKS/Android, or JKS + for standard) + [org.bouncycastle.jce.provider.BouncyCastleProvider]? + org.bouncycastle.jce.provider.BouncyCastleProvider + + + + + + Key alias name[selfsigned]? + selfsigned + + + + + + + /bin/keytool + + + + + + + + + + -genkeypair + -keyalg + RSA + -validity + 360 + -alias + + -keypass + + -storepass + + -keystore + + + + + + + JKS + + + + + + -storetype + BKS + -provider + + -providerpath + + + + + + + + + + + + + + + /&build_directory;/webserver.jar + + + /&build_directory;/war.jar + + + /&build_directory;/wskt.jar + + + + + /lib/tools.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /&build_directory;/app.jar + + + + + + + + Runs test.. + + + + + + + + + Scanning and generatiing endpoints list... + + + + + + + + + + + + + + + + + + n + + + + -dataSource + datasource.properties + + -p + + + + + + / + + + + + 8080 + + + 80 + + + + + -z + 50 + -sh + + + + + + + + + + Running... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + 8443 + + + + + + + + + + + / + + + + + 8080 + + + 80 + + + + + + + + + + + + + + + + JASPER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -acceptorImpl + + rogatkin.wskt.SSLSelectorAcceptor + -keystorePass + + + + + + + + -acceptorImpl + Acme.Serve.SelectorAcceptor + + + + + + + + + + + + + + + + + -acceptorImpl + rogatkin.web.DualSocketAcceptor + -keystorePass + + -ssl-port + 443 + + + + + + + + + + \ No newline at end of file diff --git a/build.properties b/build.properties new file mode 100755 index 0000000..009f316 --- /dev/null +++ b/build.properties @@ -0,0 +1,108 @@ +############################################################################### +# Module : Ant Build Script +# Author : Rohtash Lakra (rohtash.lakra@devamatre.com) +# Author : Rohtash Singh Lakra (rohtash.singh@gmail.com) +# Created On : 2018-03-18 12:41:50 PM +# Updated On : 2018-03-18 12:41:50 PM +# Version : 1.0.0 +# Since : 1.0.0 +# Description : This script provides the required configuration to the build +# which can be modified based on the configuration settings of +# that project. +############################################################################### +# NOTES: - Pass in the following properties from the build script based on the +# selected target: - +#------------------------------------------------------------------------------ +# TARGET(s):- +# -all +# -clean +# -compile +# -build +# -deploy +# -distribute +# +# Internal Properties: - +# -basedir=. sets the base (root) directory of the project. The default +# base directory is the current directory represented by dot (.). +# -base.dir - Current directory where build.xml exists. +# -project.name - The name of the project that is being built. This +# value should be a unique. If you are generating multiple copies of +# war files, this parameter should be passed, with additional unique +# values, to each subsequent build.war, deploy.war, build.jar Ant +# invocations. +# -deploy.dir - where the local build will be deployed. At present there +# is no use but can be used in future releases. +# -server.home - The root folder path of Web/Application Server. +# -server.default.deploy.dir - where the final build will be deployed. +# +# Java Compiler Settings: - The following are the java specific properites +# which helps the javac compiler while compiling the .java source +# files. +# -javac.fork - sets javac.fork attribute to true runs javac in a +# separate process with its own heap size settings. If fork is set to +# false, or not set (default is false), javac will run in the same +# process as Ant, which has a default maximum heap size of 64m. +# -javac.optimize - sets the optimization property of javac compiler. +# -javac.debug - enable or disable debug settings of java compiler. +# -javac.debug.level - sets the level of debugging of java compiler. +# -javac.listfiles - if set to be true, prints the list of files +# otherwise not. +# -javac.source - sets the mininum source JRE version of which the code +# is compatible with (means required to compile this version). +# -javac.target - sets the mininum target JRE version of which the code +# is compatible with (means required to run this version). +############################################################################### +# The default basedir=. (current dir) +basedir=. + +############################################################################### +# set fork attribute to true, to run javac in a separate process with its own +# heap size settings. If fork is set to false, or not set (default is false), +# javac will run in the same process as Ant, which has a default maximum heap +# size of 64m. +############################################################################### +javac.fork=true + +############################################################################### +# javac debug and optimization properties. +############################################################################### +javac.optimize=false +javac.debug=on +javac.debug.level=lines,vars,source +javac.listfiles=false + +############################################################################### +# The minimum source and target JRE versions of which the code is compatible +# (means required to run this application). +############################################################################### +javac.source=1.5 +javac.target=1.5 + +############################################################################### +# ant debubugging properties +############################################################################### +ant.verbose=true +ant.quiet=true + +############################################################################### +# The following are the Apache Ant specific details which are used while +# creating the .jar/.war file. These details are related to the Owner and +# Company Information (Vender Details) of the software. +# +# This section also gives the details of production directory/folder where +# the build(s) .jar/.war files are created. The default production folder +# is considered the base (root) directory of the project. +# +# These details help to know the owner of the software and license details. +############################################################################### +sealed=true +built-by=Rohtash Singh Lakra +impl-vendor=Rohtash Singh Lakra +impl-vendor-id=RSLakra +impl-version=1.0.0 +# specification details are same as the verdor details, so don't give separately. + +#deploy.dir=${basedir}/deploy-v${impl-version} +deploy.dir=${basedir}/release-v${impl-version} + +############################################################################### \ No newline at end of file diff --git a/build.xml b/build.xml new file mode 100755 index 0000000..3b3dc03 --- /dev/null +++ b/build.xml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+
+
+ + + + + + + + + +
+ +
\ No newline at end of file diff --git a/1.x/compatibility/bee.xml b/compatibility/bee.xml similarity index 100% rename from 1.x/compatibility/bee.xml rename to compatibility/bee.xml diff --git a/1.x/compatibility/env.xml b/compatibility/env.xml old mode 100644 new mode 100755 similarity index 89% rename from 1.x/compatibility/env.xml rename to compatibility/env.xml index 89bf75a..99ce2d1 --- a/1.x/compatibility/env.xml +++ b/compatibility/env.xml @@ -29,16 +29,16 @@ - 1.5 + 1.8 - \\jre + /jre - C:\Projects\tjws\webapps + ./builds/webapps diff --git a/compatibility/src/javax/servlet/HttpConstraintElement.java b/compatibility/src/javax/servlet/HttpConstraintElement.java new file mode 100755 index 0000000..1efc2b7 --- /dev/null +++ b/compatibility/src/javax/servlet/HttpConstraintElement.java @@ -0,0 +1,158 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.servlet; + +import javax.servlet.annotation.HttpConstraint; +import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; +import javax.servlet.annotation.ServletSecurity.TransportGuarantee; + +/** + * Java Class representation of an {@link HttpConstraint} annotation value. + * + * @since Servlet 3.0 + */ +public class HttpConstraintElement { + + private EmptyRoleSemantic emptyRoleSemantic; + private TransportGuarantee transportGuarantee; + private String[] rolesAllowed; + + /** + * Constructs a default HTTP constraint element + */ + public HttpConstraintElement() { + this(EmptyRoleSemantic.PERMIT); + } + + /** + * Convenience constructor to establish EmptyRoleSemantic.DENY + * + * @param semantic + * should be EmptyRoleSemantic.DENY + */ + public HttpConstraintElement(EmptyRoleSemantic semantic) { + this(semantic, TransportGuarantee.NONE, new String[0]); + } + + /** + * Constructor to establish non-empty getRolesAllowed and/or + * TransportGuarantee.CONFIDENTIAL. + * + * @param guarantee + * TransportGuarantee.NONE or + * TransportGuarantee.CONFIDENTIAL + * @param roleNames + * the names of the roles that are to be + * allowed access + */ + public HttpConstraintElement(TransportGuarantee guarantee, String... roleNames) { + this(EmptyRoleSemantic.PERMIT, guarantee, roleNames); + } + + /** + * Constructor to establish all of getEmptyRoleSemantic, + * getRolesAllowed, and getTransportGuarantee. + * + * @param semantic + * EmptyRoleSemantic.DENY or + * EmptyRoleSemantic.PERMIT + * @param guarantee + * TransportGuarantee.NONE or + * TransportGuarantee.CONFIDENTIAL + * @param roleNames the names of the roles that are to be allowed + * access, or missing if the semantic is EmptyRoleSemantic.DENY + */ + public HttpConstraintElement(EmptyRoleSemantic semantic, TransportGuarantee guarantee, String... roleNames) { + if (semantic == EmptyRoleSemantic.DENY && roleNames.length > 0) { + throw new IllegalArgumentException("Deny semantic with rolesAllowed"); + } + this.emptyRoleSemantic = semantic; + this.transportGuarantee = guarantee; + this.rolesAllowed = roleNames; + } + + /** + * Gets the default authorization semantic. + * + *

+ * This value is insignificant when getRolesAllowed + * returns a non-empty array, and should not be specified when a + * non-empty array is specified for getRolesAllowed. + * + * @return the {@link EmptyRoleSemantic} to be applied when + * getRolesAllowed returns an empty (that is, zero-length) + * array + */ + public EmptyRoleSemantic getEmptyRoleSemantic() { + return this.emptyRoleSemantic; + } + + /** + * Gets the data protection requirement (i.e., whether or not SSL/TLS is + * required) that must be satisfied by the transport connection. + * + * @return the {@link TransportGuarantee} indicating the data + * protection that must be provided by the connection + */ + public TransportGuarantee getTransportGuarantee() { + return this.transportGuarantee; + } + + /** + * Gets the names of the authorized roles. + * + *

+ * Duplicate role names appearing in getRolesAllowed are insignificant + * and may be discarded. The String "*" has no special meaning + * as a role name (should it occur in getRolesAllowed). + * + * @return a (possibly empty) array of role names. When the + * array is empty, its meaning depends on the value of + * {@link #getEmptyRoleSemantic}. If its value is DENY, + * and getRolesAllowed returns an empty array, + * access is to be denied independent of authentication state and + * identity. Conversely, if its value is PERMIT, it + * indicates that access is to be allowed independent of + * authentication + * state and identity. When the array contains the names of one or + * more roles, it indicates that access is contingent on membership + * in at + * least one of the named roles (independent of the value of + * {@link #getEmptyRoleSemantic}). + */ + public String[] getRolesAllowed() { + return this.rolesAllowed; + } +} diff --git a/1.x/compatibility/src/javax/servlet/HttpMethodConstraintElement.java b/compatibility/src/javax/servlet/HttpMethodConstraintElement.java old mode 100644 new mode 100755 similarity index 51% rename from 1.x/compatibility/src/javax/servlet/HttpMethodConstraintElement.java rename to compatibility/src/javax/servlet/HttpMethodConstraintElement.java index 52640ff..7ed63e7 --- a/1.x/compatibility/src/javax/servlet/HttpMethodConstraintElement.java +++ b/compatibility/src/javax/servlet/HttpMethodConstraintElement.java @@ -1,38 +1,32 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific + * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. - * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. - * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. - * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" - * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a + * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code + * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. @@ -48,51 +42,51 @@ * @since Servlet 3.0 */ public class HttpMethodConstraintElement extends HttpConstraintElement { - - private String methodName; - - /** - * Constructs an instance with default {@link HttpConstraintElement} - * value. - * - * @param methodName the name of an HTTP protocol method. The name must - * not be null, or the empty string, and must be a legitimate HTTP - * Method name as defined by RFC 2616 - */ - public HttpMethodConstraintElement(String methodName) { - if (methodName == null || methodName.length() == 0) { - throw new IllegalArgumentException("invalid HTTP method name"); - } - this.methodName = methodName; - } - /** - * Constructs an instance with specified {@link HttpConstraintElement} - * value. - * - * @param methodName the name of an HTTP protocol method. The name must - * not be null, or the empty string, and must be a legitimate HTTP - * Method name as defined by RFC 2616 - * - * @param constraint the HTTPconstraintElement value to assign to the - * named HTTP method - */ - public HttpMethodConstraintElement(String methodName, - HttpConstraintElement constraint) { - super(constraint.getEmptyRoleSemantic(), - constraint.getTransportGuarantee(), - constraint.getRolesAllowed()); - if (methodName == null || methodName.length() == 0) { - throw new IllegalArgumentException("invalid HTTP method name"); - } - this.methodName = methodName; - } - - /** - * Gets the HTTP method name. - * - * @return the Http method name - */ - public String getMethodName() { - return this.methodName; - } + + private String methodName; + + /** + * Constructs an instance with default {@link HttpConstraintElement} + * value. + * + * @param methodName the name of an HTTP protocol method. The name must + * not be null, or the empty string, and must be a legitimate + * HTTP + * Method name as defined by RFC 2616 + */ + public HttpMethodConstraintElement(String methodName) { + if(methodName == null || methodName.length() == 0) { + throw new IllegalArgumentException("invalid HTTP method name"); + } + this.methodName = methodName; + } + + /** + * Constructs an instance with specified {@link HttpConstraintElement} + * value. + * + * @param methodName the name of an HTTP protocol method. The name must + * not be null, or the empty string, and must be a legitimate + * HTTP + * Method name as defined by RFC 2616 + * + * @param constraint the HTTPconstraintElement value to assign to the + * named HTTP method + */ + public HttpMethodConstraintElement(String methodName, HttpConstraintElement constraint) { + super(constraint.getEmptyRoleSemantic(), constraint.getTransportGuarantee(), constraint.getRolesAllowed()); + if(methodName == null || methodName.length() == 0) { + throw new IllegalArgumentException("invalid HTTP method name"); + } + this.methodName = methodName; + } + + /** + * Gets the HTTP method name. + * + * @return the Http method name + */ + public String getMethodName() { + return this.methodName; + } } diff --git a/compatibility/src/javax/servlet/MultipartConfigElement.java b/compatibility/src/javax/servlet/MultipartConfigElement.java new file mode 100755 index 0000000..e4970dc --- /dev/null +++ b/compatibility/src/javax/servlet/MultipartConfigElement.java @@ -0,0 +1,135 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.servlet; + +import javax.servlet.annotation.MultipartConfig; + +/** + * Java Class represntation of an {@link MultipartConfig} annotation value. + * + * @since Servlet 3.0 + */ +public class MultipartConfigElement { + + private String location; + private long maxFileSize; + private long maxRequestSize; + private int fileSizeThreshold; + + /** + * Constructs an instance with defaults for all but location. + * + * @param location defualts to "" if values is null. + */ + public MultipartConfigElement(String location) { + if(location == null) { + this.location = ""; + } else { + this.location = location; + } + this.maxFileSize = -1L; + this.maxRequestSize = -1L; + this.fileSizeThreshold = 0; + } + + /** + * Constructs an instance with all values specified. + * + * @param location the directory location where files will be stored + * @param maxFileSize the maximum size allowed for uploaded files + * @param maxRequestSize the maximum size allowed for + * multipart/form-data requests + * @param fileSizeThreshold the size threshold after which files will + * be written to disk + */ + public MultipartConfigElement(String location, long maxFileSize, long maxRequestSize, int fileSizeThreshold) { + if(location == null) { + this.location = ""; + } else { + this.location = location; + } + this.maxFileSize = maxFileSize; + this.maxRequestSize = maxRequestSize; + this.fileSizeThreshold = fileSizeThreshold; + } + + /** + * Constructs an instance from a {@link MultipartConfig} annotation value. + * + * @param annotation the annotation value + */ + public MultipartConfigElement(MultipartConfig annotation) { + this.location = annotation.location(); + this.fileSizeThreshold = annotation.fileSizeThreshold(); + this.maxFileSize = annotation.maxFileSize(); + this.maxRequestSize = annotation.maxRequestSize(); + } + + /** + * Gets the directory location where files will be stored. + * + * @return the directory location where files will be stored + */ + public String getLocation() { + return this.location; + } + + /** + * Gets the maximum size allowed for uploaded files. + * + * @return the maximum size allowed for uploaded files + */ + public long getMaxFileSize() { + return this.maxFileSize; + } + + /** + * Gets the maximum size allowed for multipart/form-data requests. + * + * @return the maximum size allowed for multipart/form-data requests + */ + public long getMaxRequestSize() { + return this.maxRequestSize; + } + + /** + * Gets the size threshold after which files will be written to disk. + * + * @return the size threshold after which files will be written to disk + */ + public int getFileSizeThreshold() { + return this.fileSizeThreshold; + } +} diff --git a/compatibility/src/javax/servlet/Registration.java b/compatibility/src/javax/servlet/Registration.java new file mode 100755 index 0000000..5dffbe9 --- /dev/null +++ b/compatibility/src/javax/servlet/Registration.java @@ -0,0 +1,183 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.servlet; + +import java.util.Map; +import java.util.Set; + +/** + * Interface through which a {@link Servlet} or {@link Filter} may be + * further configured. + * + *

+ * A Registration object whose {@link #getClassName} method returns null + * is considered preliminary. Servlets and Filters whose implementation + * class is container implementation specific may be declared without + * any servlet-class or filter-class elements, respectively, + * and will be represented as preliminary Registration objects. + * Preliminary registrations must be completed by calling one of the + * addServlet or addFilter methods on + * {@link ServletContext}, and passing in the Servlet or Filter name + * (obtained via {@link #getName}) along with the supporting Servlet or Filter + * implementation class name, Class object, or instance, respectively. + * In most cases, preliminary registrations will be completed by an + * appropriate, container-provided {@link ServletContainerInitializer}. + * + * @since Servlet 3.0 + */ +public interface Registration { + + /** + * Gets the name of the Servlet or Filter that is represented by this + * Registration. + * + * @return the name of the Servlet or Filter that is represented by this + * Registration + */ + public String getName(); + + /** + * Gets the fully qualified class name of the Servlet or Filter that + * is represented by this Registration. + * + * @return the fully qualified class name of the Servlet or Filter + * that is represented by this Registration, or null if this + * Registration is preliminary + */ + public String getClassName(); + + /** + * Sets the initialization parameter with the given name and value + * on the Servlet or Filter that is represented by this Registration. + * + * @param name the initialization parameter name + * @param value the initialization parameter value + * + * @return true if the update was successful, i.e., an initialization + * parameter with the given name did not already exist for the + * Servlet + * or Filter represented by this Registration, and false otherwise + * + * @throws IllegalStateException if the ServletContext from which this + * Registration was obtained has already been initialized + * @throws IllegalArgumentException if the given name or value is + * null + */ + public boolean setInitParameter(String name, String value); + + /** + * Gets the value of the initialization parameter with the given name + * that will be used to initialize the Servlet or Filter represented + * by this Registration object. + * + * @param name the name of the initialization parameter whose value is + * requested + * + * @return the value of the initialization parameter with the given + * name, or null if no initialization parameter with the + * given + * name exists + */ + public String getInitParameter(String name); + + /** + * Sets the given initialization parameters on the Servlet or Filter + * that is represented by this Registration. + * + *

+ * The given map of initialization parameters is processed + * by-value, i.e., for each initialization parameter contained + * in the map, this method calls {@link #setInitParameter(String,String)}. + * If that method would return false for any of the + * initialization parameters in the given map, no updates will be + * performed, and false will be returned. Likewise, if the map contains + * an initialization parameter with a null name or value, no + * updates will be performed, and an IllegalArgumentException will be + * thrown. + * + * @param initParameters the initialization parameters + * + * @return the (possibly empty) Set of initialization parameter names + * that are in conflict + * + * @throws IllegalStateException if the ServletContext from which this + * Registration was obtained has already been initialized + * @throws IllegalArgumentException if the given map contains an + * initialization parameter with a null name or value + */ + public Set setInitParameters(Map initParameters); + + /** + * Gets an immutable (and possibly empty) Map containing the + * currently available initialization parameters that will be used to + * initialize the Servlet or Filter represented by this Registration + * object. + * + * @return Map containing the currently available initialization + * parameters that will be used to initialize the Servlet or Filter + * represented by this Registration object + */ + public Map getInitParameters(); + + /** + * Interface through which a {@link Servlet} or {@link Filter} registered + * via one of the addServlet or addFilter methods, + * respectively, on {@link ServletContext} may be further configured. + */ + interface Dynamic extends Registration { + + /** + * Configures the Servlet or Filter represented by this dynamic + * Registration as supporting asynchronous operations or not. + * + *

+ * By default, servlet and filters do not support asynchronous + * operations. + * + *

+ * A call to this method overrides any previous setting. + * + * @param isAsyncSupported true if the Servlet or Filter represented + * by this dynamic Registration supports asynchronous + * operations, + * false otherwise + * + * @throws IllegalStateException if the ServletContext from which + * this dynamic Registration was obtained has already been + * initialized + */ + public void setAsyncSupported(boolean isAsyncSupported); + } +} diff --git a/compatibility/src/javax/servlet/ServletRegistration.java b/compatibility/src/javax/servlet/ServletRegistration.java new file mode 100755 index 0000000..15e46ba --- /dev/null +++ b/compatibility/src/javax/servlet/ServletRegistration.java @@ -0,0 +1,222 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.servlet; + +import java.util.*; + +/** + * Interface through which a {@link Servlet} may be further configured. + * + * @since Servlet 3.0 + */ +public interface ServletRegistration extends Registration { + + /** + * Adds a servlet mapping with the given URL patterns for the Servlet + * represented by this ServletRegistration. + * + *

+ * If any of the specified URL patterns are already mapped to a + * different Servlet, no updates will be performed. + * + *

+ * If this method is called multiple times, each successive call + * adds to the effects of the former. + * + * @param urlPatterns the URL patterns of the servlet mapping + * + * @return the (possibly empty) Set of URL patterns that are already + * mapped to a different Servlet + * + * @throws IllegalArgumentException if urlPatterns is null + * or empty + * @throws IllegalStateException if the ServletContext from which this + * ServletRegistration was obtained has already been initialized + */ + public Set addMapping(String... urlPatterns); + + /** + * Gets the currently available mappings of the + * Servlet represented by this ServletRegistration. + * + *

+ * If permitted, any changes to the returned Collection must + * not + * affect this ServletRegistration. + * + * @return a (possibly empty) Collection of the currently + * available mappings of the Servlet represented by this + * ServletRegistration + */ + public Collection getMappings(); + + /** + * Gets the name of the runAs role of the Servlet represented by this + * ServletRegistration. + * + * @return the name of the runAs role, or null if the Servlet is + * configured to run as its caller + */ + public String getRunAsRole(); + + /** + * Interface through which a {@link Servlet} registered via one of the + * addServlet methods on {@link ServletContext} may be further + * configured. + */ + interface Dynamic extends ServletRegistration, Registration.Dynamic { + + /** + * Sets the loadOnStartup priority on the Servlet + * represented by this dynamic ServletRegistration. + * + *

+ * A loadOnStartup value of greater than or equal to + * zero indicates to the container the initialization priority of + * the Servlet. In this case, the container must instantiate and + * initialize the Servlet during the initialization phase of the + * ServletContext, that is, after it has invoked all of the + * ServletContextListener objects configured for the ServletContext + * at their {@link ServletContextListener#contextInitialized} + * method. + * + *

+ * If loadOnStartup is a negative integer, the container + * is free to instantiate and initialize the Servlet lazily. + * + *

+ * The default value for loadOnStartup is -1. + * + *

+ * A call to this method overrides any previous setting. + * + * @param loadOnStartup the initialization priority of the Servlet + * + * @throws IllegalStateException if the ServletContext from which + * this ServletRegistration was obtained has already been + * initialized + */ + public void setLoadOnStartup(int loadOnStartup); + + /** + * Sets the {@link ServletSecurityElement} to be applied to the + * mappings defined for this ServletRegistration. + * + *

+ * This method applies to all mappings added to this + * ServletRegistration up until the point that the + * ServletContext from which it was obtained has been + * initialized. + * + *

+ * If a URL pattern of this ServletRegistration is an exact target + * of a security-constraint that was established via + * the portable deployment descriptor, then this method does not + * change the security-constraint for that pattern, + * and the pattern will be included in the return value. + * + *

+ * If a URL pattern of this ServletRegistration is an exact + * target of a security constraint that was established via the + * {@link javax.servlet.annotation.ServletSecurity} annotation + * or a previous call to this method, then this method replaces + * the security constraint for that pattern. + * + *

+ * If a URL pattern of this ServletRegistration is neither the + * exact target of a security constraint that was established via + * the {@link javax.servlet.annotation.ServletSecurity} annotation + * or a previous call to this method, nor the exact target of a + * security-constraint in the portable deployment + * descriptor, then this method establishes the security constraint + * for that pattern from the argument + * ServletSecurityElement. + * + * @param constraint the {@link ServletSecurityElement} to be applied + * to the patterns mapped to this ServletRegistration + * + * @return the (possibly empty) Set of URL patterns that were already + * the exact target of a security-constraint that + * was + * established via the portable deployment descriptor. This + * method + * has no effect on the patterns included in the returned set + * + * @throws IllegalArgumentException if constraint is null + * + * @throws IllegalStateException if the {@link ServletContext} from + * which this ServletRegistration was obtained + * has + * already been initialized + */ + public Set setServletSecurity(ServletSecurityElement constraint); + + /** + * Sets the {@link MultipartConfigElement} to be applied to the + * mappings defined for this ServletRegistration. If this + * method is called multiple times, each successive call overrides the + * effects of the former. + * + * @param multipartConfig the {@link MultipartConfigElement} to be + * applied to the patterns mapped to the registration + * + * @throws IllegalArgumentException if multipartConfig is + * null + * + * @throws IllegalStateException if the {@link ServletContext} from + * which this ServletRegistration was obtained has already + * been + * initialized + */ + public void setMultipartConfig(MultipartConfigElement multipartConfig); + + /** + * Sets the name of the runAs role for this + * ServletRegistration. + * + * @param roleName the name of the runAs role + * + * @throws IllegalArgumentException if roleName is null + * + * @throws IllegalStateException if the {@link ServletContext} from + * which this ServletRegistration was obtained has already + * been + * initialized + */ + public void setRunAsRole(String roleName); + + } + +} diff --git a/compatibility/src/javax/servlet/ServletSecurityElement.java b/compatibility/src/javax/servlet/ServletSecurityElement.java new file mode 100755 index 0000000..57f0d21 --- /dev/null +++ b/compatibility/src/javax/servlet/ServletSecurityElement.java @@ -0,0 +1,183 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.servlet; + +import java.util.*; +import javax.servlet.annotation.HttpMethodConstraint; +import javax.servlet.annotation.ServletSecurity; + +/** + * Java Class represntation of a {@link ServletSecurity} annotation value. + * + * @since Servlet 3.0 + */ +public class ServletSecurityElement extends HttpConstraintElement { + + private Collection methodNames; + private Collection methodConstraints; + + /** + * Constructs an instance using the default + * HttpConstraintElement value as the default Constraint + * element and with no HTTP Method specific constraint elements. + */ + public ServletSecurityElement() { + methodConstraints = new HashSet(); + methodNames = Collections.emptySet(); + } + + /** + * Constructs an instance with a default Constraint element + * and with no HTTP Method specific constraint elements. + * + * @param constraint the HttpConstraintElement to be + * applied to all HTTP methods other than those represented in + * the + * methodConstraints + */ + public ServletSecurityElement(HttpConstraintElement constraint) { + super(constraint.getEmptyRoleSemantic(), constraint.getTransportGuarantee(), constraint.getRolesAllowed()); + methodConstraints = new HashSet(); + methodNames = Collections.emptySet(); + } + + /** + * Constructs an instance using the default + * HttpConstraintElement value as the default Constraint + * element and with a collection of HTTP Method specific constraint + * elements. + * + * @param methodConstraints the collection of HTTP method specific + * constraint elements + * + * @throws IllegalArgumentException if duplicate method names are + * detected + */ + public ServletSecurityElement(Collection methodConstraints) { + this.methodConstraints = (methodConstraints == null ? new HashSet() : methodConstraints); + methodNames = checkMethodNames(this.methodConstraints); + } + + /** + * Constructs an instance with a default Constraint element + * and with a collection of HTTP Method specific constraint elements. + * + * @param constraint the HttpConstraintElement to be + * applied to all HTTP methods other than those represented in + * the + * methodConstraints + * @param methodConstraints the collection of HTTP method specific + * constraint elements. + * + * @throws IllegalArgumentException if duplicate method names are + * detected + */ + public ServletSecurityElement(HttpConstraintElement constraint, Collection methodConstraints) { + super(constraint.getEmptyRoleSemantic(), constraint.getTransportGuarantee(), constraint.getRolesAllowed()); + this.methodConstraints = (methodConstraints == null ? new HashSet() : methodConstraints); + methodNames = checkMethodNames(this.methodConstraints); + } + + /** + * Constructs an instance from a {@link ServletSecurity} annotation value. + * + * @param annotation the annotation value + * + * @throws IllegalArgumentException if duplicate method names are + * detected + */ + public ServletSecurityElement(ServletSecurity annotation) { + super(annotation.value().value(), annotation.value().transportGuarantee(), annotation.value().rolesAllowed()); + this.methodConstraints = new HashSet(); + for(HttpMethodConstraint constraint : annotation.httpMethodConstraints()) { + this.methodConstraints.add(new HttpMethodConstraintElement(constraint.value(), new HttpConstraintElement(constraint.emptyRoleSemantic(), constraint.transportGuarantee(), constraint.rolesAllowed()))); + } + methodNames = checkMethodNames(this.methodConstraints); + } + + /** + * Gets the (possibly empty) collection of HTTP Method specific + * constraint elements. + * + *

+ * If permitted, any changes to the returned Collection must + * not + * affect this ServletSecurityElement. + * + * + * @return the (possibly empty) collection of HttpMethodConstraintElement + * objects + */ + public Collection getHttpMethodConstraints() { + return Collections.unmodifiableCollection(methodConstraints); + } + + /** + * Gets the set of HTTP method names named by the HttpMethodConstraints. + * + *

+ * If permitted, any changes to the returned Collection must + * not + * affect this ServletSecurityElement. + * + * + * + * @return the collection String method names + */ + public Collection getMethodNames() { + return Collections.unmodifiableCollection(methodNames); + } + + /** + * Checks for duplicate method names in methodConstraints. + * + * @param methodConstraints + * + * @retrun Set of method names + * + * @throws IllegalArgumentException if duplicate method names are + * detected + */ + private Collection checkMethodNames(Collection methodConstraints) { + Collection methodNames = new HashSet(); + for(HttpMethodConstraintElement methodConstraint : methodConstraints) { + String methodName = methodConstraint.getMethodName(); + if(!methodNames.add(methodName)) { + throw new IllegalArgumentException("Duplicate HTTP method name: " + methodName); + } + } + return methodNames; + } +} diff --git a/compatibility/src/javax/servlet/SessionCookieConfig.java b/compatibility/src/javax/servlet/SessionCookieConfig.java new file mode 100644 index 0000000..fb061f4 --- /dev/null +++ b/compatibility/src/javax/servlet/SessionCookieConfig.java @@ -0,0 +1,39 @@ +package javax.servlet; + +/** + * Please, don't remove this file. This file is copied from the 'servlet.jar' + * which is missing in + * 'servlet-2-3.jar' file. Just added this to avoid unwanted exception. + * + * @Author: Rohtash Singh Lakra + * Created On: 02/13/2018 12:27. + */ +public interface SessionCookieConfig { + public abstract void setName(String paramString); + + public abstract String getName(); + + public abstract void setDomain(String paramString); + + public abstract String getDomain(); + + public abstract void setPath(String paramString); + + public abstract String getPath(); + + public abstract void setComment(String paramString); + + public abstract String getComment(); + + public abstract void setHttpOnly(boolean paramBoolean); + + public abstract boolean isHttpOnly(); + + public abstract void setSecure(boolean paramBoolean); + + public abstract boolean isSecure(); + + public abstract void setMaxAge(int paramInt); + + public abstract int getMaxAge(); +} diff --git a/1.x/compatibility/src/javax/servlet/annotation/HttpConstraint.java b/compatibility/src/javax/servlet/annotation/HttpConstraint.java old mode 100644 new mode 100755 similarity index 50% rename from 1.x/compatibility/src/javax/servlet/annotation/HttpConstraint.java rename to compatibility/src/javax/servlet/annotation/HttpConstraint.java index b7aca56..afa1bbd --- a/1.x/compatibility/src/javax/servlet/annotation/HttpConstraint.java +++ b/compatibility/src/javax/servlet/annotation/HttpConstraint.java @@ -1,38 +1,32 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific + * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. - * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. - * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. - * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" - * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a + * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code + * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. @@ -57,47 +51,55 @@ @Documented @Retention(RetentionPolicy.RUNTIME) public @interface HttpConstraint { - - /** - * The default authorization semantic. - * This value is insignificant when rolesAllowed returns a - * non-empty array, and should not be specified when a non-empty - * array is specified for rolesAllowed. - * - * @return the {@link EmptyRoleSemantic} to be applied when - * rolesAllowed returns an empty (that is, zero-length) array. - */ - EmptyRoleSemantic value() default EmptyRoleSemantic.PERMIT; - - /** - * The data protection requirements (i.e., whether or not SSL/TLS is - * required) that must be satisfied by the connections on which requests - * arrive. - * - * @return the {@link TransportGuarantee} - * indicating the data protection that must be provided by the connection. - */ - TransportGuarantee transportGuarantee() default TransportGuarantee.NONE; - - /** - * The names of the authorized roles. - * - * Duplicate role names appearing in rolesAllowed are insignificant and - * may be discarded during runtime processing of the annotation. The String - * "*" has no special meaning as a role name (should it occur in - * rolesAllowed). - * - * @return an array of zero or more role names. When the array contains - * zero elements, its meaning depends on the EmptyRoleSemantic - * returned by the value method. If value returns - * DENY, and rolesAllowed returns a zero length array, - * access is to be denied independent of authentication state and identity. - * Conversely, if value returns PERMIT, it - * indicates that access is to be allowed independent of authentication - * state and identity. When the array contains the names of one or more - * roles, it indicates that access is contingent on membership in at - * least one of the named roles (independent of the - * EmptyRoleSemantic returned by the value method). - */ - String[] rolesAllowed() default {}; + + /** + * The default authorization semantic. + * This value is insignificant when rolesAllowed returns a + * non-empty array, and should not be specified when a non-empty + * array is specified for rolesAllowed. + * + * @return the {@link EmptyRoleSemantic} to be applied when + * rolesAllowed returns an empty (that is, zero-length) array. + */ + EmptyRoleSemantic value() default EmptyRoleSemantic.PERMIT; + + /** + * The data protection requirements (i.e., whether or not SSL/TLS is + * required) that must be satisfied by the connections on which requests + * arrive. + * + * @return the {@link TransportGuarantee} + * indicating the data protection that must be provided by the + * connection. + */ + TransportGuarantee transportGuarantee() default TransportGuarantee.NONE; + + /** + * The names of the authorized roles. + * + * Duplicate role names appearing in rolesAllowed are insignificant and + * may be discarded during runtime processing of the annotation. The String + * "*" has no special meaning as a role name (should it occur in + * rolesAllowed). + * + * @return an array of zero or more role names. When the array contains + * zero elements, its meaning depends on the + * EmptyRoleSemantic + * returned by the value method. If value + * returns + * DENY, and rolesAllowed returns a zero + * length array, + * access is to be denied independent of authentication state and + * identity. + * Conversely, if value returns PERMIT, it + * indicates that access is to be allowed independent of + * authentication + * state and identity. When the array contains the names of one or + * more + * roles, it indicates that access is contingent on membership in at + * least one of the named roles (independent of the + * EmptyRoleSemantic returned by the value + * method). + */ + String[] rolesAllowed() default {}; } diff --git a/compatibility/src/javax/servlet/annotation/HttpMethodConstraint.java b/compatibility/src/javax/servlet/annotation/HttpMethodConstraint.java new file mode 100755 index 0000000..bb493dd --- /dev/null +++ b/compatibility/src/javax/servlet/annotation/HttpMethodConstraint.java @@ -0,0 +1,111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.servlet.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; +import javax.servlet.annotation.ServletSecurity.TransportGuarantee; + +/** + * This annotation is used within the {@link ServletSecurity} annotation to + * represent security constraints on specific HTTP protocol messages. + * + * @since Servlet 3.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface HttpMethodConstraint { + + /** + * Http protocol method name + * + * @return the name of an HTTP protocol method. value + * may not be null, or the empty string, and must be a + * legitimate HTTP Method name as defined by RFC 2616. + */ + String value(); + + /** + * The default authorization semantic. + * This value is insignificant when rolesAllowed returns a + * non-empty array, and should not be specified when a non-empty + * array is specified for rolesAllowed. + * + * @return the {@link EmptyRoleSemantic} to be applied when + * rolesAllowed returns an empty (that is, zero-length) + * array. + */ + EmptyRoleSemantic emptyRoleSemantic() default EmptyRoleSemantic.PERMIT; + + /** + * The data protection requirements (i.e., whether or not SSL/TLS is + * required) that must be satisfied by the connections on which requests + * arrive. + * + * @return the {@link TransportGuarantee} + * indicating the data protection that must be provided by the + * connection. + */ + TransportGuarantee transportGuarantee() default TransportGuarantee.NONE; + + /** + * The names of the authorized roles. + * + * Duplicate role names appearing in rolesAllowed are insignificant and + * may be discarded during runtime processing of the annotation. The String + * "*" has no special meaning as a role name (should it occur in + * rolesAllowed). + * + * @return an array of zero or more role names. When the array contains + * zero elements, its meaning depends on the value returned by + * emptyRoleSemantic. If emptyRoleSemantic + * returns + * DENY, and rolesAllowed returns a zero + * length array, + * access is to be denied independent of authentication state and + * identity. + * Conversely, if emptyRoleSemantic returns + * PERMIT, it indicates that access is to be allowed + * independent of authentication state and identity. When the array + * contains the names of one or more roles, it indicates that access + * is + * contingent on membership in at least one of the named roles + * (independent + * of the value returned by emptyRoleSemantic). + */ + String[] rolesAllowed() default {}; +} diff --git a/1.x/compatibility/src/javax/servlet/annotation/MultipartConfig.java b/compatibility/src/javax/servlet/annotation/MultipartConfig.java old mode 100644 new mode 100755 similarity index 71% rename from 1.x/compatibility/src/javax/servlet/annotation/MultipartConfig.java rename to compatibility/src/javax/servlet/annotation/MultipartConfig.java index 69c0433..508a05e --- a/1.x/compatibility/src/javax/servlet/annotation/MultipartConfig.java +++ b/compatibility/src/javax/servlet/annotation/MultipartConfig.java @@ -1,38 +1,32 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific + * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. - * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. - * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. - * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" - * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a + * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code + * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. @@ -50,9 +44,10 @@ * class, indicating that instances of the Servlet expect requests * that conform to the multipart/form-data MIME type. * - *

Servlets annotated with MultipartConfig may retrieve the + *

+ * Servlets annotated with MultipartConfig may retrieve the * {@link javax.servlet.http.Part} components of a given - * multipart/form-data request by calling + * multipart/form-data request by calling * {@link javax.servlet.http.HttpServletRequest#getPart getPart} or * {@link javax.servlet.http.HttpServletRequest#getParts getParts}. */ @@ -60,29 +55,31 @@ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MultipartConfig { - - /** - * The directory location where files will be stored - */ - String location() default ""; - - /** - * The maximum size allowed for uploaded files. - * - *

The default is -1L, which means unlimited. - */ - long maxFileSize() default -1L; - - /** - * The maximum size allowed for multipart/form-data - * requests - * - *

The default is -1L, which means unlimited. - */ - long maxRequestSize() default -1L; - - /** - * The size threshold after which the file will be written to disk - */ - int fileSizeThreshold() default 0; + + /** + * The directory location where files will be stored + */ + String location() default ""; + + /** + * The maximum size allowed for uploaded files. + * + *

+ * The default is -1L, which means unlimited. + */ + long maxFileSize() default -1L; + + /** + * The maximum size allowed for multipart/form-data + * requests + * + *

+ * The default is -1L, which means unlimited. + */ + long maxRequestSize() default -1L; + + /** + * The size threshold after which the file will be written to disk + */ + int fileSizeThreshold() default 0; } diff --git a/1.x/compatibility/src/javax/servlet/annotation/ServletSecurity.java b/compatibility/src/javax/servlet/annotation/ServletSecurity.java old mode 100644 new mode 100755 similarity index 54% rename from 1.x/compatibility/src/javax/servlet/annotation/ServletSecurity.java rename to compatibility/src/javax/servlet/annotation/ServletSecurity.java index e40b7f9..fcaa237 --- a/1.x/compatibility/src/javax/servlet/annotation/ServletSecurity.java +++ b/compatibility/src/javax/servlet/annotation/ServletSecurity.java @@ -1,38 +1,32 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * * Copyright (c) 2008-2010 Oracle and/or its affiliates. All rights reserved. - * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific + * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. - * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. - * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. - * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" - * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a + * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code + * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. @@ -40,7 +34,6 @@ package javax.servlet.annotation; - import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -62,60 +55,62 @@ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ServletSecurity { - - /** - * Defines the access semantic to be applied to an empty rolesAllowed array. - */ - enum EmptyRoleSemantic { - /** - * access is to be permitted independent of authentication state and - * identity. - */ - PERMIT, - /** - * access is to be denied independent of authentication state and - * identity. - */ - DENY - } - - /** - * Defines the data protection requirements that must be satisfied by - * the transport - */ - enum TransportGuarantee { - /** - * no protection of user data must be performed by the transport. - */ - NONE, - /** - * All user data must be encrypted by the transport (typically - * using SSL/TLS). - */ - CONFIDENTIAL - } - - /** - * Get the {@link HttpConstraint} that defines the protection - * that is to be applied to all HTTP methods that are NOT represented in - * the array returned by httpMethodConstraints. - * - * @return a HttpConstraint object. - */ - HttpConstraint value() default @HttpConstraint; - - /** - * Get the HTTP method specific constraints. Each - * {@link HttpMethodConstraint} names an HTTP protocol method - * and defines the protection to be applied to it. - * - * @return an array of {@link HttpMethodConstraint} elements each - * defining the protection to be applied to one HTTP protocol method. For - * any HTTP method name, there must be at most one corresponding element in - * the returned array. If the returned array is of zero length, it indicates - * that no HTTP method specific constraints are defined. - */ - - - HttpMethodConstraint[] httpMethodConstraints() default {}; + + /** + * Defines the access semantic to be applied to an empty rolesAllowed array. + */ + enum EmptyRoleSemantic { + /** + * access is to be permitted independent of authentication state and + * identity. + */ + PERMIT, + /** + * access is to be denied independent of authentication state and + * identity. + */ + DENY + } + + /** + * Defines the data protection requirements that must be satisfied by + * the transport + */ + enum TransportGuarantee { + /** + * no protection of user data must be performed by the transport. + */ + NONE, + /** + * All user data must be encrypted by the transport (typically + * using SSL/TLS). + */ + CONFIDENTIAL + } + + /** + * Get the {@link HttpConstraint} that defines the protection + * that is to be applied to all HTTP methods that are NOT represented in + * the array returned by httpMethodConstraints. + * + * @return a HttpConstraint object. + */ + HttpConstraint value() default @HttpConstraint; + + /** + * Get the HTTP method specific constraints. Each + * {@link HttpMethodConstraint} names an HTTP protocol method + * and defines the protection to be applied to it. + * + * @return an array of {@link HttpMethodConstraint} elements each + * defining the protection to be applied to one HTTP protocol + * method. For + * any HTTP method name, there must be at most one corresponding + * element in + * the returned array. If the returned array is of zero length, it + * indicates + * that no HTTP method specific constraints are defined. + */ + + HttpMethodConstraint[] httpMethodConstraints() default {}; } diff --git a/dLog4j.properties b/dLog4j.properties new file mode 100755 index 0000000..7ca799c --- /dev/null +++ b/dLog4j.properties @@ -0,0 +1,76 @@ +######################################################################### # +# Log4J PatternLayouts Usage # +#------------------------------------------------------------------------ # +# %r : Time milliseconds since start # +# %t : Thread which request for log # +# %p : Priority level of message # +# %F : File Name # +# %L : Line number # +# %c : Logger category name # +# %m : Message # +# %n : New line # +# %d : Date time milliseconds # +#------------------------------------------------------------------------ # +######################################################################### # + +######################################################################### # +# Log4J Properties # +#------------------------------------------------------------------------ # +# Default Debug Status:false # +# log4j.debug=false # +# Default Logging Disable:fatal # +# log4j.disable=fatal # +# Default Logging Level:WARN # +# log4j.rootCategory=WARN # +# Default Root Loggers:ALL, devamatre, R0 # +# log4j.rootLogger=ALL, devamatre, R0 # +# # +# First Appender: Writes to Console # +# log4j.appender.devamatre=org.apache.log4j.ConsoleAppender # +# log4j.appender.devamatre.layout=org.apache.log4j.EnhancedPatternLayout # +# log4j.appender.devamatre.layout.ConversionPattern= # +# %r [%t] %-5p (%F:%L) %c - %m%n # +# log4j.appender.devamatre.layout.ConversionPattern= # +# %r [%t] %-5p [%-22.22c{1}:%L] - %m%n # +# # +# Second Appender: Writes to File # +# log4j.appender.RFA=org.apache.log4j.RollingFileAppender # +# log4j.appender.RRA.File=C:/Temp/dLogger.log # +# Control Maximum log file size # +# log4j.appender.RFA.MaxFileSize=2000KB # +# Archive log files (one backup file here) # +# log4j.appender.RFA.MaxBackupIndex=2 # +# log4j.appender.RFA.layout=org.apache.log4j.EnhancedPatternLayout # +# log4j.appender.RFA.layout.ConversionPattern=%r [%t] %-5p (%F:%L) %c - %m%n # +#------------------------------------------------------------------------ # +#log4j.debug=true +#log4j.disable=fatal +#log4j.rootCategory=INFO +#log4j.rootLogger=ALL, devamatre, RFA +log4j.rootLogger=DEBUG, devamatre + +#------------------------------------------------------------------------ # +# First Appender: Writes to Console # +#------------------------------------------------------------------------ # +log4j.appender.devamatre=org.apache.log4j.ConsoleAppender +log4j.appender.devamatre.layout=org.apache.log4j.EnhancedPatternLayout +#log4j.appender.devamatre.layout.ConversionPattern=%r [%t] %-5p [%-22.22c{1}](%L) - %m%n +log4j.appender.devamatre.layout.ConversionPattern=[%d{MM-dd-yyyy hh:mm:ss.S a}] %5p [%t] [%c{1}(%L)] - %m%n + +# Print only messages of level WARN or above in the package com.foo. +#log4j.logger. = DEBUG|INFO|OFF|WARN... +log4j.logger.com.devamatre.logger.dummy=WARN + +#------------------------------------------------------------------------ # +# Second Appender: Writes to File # +#------------------------------------------------------------------------ # +log4j.appender.RFA=org.apache.log4j.RollingFileAppender +log4j.appender.RFA.File=dCore.log +# Control Maximum log file size +log4j.appender.RFA.MaxFileSize=2000KB +# Archive log files (one backup file here) +log4j.appender.RFA.MaxBackupIndex=2 +log4j.appender.RFA.layout=org.apache.log4j.PatternLayout +log4j.appender.RFA.layout.ConversionPattern=[%d{MM-dd-yyyy hh:mm:ss a}] %5p [%t] [%c{1}(%L)] - %m%n +#------------------------------------------------------------------------ # +######################################################################### # \ No newline at end of file diff --git a/env.xml b/env.xml new file mode 100755 index 0000000..be006db --- /dev/null +++ b/env.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + : + + + + + + + + + /jre + + + + + + + + + +. + +changeme + + +1.8 + + +1.8 + + +yes + + +maven:javax.servlet:servlet-api:2.3 + + +maven:javax.servlet:javax.servlet-api:3.1.0 + +compatibility/build/compat-jsr315+.jar + + + + + + + + + + +maven:javax.websocket:javax.websocket-api:1.1 + + + + + + + + + + + + + +./lib/jasper.jar + + +./../jasper7/build +../../jasper7/java + + + +/Applications/Android/EclipseAndroidSDKs/platforms/android-23/android.jar + + +./lib/bcprov-jdk15-146.jar + + + + + + + + + /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home + + /jre/lib/rt.jar + + /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home + + /jre/lib/jsse.jar + + /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home + + /jre/lib/jce.jar + + + + + + ..\java_runtime\ + + /jre/lib/rt.jar + + ..\java_runtime\ + + /jre/lib/jsse.jar + + + + + +./lib/class-scanner.jar +./lib/FastClasspathScanner-v1.0.0.jar \ No newline at end of file diff --git a/1.x/html/arch-raspi-java8.html b/html/arch-raspi-java8.html similarity index 100% rename from 1.x/html/arch-raspi-java8.html rename to html/arch-raspi-java8.html diff --git a/1.x/html/atjeews.html b/html/atjeews.html similarity index 100% rename from 1.x/html/atjeews.html rename to html/atjeews.html diff --git a/1.x/html/atjeews.png b/html/atjeews.png similarity index 100% rename from 1.x/html/atjeews.png rename to html/atjeews.png diff --git a/1.x/html/cgi.html b/html/cgi.html similarity index 100% rename from 1.x/html/cgi.html rename to html/cgi.html diff --git a/1.x/html/jasper.html b/html/jasper.html similarity index 100% rename from 1.x/html/jasper.html rename to html/jasper.html diff --git a/html/readme.html b/html/readme.html new file mode 100755 index 0000000..045415e --- /dev/null +++ b/html/readme.html @@ -0,0 +1,1493 @@ + + + + + + +Tiny Java Web Server aka Miniature JWS + + + + + +

Tiny Java Web Server and Servlet Container

+ +

aka Miniature JWS

+

European quality software made in USA

+

+ (with Android SSL support) + +

+

+ Truth is ever to be found in simplicity, and not in the + multiplicity and confusion of things. +

+ + + + + + + + + +
Download7Bee
+
    +
  1. Introduction
  2. +
  3. Features
  4. +
  5. History
  6. +
  7. Competitors
  8. +
  9. Design
  10. +
  11. Configuration +
  12. +
  13. J2EE deployment
  14. +
  15. App server services (JNDI, + DataSource)
  16. +
  17. Embedded usage
  18. +
  19. Embeddable application
  20. +
  21. Mobile and appliance usage
  22. +
  23. Virtual hosting configuration
  24. +
  25. Proxied usage
  26. +
  27. Download
  28. +
  29. Build
  30. +
  31. Applications
  32. +
  33. VM
  34. +
  35. Support
  36. +
  37. Versions
  38. +
  39. Copyright
  40. +
  41. Contact
  42. +
+
Construction zone
+ +

Introduction

+

+ The Miniature Java Web Server is built as a servlet container with + HTTPD servlet providing standard Web server functionality. The server + is a small as in Java code as in a result byte code. General purpose + of the Web server is running and debugging servlets. However, it can + be used as a regular web server for sites with low to medium load. I + found also very convenient shipping a servlet based product packaging + with the server, so a user can start a product just after unwrapping. + You can try a web + site hosted on this server on a private Cloud. This web server also + works on PDA and smart phones as Android and Blackberry based, or on + Windows CE based when JVM installed. It gives additional flexibility + for your phone, since using WebFolder (WebBee web app) can simplify file synchronization + and provide control of your phone from web. +

+ + + + + +
+

Testimonies

+

+ Using tjws with WebServices as a "RMI"/RPC protocol, and + with HTTPS on
top, this is gold! Thanks! +

+

I've downloaded TJWS and it looks like exactly + what I"e;ve been looking for to use as a local web server to + generate a web application. +

+ I'm using the miniature java webserver on
my zaurus.
+ I wrote a few servlets for it and I'm very happy with how it + performs. +

TJWS was the only thing out there I found I + could use as a library, programmatically within unit tests. Thanks + for a great library. +

+

Features and Benefits

+
    +
  • About 100Kb footprint (TJWS is the smallest one, like 5 + times less than competitors LWS and + Jetty, more than twice less than Winstone) +
  • +
  • Very fast and reliable, it performs better than some C/C++ + based web servers, 10% faster than Apache 2.x
  • +
  • Can scale to thousands connections, clustering + configuration is about of development
  • +
  • A perfect solution for web interfaced applications
  • +
  • Standard J2EE servlet deployment for .war packaged + applications
  • +
  • Simple configuration, no hundreds of config parameters
  • +
  • Flexible JSP support
  • +
  • Limited JSS 3.0 support (JSR 315)
  • +
  • JSR 356 support (websocket). See release notes
  • +
  • Built for Java 7 with intelligent downgraded support for + Java 2
  • +
  • Runs on Android and Blackberry platforms out of the box
  • +
+

History

+

I was looking for a web server with sources to debug some + servlets at the end of 1998. One of my findings was ACME Java Web + Server. It was pretty good, but supported only JSS 1.x and JDK + 1.02. Since my servlets required a bit more, I have added support + for contemporary versions of JDK and JSDK. I just continued adding + more features and providing bug fixes after. The current version is + mostly compatible with the latest servlet container specification + (3.1) and offers also websocket support.

+ +

Competitors

+

Main competitors for TJWS are Winstone, LWS, and Jetty. TJWS can + successfully compete with more established and reputable servers as + Tomcat, Glassfish, and JBOSS. Main benefits of TJWS are simplicity and + tiny footprint.

+ +

Design

+

Modular design is used for TJWS. It gives a flexibility of + creation different configurations with exactly required features. A + heart of TJWS is a light weight servlet container. A set of predefined + servlets extends functionality of the container transferring it to a + web server or/and an application server. Predefined servlets can be + eliminated or redefined for extra flexibility.

+

+ +

+

+ Selecting or not J2EE deployment gives an extra flexibility in a final + size of a deployed application. Like for an embeddable or a mobile + application is possible to use Java Personal Profile 1.x compatible + servlet container module. For less critical in size deployment is + possible to use J2EE deployment module and JSP module. Originally + provided GNU JSP providers have been withdrawn from latest TJWS + version for keeping pure BSD license, however GNU JSP providers can be + reached in previous versions. I do not support them anyway. Only Jasper is currently supported as JSP provider. + However I separate it to avoid any licensing issues. Base module, and + J2EE deployment modules have sizes 110K, and 80K correspondingly. + Jasper's size is about 930K. (I am still looking for help to separate + Jasper on runtime and JSP parsing and compilation parts, it could be + beneficial for Android deployment.) App server services module adds + 46Kb. And finally websocket module adds 65Kb +

+ +

Configuration

+

Most of server configuration is based on command line arguments. + The arguments can be processed from a file as well. Additional + configuration values can be provided over files. J2EE deployed + application are configured based on standard web.xml deployment + descriptor.

+ +
Command line parameters
+

All command line parameters start with '-' (dash) and most of + them have a following value part. Here they are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pspecifies port number served by TJWS, default value + is 80 for non secure and 443 for secure configuration, for example + -p 8080
tspecifies name of throttles definition file. It + allows to reduce speed accessing to particular files and improve + overall performance of a server. An example of this file can look + like: + + + + +
+								
+# throttle file for tjws.sourceforge.net
+*               100000  # limit total web usage to 2/3 of our T1
+*.jpg|*.gif     50000   # limit images to 1/3 of our T1
+*.mpg           20000   # and movies to even less
+mediachest/*    20000   # MediaChest's pages are too popular
+							
+
sspecifies servlet properties file in old Sun's + legacy form. An example of this file can look like: + + + + +
+								servlet./app-bin/tree/*.code=rogatkin.servlet.Dispatcher
+servlet./app-bin/tree/*.initArgs=properties=src\javaarchitect\servlet\treeview.properties
+servlet./app-bin/chat/*.code=rogatkin.chatservlet.ChatServlet
+servlet./app-bin/chat/*.initArgs=properties=C:\\Projects\\ChatServlet\\chatservlet.properties
+servlet./app-bin/lunch.code=javaarchitect.servlet.mishka.Friday
+servlet./app-bin/lunch.initArgs=properties=src\javaarchitect\servlet\mishka.properties
+
+							
Here servlet. is just keyword. Next part is servlet + URL mapping and servlet name at the same time. Mapping notation was + changed since 1.93 to match servlet specification, so /* should be + added to old notation. Next part is dot (.) separator of servlet + class name, when code used, or init arguments comma + separated name=value pairs when initArgs is used. +
rspecifies realm file. A format of this file looks + like: + + + + +
+								realmname=path,user:password
+							
Path has similar notation as servlet mapping URL. +
aspecifies aliases definition file. Every line of + the file specifies one alias entry starting from keyword + from=webpath;dir=directory_in_filesysten_to_map, for example: + + + + +
+								from=/;dir=src\javaarchitect\servlet\tree\resource
+from=/pool;dir=data
+							
+
bbind address, if your machine has several IP + addresses, then you can specify which one to use
kbacklog size, by default 50, but can't be less than + 2
nohupserver doesn't expect any terminal window, can be + only killed to stop
cspecifies a web path of CGI + scripts directory +
eprovides session timeout in minutes and can be + negative. Negative value won't start session cleaning thread and + will use a persistent session cookie
mlimits max number of active sessions by a specified + value, can't be less than 10. Default value is no limitation
l[ar][f format_string]specifies to log accesses with optionally logged + user-agent and referer HTTP headers. When f + modifier specified a format string has to follow which is a valid + format string for java.text.MessageFormat class. Positions of + parameters are: + + + + +
+
    +
  1. IP
  2. +
  3. RFC 1413 identity
  4. +
  5. Remote user
  6. +
  7. Timestamp
  8. +
  9. Request method
  10. +
  11. Request Resource
  12. +
  13. Request Protocol
  14. +
  15. Result code
  16. +
  17. Bytes transferred to client
  18. +
  19. Local port
  20. +
  21. Referer (if requested)
  22. +
  23. User agent (if requested)
  24. +
+
+
grequests rolling log file after reaching parameter + specified line numbers. Can't be made less than 1000, and no rolling + used if not specified or parameter is 0. Since 1.102
wprovides web app deployer class name, by default + used rogatkin.web.WarRoller +
jJSP servlet class, org.gjt.jsp.JSPServlet + is default; extra init parameters can be specified for JSP servlet; + syntax of parameters is -class_name_perfix.param_name + param_value; note that value can contain variables like %context% + and %deploydir% substituted by actual values respectfully. Another + substitution happens for %classloader% by a name of a servlet + context attribute keeping an instance of a class loader used for a + web application deployment (available from version 1.15). Version + 1.22 and above introduced another variable %classpath% which + substituted by class path used for loading servlet +
nkano keep alive (server uses keep-alive by default)
katkeep alive timeout interval in seconds, default is + 30
mkamax number of a connection use in keep-alive
shHTTP only attribute for session + cookie. Can improve a security. A session cookie doesn't carry this + attribute by default. Since 1.90
ssSecure only attribute for session + cookie. Can improve a security. A session cookie doesn't carry this + attribute by default. Since 1.99
sppersistence for sessions, TJWS is + capable storing sessions data in a portable format and reload them + between restarts or nodes of a cluster. Do not use this option if + sessions contain sensitive, not serializable, or bulky data
errallows to use own or standard error print stream. + If there is no following parameter class name then used System.err + as error print stream. If a parameter specified, then it's + considered as a class name compatible for assignment to PrintStream. + Such class will be instantiated and used for error redirection +
outallows to define own class which will handle log + needs. This class has to be assignment compatible with PrintStream. + An attempt of instantiation of the class with default constructor + happens at TJWS startup, so the class has to be available in startup + class path. This class will handle err stream too unless -err + option is specified. TJWS includes class + Acme.Utils$DummyPrintStream for disabling any log printing. (since + 1.26) +
dLog file directory for default + logging, System.getProperty("user.dir") is used by + default (since 1.30) +
zdefines max number of created threads in a thread + pool used for servicing requests. 20 used when the parameter not + defined. 0 or negative - do not use thread pool
socketFactoryspecifies class name of socket factory and used for + setting a secure connection. (deprecated since 1.30) +

It accepts also any freely specified options in form + -option_name option_value. Such options passed without checking to + a custom server socket factory implementation and other modules of + the server +

acceptorImplspecifies a class name of a concerete Acceptor + implementation. Default is Acme.Serve.SimpleAcceptor (since 1.31). + See note above about processing additional connection parameters. + Since 1.30 +
dataSourcespecifies a data source properties file location. + Supported by rogatkin.app.Main run module. Since 1.30
This + option is valid only for app server runner (class rogatkin.app.Main)
+ TJWS .war deployer can process also context.xml file supplied in + META-INF directory of application .war for same purpose. Since 1.98. + A property file can contain the following properties: +
    +
  • jndi-name (required) - under this name the data + source will be registered in JNDI if name starts with jdbc, + then prefix java:comp/env/ will be added when registered in + JNDI. +
  • driver-class - class name of JDBC driver +
  • url - JDBC connection URL +
  • user - connection user +
  • password - connection password +
  • pool-size - max number of allocated connections, 0 + = no size limitation, -1 = no pool used +
  • access-timeout - timeout in ms before getting an + exception on connection request when no connections are available, + 0 means wait forever +
  • driver-class-path - defines class path to a driver + archive and/or a connection validator class, unless they are + already defined  in a boot classpath +
  • prob-query - a query to run against a given + connection to verify a validity, There are two predefined values IsValid + and isClosed used for calling corresponding methods of JDBC + connection instead of a query. Note that isValid() + method is available in JDBC 3. +
  • exception-handler- a class with static public boolean + method validate and two parameters of type SQLException, + and Connection returning false when the + connection has to be discarded after the SQLException +
Here is a quick map between properties names and context.xml + Resource tag attributes: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
jndi-namename
driver-classdriverClassName
urlurl
userusername
passwordpassword
pool-sizemaxActive
driver-class-pathdriverClassPath
prob-queryvalidationQuery
+
+

TJWS processes several Java System level definitions in addition + to command line arguments specified as JVM's -D arguments:

+

+ tjws.serve.log.encoding - this definition specifies + encoding used for log messages, it can be very convenient to debug + multi lingual web applications. +

+

+ tjws.proxy.ssl - this definition specifies that + server should process X-Forwarded-xxxx headers for calculation remote + and server addresses. If value of the property 'y', then SSL is + considered to be handled by a proxy server. (Since 1.71) +

+

+ java.protocol.handler.pkgs - this definition is used + by SSL socket factories implementations to define a different protocol + handler packages, than standard com.sun.net.ssl.internal.www.protocol +

+ +

The following definitions are used by J2EE servlet/deployer + module:

+

+ tjws.webappdir - specifies path to web application + war files location for automatic deployment. By default + TJWS_ROOT/webapps directory is used. +

+

+ tjws.webclassloader - specifies custom class loader + class name used for loading classes from war file. The class loader + must to have constructor accepting parameters as + URL[] + and + ClassLoader + . Since 1.83 +

+

+ tjws.wardeploy.warname-as-context - see details + below. +

+

+ tjws.wardeploy.as-root[.virtual_host_name] - + defines context name/war name used for deploying in root, e.g. -Dtjws.wardeploy.as-root=<app_context/war_name> + If virtual host name part is presented, then it defines a fully + qualified host name for which the root context is set. (Since 1.71) +

+ +

+ tjws.virtual - defines deployment of web applications + in virtual hosting environment.

When the definition is + specified, TJWS J2EE web applications deployer looks in all + subdirectories under automatic web application deployment directory + and considers directory name as virtual host name and directory + content as automatic web application deployment directory for + corresponding virtual host.

For example: +

+           TJWS_ROOT/webapps
+               www.travelspal.com
+                   travelspal.war
+                   webfolder.war
+               www.7bee.org
+                   sqlfair.war
+                   webchat.war
+               xumster.war
+               jaddressbook.war
+ +
+
(Since 1.71) +

+

+ class_name.debug - this definition is passed + to JSP provider for allowing debug specified class name. +

+

+ tjws.fileservlet.usecompression - this definition + advises to compress text content response when a client can accept it. + To make this suggestion per application, use tjws.webapp.<context_name>.compressresponse + Since 1.31 +

+

+ tjws.fileservlet.suppressindex this definition + advises the file servlet to do not show content of a directory when an + index file can't be found. Since 1.96 +

+

+ tjws.wardeploy.dynamically - this definition advises + J2EE deployer for monitoring .war files updates and redeploy + corresponding applications without the server restart. Optional value + of this definition specifies time interval in seconds between checks. + Since 1.50 +

+

+ tjws.wardeploy.noincremental - instructs TJWS + redeploy entire web application when newer version of .war detected. + Default is incremental deployment overriding only older files and not + touching added. Since 1.93 +

+

+ tjws.webapp.context name.init.timeout + - specifies init timeout in seconds of corresponding web application + by context name, use * if you need to define it for all contexts +

+

+ tjws.webapp.context name.threadpoolsets + - specifies core, max threads, and queue size a thread pool of + corresponding web application by context name, use * if you need to + define it for all contexts. Since 1.80 +

+

+ tjws.webapp.debug - value yes turns on additional + debug print outs for J2EE deployed apps +

+

+ tjws.app.orb.arguments - this definition can provide + comma separated parameters used for ORB initialization. Since 1.50 +

+

+ tjws.app.main - name of main class started with + offering app server services. TJWS supports not only web applications, + any desktop Java application can get benefits of app server services + as JNDI and container managed JDBC connections. Since 1.50 +

+

+ tjws.app.main.classpath - class path for main + application class specified as definition tjws.app.main, unless + the main class can be resolved from boot class path. Since 1.50 +

+

+ tjws.app.main.striprightparam - specifies a position + in command line arguments which have to be not passed to a main class + defined in tjws.app.main. It gives flexibility of separate + command line arguments used by launched application and app server + services itself. Since 1.50 +

+

+ tjws.app.main.stripleftparam specifies a position to + cut from left. See description of tjws.app.main.striprightparam. + Since 1.50 +

+

+ tjws.websocket.container "true" value specifies that + websocket end points can be deployed in scope of TJWS itself (not in + scanning from a .war packaged web application) TJWS class path is used + for such deployment. The option is useful for embedded usage of TJWS. + Since 1.111 +

+

Since TJWS has a long history it supports as a legacy way of + deployment and configuration of servlets as a new .war (web.xml) + based. The legacy deployment uses property files, like + servlets.properties and aliases.properties. J2EE way is based on + web.xml and config.xml files. When a legacy way used, the server can + keep a minimal configuration and run on JDK version started from 1.2 + (Actually the current version has 9 JDK 1.4 dependencies which can be + easily corrected if JDK 1.2 is a real requirement). Websocket + extension deployment uses the modern annotated classes mechanism.

+

+ Security +

+

Security becomes more important nowadays, so I decided to add + SSL support to TJWS. Thanks JSSE for making that fairly easy. Here + some tips how to install SSL support to the server.

+
    +
  • Download JSSE from Oracle's website or use JDK1.4.2 or + later already including this extension.
  • +
  • Generate certificate using command like: keytool + -genkey -keypass 123456 -storepass 123456 -keyalg RSA
    Read + more details in keytool documentation when you need a certificate + signed by CA. Tomcat's how-to + for SSL can be useful also. +
  • +
  • Add command line parameter -socketFactory + socket_factory_class_name and enjoy the show.
  • +
+

+ There are three SSL supporting socket factories packaged with TJWS - Acme.Serve.SSLServerSocketFactory + , rogatkin.web.DoubleHeadSocketFactory (available from v + 1.17), and rogatkin.wskt.SSLSelectorAcceptor (available from v + 1.110). First is recommended to use with core TJWS, when second with + J2EE deployment module since it provides supporting http and https at + the same time and requires Java 5+. Third is required for websocket + configuration. 7Bee script contains examples of usage two factories. + Command + bee -Dsecure=true + runs TJWS using SSLSelectorAcceptor, and + bee -Ddoublehead=true + runs DoubleHeadSocketFactory. Additional command line parameters can + be specified with each factory like : +

+
    +
  1. algorithm - encryption algorithm, SUNX509 when not + specified
  2. +
  3. clientAuth - requires client authentication, false + when not specified
  4. +
  5. keystoreFile - key store file path, + user_home/.keystore by default
  6. +
  7. keystorePass - key store password, empty string when + not specified
  8. +
  9. keystoreType - type of key store, Oracle's JKS when + not specified
  10. +
  11. protocol - secure protocol, TLS when not specified
  12. +
  13. backlog - backlog value, 1000 by default
  14. +
  15. ifAddress - bind to specified address
  16. +
  17. port - bind to specified port
  18. +
  19. ssl-port  SSL port (only for + DoubleHeadSocketFactory and rogatkin.web.DualSocketAcceptor )
  20. +
  21. ssl-backlog backlog size (only for + DoubleHeadSocketFactory and rogatkin.web.DualSocketAcceptor)
  22. +
+

+ Note that some secure + socket options will override options specified in a regular way. +

+

You may also adding your own socket factory implementations. See + the packaged socket factories as a reference implementation.

+

Starting from 1.30 Socket Factory concept was replaced by + Acceptor. It allowed to use Selector based processing requests with + 10% improved performance and required for websocket. Five concrete + Acceptor implementations are available:

+
    +
  • Acme.Serve.SelectorAcceptor - non secure, channel based + implementation (use with websocket in non blocking IO mode).
  • +
  • rogatkin.wskt.SSLSelectorAcceptor - secure, channel based + implementation (use with websocket in non blocking IO mode).
  • +
  • Acme.Serve.SimpleAcceptor - non secure, server socket based + implementation, is used by default.(since 1.31)
  • +
  • Acme.Serve.SSLAcceptor - secure, SSL socket based + implementation.
  • +
  • rogatkin.web.DualSocketAcceptor - combined secure and non + secure sockets implementation.
  • +
+

The author appreciates if you can share own implementations of + Acceptor.

+ +
J2EE deployment
+

+ For J2EE deployment you need to make sure that war.jar is specified in + classpath when you start the server. It will create webapps directory + (configured location) where you can put your .war files for auto + deployment. Deployment gets updated at startup absorbing any changes + from source .war file, however all changes done in target deployment + directory are preserved. TJWS can monitor also source .war changes + during runtime when tjws.wardeploy.dynamically is + specified, and redeploy application if changes were detected. server.xml + isn't supported and most of server specific parameters have to be + specified as command line arguments, or stored in a flat file as cmdparams. + All examples of startup scripts are presented in directory bin of a + distributive archive. Most of examples contain both ways of server + configuration and application deployment. Note that deployment + descriptor (web.xml) parameter display-name defines a + context path of a deployed web application. If you want to have + context path matching to .war name then add system property tjws.wardeploy.warname-as-context + set to yes. For command line it will look like + -Dtjws.wardeploy.warname-as-context=yes . (Since 1.24) To prevent + application update at startup time you need to remove corresponding + .war from deployment directory. It gives also a way to deploy web + applications without .war just manually create web app directory + structure. Check section 'Embeddable + application' for more options of deployment and distribution of + applications. +

+

Supported web.xml deployment tags are:

+
    +
  • context-param - yes
  • +
  • filter - yes
  • +
  • filter-mapping - yes
  • +
  • listener - yes
  • +
  • servlet - yes
  • +
  • servlet-mapping - yes
  • +
  • session-config - yes
  • +
  • mime-mapping - yes
  • +
  • welcome-file-list - yes
  • +
  • error-page - yes
  • +
  • taglib - by JSP provider
  • +
  • resource-env-ref - yes
  • +
  • resource-ref - yes
  • +
  • security-constraint - in work
  • +
  • login-config - in work
  • +
  • security-role - in work
  • +
  • env-entry - yes
  • +
  • ejb-ref - no
  • +
  • ejb-local-ref - no
  • +
  • new JSR315 - yes
  • +
  • new JSR356 - yes
  • +
  • multipart-form - this is non standard tag carries a function + of a casual multipart request processing similar to Resin. Since + 1.112
  • +
+ +

App server services

+

TJWS includes app server services module. It takes some usable + shape from version 1.50. There are two services offered:

+
    +
  • Data source with connection pooling +
  • JNDI +
+

+ For using these services app.jar has to be in class path, or/and used + for starting the server. The bin directory includes an example of + starting TJWS with app server services on. Data sources get configured + from properties files specified as �dataSource + command line option. JNDI properties as context factory and JNDI URL + get pre-populated as rogatkin.app.SimpleJndi and http://localhost:1221 correspondingly, unless + they are defined as system properties. JNDI is capable to register + local and CORBA objects. First running JNDI takes care of JNDI master + repository, and all following JNDI starts will be registered in the + master repository. If the master repository's gone, then all clients + won�t be capable to register own CORBA objects or access them, until + the repository is back. There is no persistence for stored references, + so you should do a defended programming and reregister references in + case of crashing the master repository. +

+
context.xml
+

Data source definition can be specified in context.xml placed + under META-INF directory of .war structure. (since 1.98)

+
3.0 Deployment descriptor
+

Multiple URL patterns can be defined anywhere. Some other + features are under consideration. Work on processing annotations in a + servlet code started. Async and multi part features are supported.

+ +
Jasper JSP provider integration
+

+ You can use Jasper JSP provider for servicing JSP pages inside an + application. Since the original Jasper is a bit bulky for TJWS taste, + it's recommended to strip it to a manageable size. TJWS distribution + includes instructions how to modify, build, and connect Jasper in jasper.html of webroot directory + Jasper of respectful Tomcat versions 5.x, 6.x (since 1.28), and 7.x + (since 1.83) is supported. +

+ +

Running it as a service on all Windows platforms

+

+ You can run the server of the version (>1.42/1.7) as Windows + service. File servservice.exe added to the distribution. I + wrote this service for JDK 1.4. It works without a change for Java 5 + and 6. C source code of service implementation is included. A service + starter considers that all TJWS files reside in the same directory + specified at installation of the service. .jar files can be in sub + directory lib. Command line parameters have to be specified in + cmdparams file. Use -nohup switch to avoid a console read + attempt. To get help line, run servservice.exe + -help. Parameterless version of servservice.exe is considered as a + service. +

+

+ Note that arg[0] which supposes to give a fully qualified name of a + service executable on some versions Windows ((like XP) doesn't do + that. For this reason you have to specify a fully qualified path as + the last parameter of an installation command. There is no + requirements to have servservice.exe in the same directory + where TJWS is. Here is an example of an installation command:
+ servservice.exe -install "C:\Project Files\tjws" + "C:\Project Files\gnujsp\lib\jspengine.jar" + TinyJavaWebServer TinyJavaWebServer "C:\Project + Files\tjws\servservice\Debug\servservice.exe" + -Dtjws.wardeploy.warname-as-context=yes +

+

Running it as a service on all Linux platforms

+

+ A Linux service script example tjwserv is provided in bin + directory of the distribution archive. It has to be edited to reflect + particular TJWS installation directory structure. The script has to be + stored in + /etc/init.d/ + location. Use command + update-rc.d tjwserv defaults + to enable the service. You can control it using command + service tjwserv <start|stop|restart> + . Look in Raspberry PI setup section for enabling service on Arch + Linux and other systems using systemd. +

+ + +

Embeddable application

+

+ Recently, a new type of application appeared on the market. After + starting an application is launching a browser which represents its + UI. This approach has many advantages and becomes more popular and + wider used. The Miniature Java Web Server is a right tool for creation + such kind of application. Download + and double click JAR in Explorer or launch it from a terminal typing + + java -jar + finesearch.jar + + , then point browser to http://localhost:8080/finesearch + and enjoy the web interfaced application. Starting from version 1.21 + TJWS includes a launcher of a .war packaged application from command + line or a start script. The feature is very similar to used by Winstone.  + Use:
+ java -jar webapplauncher.jar war_file_name [optional + standard TJWS CLI parameters] +
for example:
+ + java -jar webapplauncher.jar "C:\Project + Files\finesearch\finesearch_app\finesearch.war" + +
Note if extra command line arguments are not specified, then + TJWS will try to discover them from cmdparams located in a + working directory.
Version 1.22 and above makes launching Web + UI application even more simpler. Web application .war can be packaged + inside of TJWS .jar file allowing one click launch. To package web + application .war with TJWS use target 'embedded' of 7Bee + build tool and answer on few simple questions. For example: +

+ + + + + +
C:\Project Files\tjws>bee + embedded
Launcher's been built.
Enter command + line arguments for app [-nohup -p 80]? -p 80
Enter + application .war file location? C:\Project + Files\finesearch\finesearch_app\finesearch.war
+ As result finesearch.jar is created in lib directory which is + launchable using + java -jar finesearch.jar +
When JDK 6 is used you can get it running in system tray, use + javaw + for JAR launching. +
+ +
System tray menu will contain an item for going directly to + an application with web UI (since 1.24). +
Use 7Bee target + asembedded, when web application needs container provided JNDI + and data sources. (since 1.50). + +
J2EE without application server
+

+ TJWS gives a good possibility to create enterprise class J2EE + applications without an expensive and heavy weight application server. + WebBee library will take care of + SOA registry, MVC servlet framework with template based presentation + layer, data persistence and much more. Check out a demo of a real + application based on this approach. New generation of web application + building blocks WebBee with annotated JDO and forms makes creation of + rich application possible even for Android platform. +

+ +

Embedded usage

+

+ TJWS can be successfully used as a part of another Java application. + Acme.Serve.Serve can be instantiated as a Java bean with following + setting parameters in its public member arguments and log + print stream in its public member logStream. Use method addServlet(..) + for adding servlets. Note that server will do nothing without + servlets. Default file (HTTPD) and cgi servlets can be added calling addDefaultServlets(...). + Server can be started calling method serve() and + stopped calling notifyStop(). Note that serve() + doesn't exit until a server runs, so stopping should be called from a + separate thread, or serve() is ran in a separate thread.
A + minimal application with embedded TJWS looks like: +

+
public class Test {
+	public static void main(String... args) {
+		class MyServ extends Acme.Serve.Serve {
+			// Overriding method for public access
+                        public void setMappingTable(PathTreeDictionary mappingtable) { 
+                              super.setMappingTable(mappingtable);
+                        }
+                        // add the method below when .war deployment is needed
+                        public void addWarDeployer(String deployerFactory, String throttles) {
+                              super.addWarDeployer(deployerFactory, throttles);
+                        }
+                        public void addWebsocketProvider() { // add if plan to deploy websocket endpoints
+                            addWebsocketProvider(null); // list of class path file components can be provided here
+                        }
+
+                };
+
+		final MyServ srv = new MyServ();
+ 		// setting aliases, for an optional file servlet
+                Acme.Serve.Serve.PathTreeDictionary aliases = new Acme.Serve.Serve.PathTreeDictionary();
+                aliases.put("/*", new java.io.File("C:\\temp"));
+		//  note cast name will depend on the class name, since it is anonymous class
+                srv.setMappingTable(aliases);
+		// setting properties for the server, and exchangeable Acceptors
+		java.util.Properties properties = new java.util.Properties();
+		properties.put("port", 80);
+		properties.setProperty(Acme.Serve.Serve.ARG_NOHUP, "nohup");
+		properties.setProperty("acceptorImpl", "Acme.Serve.SelectorAcceptor"); // this acceptor is requireed for websocket support
+		srv.arguments = properties;
+		srv.addDefaultServlets(null); // optional file servlet
+		srv.addWebsocketProvider();  // enable websocket
+		srv.addServlet("/myservlet", new MyServlet()); // optional
+		// the pattern above is exact match, use /myservlet/* for mapping any path startting with /myservlet (Since 1.93)
+		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+			public void run() {
+				srv.notifyStop();
+				srv.destroyAllServlets();
+			}
+		}));
+		srv.serve();
+	}
+}
+ 
+

The File servlet without aliases definitions maps your file + system directly to a web accessable one, so setting up aliases is + recommended.

+ +

+ J2EE servlet deployment is possible in an embedded usage. You need to + assure that JDK 1.5 or above is used and war.jar is in a class path of + an application.
Add a line as below: +

+
+      ((Test$1)srv).addWarDeployer(null, null);
+
+

The default war deployer will look in directory + "user.dir/webapps" and deploy all wars there. You can redefine a + deploy repository by setting

+ System.setProperty("tjws.webappdir", newDeployDirectory); + +

prior of calling addWarDeployer()

+

+ TJWS works perfectly on Android platform as embedded server enriching + your Android application by a capability to receive uploads, check Kamerton application using TJWS for uploading + music to Android device. +

+ + +

Mobile and appliance usage

+ TJWS provenly runs on wide specter mobile devices as Sharp Zaurus, + Windows CE/Mobile, all Android, and Blackberry platforms. Java gives + great portability of TJWS between different mobile devices. +
Run it on Zaurus
+

Zaurus version is currently retired, since Zaurus has been + replaced by Android.

+
Run it on Windows Mobile
+

Since Microsoft dropped Java and allow to install only products + from mobile store on Windows surface tablets, here is no good + possibility to run TJWS. So here is a plan to create Objective C and + C++ library supporting core functionality of TJWS to be able to run it + on iOS and Windows Mobile platforms.

+
Run it on Raspberry Pi
+

TJWS is naturally created for running web applications on + Raspbery Pi. It will outperform most of other application servers on + the platfrom including Jetty, JBOSS and Tomcat. Start time for it is + just around 11 seconds, when you can observe times close to 1 minute + with other application servers. Here are few notes helping to start + using it:

+
    +
  • Debian "wheezy" is preferred as OS for Raspberry Pi and TJWS
  • +
  • Download Oracle JRE marked as Linux ARM + v6/v7 Hard Float ABI
  • +
  • If you use Linux "dd" utility on Ubuntu to transfer Debian + image to SD card, then keep it mounted and use device name as /dev/sdc + (last letter can be "b" for some systems) +
  • +
  • There is + a good resource for beatifying JRE installation +
  • +
+

+ If you plan to use Raspberry Pi mostly as server operating 24/7, then + I recommend to install Arch Linux especially if your network + connection is wireless. Since Arch Linux specific is less covered on + net, I prepared my own guide + which can help you start using TJWS faster.
Raspberry Pi + development is certainly addicting, so if you are on same boat feel + free to drop me a note. +

+
Run it on Android devices
+

+ TJWS provides Android packaging for run the server on Android devices. + This packaging got name Atjeews and provided as a + separate download. Atjeews is also available at Google Play under same + name. Atjeews is just a small server launcher Java program. The server + runs FileServlet against Android root directory "/". You can deploy + any web application on it just loading war files. Atjeews can be + mapped to any port and supports SSL. +

+   +
+ Since Android devices use Dalvik JVM, you need to convert all content + of WEB-INF/lib and class directories of your web application to DEX + format supported by Dalvik. Use DX tool for that. +
The following command will work: +
+ dx --dex --output=<original_jar_file> <dalvik(dex) + jar> +
Please note that your web application has to be JDK 1.5 + compatible since Android OS below version 3.0 supports only Java 1.5. + + 7Bee + script + (7Bee + version of 1.1.1 or + above required) is availble for converting war files to format + supported by Android platfrom. The script is highly recommended to use + when your web application includes JSP pages, since the script take + care of precompilation of JSP files and DEX converting. Atjeews is + bundled with Jasper to run JSP. See more about Atjeews + here. Since 1.83 +
Blackberry BAR Atjeews packaging added to version 1.95. It + supposes also appearing in RIM AppWorld as a + free application. +

+

Run it on iPhone?

+

There are several options to run Java applications on iPhone and + iPad. You will need to jail break your iPhone though. Since Steeve + isn't with Apple anymore, there is a good chance for porting Davlik to + iOS platfrom. I heard that iOS 9.0 (current is 8.0) will have Java + included

+ + +

Use TJWS as proxied

+

+ TJWS can be used with proxy servers. Definition tjws.proxy.ssl + can be specified to correctly determinate remote host and access + protocol.

To use Apache as a proxy server you can: +

    +
  1. make sure that mod_proxy enabled in httpd.conf
  2. +
  3. add below directives in httpd.conf
    +   ProxyRequests On
    +   ProxyVia On
    +   ProxyPass /context_path/ http://tjws_host:<TJWS port>/web_app_context/
    +   ProxyPassReverse /context_path/ http://tjws_host:<TJWS port>/web_app_context/
    +# for pushing authentication
    +   RewriteEngine on
    +   RewriteBase /
    +
    +   RewriteCond %{REMOTE_USER} !=""
    +   RewriteRule .* - [E=E_USER:%{REMOTE_USER}]
    +
    +   RequestHeader set my_new_header %{E_USER}e
    +
    +
  4. +
+
Another example of Apache configuration to use proxied TJWS as + virtual host: +
+<VirtualHost *:*>
+ProxyPreserveHost On
+ProxyPass / http://localhost:8080/
+ProxyPassReverse / http://localhost:8080/
+ServerName www.tjws.com
+</VirtualHost>
+
+ To use + Nginx as a proxy server : +
+    server {
+        listen       80;
+        server_name  localhost;
+...
+        location / {
+            proxy_pass        http://localhost:8080;
+            proxy_set_header  x-Forwarded-for  $remote_addr;
+            proxy_set_header  X-Forwarded-Host $host;
+        }
+...        
+
+ Please note that Nginx doesn't support keep alive for proxy requests + yet, so you can observe some performance degradation. +

+

+ Download +

+

+ Please download + (version 1.114) +

+ +

+ Visit Atjeews at GitHub for Android version of the server and + download APK at Google + Play. +

+

+ Sources of TJWS are available on GitHub +

+

+ Note: Base TJWS is Java 2 (JDK 1.2) + compatible, SSL module requires extra classes introduced in JDK + 1.3-1.4. Base TJWS runs also on servlet specification 2.3, when the + rest of server is 3.1 version compatible. It makes building of TJWS a + bit tricky. Some methods originally introduced in TJWS are conflicting + with JSR 315, so the author is looking how to eliminate this conflict + with a minimal impact of backward compatibility. J2EE war deployment + requires Java 5 (JDK 1.5, 1.6, 1.7, or 1.8). If you would like to make + own build, then you will need to download 7Bee Java based build + tool. The env.xml assumes target 1.4 for TJWS and 1.7 for the rest. It may need being + edited to provide SDK paths and targets. Modify variable 'j2ee + target version' in env.xml to 1.5 to avoid using System tray + feature of JDK 1.6 and up. Specify env.xml variable 'android' + as yes to compile the server to run on Android + devices (since 1.83). App servers features are not supported for + Android though. Since a build tool is a matter of personal taste, you + can use any other favorite build tools. +

+

+ Attention POSIX systems users, the distributive archive has access + attribute not set, so execute + chmod -R +rwx WebServer + after unpackaging WebServer-nnn.zip +

+

+ Zaurus version get + here and .ipk + version (use kill to stop) +

+ +
Last changes history
+ +
    +
  • nohup option
  • +
  • getSession() never null fix pointed by Warren E. + Downs +
  • +
  • messed sessions fix when browser sends more than one session + cookies
  • +
  • session persistence between server re-runs (here are some + issues when classes loaded under WEB-INF/..)
  • +
  • fixes realm not got applied to servlets, hanging when + accessed reserved device, like con:, prt: pointed by users (Niel + Markwick, and others)
  • +
  • added J2EE web app deployment and JSP support (JASPER) as a + separate module
  • +
  • support of filters and listeners, requested by Argan
  • +
  • keep-alive support, requested by Torben Bruun
  • +
  • err option to keep System.err unchanged or customize it, + requested by Xavier
  • +
  • many keep-alive fixes came from Martin Egholm Nielsen
  • +
  • fixes in web app servlet most reported by Nicolas Prochazka
  • +
  • supporting HTTP and HTTPS transports in the same instance
  • +
  • exit out of serve() by Andr� Kischkel
  • +
  • thread pooling for servicing requests
  • +
  • unavailable, and path pattern related fixes
  • +
  • web app launcher including embedded .war
  • +
  • JSP engine with spec 2.0/2.1 support as Japser
  • +
  • filter for include, forward, and error. Multiple URL + patterns
  • +
  • HTTP Range request support for file servlet
  • +
  • added Response Buffer and Request Dispatcher support in base + server
  • +
  • flexible support of server sockets including Selector based
  • +
  • default log directory by Italia Roberto
  • +
  • compression of text content by file servlet
  • +
  • stronger security for session id
  • +
  • fix: not eating unconsumed part of input stream for + keep-alive connection (reported by Bill Burke@redhat)
  • +
  • dynamic redeploy advised by poll results
  • +
  • data sources and connection pooling advised by poll results
  • +
  • missed processing of charset in POST request pointed by Jack
  • +
  • virtual host by ganesan
  • +
  • closing all connections at stop requestedd by Weinan + Li@redhat
  • +
  • JSR 315 Comet support requested by Ivan Voronov +
  • +
  • Base server vulnerability related directory transversal + using '..' pointed by Jo�o Sampaio
  • +
  • Android compatibility of war deployment requested by Alex + Xin
  • +
  • Adjustung behavior matching to servlet specification done by + Andreas
  • +
  • Using servlets mapping URL patterns matching to servlet + specification including extensions mapping, by Bruno B
  • +
  • Accurate handling keep allive by Andreas
  • +
  • Proper freeing resources in CGI servlet by Frank
  • +
  • SSL handler default class updated by Jan
  • +
  • Reliable detection of chunked encoding by Darren
  • +
  • JSR 356 (websocket) by Robert +
+
+ +

Tested web applications

+

I use TJWS primary for my business, however I verified + functionality of some popular web applications. Here are just few of + them:

+
    +
  1. Apache Slide (WebDav) and also WebDav servlet from GitHub
  2. +
  3. jCVSWeb/jCVSServlet 1.41/1.01 (CVS web front-end)
  4. +
  5. Pebble 2.2 (Blogger solution)
  6. +
  7. DaveNPort 0.9.10 (Samba web front-end)
  8. +
  9. Apache Axis2 1.0
  10. +
  11. JASIG - single sign on service
  12. +
  13. SimpleCaptcha
  14. +
  15. Quercus® (PHP engine)
  16. +
  17. Apache Myfaces
  18. +
  19. MetricStream EGRCP
  20. +
  21. Google Web Toolkit (GWT)
  22. +
  23. Stripes (JSP framework)
  24. +
  25. Red5 (Streaming media server)
  26. +
  27. OIOSAML.java SAML SSO servlet filter
  28. +
  29. IBM's WeatherServer (Comet)
  30. +
  31. JEExplorer from Denmark
  32. +
  33. VAADIN another flavor of popular GWT
  34. +
  35. Javamelody enterprise application monitoring and profiling + tool
  36. +
  37. Music Barrel - a music jukebox for Raspberry PI and PC
  38. +
+ +

Build Tool

+

+ TJWS is proudly built using most sophisticated Java build tool + 7Bee. The tool is available in sources at GitHub. + Another build tools can be used as well, although I support 7Bee only. + There is also no way to convert .war files to be deployed on Android, + than using 7Bee. The following values needed to be provided in env.xml + to build TJWS: +

+
    +
  1. SERVLET_LIB - fully qualified path to servlet.jar or other + lib/directory containing JSS 2.3 classes
  2. +
  3. SERVLET_LIB_30 - fully qualified path to servlet.jar or other + lib/directory containing JSS 3.0 classes
  4. +
  5. SERVLET_SRC - fully qualified path to sources of JSS classes, + used only for packaging text resources in launcher packaging and can + be omitted, unless launcher has to be built
  6. +
  7. SERVLET_BUILD - fully qualified path to binaries of classes + of JSS, used only for packaging JSS in launcher packaging and can be + omitted, unless launcher with JSP has to be built
  8. +
  9. JSP_LIB - fully qualified path to jsp.jar or other + lib/directory containing JSP API classes
  10. +
  11. WEBSOCKETS_CLIENT_LIB, and WEBSOCKETS_SERVER_LIB - fully + qualified pathes for JSR 356 API client and server jars respectfully
  12. +
+ Note: environment variables for versions prior + 1.28 are slightly different. + +

JVMs

+

TJWS was tested with most popular JVMs under Windows, Linux, Mac + OS, and Solaris platforms and also on mobile platforms as Sharp + Zaurus, Android, and Windows Mobile. Oracle, IBM J9, JRocket, Open + JDK, Dalvik, and GNU VMs are capable to run TJWS.

+ +

Copyrights

+

The Miniature Java Web Server carries all copyrights of the + original author as stated in the license you can find in any source + file.

+
License
+

The Tiny Java Web Server inherited BSD like license from the + original code, check any source file for details.

+ +

Support

+

+ I provide support of the server on voluntary basis. Feel free to send + bug report on enhancement request. I also provide consulting service + related to creation of web 2.0 J2EE scalable applications. See an + example ResumeFair +

+
Discussion forum
+

+ Feel free also to share your concerns, questions, and discoveries in the + Discussion forum. +

+
Extra Bonus
+

+ Version of 1.07 and later includes some useful web applications + packaged as .war files and deployed at first server run. To enjoy the + applications just follow a link on a start page. If you do not want to + have these applications deployed, just remove corresponding .war files + from webapps directory before first server run. +

+
Help wanted
+

I'm looking for developers to finish work on pending web.xml, + fragment.xml, and common.xml instructions. Another plan is adding + SOAP/RPC support for easy SOA. SSI servlet is also waiting to be + developed. There are tons opportunities to develop Android web + applications.

+
Check also...
+

+ MediaChest + Comprehensive tools to handle all media files as digital photos + and  music +

+

+ xBox - Bean + box supporting XML serialization (do not confuse with proposed later java.beans.Encoder) +

+

+ jAddressBook + is an address book with a float XML format of addresses and another + profile information, web 2 UI. +

+

+ Music + Barrel Conver any computer including Raspberry Pi to a music jukebox + remote controllable from your phone or tablet. +

+

+ Remote + file management - the tool every IT professional or advanced user + must have, web interfaced file manager with many useful functions. +

+ + +

Contact

+

+ Bugs, questions, and enhancement requests you can send to Dmitriy Rogatkin.Happy web + servicing! +

+

+

© 2015
+ + diff --git a/1.x/html/wskt-notes.html b/html/wskt-notes.html similarity index 100% rename from 1.x/html/wskt-notes.html rename to html/wskt-notes.html diff --git a/1.x/idl/remotecontext.idl b/idl/remotecontext.idl similarity index 100% rename from 1.x/idl/remotecontext.idl rename to idl/remotecontext.idl diff --git a/libs/bcprov-jdk15on-159.jar b/libs/bcprov-jdk15on-159.jar new file mode 100644 index 0000000..9049e56 Binary files /dev/null and b/libs/bcprov-jdk15on-159.jar differ diff --git a/libs/class-scanner.jar b/libs/class-scanner.jar new file mode 100644 index 0000000..8a523fc Binary files /dev/null and b/libs/class-scanner.jar differ diff --git a/libs/commons-logging-1.2.jar b/libs/commons-logging-1.2.jar new file mode 100644 index 0000000..93a3b9f Binary files /dev/null and b/libs/commons-logging-1.2.jar differ diff --git a/libs/jasper.jar b/libs/jasper.jar new file mode 100755 index 0000000..0a54ac8 Binary files /dev/null and b/libs/jasper.jar differ diff --git a/libs/javax.json-1.0.4.jar b/libs/javax.json-1.0.4.jar new file mode 100644 index 0000000..09967d8 Binary files /dev/null and b/libs/javax.json-1.0.4.jar differ diff --git a/libs/javax.servlet-3.0.jar b/libs/javax.servlet-3.0.jar new file mode 100755 index 0000000..3b84634 Binary files /dev/null and b/libs/javax.servlet-3.0.jar differ diff --git a/libs/javax.servlet.jsp.jar b/libs/javax.servlet.jsp.jar new file mode 100644 index 0000000..9c0631c Binary files /dev/null and b/libs/javax.servlet.jsp.jar differ diff --git a/libs/javax.websocket-api-1.1.jar b/libs/javax.websocket-api-1.1.jar new file mode 100644 index 0000000..2ad17a8 Binary files /dev/null and b/libs/javax.websocket-api-1.1.jar differ diff --git a/libs/jsch-0.1.54.jar b/libs/jsch-0.1.54.jar new file mode 100644 index 0000000..55a9967 Binary files /dev/null and b/libs/jsch-0.1.54.jar differ diff --git a/libs/log4j-1.2.17.jar b/libs/log4j-1.2.17.jar new file mode 100755 index 0000000..068867e Binary files /dev/null and b/libs/log4j-1.2.17.jar differ diff --git a/libs/tomcat-6.0.33-tomcat-juli.jar b/libs/tomcat-6.0.33-tomcat-juli.jar new file mode 100644 index 0000000..864cc39 Binary files /dev/null and b/libs/tomcat-6.0.33-tomcat-juli.jar differ diff --git a/libs/tomcat-api-7.0.35.jar b/libs/tomcat-api-7.0.35.jar new file mode 100755 index 0000000..be1b27f Binary files /dev/null and b/libs/tomcat-api-7.0.35.jar differ diff --git a/1.x/notes/111/changelog.txt b/notes/1.1.1/changelog.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/111/changelog.txt rename to notes/1.1.1/changelog.txt diff --git a/1.x/notes/111/notes.txt b/notes/1.1.1/notes.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/111/notes.txt rename to notes/1.1.1/notes.txt diff --git a/1.x/notes/112/changelog.txt b/notes/1.1.2/changelog.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/112/changelog.txt rename to notes/1.1.2/changelog.txt diff --git a/1.x/notes/112/notes.txt b/notes/1.1.2/notes.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/112/notes.txt rename to notes/1.1.2/notes.txt diff --git a/1.x/notes/113/changelog.txt b/notes/1.1.3/changelog.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/113/changelog.txt rename to notes/1.1.3/changelog.txt diff --git a/1.x/notes/113/notes.txt b/notes/1.1.3/notes.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/113/notes.txt rename to notes/1.1.3/notes.txt diff --git a/1.x/notes/114/changelog.txt b/notes/1.1.4/changelog.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/114/changelog.txt rename to notes/1.1.4/changelog.txt diff --git a/1.x/notes/114/notes.txt b/notes/1.1.4/notes.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/114/notes.txt rename to notes/1.1.4/notes.txt diff --git a/1.x/notes/115/changelog.txt b/notes/1.1.5/changelog.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/115/changelog.txt rename to notes/1.1.5/changelog.txt diff --git a/1.x/notes/115/notes.txt b/notes/1.1.5/notes.txt old mode 100644 new mode 100755 similarity index 100% rename from 1.x/notes/115/notes.txt rename to notes/1.1.5/notes.txt diff --git a/realm.properties b/realm.properties new file mode 100644 index 0000000..e69de29 diff --git a/resources/Certificate Info.txt b/resources/Certificate Info.txt new file mode 100755 index 0000000..dfe9ca0 --- /dev/null +++ b/resources/Certificate Info.txt @@ -0,0 +1,24 @@ +How to create the certificate for testing. +======================================================================================================================================================== +Using this certificate for R&D +======================================================================================================================================================== +--.jks certificate +keytool -genkey -keyalg RSA -alias selfsigned -keystore tjws.jks -storepass password -validity 65537 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1 -validity 9999 +keytool -importkeystore -srckeystore tjws.jks -destkeystore tjws.jks -deststoretype pkcs12 +openssl x509 -in tjws.jks -text -noout + + +--.bks certificate +keytool -genkey -keyalg RSA -alias selfsigned -keystore tjws.bks -storepass password -validity 65537 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1 -validity 9999 +keytool -importkeystore -srckeystore tjws.bks -destkeystore tjws.bks -deststoretype pkcs12 +openssl x509 -in tjws.bks -text -noout + + +======================================================================================================================================================== +================ Generate the self-signed key and certficate ================ +Password:password +openssl req -newkey rsa:2048 -nodes -keyout tjws.key -out tjws.csr +openssl req -newkey rsa:2048 -nodes -keyout tjws.key -x509 -days 65537 -out tjws.crt + +#If you want to decode certificates on your own computer, run this OpenSSL command: +openssl x509 -in tjws.crt -text -noout diff --git a/1.x/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator b/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator similarity index 100% rename from 1.x/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator rename to resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator diff --git a/resources/icons/tjws-icons.zip b/resources/icons/tjws-icons.zip new file mode 100644 index 0000000..8cee466 Binary files /dev/null and b/resources/icons/tjws-icons.zip differ diff --git a/resources/raw/tjws.bks b/resources/raw/tjws.bks new file mode 100644 index 0000000..4396087 Binary files /dev/null and b/resources/raw/tjws.bks differ diff --git a/resources/raw/tjws.crt b/resources/raw/tjws.crt new file mode 100644 index 0000000..4821914 --- /dev/null +++ b/resources/raw/tjws.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIJAL7OuDjhmcFlMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwIBcNMTgwMzE5MTY1OTU2WhgPMjE5NzA4MjQxNjU5NTZa +MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ +bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDG81u6dp7dMBWKUTvpOcBrh19u3msjUwjMw+gEd6oG0R8RUxPKs+tQ +M5ovbbUQfzn3SBro5QrvE82wZzOefAt2ariCJ8ehl1BNXBIcoKvWwHPiZNyboGOP +Ie3vqsMBa7mFhHdgGVLZh/X0IBSg6S2vMbDw03Hmte33fQn0yKCXwyG8SLUTd6hs +OUvxPHc3sVxtb2kudfGqZa+KNVf+X3VKIqF4+A0dTACh2xK0fu2NKO+qP1jj9WeM +rN/zp7xqFp7EJ1T0OXDpeqh6qNvnD5nhP7Q/SF+rff6G5UW/2mBm6n8+z3gA/fMw +NrtKdpgdJKjiqBnSW167ixY3ls9grYi5AgMBAAGjgacwgaQwHQYDVR0OBBYEFBWA +HEE3vY1NG15RtqWQa61v7H9jMHUGA1UdIwRuMGyAFBWAHEE3vY1NG15RtqWQa61v +7H9joUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8G +A1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkAvs64OOGZwWUwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAbEgqG+zxwFm/TUFo/slvJZzIdhTK +AeQ9hmdjn8vCcSvRQ2zTzq6YLVk3NEyd7EWb2RZop5+7aGoXT3zqnNjzI6QFLcfK ++C2BLj5oA25ZnZSD8z76FyQKPR8z8iLDaqfFZ5AGsT0xSb61yVdrvf3oV+m5j0uR +ElNDNs/YDy/vRoK/NXdqdozPbZv4Ed63jNnbtswanuZ4x/tG868fsaaxjF+i7I8Z +L2Mgx8ymKXPPlKTHiPXQGkNvxlrTn7p5DrYyNNTp27X/0VymnKcKQ0G29CbqOuQl +/LBlkGw+ZiPhojh80/RmWx3aQeSjfyiVRr0e9FCW93rY9kEaV+qCUYvn3g== +-----END CERTIFICATE----- diff --git a/resources/raw/tjws.csr b/resources/raw/tjws.csr new file mode 100644 index 0000000..78bf86b --- /dev/null +++ b/resources/raw/tjws.csr @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC1zCCAb8CAQAweTELMAkGA1UEBhMCQ0ExEzARBgNVBAgTCkNhbGlmb3JuaWEx +EzARBgNVBAcTCk1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMG +A1UECxMMUlNMYWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzIO6T9/Zr6ekzgggelCNBHMPQ+rEvEqb3 +Z49pTjmhfMJRd46PmYW5eufLw++AYPQPQowdTGiFqb75yKw+etVBYmz+fQ/7orI5 +9esl18undpR67CgrlgRHhR6Qpc8147C86ou2bKpCU4iCtkwZO1Sh0Z5+FkSOm93s +P8kGoW63OIUaZYo2e9REkbUqZWvT3gcgxTKcfTU28HBPtICE5Ic1q7CLEnrnsAYC +30VWgxIryxdt1vCP2mdj9SmDJGlJkP7y+S20HQ8d6v7kQ2Q3f+3uCoAzzv6uGNCK +lokHPdn94+rMLACAfTbdRHfvL8GPLXRPnQXCWfx1auqadhKCp1LDAgMBAAGgGTAX +BgkqhkiG9w0BCQcxChMIcGFzc3dvcmQwDQYJKoZIhvcNAQEFBQADggEBAJiLGXtf +tANO+nj83/K1iPXb8Bpa1bbcwLcJGJbrcJsQvh9bzXHsKSTeovbAwvRnRyXGpAt8 +4gXdvDqwDmnw4ZI9ui5FHcDgYfnwS7HLxhN5YDHaKOHr4wpZY6enLrYER8H4y7Ky +aHLJvYN8MeARfWPShPUdpjT6qnuEwf6SUbeoCTH9SUEJysG54uAp9L/Ky4DY85W6 +SRhCnlcw515D4EM0FmGBEIynqqi12yzZibbB9PpiObg0+YGlBjjiFob4gz49RThU +B2ffVTiATF2uP7aRkPxvLqJbiyY2tvbDgMblLskKgye6FakKVtfVFxZNy9zruLni ++Dbg8vWYULcKXgw= +-----END CERTIFICATE REQUEST----- diff --git a/resources/raw/tjws.jks b/resources/raw/tjws.jks new file mode 100644 index 0000000..69bf5e8 Binary files /dev/null and b/resources/raw/tjws.jks differ diff --git a/resources/raw/tjws.key b/resources/raw/tjws.key new file mode 100644 index 0000000..e2f3fd8 --- /dev/null +++ b/resources/raw/tjws.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxvNbunae3TAVilE76TnAa4dfbt5rI1MIzMPoBHeqBtEfEVMT +yrPrUDOaL221EH8590ga6OUK7xPNsGcznnwLdmq4gifHoZdQTVwSHKCr1sBz4mTc +m6BjjyHt76rDAWu5hYR3YBlS2Yf19CAUoOktrzGw8NNx5rXt930J9Migl8MhvEi1 +E3eobDlL8Tx3N7FcbW9pLnXxqmWvijVX/l91SiKhePgNHUwAodsStH7tjSjvqj9Y +4/VnjKzf86e8ahaexCdU9Dlw6Xqoeqjb5w+Z4T+0P0hfq33+huVFv9pgZup/Ps94 +AP3zMDa7SnaYHSSo4qgZ0lteu4sWN5bPYK2IuQIDAQABAoIBAFUoTZcetxlOP6oY +42ANDEP6ierW4V0ZaabcJC/lWK3aTUYJHWuiX5LQw6qRdvM8wf8KqhoOEAQNoflj +80BfMDjbrWZoyJZuQj0ar9X5IBSoA/Jf4d3rZTIa/9GaciXlil+QN9i2fjQGckyw +fqPxq1BWILq0hwiNzvIkX2KbjcHnTdhYvEc1csz6x5WCV3fRuBRF1rX+HN8HAx8V +AaeGluHcCTRJW8FYIfkYrMdieGoKN4APuVjnVXcV4+UhrAGtxPi2inwSdTgNPZp0 +/YwqcdUjY/49xjq+6AoY9g0Gan/J86eg3ErZ6TEDVrHkD0MjbZH/RPZmcgOXXcD5 +BVN4ZAECgYEA/JP26fcQ/qhKDGd7G5MmfSl0eMzzwNW7L2pQC+lmpkoTQF1d+Prz +CQ+hG3SdLbvXcVGVWbdlNBsZL2GFK75n7yLiKSCEWsK3+zWCADzZ0vUTh8DNRv++ +F5U8zwTvzLN9mlzfAMvbJlcSaw7kpQRXS5fGMUieE785DOKIGHM2M+ECgYEAyaVk +17SITRjT3YXw/H6atzPwCJ7vyPesj8P6dmvZLKoamDBZW3lfi0Dx9qo5SW6D9smd +Bm68+CPBzZmj9cqoYhwusTlTLAfbHoHVax0WSuxquw/33Itu/BIHFHG45lyK57cn +ALgp9Fre9YvjtQxLHOxwnE2fkz6GhDNNhC7db9kCgYAEJpZXL/U6ih91ZrnyMQ/f +3K+KUKvszlZeKBwapgJG107Lrv0dW1plGrmmDtuKZdzbguC2cbobChr22V5r4pwo +pOUckek66JpHaZCyWk2mFtr0TynQceF4174BFO6v6X816zLK+46laabm1X7Sa2jX +2C2sn6nhXzIb0Rk1dac9YQKBgAx218Ppmd9CIJ550AqbfM7EPBscT/AZNyZv08SM +KBF1tk0f9/YKi5hc/Ffl78KVPTz8+2LRZ4bjFvCxhYwE6eGeolg8FeML3USGe/2x +/5XEBVjoxMZyK/sS1jMyUF6U69Uk4hlOSPGcyFlfO0UOrHnuN4vB1JJSdBgp36nD +B9cJAoGBAL+BclnADVfBMDJX6oHf4KdYbgvhNo2UCnwe0q3LDaFAGKiXtgd+yRXT +0RR0H3ErNSoMioCCxA3EUjZ6URdqiwh0m+ieYZ8yMy1bIgG10s9WTPv1g7P6lFBj +YXPcJxHQyUWFiVg8wJADSwn3rf7pp25kNplhQ9U9MWoXIXLhonXU +-----END RSA PRIVATE KEY----- diff --git a/1.x/bin/tjws.bat b/scripts/tjws.bat similarity index 100% rename from 1.x/bin/tjws.bat rename to scripts/tjws.bat diff --git a/1.x/bin/tjws.sh b/scripts/tjws.sh similarity index 100% rename from 1.x/bin/tjws.sh rename to scripts/tjws.sh diff --git a/1.x/bin/tjwserv b/scripts/tjwserv similarity index 100% rename from 1.x/bin/tjwserv rename to scripts/tjwserv diff --git a/1.x/bin/tjwserv.service b/scripts/tjwserv.service similarity index 100% rename from 1.x/bin/tjwserv.service rename to scripts/tjwserv.service diff --git a/src/Acme/IOHelper.java b/src/Acme/IOHelper.java new file mode 100755 index 0000000..04e8156 --- /dev/null +++ b/src/Acme/IOHelper.java @@ -0,0 +1,739 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package Acme; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.security.cert.CertificateException; + +import javax.servlet.http.HttpServletResponse; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import com.rslakra.logger.LogManager; + +import rogatkin.web.WebApp; + +/** + * @author Rohtash Singh Lakra + * @date 03/15/2018 04:13:46 PM + */ +public final class IOHelper { + /** UTF-8 */ + public static String UTF_8 = "UTF-8"; + /** ISO-8859-1 */ + public static String ISO_8859_1 = "ISO-8859-1"; + + /** JVM-Type - JVM_ANDROID */ + public static String JVM_ANDROID = "Dalvik".intern(); + + /** HTTP - Constants. */ + public static String EXPIRES = "Expires"; + public static String PRAGMA = "Pragma"; + public static String PRAGMA_PUBLIC = "public"; + public static String CACHE_CONTROL = "Cache-Control"; + public static String USER_AGENT = "User-Agent"; + public static String NO_CACHE = "no-cache"; + + /** Content-Type */ + public static String CONTENT_TYPE_HTML = "text/html; charset=utf-8"; + public static String CONTENT_TYPE_JSON = "application/json"; + public static String CONTENT_TYPE_ICON = "image/x-icon"; + + /** Content-Type */ + private static final String LINE_SEPARATOR = System.getProperty("line.separator").intern(); + + /** singleton instance. */ + private IOHelper() { + throw new RuntimeException("Object creation is not allowed for this object!"); + } + + /** + * Returns the system line separator. + * + * @return + */ + public static final String getLineSeparator() { + return LINE_SEPARATOR; + } + + /** + * Installs the bouncy castle provider. + */ + public static void addBouncyCastleProvider() { + try { + /* add bouncy castle provider. */ + Security.addProvider(new BouncyCastleProvider()); + LogManager.debug("Added BouncyCastleProvider!"); + } catch (Exception ex) { + LogManager.error(ex); + } + } + + /** + * Returns true if the object is null otherwise false. + * + * @param string + * @return + */ + public static boolean isNull(Object object) { + return (object == null); + } + + /** + * Returns true if the object is not null otherwise false. + * + * @param object + * @return + */ + public static boolean isNotNull(Object object) { + return (!isNull(object)); + } + + /** + * Returns true if either the string is null or length is 0(zero) otherwise + * false. + * + * @param string + * @return + */ + public static boolean isNullOrEmpty(CharSequence string) { + return (isNull(string) || string.length() == 0); + } + + /** + * Returns true if the JVM is android (dalvik) otherwise false. + * + * @param + * @return + */ + public static boolean isAndroid() { + return (System.getProperty("java.vm.name").startsWith(JVM_ANDROID)); + } + + /** + * Returns the path string for the given class. + * + * @param className + * @return + */ + public static String pathString(Class className, boolean pathOnly) { + String urlString = null; + URL url = className.getResource(className.getSimpleName() + ".class"); + if (url != null) { + urlString = url.toExternalForm(); + /* + * The urlString most likely ends with a /, then the + * full + * class name with . replaced with /, and .class. Cut that part off + * if + * present. If not also check + * for backslashes instead. If that's also not present just return + * null + */ + if (pathOnly) { + int fileIndex = urlString.indexOf(className.getSimpleName()); + urlString = urlString.substring(0, fileIndex); + } + + /* + * urlString is now the URL of the location, but + * possibly + * with jar: in front and a trailing ! + */ + if (urlString.startsWith("jar:") && urlString.endsWith("!")) { + urlString = urlString.substring(4, urlString.length() - 1); + } + + /* + * urlString is now the URL of the location, but + * possibly + * with file: in front. + */ + else if (urlString.startsWith("file:")) { + urlString = urlString.substring("file:".length(), urlString.length()); + } + } + + return urlString; + } + + /** + * Returns the path string for the given class. + * + * @param className + * @return + */ + public static String pathString(Class className) { + return pathString(className, true); + } + + /** + * + * @param parentFolder + * @param fileName + * @return + */ + public static String pathString(final String parentFolder, final String fileName) { + if (IOHelper.isNullOrEmpty(parentFolder)) { + return fileName; + } else if (IOHelper.isNullOrEmpty(fileName)) { + return parentFolder; + } else if (parentFolder.endsWith(File.separator) || fileName.startsWith(File.separator)) { + return parentFolder + fileName; + } else { + return parentFolder + File.separator + fileName; + } + } + + /** + * Sets the default headers to the specified response. + * + * @param servletResponse + */ + public static void setDefaultHeaders(HttpServletResponse servletResponse) { + if (servletResponse != null) { + servletResponse.setDateHeader(EXPIRES, -1); + servletResponse.setHeader(PRAGMA, PRAGMA_PUBLIC); + servletResponse.setHeader(CACHE_CONTROL, NO_CACHE); + } + } + + /** + * Closes the specified mCloseables objects. + * + * @param mCloseables + */ + public static final void closeSilently(Object... mCloseables) { + if (isNotNull(mCloseables)) { + for (Object mCloseable : mCloseables) { + try { + if (mCloseable instanceof Closeable) { + ((Closeable) mCloseable).close(); + } else if (mCloseable instanceof Socket) { + ((Socket) mCloseable).close(); + } else if (mCloseable instanceof ServerSocket) { + ((ServerSocket) mCloseable).close(); + } + } catch (IOException ex) { + LogManager.error(ex); + } + } + } + } + + /** + * Returns the bytes of the specified input stream. + * + * @param inputStream + * @return + * @throws IOException + */ + public static byte[] readBytes(final InputStream inputStream, final boolean closeStream) throws IOException { + LogManager.debug("+readBytes(inputStream, " + closeStream + ")"); + byte[] resultBytes = null; + if (inputStream != null) { + ByteArrayOutputStream outputStream = null; + BufferedInputStream bInputStream = new BufferedInputStream(inputStream); + try { + bInputStream = new BufferedInputStream(inputStream); + outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[bInputStream.available()]; + int length = 0; + while ((length = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, length); + } + + outputStream.flush(); + resultBytes = outputStream.toByteArray(); + } catch (IOException ex) { + LogManager.error(ex); + throw ex; + } finally { + /* close streams. */ + closeSilently(outputStream); + if (closeStream) { + closeSilently(bInputStream); + } + } + } + + LogManager.debug("-readBytes(), resultBytes:" + resultBytes); + return resultBytes; + } + + /** + * Returns the bytes of the specified pathString. + * + * @param pathString + * @param closeStream + * @return + * @throws IOException + */ + public static byte[] readBytes(final String pathString, final boolean closeStream) throws IOException { + return readBytes(new FileInputStream(pathString), closeStream); + } + + /** + * Writes the bytes to outputStream and closes it. + * + * @param dataBytes + * @param outputStream + * @param closeStream + * @throws IOException + */ + public static boolean writeBytes(byte[] dataBytes, OutputStream outputStream, boolean closeStream) throws IOException { + boolean result = false; + if (dataBytes != null && outputStream != null) { + try { + outputStream.write(dataBytes); + /* flush output streams. */ + outputStream.flush(); + result = true; + } catch (IOException ex) { + LogManager.error(ex); + throw ex; + } finally { + /* close streams. */ + if (closeStream) { + closeSilently(outputStream); + } + } + } + + return result; + } + + /** + * Copies the contents of an sourceStream into an + * targetStream. + * + * @param sourceStream + * @param targetStream + * @param closeStreams + * @return + * @throws IOException + */ + public static int copyStream(final InputStream sourceStream, final OutputStream targetStream, boolean closeStreams) throws IOException { + LogManager.debug("+copyStream(" + sourceStream + ", " + targetStream + ", " + closeStreams + ")"); + int fileSize = 0; + if (sourceStream != null && targetStream != null) { + try { + // buffer + byte[] buffer = new byte[sourceStream.available()]; + int byteCount = 0; + while ((byteCount = sourceStream.read(buffer)) != -1) { + targetStream.write(buffer, 0, byteCount); + fileSize += byteCount; + } + + /* flush output streams. */ + targetStream.flush(); + } catch (IOException ex) { + LogManager.error(ex); + throw ex; + } finally { + /* close streams. */ + if (closeStreams) { + closeSilently(sourceStream, targetStream); + } + } + } + + LogManager.debug("-copyStream(), fileSize:" + fileSize); + return fileSize; + } + + /** + * Converts the specified bytes to the specified + * charsetName String. + * + * @param bytes + * @param charsetName + * @return + */ + public static String bytesAsString(byte[] bytes, String charsetName) { + String bytesAsString = null; + if (!IOHelper.isNull(bytes)) { + try { + if (IOHelper.isNullOrEmpty(charsetName)) { + bytesAsString = new String(bytes); + } else { + bytesAsString = new String(bytes, charsetName); + } + } catch (Exception ex) { + LogManager.error(ex); + bytesAsString = (IOHelper.isNull(bytes) ? null : bytes.toString()); + } + } + + return bytesAsString; + } + + /** + * Returns the string representation of the given bytes. + * + * @param bytes + * @return + */ + public static String bytesAsString(byte[] bytes) { + return bytesAsString(bytes, null); + } + + /** + * /** + * Returns the UTF-8 String representation of the given bytes. + * + * @param bytes + * @param replaceNonDigitCharacters + * @return + */ + public static String toUTF8String(byte[] bytes, boolean replaceNonDigitCharacters) { + String utf8String = bytesAsString(bytes, UTF_8); + if (replaceNonDigitCharacters && IOHelper.isNullOrEmpty(utf8String)) { + utf8String = utf8String.replaceAll("\\D+", ""); + } + + return utf8String; + } + + /** + * Returns the UTF-8 String representation of the given bytes. + * + * @param bytes + * @return + */ + public static String toUTF8String(byte[] bytes) { + return toUTF8String(bytes, false); + } + + /** + * Returns the UTF-8 String representation of the given string. + * + * @param string + * @return + */ + public static String toUTF8String(String string) { + return toUTF8String(string.getBytes()); + } + + /** + * Returns the ISO-8859-1 String representation of the given + * bytes. + * + * @param bytes + * @return + */ + public static String toISOString(byte[] bytes) { + return bytesAsString(bytes, ISO_8859_1); + } + + /** + * Converts the specified string into bytes using the specified + * charsetName. + * + * @param string + * @param charsetName + * @return + */ + public static byte[] toBytes(String string, String charsetName) { + byte[] stringAsBytes = null; + if (!IOHelper.isNullOrEmpty(string)) { + try { + stringAsBytes = IOHelper.isNullOrEmpty(charsetName) ? string.getBytes() : string.getBytes(charsetName); + } catch (Exception ex) { + LogManager.error(ex); + } + } + + return stringAsBytes; + } + + /** + * Converts the specified string into bytes. + * + * @param string + * @return + */ + public static byte[] toBytes(String string) { + return toBytes(string, null); + } + + /** + * Converts the specified string into UTF-8 bytes. + * + * @param string + * @return + */ + public static byte[] toUTF8Bytes(String string) { + return toBytes(string, UTF_8); + } + + /** + * Returns the bytes of the specified input stream. + * + * @param inputStream + * @return + * @throws IOException + */ + public static InputStream toInputStream(final byte[] dataBytes) { + return new ByteArrayInputStream(dataBytes); + } + + /** + * Sends the given responseBytes as response. + * + * @param contentType + * @param responseBytes + * @param servletResponse + * @throws IOException + */ + public static void sendResponse(final String contentType, final byte[] responseBytes, final HttpServletResponse servletResponse) { + try { + servletResponse.setContentType(contentType); + setDefaultHeaders(servletResponse); + writeBytes(responseBytes, servletResponse.getOutputStream(), true); + } catch (IOException ex) { + LogManager.error(ex); + } + } + + /** + * Returns the "favicon.ico" icon image 16X16 pixels in size. + * + * @return + */ + public static byte[] readIconBytes(final InputStream inputStream) { + try { + return readBytes(inputStream, true); + } catch (IOException ex) { + LogManager.error(ex); + return null; + } + } + + /** + * Returns the "favicon.ico" icon image 16X16 pixels in size. + * + * @return + */ + public static byte[] readIconBytes() { + try { + final String iconPath = IOHelper.pathString(IOHelper.pathString(WebApp.class), "../resource/tjws.gif"); + return readIconBytes(new FileInputStream(iconPath)); + } catch (IOException ex) { + LogManager.error(ex); + return null; + } + } + + /** + * Returns the user's directory. + * + * @return + */ + public static String getUserDir() { + return System.getProperty("user.dir"); + } + + /** + * Returns the user's home directory. + * + * @return + */ + public static String getUserHome() { + return System.getProperty("user.home"); + } + + /** + * Returns the java home folder. + * + * @return + */ + public static String getJavaHome() { + return System.getProperty("java.home"); + } + + /** + * Returns the logs directory under the project. + * + * @return + */ + public static String getLogsDir() { + return getUserDir() + File.separator + "logs"; + } + + /** + * Returns the java's temp folder. + * + * @return + */ + public static String getTempDir() { + return System.getProperty("java.io.tmpdir"); + } + + /** + * Returns the string representation of the throwable object. + * + * @param throwable + * @return + */ + public static final String toString(final Throwable throwable) { + if (throwable != null) { + final StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + throwable.printStackTrace(printWriter); + closeSilently(printWriter); + return stringWriter.toString(); + } + + return null; + } + + /** + * Returns the string representation of the given objects. + * + * @param objects + * @param addNewLine + * @return + */ + public static final String toString(final Object[] objects, final boolean addNewLine) { + final StringBuffer strBuilder = new StringBuffer(); + if (isNotNull(objects)) { + if (addNewLine) { + strBuilder.append("\n"); + } + + for (int i = 0; i < objects.length; i++) { + if (isNotNull(objects[i])) { + if (objects[i] instanceof String) { + strBuilder.append((String) objects[i]); + } else { + strBuilder.append(objects[i].toString()); + } + } + + // append new line character. + if (i < objects.length - 1) { + if (addNewLine) { + strBuilder.append("\n"); + } else { + strBuilder.append(" "); + } + } + } + } + + return strBuilder.toString(); + } + + /** + * Returns the string representation of the given objects. + * + * @param objects + * @return + */ + public static final String toString(final Object[] objects) { + return toString(objects, false); + } + + /** + * Returns the boolean value of the given object. + * + * @param object + * @return + */ + public static final boolean parseBoolean(final Object object) { + return (isNull(object) ? false : Boolean.valueOf(object.toString())); + } + + /** + * Returns true if the key store is supported otherwise false. + * + * @param keyStoreStream + * @param keyStorePassword + * @return + */ + public static boolean isKeyStoreSupported(final InputStream keyStoreStream, final String keyStorePassword) { + final String trustStoreType = KeyStore.getDefaultType(); + KeyStore keyStore = null; + try { + keyStore = KeyStore.getInstance(trustStoreType); + try { + keyStore.load(keyStoreStream, keyStorePassword.toCharArray()); + } catch (NoSuchAlgorithmException ex) { + LogManager.error(ex); + return false; + } catch (CertificateException ex) { + LogManager.error(ex); + return false; + } catch (IOException ex) { + LogManager.error(ex); + return false; + } + } catch (KeyStoreException ex) { + LogManager.error(ex); + return false; + } catch (Exception ex) { + LogManager.error(ex); + return false; + } + + return true; + } + + /** + * Returns the new IOException. + * + * @param throwable + * @return + */ + public static IOException newIOException(final Throwable throwable) { + return new IOException(throwable.toString(), throwable); + } + +} diff --git a/src/Acme/Resource/mime.properties b/src/Acme/Resource/mime.properties new file mode 100644 index 0000000..623a840 --- /dev/null +++ b/src/Acme/Resource/mime.properties @@ -0,0 +1,110 @@ +# $Id: mime.properties,v 1.4 2012/08/13 04:10:58 dmitriy Exp $ +HTML=text/html +HTM=text/html +TXT=text/plain +XML=text/xml +CSS=text/css +SGML=text/x-sgml +SGM=text/x-sgml +GIF=image/gif +JPG=image/jpeg +JPEG=image/jpeg +JPE=image/jpeg +PNG=image/png +BMP=image/bmp +TIF=image/tiff +TIFF=image/tiff +RGB=image/x-rgb +XPM=image/x-xpixmap +XBM=image/x-xbitmap +SVG=image/svg+xml +SVGZ=image/svg+xml +ICO=image/vnd.microsoft.icon +# Audio +AU=audio/basic +SND=audio/basic +MID=audio/mid +MIDI=audio/mid +RMI=audio/mid +KAR=audio/mid +MPGA=audio/mpeg +MP2=audio/mpeg +MP3=audio/mpeg +WAV=audio/wav +AIFF=audio/aiff +AIFC=audio/aiff +AIF=audio/x-aiff +RA=audio/x-realaudio +RPM=audio/x-pn-realaudio-plugin +RAM=audio/x-pn-realaudio +SD2=audio/x-sd2 +# Applications +BIN=application/octet-stream +DMS=application/octet-stream +LHA=application/octet-stream +LZH=application/octet-stream +EXE=application/octet-stream +DLL=application/octet-stream +CLASS=application/octet-stream +HQX=application/mac-binhex40 +PS=application/postscript +AI=application/postscript +EPS=application/postscript +PDF=application/pdf +RTF=application/rtf +DOC=application/msword +DOCX=application/msword +PPT=application/powerpoint +PPTX=application/powerpoint +FIF=application/fractals +P7C=application/pkcs7-mime +# Application/x +JS=application/x-javascript +Z=application/x-compress +GZ=application/x-gzip +TAR=application/x-tar +TGZ=application/x-compressed +ZIP=application/x-zip-compressed +DIR=application/x-director +DCR=application/x-director +DXR=application/x-director +DVI=application/x-dvi +TEX=application/x-tex +LATEX=application/x-latex +TCL=application/x-tcl +CER=application/x-x509-ca-cert +CRT=application/x-x509-ca-cert +DER=application/x-x509-ca-cert +ISO=application/x-iso9660-image +OTF= font/opentype +TTF= font/truetype +EOT=application/vnd.ms-fontobject +APK=application/vnd.android.package-archive +# Video +MPG=video/mpeg +MPE=video/mpeg +MPEG=video/mpeg +QT=video/quicktime +MOV=video/quicktime +AVI=video/x-msvideo +MOVIE=video/x-sgi-movie +MP4=video/mp4v-es, audio/mp4 +# Chemical +PDB=chemical/x-pdb +XYZ=chemical/x-pdb +# X- +ICE=x-conference/x-cooltalk +JNLP=application/x-java-jnlp-file +WRL=x-world/x-vrml +VRML=x-world/x-vrml +WML=text/vnd.wap.wml +WMLC=application/vnd.wap.wmlc +WMLS=text/vnd.wap.wmlscript +WMLSC=application/vnd.wap.wmlscriptc +WBMP=image/vnd.wap.wbmp +FLAC=audio/flac +OGG=audio/ogg +OGA=audio/ogg +SPX=audio/ogg +OGV=video/ogg +OGX=application/ogg \ No newline at end of file diff --git a/1.x/src/Acme/Serve/CgiServlet.java b/src/Acme/Serve/CgiServlet.java old mode 100644 new mode 100755 similarity index 67% rename from 1.x/src/Acme/Serve/CgiServlet.java rename to src/Acme/Serve/CgiServlet.java index e21c9e4..1f3f972 --- a/1.x/src/Acme/Serve/CgiServlet.java +++ b/src/Acme/Serve/CgiServlet.java @@ -6,15 +6,15 @@ // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. +// notice, this list of conditions and the following disclaimer. // 2. Redistributions 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. +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -29,7 +29,6 @@ package Acme.Serve; import java.io.BufferedReader; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -40,32 +39,39 @@ import java.util.Vector; import javax.servlet.ServletException; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Cookie; + +import Acme.IOHelper; +import Acme.Utils; /// Runs CGI programs. //

// Note: although many implementations of CGI set the working directory of // the subprocess to be the directory containing the executable file, the -// CGI spec actually says nothing about the working directory. Since +// CGI spec actually says nothing about the working directory. Since // Java has no method for setting the working directory, this implementation // does not set it. //

-// Fetch the software.
+// Fetch the +/// software.
// Fetch the entire Acme package. //

// @see Acme.Serve.Serve public class CgiServlet extends HttpServlet { - + + /** serialVersionUID */ + private static final long serialVersionUID = 1L; + // / Returns a string containing information about the author, version, and // copyright of the servlet. public String getServletInfo() { return "TJWS CGI extension $Id: CgiServlet.java,v 1.10 2012/08/24 03:06:34 dmitriy Exp $"; } - + // / Services a single request from the client. // @param req the servlet request // @param req the servlet response @@ -81,27 +87,26 @@ public void service(HttpServletRequest req, HttpServletResponse res) throws Serv else dispatchPathname(req, res, getServletContext().getRealPath(req.getServletPath() + pathInfo)); } - + private void dispatchPathname(HttpServletRequest req, HttpServletResponse res, String path) throws IOException { if (new File(path).exists()) serveFile(req, res, path); else res.sendError(HttpServletResponse.SC_NOT_FOUND); } - - private void serveFile(HttpServletRequest req, HttpServletResponse res, String path) throws IOException { + + private void serveFile(HttpServletRequest req, HttpServletResponse response, String path) throws IOException { String queryString = req.getQueryString(); int contentLength = req.getContentLength(); int c; - + log("running " + path + "?" + queryString); - - // Make argument list. - String argList[] = (path + (queryString != null && queryString.indexOf("=") == -1 ? "+" + queryString : "")) - .split("\\+"); /* 1.4 */ - + + /* Make argument list. - 1. 4 */ + String argList[] = (path + (queryString != null && queryString.indexOf("=") == -1 ? "+" + queryString : "")).split("\\+"); + // Make environment list. - Vector envVec = new Vector(); + Vector envVec = new Vector(); envVec.addElement(makeEnv("PATH", "/usr/local/bin:/usr/ucb:/bin:/usr/bin")); envVec.addElement(makeEnv("GATEWAY_INTERFACE", "CGI/1.1")); envVec.addElement(makeEnv("SERVER_SOFTWARE", getServletContext().getServerInfo())); @@ -110,61 +115,74 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, String p envVec.addElement(makeEnv("REMOTE_ADDR", req.getRemoteAddr())); envVec.addElement(makeEnv("REMOTE_HOST", req.getRemoteHost())); envVec.addElement(makeEnv("REQUEST_METHOD", req.getMethod())); - if (contentLength != -1) + if (contentLength != -1) { envVec.addElement(makeEnv("CONTENT_LENGTH", Integer.toString(contentLength))); - if (req.getContentType() != null) + } + + if (req.getContentType() != null) { envVec.addElement(makeEnv("CONTENT_TYPE", req.getContentType())); + } envVec.addElement(makeEnv("SCRIPT_NAME", req.getServletPath())); - if (req.getPathInfo() != null) + if (req.getPathInfo() != null) { envVec.addElement(makeEnv("PATH_INFO", req.getPathInfo())); - if (req.getPathTranslated() != null) + } + if (req.getPathTranslated() != null) { envVec.addElement(makeEnv("PATH_TRANSLATED", req.getPathTranslated())); - if (queryString != null) + } + if (queryString != null) { envVec.addElement(makeEnv("QUERY_STRING", queryString)); + } envVec.addElement(makeEnv("SERVER_PROTOCOL", req.getProtocol())); - if (req.getRemoteUser() != null) + if (req.getRemoteUser() != null) { envVec.addElement(makeEnv("REMOTE_USER", req.getRemoteUser())); - if (req.getAuthType() != null) + } + if (req.getAuthType() != null) { envVec.addElement(makeEnv("AUTH_TYPE", req.getAuthType())); - Enumeration hnEnum = req.getHeaderNames(); - while (hnEnum.hasMoreElements()) { - String name = (String) hnEnum.nextElement(); + } + + Enumeration enumHeaders = req.getHeaderNames(); + while (enumHeaders.hasMoreElements()) { + String name = (String) enumHeaders.nextElement(); String value = req.getHeader(name); - if (value == null) + if (value == null) { value = ""; + } envVec.addElement(makeEnv("HTTP_" + name.toUpperCase().replace('-', '_'), value)); } String envList[] = makeList(envVec); - + // Start the command. - Process proc = Runtime.getRuntime().exec(argList, envList); - OutputStream procOut = proc.getOutputStream(); - BufferedReader procIn = new BufferedReader(new InputStreamReader(proc.getInputStream())); - InputStream procErr = proc.getErrorStream(); + Process process = Runtime.getRuntime().exec(argList, envList); + OutputStream processOutputStream = process.getOutputStream(); + BufferedReader processInputStream = new BufferedReader(new InputStreamReader(process.getInputStream())); + InputStream processErrorStream = process.getErrorStream(); try { // If it's a POST, copy the request data to the process. if (req.getMethod().equalsIgnoreCase("post")) { InputStream reqIn = req.getInputStream(); for (int i = 0; i < contentLength; ++i) { c = reqIn.read(); - if (c == -1) + if (c == -1) { break; - procOut.write(c); + } + processOutputStream.write(c); } - procOut.close(); + processOutputStream.close(); } - + // Now read the response from the process. - OutputStream resOut = res.getOutputStream(); + OutputStream resOut = response.getOutputStream(); // Some of the headers have to be intercepted and handled. boolean firstLine = true; while (true) { - String line = procIn.readLine(); - if (line == null) + String line = processInputStream.readLine(); + if (line == null) { break; + } line = line.trim(); - if (line.equals("")) + if (line.equals("")) { break; + } int colon = line.indexOf(":"); if (colon == -1) { // No colon. If it's the first line, parse it for status. @@ -172,14 +190,14 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, String p StringTokenizer tok = new StringTokenizer(line, " "); try { switch (tok.countTokens()) { - case 2: - tok.nextToken(); - res.setStatus(Integer.parseInt(tok.nextToken())); - break; - case 3: - tok.nextToken(); - res.setStatus(Integer.parseInt(tok.nextToken()), tok.nextToken()); - break; + case 2: + tok.nextToken(); + response.setStatus(Integer.parseInt(tok.nextToken())); + break; + case 3: + tok.nextToken(); + response.setStatus(Integer.valueOf(tok.nextToken()), tok.nextToken()); + break; } } catch (NumberFormatException ignore) { } @@ -194,71 +212,76 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, String p StringTokenizer tok = new StringTokenizer(value, " "); try { switch (tok.countTokens()) { - case 1: - res.setStatus(Integer.parseInt(tok.nextToken())); - break; - case 2: - res.setStatus(Integer.parseInt(tok.nextToken()), tok.nextToken()); - break; + case 1: + response.setStatus(Integer.parseInt(tok.nextToken())); + break; + case 2: + response.setStatus(Integer.parseInt(tok.nextToken()), tok.nextToken()); + break; } } catch (NumberFormatException ignore) { } } else if (name.equalsIgnoreCase("Content-type")) { - res.setContentType(value); + response.setContentType(value); } else if (name.equalsIgnoreCase("Content-length")) { try { - res.setContentLength(Integer.parseInt(value)); - } catch (NumberFormatException ignore) { + response.setContentLength(Integer.parseInt(value)); + } catch (NumberFormatException ex) { } } else if (name.equalsIgnoreCase("Location")) { - res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - res.setHeader(name, value); + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + response.setHeader(name, value); } else if (name.equalsIgnoreCase(Serve.ServeConnection.SETCOOKIE)) { int x = value.indexOf("="); if (x > 0) { String n = value.substring(0, x); String v = value.substring(x + 1).trim(); - res.addCookie(new Cookie(n, v)); + response.addCookie(new Cookie(n, v)); } } else { // Not a special header. Just set it. - res.setHeader(name, value); + response.setHeader(name, value); } } } // Copy the rest of the data uninterpreted. - Acme.Utils.copyStream(procIn, resOut, null); - } catch (IOException e) { + Utils.copyStream(processInputStream, resOut, null); + } catch (IOException ex) { // res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); // There's some weird bug in Java, when reading from a Process // you get a spurious IOException. We have to ignore it. } finally { - try { - procOut.close(); - } catch (IOException e) { - } - try { - procIn.close(); - } catch (IOException e) { - } - try { - procErr.close(); - } catch (IOException e) { - } - // TODO make it configurable - //proc.destroy(); + IOHelper.closeSilently(processOutputStream); + IOHelper.closeSilently(processInputStream); + IOHelper.closeSilently(processErrorStream); + + // TODO make it configurable + // proc.destroy(); } } - - private static String makeEnv(String name, String value) { + + /** + * + * @param name + * @param value + * @return + */ + private static String makeEnv(final String name, final String value) { return name + "=" + value; } - - private static String[] makeList(Vector vec) { - String list[] = new String[vec.size()]; - for (int i = 0; i < vec.size(); ++i) - list[i] = (String) vec.elementAt(i); + + /** + * + * @param strVector + * @return + */ + private static String[] makeList(Vector strVector) { + String list[] = new String[strVector.size()]; + for (int i = 0; i < strVector.size(); ++i) { + list[i] = (String) strVector.elementAt(i); + } + return list; } - + } diff --git a/1.x/src/Acme/Serve/FileServlet.java b/src/Acme/Serve/FileServlet.java old mode 100644 new mode 100755 similarity index 77% rename from 1.x/src/Acme/Serve/FileServlet.java rename to src/Acme/Serve/FileServlet.java index 8e23b0b..e31c08f --- a/1.x/src/Acme/Serve/FileServlet.java +++ b/src/Acme/Serve/FileServlet.java @@ -6,15 +6,15 @@ // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. +// notice, this list of conditions and the following disclaimer. // 2. Redistributions 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. +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -25,7 +25,7 @@ // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ -// +// // All enhancements Copyright (C)1998-2005 by Dmitriy Rogatkin // http://tjws.sourceforge.net @@ -45,13 +45,14 @@ import java.util.Arrays; import java.util.Date; import java.util.Enumeration; -import java.util.zip.GZIPOutputStream; //import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import Acme.IOHelper; import Acme.Utils; /// Servlet similar to a standard httpd. @@ -61,38 +62,37 @@ // Redirects directory URLs that lack a trailing /. // Handles If-Modified-Since. //

-// Fetch the software.
+// Fetch the +/// software.
// Fetch the entire Acme package. //

// @see Acme.Serve.Serve public class FileServlet extends HttpServlet { - public static final String DEF_USE_COMPRESSION = "tjws.fileservlet.usecompression"; + /** serialVersionUID */ + private static final long serialVersionUID = 1L; + public static final String DEF_USE_COMPRESSION = "tjws.fileservlet.usecompression"; public static final String DEF_USE_SUPRESSIND = "tjws.fileservlet.suppressindex"; - + // We keep a single throttle table for all instances of the servlet. // Normally there is only one instance; the exception is subclasses. - static Acme.WildcardDictionary throttleTab = null; - + static Acme.WildcardDictionary throttleTab = null; + static final String[] DEFAULTINDEXPAGES = { "index.html", "index.htm", "default.htm", "default.html", "index.php", "index.jsp" }; - + static final DecimalFormat lengthftm = new DecimalFormat("#"); - + static final String BYTES_UNIT = "bytes"; - - protected String charSet = Serve.UTF8;// "iso-8859-1"; - + protected String charSet = IOHelper.UTF_8; private static final boolean logenabled = false; - - // true; - - private Method canExecute, getFreeSpace; // TODO implement free space - - private boolean useCompression; + // TODO implement free space + private Method canExecute, getFreeSpace; + + private boolean useCompression; private boolean supressIndex; - + // / Constructor. public FileServlet() { try { @@ -108,23 +108,24 @@ public FileServlet() { useCompression = System.getProperty(DEF_USE_COMPRESSION) != null; supressIndex = System.getProperty(DEF_USE_SUPRESSIND) != null; } - + // / Constructor with throttling. // @param throttles filename containing throttle settings // @param charset used for displaying directory page // @see ThrottledOutputStream public FileServlet(String throttles, String charset) throws IOException { this(); - if (charset != null) + if (charset != null) { this.charSet = charset; + } readThrottles(throttles); } - + private void readThrottles(String throttles) throws IOException { Acme.WildcardDictionary newThrottleTab = ThrottledOutputStream.parseThrottleFile(throttles); - if (throttleTab == null) + if (throttleTab == null) { throttleTab = newThrottleTab; - else { + } else { // Merge the new one into the old one. Enumeration keys = newThrottleTab.keys(); Enumeration elements = newThrottleTab.elements(); @@ -135,40 +136,37 @@ private void readThrottles(String throttles) throws IOException { } } } - + // / Returns a string containing information about the author, version, and // copyright of the servlet. public String getServletInfo() { return "TJWS: File servlet similar to httpd"; } - + // / Services a single request from the client. // @param req the servlet request // @param req the servlet response // @exception ServletException when an exception has occurred public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { boolean headOnly; - if (req.getMethod().equalsIgnoreCase("get") || req.getAttribute("javax.servlet.forward.request_uri") != null - || req.getAttribute("javax.servlet.include.request_uri") != null) + if (req.getMethod().equalsIgnoreCase("get") || req.getAttribute("javax.servlet.forward.request_uri") != null || req.getAttribute("javax.servlet.include.request_uri") != null) headOnly = false; else if (req.getMethod().equalsIgnoreCase("head")) headOnly = true; else { - res.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Method "+req.getMethod()); + res.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Method " + req.getMethod()); return; } - req.setCharacterEncoding(Serve.UTF8); + req.setCharacterEncoding(IOHelper.UTF_8); String path = Utils.canonicalizePath(req.getPathInfo()); - log("Canonical path:"+path+" for "+req.getPathInfo()+" and servelt path "+req.getServletPath()); - //res.setBufferSize(Utils.COPY_BUF_SIZE/2); + log("Canonical path:" + path + " for " + req.getPathInfo() + " and servelt path " + req.getServletPath()); + // res.setBufferSize(Utils.COPY_BUF_SIZE/2); dispatchPathname(req, res, headOnly, path); } - - private void dispatchPathname(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path) - throws IOException { + + private void dispatchPathname(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path) throws IOException { log("path trans: " + req.getPathTranslated()); - String filename = req.getPathTranslated() != null ? req.getPathTranslated().replace('/', File.separatorChar) - : ""; + String filename = req.getPathTranslated() != null ? req.getPathTranslated().replace('/', File.separatorChar) : ""; File file = new File(filename); log("retrieving '" + filename + "' for path " + path); if (file.exists()) { @@ -180,11 +178,10 @@ private void dispatchPathname(HttpServletRequest req, HttpServletResponse res, b showIdexFile(req, res, headOnly, path, filename); } } else - res.sendError(HttpServletResponse.SC_NOT_FOUND, file.getName()+" not found"); + res.sendError(HttpServletResponse.SC_NOT_FOUND, file.getName() + " not found"); } - - private void showIdexFile(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, - String parent) throws IOException { + + private void showIdexFile(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, String parent) throws IOException { log("showing index in directory " + parent); for (int i = 0; i < DEFAULTINDEXPAGES.length; i++) { File indexFile = new File(parent, DEFAULTINDEXPAGES[i]); @@ -194,14 +191,13 @@ private void showIdexFile(HttpServletRequest req, HttpServletResponse res, boole } } // index not found - if (supressIndex) - res.sendError(HttpServletResponse.SC_NOT_FOUND, "No index file found"); - else - serveDirectory(req, res, headOnly, path, new File(parent)); + if (supressIndex) + res.sendError(HttpServletResponse.SC_NOT_FOUND, "No index file found"); + else + serveDirectory(req, res, headOnly, path, new File(parent)); } - - private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, File file) - throws IOException { + + private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, File file) throws IOException { log("getting " + file); if (logenabled) { Enumeration enh = req.getHeaderNames(); @@ -210,6 +206,7 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean log("hdr:" + hn + ":" + req.getHeader(hn)); } } + if (!file.canRead()) { res.sendError(HttpServletResponse.SC_FORBIDDEN); return; @@ -217,25 +214,28 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean // by Niel Markwick try { file.getCanonicalPath(); - } catch (Exception e) { - res.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden, exception:" + e); + } catch (Exception ex) { + res.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden, exception:" + ex); return; } - + // Handle If-Modified-Since. res.setStatus(HttpServletResponse.SC_OK); long lastMod = file.lastModified(); long ifModSince = req.getDateHeader("If-Modified-Since"); - boolean noContLen = false; + boolean noContLen = false; if (ifModSince != -1 && ifModSince >= lastMod) { res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); headOnly = true; noContLen = true; } + // TODO add processing If-None-Match, If-Unmodified-Since and If-Match String contentType = getServletContext().getMimeType(file.getName()); - if (contentType != null) + if (contentType != null) { res.setContentType(contentType); + } + long flen = file.length(); // check for range String range = req.getHeader("Range"); @@ -248,25 +248,27 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean if (i > 0) { try { sr = Long.parseLong(range.substring(BYTES_UNIT.length() + 1, i)); - if (sr < 0) + if (sr < 0) { throw new NumberFormatException("Invalid start range value:" + sr); + } try { er = Long.parseLong(range.substring(i + 1)); } catch (NumberFormatException nfe) { er = flen - 1; } } catch (NumberFormatException nfe) { - + // ignore me! } + } // else invalid range? ignore? } // else other units not supported log("range values " + sr + " to " + er); } else { - res.setHeader("Accept-Ranges", "bytes"); // by Alexander Ryumshin + res.setHeader("Accept-Ranges", "bytes"); // by Alexander Ryumshin } long clen = er < 0 ? flen : (er - sr + 1); res.setDateHeader("Last-modified", lastMod); - + if (er > 0) { if (sr > er || er >= flen) { // TODO If-Range presence can change behavior @@ -278,6 +280,7 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean res.setHeader("Content-Range", BYTES_UNIT + " " + sr + '-' + er + '/' + flen); log("content-range:" + BYTES_UNIT + " " + sr + '-' + er + '/' + flen); } + // String ifRange = req.getHeader("If-Range"); // res.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); boolean doCompress = false; @@ -287,19 +290,24 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean doCompress = true; } } + if ((doCompress == false || headOnly) && !noContLen) { - if (clen < Integer.MAX_VALUE) + if (clen < Integer.MAX_VALUE) { res.setContentLength((int) clen); - else + } else { res.setHeader("Content-Length", Long.toString(clen)); + } } - String dnla = req.getHeader("GetContentFeatures.DLNA.ORG"); // check also Pragma: getIfoFileURI.dlna.org + // check also Pragma: getIfoFileURI.dlna.org + String dnla = req.getHeader("GetContentFeatures.DLNA.ORG"); if ("1".equals(dnla)) { res.setHeader("transferMode.dlna.org", "Streaming"); - //res.setHeader("contentFeatures.dlna.org", "DLNA.ORG_OP=00;DLNA.ORG_CI=0"); - //res.setHeader("",""); + // res.setHeader("contentFeatures.dlna.org", + // "DLNA.ORG_OP=00;DLNA.ORG_CI=0"); + // res.setHeader("",""); } + OutputStream out = null; InputStream in = null; try { @@ -313,48 +321,61 @@ private void serveFile(HttpServletRequest req, HttpServletResponse res, boolean out = new ThrottledOutputStream(out, throttleItem.getMaxBps()); } } - + in = new FileInputStream(file); while (sr > 0) { long sl = in.skip(sr); - if (sl > 0) + if (sl > 0) { sr -= sl; - else { + } else { res.sendError(HttpServletResponse.SC_CONFLICT, "Conflict"); // better can be Internal Server Error return; } } copyStream(in, out, clen); - if (doCompress) + if (doCompress) { ((GZIPOutputStream) out).finish(); + } } } finally { - if (in != null) - try { - in.close(); - } catch (IOException ioe) { - } + IOHelper.closeSilently(in); if (out != null) { out.flush(); out.close(); } } } - - // / Copy a file from in to out. - // Sub-classes can override this in order to do filtering of some sort. + + /** + * Copy a file from in to out. + * Sub-classes can override this in order to do filtering of some sort. + * + * @param in + * @param out + * @param len + * @throws IOException + */ public void copyStream(InputStream in, OutputStream out, long len) throws IOException { - Acme.Utils.copyStream(in, out, len); + Utils.copyStream(in, out, len); } - - private void serveDirectory(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, - File file) throws IOException { + + /** + * + * @param req + * @param res + * @param headOnly + * @param path + * @param file + * @throws IOException + */ + private void serveDirectory(HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, File file) throws IOException { log("indexing " + file); if (!file.canRead()) { res.sendError(HttpServletResponse.SC_FORBIDDEN); return; } + res.setStatus(HttpServletResponse.SC_OK); res.setContentType("text/html;charset=" + charSet); OutputStream out = res.getOutputStream(); @@ -380,39 +401,50 @@ private void serveDirectory(HttpServletRequest req, HttpServletResponse res, boo File aFile = new File(file, names[i]); String aFileType; long aFileLen; - if (aFile.isDirectory()) + if (aFile.isDirectory()) { aFileType = "d"; - else if (aFile.isFile()) + } else if (aFile.isFile()) { aFileType = "-"; - else + } else { aFileType = "?"; + } + String aFileRead = (aFile.canRead() ? "r" : "-"); String aFileWrite = (aFile.canWrite() ? "w" : "-"); String aFileExe = "-"; - if (canExecute != null) + if (canExecute != null) { try { - if (((Boolean) canExecute.invoke(aFile, Utils.EMPTY_OBJECTS)).booleanValue()) + if (((Boolean) canExecute.invoke(aFile, Utils.EMPTY_OBJECTS)).booleanValue()) { aFileExe = "x"; + } } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } + } + String aFileSize = lengthftm.format(aFileLen = aFile.length()); - total += (aFileLen + 1023) / 1024; // - while (aFileSize.length() < 12) + total += (aFileLen + 1023) / 1024; // + while (aFileSize.length() < 12) { aFileSize = " " + aFileSize; - String aFileDate = Acme.Utils.lsDateStr(new Date(aFile.lastModified())); - while (aFileDate.length() < 14) + } + + String aFileDate = Utils.lsDateStr(new Date(aFile.lastModified())); + while (aFileDate.length() < 14) { aFileDate += " "; + } + String aFileDirsuf = (aFile.isDirectory() ? "/" : ""); String aFileSuf = (aFile.isDirectory() ? "/" : ""); -// TODO HTML encode file name - p.println(aFileType + aFileRead + aFileWrite + aFileExe + " " + aFileSize + " " + aFileDate + " " - + "" + Utils.htmlEncode(names[i], false) + aFileSuf + ""); + // TODO HTML encode file name + /* 1. 4 */ + p.println(aFileType + aFileRead + aFileWrite + aFileExe + " " + aFileSize + " " + aFileDate + " " + "" + Utils.htmlEncode(names[i], false) + aFileSuf + ""); } - if (total != 0) + + if (total != 0) { total += 3; + } + p.println("total " + total); p.println(""); p.println("


"); @@ -422,7 +454,7 @@ else if (aFile.isFile()) } out.close(); } - + /** * * @param req @@ -437,26 +469,32 @@ else if (aFile.isFile()) * @throws IOException * in redirection */ - private boolean redirectDirectory(HttpServletRequest req, HttpServletResponse res, String path, File file) - throws IOException { + private boolean redirectDirectory(HttpServletRequest req, HttpServletResponse res, String path, File file) throws IOException { int pl = path.length(); if (pl > 0 && path.charAt(pl - 1) != '/') { // relative redirect int sp = path.lastIndexOf('/'); - if (sp < 0) + if (sp < 0) { path += '/'; - else + } else { path = path.substring(sp + 1) + '/'; + } log("redirecting dir " + path); res.sendRedirect(path); return true; } + return false; } - - //@Override + + /** + * + * @param msg + * @see javax.servlet.GenericServlet#log(java.lang.String) + */ public void log(String msg) { - if (logenabled) + if (logenabled) { super.log(msg); + } } } \ No newline at end of file diff --git a/1.x/src/Acme/Serve/Main.java b/src/Acme/Serve/Main.java old mode 100644 new mode 100755 similarity index 62% rename from 1.x/src/Acme/Serve/Main.java rename to src/Acme/Serve/Main.java index ff13ec1..7960fb7 --- a/1.x/src/Acme/Serve/Main.java +++ b/src/Acme/Serve/Main.java @@ -1,30 +1,30 @@ -/* tjws - Main.java - * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. +/* + * tjws - Main.java + * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: Main.java,v 1.25 2013/07/24 06:20:37 cvs Exp $ - * Created on Feb 22, 2007 - * @author Dmitriy + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: Main.java,v 1.25 2013/07/24 06:20:37 cvs Exp $ + * Created on Feb 22, 2007 + * @author Dmitriy */ package Acme.Serve; @@ -46,45 +46,48 @@ import java.util.NoSuchElementException; import java.util.StringTokenizer; +import Acme.IOHelper; import Acme.Utils; public class Main extends Serve { + /** serialVersionUID */ + private static final long serialVersionUID = 1L; public static final String CLI_FILENAME = "cmdparams"; - private static final String progName = "Serve"; - protected static Serve serve; - - private static Thread sdHook; + private static Thread shutDownHook; - /** main entry for standalone run + /** + * main entry for standalone run * * @param args */ public static void main(String[] args) { - //int code = main1(args); - Runtime.getRuntime().halt(main1(args)); + Runtime.getRuntime().halt(runMain(args)); } - + /** * Main entry for embedded run + * * @param args */ - public static int main1(String[] args) { + public static int runMain(String[] args) { String workPath = System.getProperty("user.dir", "."); StringBuffer messages = null; - + int argc = args.length; int argn; - if (argc == 0) { // a try to read from file for java -jar server.jar + if (argc == 0) { + // a try to read from file for java -jar server.jar args = readArguments(workPath, CLI_FILENAME); if (args == null) { - messages = appendMessage(messages, "Can't read from CLI file ("+CLI_FILENAME+") at "+workPath+"\n"); - } else + messages = appendMessage(messages, "Can't read from CLI file (" + CLI_FILENAME + ") at " + workPath + "\n"); + } else { argc = args.length; + } } - - Map arguments = new HashMap(20); + + Map arguments = new HashMap(20); arguments.put(ARG_WORK_DIRECTORY, workPath); // Parse args. // TODO: redesign process of parameters based on a map @@ -106,13 +109,14 @@ public static int main1(String[] args) { arguments.put(ARG_ALIASES, args[argn]); } else if (args[argn].equals("-b") && argn + 1 < argc) { ++argn; - if (arguments.containsKey(ARG_BINDADDRESS)) - messages = appendMessage(messages, "Multiple usage of a bind address. "+args[argn]+" ignored\n"); - else + if (arguments.containsKey(ARG_BINDADDRESS)) { + messages = appendMessage(messages, "Multiple usage of a bind address. " + args[argn] + " ignored\n"); + } else { arguments.put(ARG_BINDADDRESS, args[argn]); + } } else if (args[argn].equals("-k") && argn + 1 < argc) { ++argn; - arguments.put(ARG_BACKLOG, args[argn]/*new Integer(args[argn])*/); + arguments.put(ARG_BACKLOG, args[argn]); } else if (args[argn].equals("-j") && argn + 1 < argc) { ++argn; arguments.put(ARG_JSP, args[argn]); @@ -148,17 +152,16 @@ public static int main1(String[] args) { ++argn; arguments.put(ARG_LOG_DIR, args[argn]); } else if (args[argn].startsWith("-l")) { - arguments - .put(ARG_ACCESS_LOG_FMT, - "{0}:{9,number,#} {1} {2} [{3,date,dd/MMM/yyyy:HH:mm:ss Z}] \"{4} {5} {6}\" {7,number,#} {8,number} {10} {11}"); + arguments.put(ARG_ACCESS_LOG_FMT, "{0}:{9,number,#} {1} {2} [{3,date,dd/MMM/yyyy:HH:mm:ss Z}] \"{4} {5} {6}\" {7,number,#} {8,number} {10} {11}"); if (args[argn].length() > 2) { arguments.put(ARG_LOG_OPTIONS, args[argn].substring(2).toUpperCase()); - if (args[argn].indexOf('f') >= 0 && argn < argc-1) { + if (args[argn].indexOf('f') >= 0 && argn < argc - 1) { ++argn; arguments.put(ARG_ACCESS_LOG_FMT, args[argn]); } - } else + } else { arguments.put(ARG_LOG_OPTIONS, ""); + } } else if (args[argn].startsWith("-nohup")) { arguments.put(ARG_NOHUP, ARG_NOHUP); } else if (args[argn].equals("-m") && argn + 1 < argc) { @@ -176,29 +179,22 @@ public static int main1(String[] args) { try { arguments.put(ARG_ERR, (PrintStream) Class.forName(args[argn]).newInstance()); } catch (Error er) { - messages = appendMessage(messages, - "Problem of processing class parameter of error redirection stream: ").append(er) - .append('\n'); + messages = appendMessage(messages, "Problem of processing class parameter of error redirection stream: ").append(er).append('\n'); } catch (Exception ex) { - messages = appendMessage(messages, - "Exception in processing class parameter of error redirection stream: ").append(ex) - .append('\n'); + messages = appendMessage(messages, "Exception in processing class parameter of error redirection stream: ").append(ex).append('\n'); } - } else + } else { arguments.put(ARG_ERR, System.err); + } } else if (args[argn].equals("-out")) { if (argn + 1 < argc && args[argn + 1].startsWith("-") == false) { ++argn; try { arguments.put(ARG_OUT, (PrintStream) Class.forName(args[argn]).newInstance()); } catch (Error er) { - messages = appendMessage(messages, - "Problem of processing class parameter of out redirection stream: ").append(er).append( - '\n'); + messages = appendMessage(messages, "Problem of processing class parameter of out redirection stream: ").append(er).append('\n'); } catch (Exception ex) { - messages = appendMessage(messages, - "Exception in processing class parameter of out redirection stream: ").append(ex) - .append('\n'); + messages = appendMessage(messages, "Exception in processing class parameter of out redirection stream: ").append(ex).append('\n'); } } } else if (args[argn].equals("-sh")) { @@ -207,32 +203,44 @@ public static int main1(String[] args) { arguments.put(ARG_SECUREONLY_SC, ARG_SECUREONLY_SC); } else if (args[argn].equals("-g") && argn + 1 < argc) { arguments.put(ARG_LOGROLLING_LINES, Integer.valueOf(args[++argn])); - } else if (args[argn].startsWith("-")) { // free args, note it generate problem since free arguments can match internal arguments + } else if (args[argn].startsWith("-")) { + /* + * free args, note it generate problem since free arguments can + * match internal arguments + */ if (args[argn].length() > 1) { String name = args[argn].substring(1); if (arguments.containsKey(name)) - messages = appendMessage(messages, "Multiple usage of '-"+name+"'="+args[++argn]+ " ignored\n"); + messages = appendMessage(messages, "Multiple usage of '-" + name + "'=" + args[++argn] + " ignored\n"); else - arguments.put(name,// .toUpperCase(), - argn < argc - 1 ? args[++argn] : ""); - //System.out.println("Added free arg:"+args[argn-1]+"="+args[argn]); - } else + arguments.put(name, // .toUpperCase(), + argn < argc - 1 ? args[++argn] : ""); + // System.out.println("Added free + // arg:"+args[argn-1]+"="+args[argn]); + } else { messages = appendMessage(messages, "Parameter '-' ignored, perhaps extra blank separator was used.\n"); - } else + } + } else { usage(); - + } + ++argn; } - if (argn != argc) + + if (argn != argc) { usage(); - if (System.getProperty(DEF_PROXY_CONFIG) != null) + } + + if (System.getProperty(DEF_PROXY_CONFIG) != null) { arguments.put(ARG_PROXY_CONFIG, System.getProperty(DEF_PROXY_CONFIG)); - // log and error stream manipulation + } + + // log and error stream manipulation // TODO add log rotation feature, it can be done as plug-in PrintStream printstream = System.err; - if (arguments.get(ARG_OUT) != null) + if (arguments.get(ARG_OUT) != null) { printstream = (PrintStream) arguments.get(ARG_OUT); - else { + } else { String logEncoding = System.getProperty(DEF_LOGENCODING); try { File logDir = new File(workPath); @@ -245,14 +253,16 @@ public static int main1(String[] args) { } } File logFile = new File(logDir, "TJWS-" + System.currentTimeMillis() + ".log"); - int logRollThreshold = arguments.get(ARG_LOGROLLING_LINES)!=null?((Integer)arguments.get(ARG_LOGROLLING_LINES)).intValue():0; - OutputStream logStream = logRollThreshold>1000?(OutputStream)new RollingOutputStream(logFile, logRollThreshold): (OutputStream)new FileOutputStream(logFile); - if (logEncoding != null) - printstream = new PrintStream(logStream, true, logEncoding); /* 1.4 */ - else + int logRollThreshold = arguments.get(ARG_LOGROLLING_LINES) != null ? ((Integer) arguments.get(ARG_LOGROLLING_LINES)).intValue() : 0; + OutputStream logStream = logRollThreshold > 1000 ? (OutputStream) new RollingOutputStream(logFile, logRollThreshold) : (OutputStream) new FileOutputStream(logFile); + if (logEncoding != null) { + /* 1.4 */ + printstream = new PrintStream(logStream, true, logEncoding); + } else { printstream = new PrintStream(logStream, true); - } catch (IOException e) { - System.err.println("I/O problem at setting a log stream " + e); + } + } catch (IOException ex) { + System.err.println("I/O problem at setting a log stream " + ex); } } if (arguments.get(ARG_ERR) != null) { @@ -260,62 +270,75 @@ public static int main1(String[] args) { } else { System.setErr(printstream); } - if (messages != null) + if (messages != null) { System.err.println(messages); + } /** * format path mapping from=givenpath;dir=realpath */ PathTreeDictionary mappingtable = new PathTreeDictionary(); if (arguments.get(ARG_ALIASES) != null) { File file = new File((String) arguments.get(ARG_ALIASES)); - if (file.isAbsolute() == false) + if (file.isAbsolute() == false) { file = new File(workPath, file.getPath()); + } + if (file.exists() && file.canRead()) { try { // DataInputStream in = new DataInputStream( // new FileInputStream(file)); BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file))); do { - String mappingstr = in.readLine(); // no arguments in non ASCII encoding allowed - if (mappingstr == null) + // no arguments in non ASCII encoding allowed + String mappingstr = in.readLine(); + if (mappingstr == null) { break; - if (mappingstr.startsWith("#")) + } + + if (mappingstr.startsWith("#")) { continue; + } + StringTokenizer maptokenzr = new StringTokenizer(mappingstr, "=;"); if (maptokenzr.hasMoreTokens()) { if (maptokenzr.nextToken("=").equalsIgnoreCase("from")) { if (maptokenzr.hasMoreTokens()) { String srcpath = maptokenzr.nextToken("=;").trim(); - if (maptokenzr.hasMoreTokens() - && maptokenzr.nextToken(";=").equalsIgnoreCase("dir")) + if (maptokenzr.hasMoreTokens() && maptokenzr.nextToken(";=").equalsIgnoreCase("dir")) try { if (maptokenzr.hasMoreTokens()) { File mapFile = new File(maptokenzr.nextToken()); - if (mapFile.isAbsolute() == false) + if (mapFile.isAbsolute() == false) { mapFile = new File(workPath, mapFile.getPath()); - if (srcpath.endsWith("/*") == false) - if (srcpath.endsWith("/")) + } + + if (srcpath.endsWith("/*") == false) { + if (srcpath.endsWith("/")) { srcpath += "*"; - else + } else { srcpath += "/*"; - if (mapFile.getCanonicalFile().exists()) + } + } + + if (mapFile.getCanonicalFile().exists()) { mappingtable.put(srcpath, mapFile); - else - System.err.println("TJWS: Mapping file " + mapFile + " (" + srcpath - + ") doesn't exist or not readable."); + } else { + System.err.println("TJWS: Mapping file " + mapFile + " (" + srcpath + ") doesn't exist or not readable."); + } } - } catch (NullPointerException e) { + } catch (NullPointerException ex) { } } } } } while (true); + + in.close(); } catch (IOException e) { System.err.println("TJWS: Problem reading aliases file: " + arguments.get(ARG_ALIASES) + "/" + e); } } else - System.err.println("TJWS: File " + file + " (" + arguments.get(ARG_ALIASES) - + ") doesn't exist or not readable."); + System.err.println("TJWS: File " + file + " (" + arguments.get(ARG_ALIASES) + ") doesn't exist or not readable."); } // format realmname=path,user:password,,,, // TODO consider to add a role, like realmname=path,user:password[:role] @@ -326,13 +349,16 @@ public static int main1(String[] args) { if (file.isAbsolute() == false) file = new File(workPath, file.getPath()); BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file))); - do { String realmstr = in.readLine(); - if (realmstr == null) + if (realmstr == null) { break; - if (realmstr.startsWith("#")) + } + + if (realmstr.startsWith("#")) { continue; + } + StringTokenizer rt = new StringTokenizer(realmstr, "=,:"); if (rt.hasMoreTokens()) { String realmname = null; @@ -346,14 +372,15 @@ public static int main1(String[] args) { String password = rt.nextToken(); BasicAuthRealm realm = null; Object o[] = realms.get(realmPath); - if (o != null && o[0] != null) + if (o != null && o[0] != null) { realm = (BasicAuthRealm) o[0]; - else { + } else { realm = new BasicAuthRealm(realmname); - if (realmPath.endsWith("/*") == false) - realmPath+="/*"; - else if (realmPath.endsWith("/")) - realmPath+="*"; + if (realmPath.endsWith("/*") == false) { + realmPath += "/*"; + } else if (realmPath.endsWith("/")) { + realmPath += "*"; + } realms.put(realmPath, realm); } realm.put(user, password); @@ -362,6 +389,8 @@ else if (realmPath.endsWith("/")) } } } while (true); + + in.close(); } catch (IOException ioe) { System.err.println("TJWS: I/O problem in reading realms file " + arguments.get(ARG_REALMS) + ": " + ioe); } @@ -372,30 +401,36 @@ else if (realmPath.endsWith("/")) serve.setMappingTable(mappingtable); serve.setRealms(realms); File tempFile = arguments.get(ARG_SERVLETS) == null ? null : new File((String) arguments.get(ARG_SERVLETS)); - if (tempFile != null && tempFile.isAbsolute() == false) + if (tempFile != null && tempFile.isAbsolute() == false) { tempFile = new File(workPath, tempFile.getPath()); + } + final File servFile = tempFile; // TODO analyze possible race condition - if (servFile != null) + if (servFile != null) { new Thread(new Runnable() { public void run() { readServlets(servFile); } }).start(); + } + // And add the standard Servlets. String throttles = (String) arguments.get(ARG_THROTTLES); - if (throttles == null) + if (throttles == null) { serve.addDefaultServlets((String) arguments.get(ARG_CGI_PATH)); - else + } else { try { serve.addDefaultServlets((String) arguments.get(ARG_CGI_PATH), throttles); } catch (IOException e) { serve.log("Problem reading throttles file: " + e, e); System.exit(1); } + } + serve.addWebsocketProvider((String) arguments.get(ARG_WEBSOCKET)); serve.addWarDeployer((String) arguments.get(ARG_WAR), throttles); - if (arguments.get(ARG_NOHUP) == null) + if (arguments.get(ARG_NOHUP) == null) { new Thread(new Runnable() { public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); @@ -415,99 +450,120 @@ public void run() { } } }, "Stop Monitor").start(); - else { - Runtime.getRuntime().addShutdownHook(sdHook = new Thread(new Runnable() { + } else { + shutDownHook = new Thread(new Runnable() { synchronized public void run() { serve.destroyAllServlets(); } - }, "ShutDownHook")); + }, "ShutDownHook"); + Runtime.getRuntime().addShutdownHook(shutDownHook); } + // And run. - int code = serve.serve(); - if (code != 0 && arguments.get(ARG_NOHUP) == null) + Status code = serve.serve(); + if (code != Status.STOPPED && arguments.get(ARG_NOHUP) == null) { try { + // to break termination thread System.out.println(); - System.in.close(); // to break termination thread - } catch (IOException e) { + System.in.close(); + } catch (IOException ex) { + serve.log(ex); } + } + try { - if (sdHook != null) - Runtime.getRuntime().removeShutdownHook(sdHook); + if (shutDownHook != null) { + Runtime.getRuntime().removeShutdownHook(shutDownHook); + } serve.destroyAllServlets(); - } catch (IllegalStateException ise) { - - } catch (Throwable t) { - if (t instanceof ThreadDeath) - throw (ThreadDeath)t; - serve.log("At destroying ", t); + } catch (IllegalStateException ex) { + // ignore me! + } catch (Throwable th) { + if (th instanceof ThreadDeath) { + throw (ThreadDeath) th; + } + serve.log("At destroying ", th); } killAliveThreads(); printstream.close(); - return code; + + return code.getStatus(); } - + + /** + * + * @param messages + * @param message + * @return + */ private static StringBuffer appendMessage(StringBuffer messages, String message) { - if (messages == null) + if (messages == null) { messages = new StringBuffer(100); + } return messages.append(message); } - + + /** + * + * @param workPath + * @param file + * @return + */ public static String[] readArguments(String workPath, String file) { BufferedReader br = null; try { br = new BufferedReader(new FileReader(new File(workPath, file))); return Utils.splitStr(br.readLine(), "\""); - } catch (Exception e) { // many can happen - //e.printStackTrace(); + } catch (Exception ex) { + // many can happen + // e.printStackTrace(); return null; } finally { - if (br != null) - try { - br.close(); - } catch (IOException ioe) { - } + IOHelper.closeSilently(br); } } - + + /** + * + * @throws IOException + */ public static void stop() throws IOException { serve.notifyStop(); } - + + /** + * + */ private static void usage() { - System.out.println(Identification.serverName + " " + Identification.serverVersion + "\n" + "Usage: " - + progName + " [-p port] [-s servletpropertiesfile] [-a aliasmappingfile]\n" - + " [-b bind address] [-k backlog] [-l[a][r][f access_log_fmt]]\n" - + " [-c cgi-bin-dir] [-m max_active_session] [-d log_directory]\n" - + " [-sp] [-j jsp_servlet_class] [-w war_deployment_module_class]\n" - + " [-nka] [-kat timeout_in_secs] [-mka max_times_connection_use]\n" - + " [-e [-]duration_in_minutes] [-nohup] [-z max_threadpool_size]\n" - + " [-err [class_name?PrintStream]] [-out [class_name?PrintStream]] [-g ]\n" - + " [-acceptorImpl class_name_of_Accpetor_impl [extra_acceptor_parameters] ]\n" + " Legend:\n" - + " -sp session persistence\n" + " -l access log a - with user agent, and r - referer\n" - + " -nka no keep alive for connection"); + System.out.println(Identification.serverName + " " + Identification.serverVersion + "\n" + "Usage: " + progName + " [-p port] [-s servletpropertiesfile] [-a aliasmappingfile]\n" + " [-b bind address] [-k backlog] [-l[a][r][f access_log_fmt]]\n" + " [-c cgi-bin-dir] [-m max_active_session] [-d log_directory]\n" + " [-sp] [-j jsp_servlet_class] [-w war_deployment_module_class]\n" + " [-nka] [-kat timeout_in_secs] [-mka max_times_connection_use]\n" + " [-e [-]duration_in_minutes] [-nohup] [-z max_threadpool_size]\n" + " [-err [class_name?PrintStream]] [-out [class_name?PrintStream]] [-g ]\n" + " [-acceptorImpl class_name_of_Accpetor_impl [extra_acceptor_parameters] ]\n" + " Legend:\n" + " -sp session persistence\n" + " -l access log a - with user agent, and r - referer\n" + " -nka no keep alive for connection"); System.exit(1); } - + + /** + * + */ private static void killAliveThreads() { serve.serverThreads.interrupt(); ThreadGroup tg = Thread.currentThread().getThreadGroup(); while (tg.getParent() != null) tg = tg.getParent(); int ac = tg.activeCount() + tg.activeGroupCount() + 10; - + Thread[] ts = new Thread[ac]; ac = tg.enumerate(ts, true); - if (ac == ts.length) + if (ac == ts.length) { serve.log("Destroy:interruptRunningProcesses: Not all threads will be stopped."); + } + // kill non daemon - for (int i = 0; i < ac; i++) + for (int i = 0; i < ac; i++) { if (ts[i].isDaemon() == false) { String tn = ts[i].getName(); - //System.err.println("Interrupting and kill " + tn); - - if (ts[i] == Thread.currentThread() || "Stop Monitor".equals(tn) || "ShutDownHook".equals(tn) - || "DestroyJavaVM".equals(tn) || (tn != null && tn.startsWith("AWT-")) || "main".equals(tn)) + // System.err.println("Interrupting and kill " + tn); + if (ts[i] == Thread.currentThread() || "Stop Monitor".equals(tn) || "ShutDownHook".equals(tn) || "DestroyJavaVM".equals(tn) || (tn != null && tn.startsWith("AWT-")) || "main".equals(tn)) { continue; + } + ts[i].interrupt(); Thread.yield(); if (ts[i].isAlive()) { @@ -515,22 +571,26 @@ private static void killAliveThreads() { ts[i].stop(); } catch (Throwable t) { if (t instanceof ThreadDeath) { - serve - .log( - "Thread death exception happened and stopping thread, thread stopping loop will be terminated", - t); + serve.log("Thread death exception happened and stopping thread, thread stopping loop will be terminated", t); throw (ThreadDeath) t; } else serve.log("An exception at stopping " + ts[i] + " " + t); } } - }// else - //serve.log("Daemon thread "+ts[i].getName()+" is untouched."); + } // else + // serve.log("Daemon thread "+ts[i].getName()+" is untouched."); + } } - + + /** + * + * @param servFile + */ private static void readServlets(File servFile) { /** - * servlet.properties file format servlet. .code= servlet. .initArgs= , + * servlet.properties file format servlet. .code= + * servlet. .initArgs= , + * */ Hashtable servletstbl, parameterstbl; servletstbl = new Hashtable(); @@ -539,14 +599,19 @@ private static void readServlets(File servFile) { try { BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(servFile))); /** - * format of servlet.cfg file servlet_name;servlet_class;init_parameter1=value1;init_parameter2=value2... + * format of servlet.cfg file + * servlet_name;servlet_class;init_parameter1=value1;init_parameter2=value2... */ do { String servletdsc = in.readLine(); - if (servletdsc == null) + if (servletdsc == null) { break; - if (servletdsc.startsWith("#")) + } + + if (servletdsc.startsWith("#")) { continue; + } + StringTokenizer dsctokenzr = new StringTokenizer(servletdsc, ".=,", false); if (dsctokenzr.hasMoreTokens()) { if (!dsctokenzr.nextToken().equalsIgnoreCase("servlet")) { @@ -555,39 +620,41 @@ private static void readServlets(File servFile) { } if (dsctokenzr.hasMoreTokens()) { String servletname = dsctokenzr.nextToken(); - while (dsctokenzr.hasMoreTokens()) { String lt = dsctokenzr.nextToken(); if (lt.equalsIgnoreCase("code")) { - if (dsctokenzr.hasMoreTokens()) + if (dsctokenzr.hasMoreTokens()) { servletstbl.put(servletname, dsctokenzr.nextToken("=")); + } } else if (lt.equalsIgnoreCase("initArgs")) { Hashtable initparams = new Hashtable(); while (dsctokenzr.hasMoreTokens()) { String key = dsctokenzr.nextToken("="); if (key.startsWith(",")) key = key.substring(1); - //System.err.println("Key:"+key); + // System.err.println("Key:"+key); try { - initparams.put(key, dsctokenzr.nextToken(",").substring(1).replaceAll("%2c", ",")); - //System.err.println("Key:"+key+" val:"+initparams.get(key)); - } catch(NoSuchElementException nse) { - initparams.put(key,""); + initparams.put(key, dsctokenzr.nextToken(",").substring(1).replaceAll("%2c", ",")); + // System.err.println("Key:"+key+" + // val:"+initparams.get(key)); + } catch (NoSuchElementException nse) { + initparams.put(key, ""); break; } } - //System.err.println("init:"+initparams+" for "+servletname); + // System.err.println("init:"+initparams+" + // for "+servletname); parameterstbl.put(servletname, initparams); } else { - servletname +='.'+lt; - serve - .log("No expected token (code|initArgs), "+lt+" added to servlet " - + servletname +" for line: "+servletdsc); + servletname += '.' + lt; + serve.log("No expected token (code|initArgs), " + lt + " added to servlet " + servletname + " for line: " + servletdsc); } } } } } while (true); + + in.close(); } catch (IOException e) { serve.log("IO problem in processing servlets definition file (" + servFile + "): " + e); } @@ -595,12 +662,13 @@ private static void readServlets(File servFile) { String servletname; while (se.hasMoreElements()) { servletname = (String) se.nextElement(); - //System.err.println("Adding servlet fro "+servletname+" as "+servletstbl.get(servletname)); - serve.addServlet(servletname, (String) servletstbl.get(servletname), (Hashtable) parameterstbl - .get(servletname)); + // System.err.println("Adding servlet fro "+servletname+" as + // "+servletstbl.get(servletname)); + serve.addServlet(servletname, (String) servletstbl.get(servletname), (Hashtable) parameterstbl.get(servletname)); } - } else + } else { serve.log("Servlets definition file neither provided, found, nor readable: " + servFile); + } } static class RollingOutputStream extends FilterOutputStream { @@ -608,24 +676,25 @@ static class RollingOutputStream extends FilterOutputStream { private File nameBase; private volatile int currentLine; private int numRoll; - + public RollingOutputStream(File file, int rollingSize) throws IOException { super(null); rollingThresh = rollingSize; - if (rollingThresh < 1000) + if (rollingThresh < 1000) { rollingThresh = 1000; + } nameBase = file; out = new FileOutputStream(nameBase); } - - //@Override 1.4 + + // @Override 1.4 public void flush() throws IOException { super.flush(); if (currentLine++ > rollingThresh) { synchronized (this) { if (currentLine++ > rollingThresh) { out.close(); - if (nameBase.renameTo(new File(nameBase.getPath()+ "." + new DecimalFormat("0000").format(numRoll++)))) { + if (nameBase.renameTo(new File(nameBase.getPath() + "." + new DecimalFormat("0000").format(numRoll++)))) { out = new FileOutputStream(nameBase); currentLine = 0; } else { diff --git a/src/Acme/Serve/SSLAcceptor.java b/src/Acme/Serve/SSLAcceptor.java new file mode 100755 index 0000000..ddbf3d6 --- /dev/null +++ b/src/Acme/Serve/SSLAcceptor.java @@ -0,0 +1,348 @@ +/* + * tjws - SSLAcceptor.java + * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: SSLAcceptor.java,v 1.10 2013/03/02 09:11:56 cvs Exp $ + * Created on Feb 21, 2007 + * @author dmitriy + */ +package Acme.Serve; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.KeyStore; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Map; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; +import Acme.Utils; +import Acme.Serve.Serve.Acceptor; + +public class SSLAcceptor implements Acceptor { + // SUNX509 + public static final String ARG_ALGORITHM = "algorithm"; + // by default false + public static final String ARG_CLIENTAUTH = "clientAuth"; + // ARG_KEYSTOREFILE + public static final String ARG_KEYSTOREFILE = "keystoreFile"; + // ARG_USE_KEYSTORE_BYTES + public static final String ARG_USE_KEYSTORE_BYTES = "useKeyStoreBytes"; + // ARG_KEYSTORE_BYTES + public static final String ARG_KEYSTORE_BYTES = "keyStoreBytes"; + // PROP_KEYSTOREFILE + public static final String PROP_KEYSTOREFILE = "javax.net.ssl.keyStore"; + // KEYSTOREPASS + public static final String ARG_KEYSTOREPASS = "keystorePass"; + public static final String PROP_KEYSTOREPASS = "javax.net.ssl.keyStorePassword"; + // KEYSTORETYPE + public static final String ARG_KEYSTORETYPE = "keystoreType"; + // PROP_KEYSTORETYPE + public static final String PROP_KEYSTORETYPE = "javax.net.ssl.keyStoreType"; + // PROP_KEYSTORETYPE + public static final String ARG_KEYPASS = "keyPass"; + // TLS ARG_PROTOCOL + public static final String ARG_PROTOCOL = "protocol"; + public static final String ARG_BACKLOG = Serve.ARG_BACKLOG; + public static final String ARG_SO_HS_TIMEOUT = "socket-handshake-timeout"; + public static final String ARG_IFADDRESS = "ifAddress"; + public static final String ARG_PORT = "ssl-port"; + public static final String PROTOCOL_HANDLER_JSSE10 = "com.sun.net.ssl.internal.www.protocol"; + public static final String PROTOCOL_HANDLER = "javax.net.ssl.internal.www.protocol"; + + /** + * The name of the system property containing a "|" delimited list of + * protocol handler packages. + */ + public static final String PROTOCOL_PACKAGES = "java.protocol.handler.pkgs"; + + /** + * Certificate encoding algorithm to be used. + */ + public final static String SUNX509 = "SunX509"; + + /** + * default SSL port + */ + public final static int PORT = 8443; + + /** + * default backlog + */ + public final static int BACKLOG = 1000; + + /** + * Storage type of the key store file to be used. + */ + public final static String KEYSTORETYPE = "JKS"; + + /** + * SSL protocol variant to use. + */ + public final static String TLS = "TLS"; + + /** + * SSL protocol variant to use. + */ + public static final String protocol = TLS; + + /** + * Password for accessing the key store file. + */ + private static final String KEYSTOREPASS = "changeme"; + + /** + * default socket SSL handshake timeout preventing DoS attacks + */ + protected static final int SO_HS_TIMEOIUT = 30 * 1000; + + /** + * Pathname to the key store file to be used. + */ + protected String keystoreFile = System.getProperty("user.home") + File.separator + ".keystore"; + protected ServerSocket socket; + protected static int socketHandshakeTimeout; + + /** + * Returns the keystore file path. + * + * @return + */ + private String getKeystoreFile() { + return (this.keystoreFile); + } + + /** + * @see Acme.Serve.Serve.Acceptor#accept() + */ + public Socket accept() throws IOException { + return socket.accept(); + } + + /** + * Disconnects the socket and set it null. + * + * @see Acme.Serve.Serve.Acceptor#destroy() + */ + public void destroy() throws IOException { + IOHelper.closeSilently(socket); + socket = null; + } + + /** + * Initialize the SSL server socket. + * + * @see Acme.Serve.Serve.Acceptor#init(java.util.Map, java.util.Map) + */ + public void init(Map inProperties, Map outProperties) throws IOException { + // Create the proxy and return + SSLServerSocketFactory sslSocketFactory = initSSLContext(inProperties, outProperties).getServerSocketFactory(); + int port = Utils.parseInt(inProperties.get(ARG_PORT), Utils.parseInt(inProperties.get(Serve.ARG_PORT), PORT)); + + if (inProperties.get(ARG_BACKLOG) == null) { + if (inProperties.get(ARG_IFADDRESS) == null) { + socket = sslSocketFactory.createServerSocket(port); + } else { + socket = sslSocketFactory.createServerSocket(port, BACKLOG, InetAddress.getByName((String) inProperties.get(ARG_IFADDRESS))); + } + } else if (inProperties.get(ARG_IFADDRESS) == null) { + socket = sslSocketFactory.createServerSocket(port, Utils.parseInt(inProperties.get(ARG_BACKLOG), BACKLOG)); + } else { + socket = sslSocketFactory.createServerSocket(port, Utils.parseInt(inProperties.get(ARG_BACKLOG), BACKLOG), InetAddress.getByName((String) inProperties.get(ARG_IFADDRESS))); + } + + LogManager.debug("socket:" + socket); + initServerSocket(socket, "true".equals(inProperties.get(ARG_CLIENTAUTH))); + if (outProperties != null) { + outProperties.put(Serve.ARG_BINDADDRESS, socket.getInetAddress().getHostName()); + } + + /* + * note it isn't use for the implementation since there is no control + * over handshake + */ + socketHandshakeTimeout = Utils.parseInt(inProperties.get(ARG_SO_HS_TIMEOUT), SO_HS_TIMEOIUT); + } + + /** + * + * @param inProperties + * @param outProperties + * @return + * @throws IOException + */ + protected SSLContext initSSLContext(Map inProperties, Map outProperties) throws IOException { + // init keystore + KeyStore keyStore = null; + InputStream keyStoreStream = null; + String keystorePass = null; + LogManager.debug("isAndroid:" + IOHelper.isAndroid()); + try { + String keystoreType = getWithDefault(inProperties, ARG_KEYSTORETYPE, KEYSTORETYPE); + LogManager.debug("keystoreType:" + keystoreType); + keyStore = KeyStore.getInstance(keystoreType); + String keystoreFile = (String) inProperties.get(ARG_KEYSTOREFILE); + if (keystoreFile == null) { + keystoreFile = getKeystoreFile(); + } + LogManager.debug("keystoreFile:" + keystoreFile); + // if (IOHelper.toBoolean(inProperties.get(ARG_USE_KEYSTORE_BYTES))) + // { + // LogManager.debug("using keystore bytes."); + // final byte[] keyStoreBytes = (byte[]) + // inProperties.get(ARG_KEYSTORE_BYTES); + // keyStoreStream = IOHelper.toInputStream(keyStoreBytes); + // } else { + // keyStoreStream = new FileInputStream(keystoreFile); + // } + keyStoreStream = new FileInputStream(keystoreFile); + keystorePass = getWithDefault(inProperties, ARG_KEYSTOREPASS, KEYSTOREPASS); + keyStore.load(keyStoreStream, keystorePass.toCharArray()); + } catch (Exception ex) { + LogManager.error("Error initializing SSLAcceptor!", ex); + throw IOHelper.newIOException(ex); + } finally { + IOHelper.closeSilently(keyStoreStream); + } + + try { + // Register the JSSE security Provider (if it is not already there) + if (!IOHelper.isAndroid()) { + try { + Security.addProvider((Provider) Class.forName("com.sun.net.ssl.internal.ssl.Provider").newInstance()); + } catch (Throwable th) { + LogManager.error("Error adding SSL provider!", th); + if (th instanceof ThreadDeath) { + throw (ThreadDeath) th; + } + // TODO think to do not propagate absence of the provider, + // since other can still work + throw IOHelper.newIOException(th); + } + } + + // Create an SSL context used to create an SSL socket factory + String protocol = getWithDefault(inProperties, ARG_PROTOCOL, TLS); + LogManager.debug("protocol:" + protocol); + final SSLContext sslContext = SSLContext.getInstance(protocol); + LogManager.debug("sslContext:" + sslContext); + + // Create the key manager factory used to extract the server key + String algorithm = getWithDefault(inProperties, ARG_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm); + LogManager.debug("keyManagerType:" + keyManagerFactory.getAlgorithm()); + + String keyPass = getWithDefault(inProperties, ARG_KEYPASS, keystorePass); + keyManagerFactory.init(keyStore, keyPass.toCharArray()); + + // Create trust manager + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + LogManager.debug("trustManagerType:" + trustManagerFactory.getAlgorithm() + ", Provider:" + trustManagerFactory.getProvider()); + trustManagerFactory.init(keyStore); + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + // Initialize the context with the key managers + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom()); + LogManager.debug("sslContext - Protocol:" + sslContext.getProtocol() + ", Provider:" + sslContext.getProvider()); + return sslContext; + } catch (Exception ex) { + LogManager.error("Error while creating SSLSocket!", ex); + throw IOHelper.newIOException(ex); + } + } + + /** + * Register our URLStreamHandler for the "https:" protocol. + */ + protected static void initHandler() { + String packages = System.getProperty(PROTOCOL_PACKAGES); + if (packages == null) { + packages = PROTOCOL_HANDLER; + } else if (packages.indexOf(PROTOCOL_HANDLER) < 0) { + packages += "|" + PROTOCOL_HANDLER; + } + LogManager.debug("packages:" + packages); + System.setProperty(PROTOCOL_PACKAGES, packages); + } + + /** + * Returns the string representation of this object. + * + * @see java.lang.Object#toString() + */ + public String toString() { + return "SSLAcceptor - " + (socket != null ? socket.toString() : "Uninitialized!"); + } + + static { + initHandler(); + } + + /** + * Set the requested properties for this server socket. + * + * @param serverSocket + * @param needClientAuth + */ + protected void initServerSocket(final ServerSocket serverSocket, final boolean needClientAuth) { + LogManager.debug("+initServerSocket(" + serverSocket + "" + needClientAuth + ")"); + final SSLServerSocket sslServerSocket = (SSLServerSocket) serverSocket; + // Enable all available cipher suites when the socket is connected + LogManager.debug("SupportedCipherSuites:" + IOHelper.toString(sslServerSocket.getSupportedCipherSuites())); + LogManager.debug("SupportedProtocols:" + IOHelper.toString(sslServerSocket.getSupportedProtocols())); + LogManager.debug("setNeedClientAuth:" + needClientAuth); + + sslServerSocket.setEnabledCipherSuites(sslServerSocket.getSupportedCipherSuites()); + sslServerSocket.setEnabledProtocols(sslServerSocket.getSupportedProtocols()); + // Set client authentication if necessary + sslServerSocket.setNeedClientAuth(needClientAuth); + LogManager.debug("-initServerSocket()"); + } + + /** + * + * @param args + * @param name + * @param defValue + * @return + */ + private String getWithDefault(Map args, String name, String defValue) { + String result = (String) args.get(name); + return (result == null ? defValue : result); + } +} diff --git a/src/Acme/Serve/SelectorAcceptor.java b/src/Acme/Serve/SelectorAcceptor.java new file mode 100755 index 0000000..6585cf0 --- /dev/null +++ b/src/Acme/Serve/SelectorAcceptor.java @@ -0,0 +1,145 @@ +/* + * tjws - SelectorAcceptor.java + * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: SelectorAcceptor.java,v 1.8 2008/01/18 10:05:23 dmitriy Exp $ + * Created on Feb 21, 2007 + * @author dmitriy + */ +package Acme.Serve; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.util.Iterator; +import java.util.Map; + +import com.rslakra.logger.LogManager; + +import Acme.Serve.Serve.Acceptor; + +public class SelectorAcceptor implements Acceptor { + + private ServerSocketChannel channel; + private Selector selector; + private Iterator selKeyItr; + + public Socket accept() throws IOException { + do { + if (selKeyItr == null) { + if (selector.select() > 0) { + selKeyItr = selector.selectedKeys().iterator(); + } else { + throw new IOException(); + } + } + + if (selKeyItr.hasNext()) { + // Get key from set + SelectionKey selectionKey = selKeyItr.next(); + + // Remove current entry + selKeyItr.remove(); + // TODO add processing CancelledKeyException + if (selectionKey.isValid() && selectionKey.isAcceptable()) { + // Get channel + ServerSocketChannel keyChannel = (ServerSocketChannel) selectionKey.channel(); + // Get server socket + ServerSocket serverSocket = keyChannel.socket(); + // Accept request + return serverSocket.accept(); + } + } else { + selKeyItr = null; + } + } while (true); + } + + /** + * + * @throws IOException + * @see Acme.Serve.Serve.Acceptor#destroy() + */ + public void destroy() throws IOException { + String exceptions = ""; + try { + channel.close(); + } catch (IOException e) { + exceptions += e.toString(); + } + try { + selector.close(); + } catch (IOException ex) { + exceptions += ex.toString(); + } + + if (exceptions.length() > 0) { + throw new IOException(exceptions); + } + } + + /** + * @see Acme.Serve.Serve.Acceptor#init(Acme.Serve.Serve, java.util.Map, + * java.util.Map) + */ + public void init(Map inProperties, Map outProperties) throws IOException { + selector = Selector.open(); + channel = ServerSocketChannel.open(); + channel.configureBlocking(false); + int port = inProperties.get(Serve.ARG_PORT) != null ? ((Integer) inProperties.get(Serve.ARG_PORT)).intValue() : Serve.DEF_PORT; + InetSocketAddress socketAddress = null; + if (inProperties.get(Serve.ARG_BINDADDRESS) != null) { + try { + socketAddress = new InetSocketAddress((String) inProperties.get(Serve.ARG_BINDADDRESS), port); + } catch (Exception ex) { + LogManager.error(ex); + } + } + + if (socketAddress == null) { + socketAddress = new InetSocketAddress(port); + } + + // TODO add ARG_BACKLOG + channel.socket().bind(socketAddress); + + // Register interest in when connection + channel.register(selector, SelectionKey.OP_ACCEPT); + if (outProperties != null) { + if (channel.socket().isBound()) { + outProperties.put(Serve.ARG_BINDADDRESS, channel.socket().getInetAddress().getHostName()); + } else { + outProperties.put(Serve.ARG_BINDADDRESS, InetAddress.getLocalHost().getHostName()); + } + } + } + + public String toString() { + return "SelectorAcceptor - " + (channel == null ? "unset" : "" + channel.socket()); + } +} diff --git a/src/Acme/Serve/Serve.java b/src/Acme/Serve/Serve.java new file mode 100755 index 0000000..fd117c8 --- /dev/null +++ b/src/Acme/Serve/Serve.java @@ -0,0 +1,6728 @@ +// Serve - minimal Java servlet container class +// +// Copyright (C)1996,1998 by Jef Poskanzer . All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)1998-2014 by Dmitriy Rogatkin +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +// $Id: Serve.java,v 1.269 2013/08/20 04:11:09 cvs Exp $ + +package Acme.Serve; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.BindException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.SecureRandom; +import java.text.MessageFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TimeZone; +import java.util.TreeSet; +import java.util.Vector; + +import javax.net.ssl.SSLSocket; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRegistration; +import javax.servlet.ServletRegistration.Dynamic; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.SingleThreadModel; +import javax.servlet.UnavailableException; +import javax.servlet.descriptor.JspConfigDescriptor; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionActivationListener; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; +import javax.servlet.http.HttpSessionContext; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; +import javax.servlet.http.Part; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; +import Acme.ThreadPoolFactory; +import Acme.Utils; + +/// Minimal Java servlet container class. +//

+// This class implements a very small embeddable servlet container. +// It runs Servlets compatible with the API used by Sun's +// Java System Application +/// server. +// Servlet API can be found here. +// It comes with default Servlets which provide the usual +// httpd services, returning files and directory listings. +//

+// This is not in any sense a competitor for Java System Application server. +// Java System Application server is a full-fledged HTTP server and more. +// Acme.Serve is tiny, about 5000 lines, and provides only the +// functionality necessary to deliver an Applet's .class files +// and then start up a Servlet talking to the Applet. +// They are both written in Java, they are both web servers, and +// they both implement the Servlet API; other than that they couldn't +// be more different. +//

+// This is actually the second HTTP server I've written. +// The other one is called +// thttpd, +// it's written in C, and is also pretty small although much more +// featureful than this. +//

+// Other Java HTTP servers: +//

+//

+// A June 1997 BYTE +// magazine article mentioning this server.
+// A December 1997 BYTE +// magazine article giving it an Editor's Choice Award of Distinction.
+// Fetch the +// software.
+// Fetch the entire Acme package. +//

+// @see Acme.Serve.servlet.http.HttpServlet +// @see FileServlet +// @see CgiServlet +//

Post notes

+// Currently the server 3 more times complex and can compete with +// most popular app and web servers used for deploying of web +// Java applications. + +// Inheritance can extend usage of this server +public class Serve implements ServletContext, Serializable { + + /** serialVersionUID */ + private static final long serialVersionUID = 1L; + + public static final String ARG_PORT = "port"; + public static final String ARG_THROTTLES = "throttles"; + public static final String ARG_SERVLETS = "servlets"; + public static final String ARG_REALMS = "realms"; + public static final String ARG_ALIASES = "aliases"; + public static final String ARG_BINDADDRESS = "bind-address"; + public static final String ARG_BACKLOG = "backlog"; + public static final String ARG_CGI_PATH = "cgi-path"; + public static final String ARG_ERR = "error-stream"; + public static final String ARG_OUT = "out-stream"; + public static final String ARG_SESSION_TIMEOUT = "session-timeout"; + public static final String ARG_LOG_DIR = "log-dir"; + public static final String ARG_LOG_OPTIONS = "log-options"; + public static final String ARG_LOGROLLING_LINES = "log-rolling-lines-threshold"; + + public static final String ARG_NOHUP = "nohup"; + + public static final String ARG_JSP = "JSP"; + public static final String ARG_WAR = "war-deployer"; + public static final String ARG_WEBSOCKET = "WEBSOCKET-PROVIDER"; + public static final String ARG_KEEPALIVE = "keep-alive"; + public static final String ARG_PROXY_CONFIG = "proxy-config"; + public static final String DEF_LOGENCODING = "tjws.serve.log.encoding"; + public static final String DEF_PROXY_CONFIG = "tjws.proxy.ssl"; + public static final String ARG_KEEPALIVE_TIMEOUT = "timeout-keep-alive"; + public static final String ARG_MAX_CONN_USE = "max-alive-conn-use"; + public static final String ARG_SESSION_PERSIST = "sssn-persistance"; + public static final String ARG_MAX_ACTIVE_SESSIONS = "max-active-sessions"; + public static final String ARG_ACCESS_LOG_FMT = "access-log-format"; + public static final String ARG_ACCEPTOR_CLASS = "acceptorImpl"; + public static final String ARG_WORK_DIRECTORY = "workdirectory"; + public static final String ARG_SESSION_SEED = "SessionSeed"; + public static final String ARG_SESSION_SEED_ALG = "SecureRandomAlgorithm"; + public static final String ARG_HTTPONLY_SC = "sessionhttponly"; + public static final String ARG_SECUREONLY_SC = "sessionsecureonly"; + + public static final String ARG_THREAD_POOL_SIZE = Utils.ThreadPool.MAXNOTHREAD; + // in minutes + protected static final int DEF_SESSION_TIMEOUT = 30; + protected static final int DEF_MIN_ACT_SESS = 10; + protected static final int DESTROY_TIME_SEC = 15; + protected static final int HTTP_MAX_HDR_LEN = 1024 * 1024 * 10; + public static final int DEF_PORT = 8080; + public static final String BGCOLOR = "BGCOLOR=\"#D1E9FE\""; + public final static String LINE_SEP = System.getProperty("line.separator", "\n"); + + /** max number of alive connections default value */ + protected static final int DEF_MAX_CONN_USE = 100; + protected static final Integer INT_ZERO = new Integer(0); + + protected String hostName; + private transient PrintStream logStream; + + private boolean useAccLog; + private boolean keepAlive; + private boolean proxyConfig; + private boolean proxySSL; + private int timeoutKeepAlive; + private int maxAliveConnUse; + private boolean showUserAgent; + private boolean showReferer; + protected String keepAliveHdrParams; + + protected transient PathTreeDictionary defaultRegistry; + protected transient HashMap virtuals; + protected transient PathTreeDictionary realms; + protected transient PathTreeDictionary mappingtable; + private Hashtable attributes; + + protected transient KeepAliveCleaner keepAliveCleaner; + protected transient ThreadGroup serverThreads; + protected transient Utils.ThreadPool threadPool; + protected transient Constructor gzipInStreamConstr; + private static final ThreadLocal currentRegistry = new ThreadLocal(); + + // TODO for sessions consider configurable strength + private byte[] uniqer = new byte[20]; + private SecureRandom secureRandom; + + protected HttpSessionContextImpl sessions; + public int expiredIn; + public boolean httpSessCookie; + public boolean secureSessCookie; + public Map arguments; + public Properties mime; + public WebsocketProvider websocketProvider; + + /** + * + * @author Rohtash Lakra (rohtash.lakra@devamatre.com) + * @author Rohtash Singh Lakra (rohtash.singh@gmail.com) + * @created 2018-03-20 07:37:46 PM + * @version 1.0.0 + * @since 1.0.0 + */ + private static class ServerThreadPoolFactory implements ThreadPoolFactory { + + /** serverThreadGroup */ + private final ThreadGroup serverThreadGroup; + + /** + * + * @param serverThreadGroup + */ + public ServerThreadPoolFactory(final ThreadGroup serverThreadGroup) { + this.serverThreadGroup = serverThreadGroup; + } + + /** + * @param runnable + * @return + * @see Acme.ThreadFactory#create(java.lang.Runnable) + */ + @Override + public Thread create(Runnable runnable) { + final Thread result = new Thread(serverThreadGroup, runnable); + result.setDaemon(true); + return result; + } + } + + /** + * + * @param arguments + * @param logStream + */ + public Serve(Map arguments, PrintStream logStream) { + this.arguments = arguments; + this.logStream = logStream; + defaultRegistry = new PathTreeDictionary(); + realms = new PathTreeDictionary(); + attributes = new Hashtable(); + serverThreads = new ThreadGroup("TJWS Threads"); + Properties props = new Properties(); + props.putAll(arguments); + // TODO do not create thread pool unless requested + threadPool = new Utils.ThreadPool(props, new ServerThreadPoolFactory(serverThreads)); + setAccessLogged(); + keepAlive = arguments.get(ARG_KEEPALIVE) == null || ((Boolean) arguments.get(ARG_KEEPALIVE)).booleanValue(); + int timeoutKeepAliveSec = Utils.parseInt(arguments.get(ARG_KEEPALIVE_TIMEOUT), 30); + timeoutKeepAlive = timeoutKeepAliveSec * 1000; + maxAliveConnUse = Utils.parseInt(arguments.get(ARG_MAX_CONN_USE), DEF_MAX_CONN_USE); + keepAliveHdrParams = "timeout=" + timeoutKeepAliveSec + ", max=" + maxAliveConnUse; + + expiredIn = Utils.parseInt(arguments.get(ARG_SESSION_TIMEOUT), DEF_SESSION_TIMEOUT); + String seed = (String) arguments.get(ARG_SESSION_SEED); + String randomProvider = (String) arguments.get(ARG_SESSION_SEED_ALG); // "SHA1PRNG"; + int seedLength = Utils.parseInt(seed, 0); + if (seed != null && seedLength == 0) { + secureRandom = new SecureRandom(seed.getBytes()); + } else { + if (randomProvider != null) { + try { + secureRandom = SecureRandom.getInstance(randomProvider); + } catch (NoSuchAlgorithmException ex) { + log("TJWS: Unsupported or incorrect secure rndom algorithm: " + randomProvider + "(" + ex + "), a default is used", ex); + } + } + + if (secureRandom == null) { + secureRandom = new SecureRandom(); + } + + seedLength = seedLength <= 0 ? 100 : seedLength; + byte bseed[] = null; + secureRandom.setSeed(bseed = secureRandom.generateSeed(seedLength)); + secureRandom.nextBytes(bseed); + secureRandom.setSeed(bseed); + } + + httpSessCookie = arguments.get(ARG_HTTPONLY_SC) != null; + secureSessCookie = arguments.get(ARG_SECUREONLY_SC) != null; + try { + gzipInStreamConstr = Class.forName("java.util.zip.GZIPInputStream").getConstructor(new Class[] { InputStream.class }); + } catch (ClassNotFoundException ex) { + log(ex); + } catch (NoSuchMethodException ex) { + log(ex); + } + + String proxyArg = (String) arguments.get(ARG_PROXY_CONFIG); + if (proxyArg != null) { + proxyConfig = true; + proxySSL = "y".equalsIgnoreCase(proxyArg); + } + initMime(); + } + + /** + * Default constructor to create TJWS as a bean + * + */ + public Serve() { + this(new HashMap(), System.err); + } + + protected void setAccessLogged() { + String logflags = (String) arguments.get(ARG_LOG_OPTIONS); + if (logflags != null) { + useAccLog = true; + showUserAgent = logflags.indexOf('A') >= 0; + showReferer = logflags.indexOf('R') >= 0; + } else { + useAccLog = false; + } + } + + protected boolean isAccessLogged() { + return useAccLog; + } + + protected boolean isShowReferer() { + return showReferer; + } + + protected boolean isShowUserAgent() { + return showUserAgent; + } + + protected boolean isKeepAlive() { + return keepAlive; + } + + protected int getKeepAliveDuration() { + return timeoutKeepAlive; + } + + protected String getKeepAliveParamStr() { + return keepAliveHdrParams; + } + + protected int getMaxTimesConnectionUse() { + return maxAliveConnUse; + } + + protected void initMime() { + mime = new Properties(); + try { + mime.load(getClass().getClassLoader().getResourceAsStream("Acme/Resource/mime.properties")); + } catch (Exception ex) { + log("TJWS: MIME map can't be loaded:" + ex); + } + } + + // / Register a Servlet by class name. Registration consists of a URL + // pattern, which can contain wildcards, and the class name of the Servlet + // to launch when a matching URL comes in. Patterns are checked for + // matches in the order they were added, and only the first match is run. + public ServletRegistration.Dynamic addServlet(String urlPat, String className) { + addServlet(urlPat, className, (Hashtable) null); + return null; + } + + /** + * Adds a servlet to run + * + * @param urlPat + * servlet invoker URL pattern + * @param className + * servlet class name + * @param initParams + * servlet init parameters + */ + public void addServlet(String urlPat, String className, Hashtable initParams) { + // Check if we're allowed to make one of these. + SecurityManager security = System.getSecurityManager(); + if (security != null) { + int i = className.lastIndexOf('.'); + if (i > 0) { + security.checkPackageAccess(className.substring(0, i)); + security.checkPackageDefinition(className.substring(0, i)); + } + } + + // Make a new one. + try { + addServlet(urlPat, (Servlet) Class.forName(className).newInstance(), initParams, null); + } catch (ClassNotFoundException e) { + log("TJWS: Class not found: " + className); + ClassLoader cl = getClass().getClassLoader(); + log("TJWS: Class loader: " + cl); + if (cl instanceof java.net.URLClassLoader) { + log("TJWS: CP: " + java.util.Arrays.asList(((java.net.URLClassLoader) cl).getURLs())); + } + } catch (ClassCastException e) { + log("TJWS: Servlet class doesn't implement javax.servlet.Servlet: " + e.getMessage()); + } catch (InstantiationException e) { + log("TJWS: Can't instantiate servlet: " + e.getMessage()); + } catch (IllegalAccessException e) { + log("TJWS: Illegal class access: " + e.getMessage()); + } catch (Exception e) { + log("TJWS: Unexpected problem of servlet creation: " + e, e); + } + } + + /** + * Register a Servlet. Registration consists of a URL pattern, which can + * contain wildcards, and the Servlet to launch when a matching URL comes + * in. Patterns are checked for matches in the order they were added, and + * only the first match is run. + * + * @param urlPat + * servlet invoker URL pattern + * @param servlet + * already instantiated servlet but init + * @param host + * name the servlet attached to, when verual hosts are used, use + * null for all hosts + */ + public void addServlet(String urlPat, Servlet servlet, String hostName) { + addServlet(urlPat, servlet, (Hashtable) null, hostName); + } + + /** + * Register a Servlet. Registration consists of a URL pattern, which can + * contain wildcards, and the Servlet to launch when a matching URL comes + * in. Patterns are checked for matches in the order they were added, and + * only the first match is run. + * + * @param urlPat + * servlet invoker URL pattern + * @param servlet + * already instantiated servlet but init + */ + public javax.servlet.ServletRegistration.Dynamic addServlet(String urlPat, Servlet servlet) { + addServlet(urlPat, servlet, (String) null); + return null; + } + + /** + * Register a Servlet + * + * @param urlPat + * @param servlet + * @param initParams + */ + public synchronized void addServlet(String urlPath, Servlet servlet, Hashtable initParams, String virtualHost) { + setHost(virtualHost); + try { + if (getServlet(urlPath) != null) { + log("TJWS: Servlet overriden by " + servlet + ", for path:" + urlPath); + } + + servlet.init(new ServeConfig((ServletContext) this, initParams, urlPath)); + if (virtualHost != null) { + if (virtuals == null) { + virtuals = new HashMap(); + } + + virtualHost = virtualHost.toLowerCase(); + PathTreeDictionary virtualRegistry = virtuals.get(virtualHost); + if (virtualRegistry == null) { + virtualRegistry = new PathTreeDictionary(); + virtuals.put(virtualHost, virtualRegistry); + } + virtualRegistry.put(urlPath, servlet); + } else { + defaultRegistry.put(urlPath, servlet); + } + } catch (ServletException ex) { // + // it handles UnavailableException as well without an attempt to + // re-adding + log("TJWS: Problem initializing servlet, it won't be used: " + ex); + } + } + + /** + * + * @param servlet + * @return + */ + public Servlet unloadServlet(Servlet servlet) { + PathTreeDictionary registry = currentRegistry.get(); + if (registry == null) { + registry = defaultRegistry; + } + synchronized (registry) { + return (Servlet) registry.remove(servlet)[0]; + } + } + + /** + * + * @param servletContext + */ + public void unloadSessions(ServletContext servletContext) { + if (sessions == null) { + return; + } + + File store = getPersistentFile(servletContext); + Writer storeWriter = null; + try { + if (store != null) { + storeWriter = new FileWriter(store); + } + // TODO consider moving implementation to HttpSessionContextImpl + // TODO think of concurrency + Enumeration itr = sessions.elements(); + int sc = 0; + while (itr.hasMoreElements()) { + AcmeSession session = (AcmeSession) itr.nextElement(); + if (session.getServletContext() == servletContext) { + if (storeWriter != null) + try { + session.save(storeWriter); + } catch (Throwable t) { + if (t instanceof ThreadDeath) { + throw (ThreadDeath) t; + } + log("TJWS: problem in session serialization for " + servletContext + " / " + session, t); + } + session.invalidate(); + sc++; + } + } + + if (sc > 0 && ssclThread != null) { + ssclThread.interrupt(); + } + log("TJWS: invalidated " + sc + " sessions for context " + servletContext, null); + } catch (IOException ioe) { + log("TJWS: problem in persisting sessions for " + servletContext, ioe); + } finally { + IOHelper.closeSilently(storeWriter); + } + } + + /** + * + * @param servletContext + */ + public void restoreSessions(ServletContext servletContext) { + File store = sessions == null ? null : getPersistentFile(servletContext); + if (store != null && store.exists()) { + BufferedReader bReader = null; + try { + bReader = new BufferedReader(new FileReader(store)); + AcmeSession session; + while ((session = AcmeSession.restore(bReader, Math.abs(expiredIn) * 60, servletContext, sessions)) != null) { + if (session.checkExpired() == false) { + sessions.put(session.getId(), session); + } + } + } catch (IOException ioe) { + log("TJWS: problem in sessions deserialization for " + servletContext, ioe); + } finally { + IOHelper.closeSilently(bReader); + } + } + } + + // Register a standard set of Servlets. These will return + // files or directory listings, and run CGI programs, much like a + // standard HTTP server. + //

+ // Because of the pattern checking order, this should be called + // after you've added any custom Servlets. + //

+ // The current set of default servlet mappings: + //

    + //
  • If enabled, *.cgi goes to CgiServlet, and gets run as a CGI program. + //
  • * goes to FileServlet, and gets served up as a file or directory. + //
+ // @param cgi whether to run CGI programs + // TODO: provide user specified CGI directory + public void addDefaultServlets(String cgi) { + try { + addDefaultServlets(cgi, null); + } catch (IOException ex) { + /* ignore, makes sense only for throtles */ + } + } + + /** + * Register a standard set of Servlets, with optional throttles. These will + * return files or directory listings, and run CGI programs, much like a + * standard HTTP server. + *

+ * Because of the pattern checking order, this should be called after + * you've added any custom Servlets. + *

+ * The current set of default servlet mappings: + *

    + *
  • If enabled, *.cgi goes to CgiServlet, and gets run as a CGI program. + *
  • * goes to FileServlet, and gets served up as a file or directory. + *
+ * + * @param cgi + * whether to run CGI programs + * @param throttles + * filename to read FileServlet throttle settings from, can be + * null + * @throws IOException + */ + public void addDefaultServlets(String cgi, String throttles) throws IOException { + // TODO: provide user specified CGI directory + if (cgi != null) { + if (getServlet("/" + cgi + "/*") == null) { + addServlet("/" + cgi + "/*", new Acme.Serve.CgiServlet()); + } else { + log("TJWS: Servlet for path '/" + cgi + "' already defined and no default will be used."); + } + } + + if (getServlet("/*") == null) { + if (throttles != null) { + addServlet("/*", new Acme.Serve.FileServlet(throttles, null)); + } else { + addServlet("/*", new Acme.Serve.FileServlet()); + } + } else { + log("TJWS: Servlet for path '/' already defined and no default will be used."); + } + } + + /** + * TODO review this method and figure throttles use + * + * @param deployerFactory + * @param throttles + */ + protected void addWarDeployer(String deployerFactory, String throttles) { + if (deployerFactory == null) { // try to use def + deployerFactory = "rogatkin.web.WarRoller"; + } + + try { + WarDeployer wd = (WarDeployer) Class.forName(deployerFactory).newInstance(); + wd.deploy(this); + } catch (ClassNotFoundException cnf) { + log("TJWS: Problem initializing war deployer: " + cnf); + } catch (Throwable ex) { + if (ex instanceof ThreadDeath) { + throw (ThreadDeath) ex; + } + log("TJWS: Problem in war(s) deployment", ex); + } + } + + /** + * + * @param provider + */ + protected void addWebsocketProvider(String provider) { + if (provider == null) { + provider = "rogatkin.wskt.SimpleProvider"; + } + + try { + websocketProvider = (WebsocketProvider) Class.forName(provider).newInstance(); + websocketProvider.init(this); + websocketProvider.deploy(this, null); + } catch (ClassNotFoundException cnf) { + log("TJWS: Problem finding websocket provider: " + cnf); + } catch (Throwable t) { + if (t instanceof ThreadDeath) { + throw (ThreadDeath) t; + } + log("TJWS: Problem initializing websocket provider", t); + } + } + + /** + * + * @return + */ + protected File getPersistentFile() { + return getPersistentFile(null); + } + + /** + * + * @param servletContext + * @return + */ + protected File getPersistentFile(ServletContext servletContext) { + if (arguments.get(ARG_SESSION_PERSIST) == null || ((Boolean) arguments.get(ARG_SESSION_PERSIST)) == Boolean.FALSE) { + return null; + } + + String workPath = (String) arguments.get(ARG_WORK_DIRECTORY); + if (workPath == null) { + workPath = "."; + } + + if (hostName == null) { + hostName = "unknown"; + } + hostName = sanitizeAsFile(hostName); + return new File(workPath, hostName + '-' + (arguments.get(ARG_PORT) == null ? String.valueOf(DEF_PORT) : arguments.get(ARG_PORT)) + (servletContext == null ? "" : "-" + servletContext.getServletContextName()) + "-session.obj"); + } + + /** + * + * @param name + * @return + */ + protected String sanitizeAsFile(String name) { + return name.replaceAll("\\.|:|\\\\|/", "-"); + } + + // Run the server. Returns only on errors. + private transient boolean running; + protected transient Acceptor acceptor; + protected transient Thread ssclThread; + + /** + * + * @author Rohtash Lakra (rohtash.lakra@devamatre.com) + * @author Rohtash Singh Lakra (rohtash.singh@gmail.com) + * @created 2018-03-20 07:58:34 PM + * @version 1.0.0 + * @since 1.0.0 + */ + protected class SessionCleaner implements Runnable { + + /** + * + * @param serve + */ + public SessionCleaner() { + } + + /** + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + while (isRunning()) { + try { + Thread.sleep(expiredIn * 60 * 1000); + } catch (InterruptedException ie) { + if (!isRunning()) { + break; + } + } + + Enumeration itr = sessions.keys(); + while (itr.hasMoreElements()) { + Object sid = itr.nextElement(); + if (sid != null) { + AcmeSession session = (AcmeSession) sessions.get(sid); + if (session != null && (session.checkExpired() || !session.isValid())) { + session = (AcmeSession) sessions.remove(sid); + if (session != null && session.isValid()) { + try { + session.invalidate(); + } catch (IllegalStateException ise) { + + } + } + } + } + } + } + } + } + + /** + * @author Rohtash Singh Lakra + * @date 03/16/2018 12:00:30 PM + */ + public static enum Status { + BIND_ERROR(-5), + NOT_FINISHED_CORRECTLY(-4), + IO_ERROR(-3), + TERMINATED_WITH_ERROR(-2), + ERROR(-1), + STOPPED(0), + RUNNING(1), + STILL_RUNNING(2),; + + /** status */ + private int status; + + /** + * + * @param status + */ + private Status(int status) { + this.status = status; + } + + /** + * + * @return + */ + public int getStatus() { + return status; + } + + /** + * + * @see java.lang.Enum#toString() + */ + public String toString() { + return String.valueOf(getStatus()); + } + + /** + * + * @param status + * @return + */ + public static Status toStatus(final int status) { + Status[] serveStatus = values(); + for (int i = 0; i < serveStatus.length; i++) { + if (serveStatus[i].getStatus() == status) { + return serveStatus[i]; + } + } + + return null; + } + } + + /** + * Returns true if the server is running otherwise false. + * + * @return + */ + public boolean isRunning() { + return running; + } + + /** + * Launches the server It doesn't exist until server runs, so start it in a + * dedicated thread. + * + * Returns the following values: - + * 0 if the server successfully terminated, and, + * 1 or 2 if it can't be started, and + * -1 if it was terminated during some errors, and + * -2 if it was ran over running instance, and + * -3 if not terminated correctly from previous run. + * + * @return + */ + public Status serve() { + if (isRunning()) { + // still running + return Status.STILL_RUNNING; + } + + if (acceptor != null) { + // not finished correctly + return Status.NOT_FINISHED_CORRECTLY; + } + + try { + acceptor = createAcceptor(); + } catch (Throwable ex) { + log("TJWS: Acceptor [" + acceptor + ": " + ex.getLocalizedMessage(), ex); + if (ex instanceof ThreadDeath) { + throw (ThreadDeath) ex; + } + acceptor = null; + if (ex instanceof BindException) { + return Status.BIND_ERROR; + } else if (ex instanceof IOException) { + return Status.IO_ERROR; + } + + return Status.ERROR; + } + + /* if here, means no error and server is running. */ + running = true; + if (expiredIn > 0) { + // sessions cleaner thread + ssclThread = new Thread(serverThreads, new SessionCleaner(), "Session Cleaner"); + ssclThread.setPriority(Thread.MIN_PRIORITY); + // ssclThread.setDaemon(true); + ssclThread.start(); + } + + /* keep alive clearner */ + keepAliveCleaner = new KeepAliveCleaner(); + keepAliveCleaner.start(); + File fileSessions = getPersistentFile(); + if (fileSessions != null && fileSessions.exists()) { + BufferedReader bReader = null; + try { + bReader = new BufferedReader(new FileReader(fileSessions)); + sessions = HttpSessionContextImpl.restore(bReader, Math.abs(expiredIn) * 60, this); + } catch (IOException ioe) { + log("TJWS: IO error in restoring sessions.", ioe); + } catch (Exception ex) { + log("TJWS: Unexpected problem in restoring sessions.", ex); + } finally { + IOHelper.closeSilently(bReader); + } + } + + if (sessions == null) { + sessions = new HttpSessionContextImpl(); + } + + // TODO: display address as name and as ip + log("TJWS httpd " + hostName + " - " + acceptor + " is listening."); + try { + while (isRunning()) { + try { + final Socket socket = acceptor.accept(); + // TODO consider to use ServeConnection object pool + // TODO consider req/resp objects pooling + keepAliveCleaner.addConnection(new ServeConnection(socket, this)); + } catch (IOException ex) { + log("TJWS: Accept: " + ex); + } catch (SecurityException ex) { + log("TJWS: Illegal access: " + ex); + } catch (IllegalStateException ex) { + log("TJWS: Illegal state: " + ex); + } + } + } catch (Throwable th) { + log("TJWS: Unhandled exception: " + th + ", server is terminating.", th); + if (th instanceof ThreadDeath) { + throw (Error) th; + } + return Status.ERROR; + } finally { + if (acceptor != null) { + try { + acceptor.destroy(); + acceptor = null; + } catch (IOException ex) { + log("Error destroying acceptor!", ex); + } + } + + running = false; + if (ssclThread != null) { + ssclThread.interrupt(); + } + + ssclThread = null; + keepAliveCleaner.interrupt(); + try { + keepAliveCleaner.join(); + } catch (InterruptedException ex) { + } + + // clear rest, although should be empty + keepAliveCleaner.clear(); + keepAliveCleaner = null; + if (websocketProvider != null) { + try { + websocketProvider.destroy(); + } catch (Exception ex) { + // just in case + log("Error destroying websocket provider!", ex); + } + } + } + + return Status.STOPPED; + } + + /** + * Tells the server to stop + * + * @throws IOException + */ + public void notifyStop() { + if (acceptor != null) { + running = false; + try { + acceptor.destroy(); + acceptor = null; + } catch (IOException ioe) { + log("TJWS: IO exception at destroying acceptor: " + acceptor, ioe); + } catch (Exception e) { + acceptor = null; + log("TJWS: An exception at destroying acceptor: " + acceptor, e); + } + } + } + + public static interface Acceptor { + /** + * + * @param inProperties + * @param outProperties + * @throws IOException + */ + public void init(Map inProperties, Map outProperties) throws IOException; + + /** + * + * @return + * @throws IOException + */ + public Socket accept() throws IOException; + + /** + * + * @throws IOException + */ + public void destroy() throws IOException; + } + + public static interface AsyncCallback { + public void notifyTimeout(); + + public long getTimeout(); + } + + public static interface WebsocketProvider { + public void init(Serve serve); + + public void handshake(Socket socket, String path, Servlet servlet, HttpServletRequest request, HttpServletResponse response) throws IOException; + + public void upgrade(Socket socket, String path, Servlet servlet, HttpServletRequest request, HttpServletResponse response) throws IOException; + + public void destroy(); + + public void deploy(ServletContext servletContext, List classPathFiles); + } + + /** + * + * @return + * @throws IOException + */ + protected Acceptor createAcceptor() throws IOException { + String acceptorClass = (String) arguments.get(ARG_ACCEPTOR_CLASS); + if (acceptorClass == null) { + acceptorClass = "Acme.Serve.SimpleAcceptor"; + } + // assured defaulting here + try { + log("Loading Acceptor:" + acceptorClass); + acceptor = (Acceptor) Class.forName(acceptorClass).newInstance(); + log("Acceptor:" + acceptor); + } catch (InstantiationException ex) { + log("TJWS: Couldn't instantiate Acceptor, the Server is inoperable!", ex); + } catch (IllegalAccessException ex) { + log("TJWS: Error instantiate Acceptor!", ex); + Constructor objectAcceptor; + try { + log("Retrying to load Acceptor:" + acceptorClass); + objectAcceptor = Class.forName(acceptorClass).getDeclaredConstructor(Utils.EMPTY_CLASSES); + objectAcceptor.setAccessible(true); + acceptor = (Acceptor) objectAcceptor.newInstance(Utils.EMPTY_OBJECTS); + } catch (Throwable th) { + log("TJWS: Acceptor is not accessable or can't be instantiated, the Server is inoperable!", th); + } + } catch (ClassNotFoundException ex) { + log("TJWS: Acceptor class not found, the Server is inoperable!", ex); + System.exit(Status.TERMINATED_WITH_ERROR.getStatus()); + } + + Map acceptorProperties = new Properties(); + log("TJWS: Init Acceptor:" + acceptor); + acceptor.init(arguments, acceptorProperties); + hostName = (String) acceptorProperties.get(ARG_BINDADDRESS); + + log("TJWS: Loaded Acceptor:" + acceptor); + return acceptor; + } + + /** + * + * @param hostName + */ + public void setHost(String hostName) { + if (virtuals == null) { + currentRegistry.set(defaultRegistry); + } else { + if (hostName == null) { + currentRegistry.set(defaultRegistry); + } else { + // separate port part + int colonIndex = hostName.indexOf(':'); + if (colonIndex > 0) { + hostName = hostName.substring(0, colonIndex); + } + + PathTreeDictionary registry = virtuals.get(hostName.toLowerCase()); + if (registry != null) { + currentRegistry.set(registry); + } else { + currentRegistry.set(defaultRegistry); + } + } + } + } + + // ///////////////// Methods from ServletContext ///////////////////// + + // / Gets a servlet by name. + // @param name the servlet name + // @return null if the servlet does not exist + public Servlet getServlet(String name) { + PathTreeDictionary registry = currentRegistry.get(); + if (registry == null) { + registry = defaultRegistry; + } + + try { + return (Servlet) registry.get(name)[0]; + } catch (NullPointerException ex) { + log(ex); + } + + return null; + } + + // / Enumerates the servlets in this context (server). Only servlets that + // are accessible will be returned. This enumeration always includes the + // servlet itself. + public Enumeration getServlets() { + PathTreeDictionary registry = currentRegistry.get(); + if (registry == null) { + registry = defaultRegistry; + } + + return registry.elements(); + } + + // / Enumerates the names of the servlets in this context (server). Only + // servlets that are accessible will be returned. This enumeration always + // includes the servlet itself. + public Enumeration getServletNames() { + PathTreeDictionary registry = currentRegistry.get(); + if (registry == null) { + registry = defaultRegistry; + } + + return registry.keys(); + } + + // / Destroys all currently-loaded servlets. + public synchronized void destroyAllServlets() { + // log("Entering destroyAllServlets()", new + // Exception("Entering destroyAllServlets()")); + // serialize sessions + // invalidate all sessions + // TODO consider merging two pieces below, generally if session is + // stored, + // it shouldn't be invalidated + File fileSessions = getPersistentFile(); + if (fileSessions != null && sessions != null) { + Writer writer = null; + try { + writer = new FileWriter(fileSessions); + sessions.save(writer); + log("TJWS: Sessions stored."); + } catch (IOException ioe) { + log("TJWS: IO error in storing sessions " + ioe); + } catch (Throwable th) { + log("TJWS: Unexpected problem in storing sessions " + th); + if (th instanceof ThreadDeath) { + throw (ThreadDeath) th; + } + } finally { + IOHelper.closeSilently(writer); + } + + Enumeration e = sessions.keys(); + while (e.hasMoreElements()) { + Object sid = e.nextElement(); + if (sid != null) { + AcmeSession as = (AcmeSession) sessions.get(sid); + if (as != null) { + as = (AcmeSession) sessions.remove(sid); + if (as != null && as.isValid()) { + try { + as.invalidate(); + } catch (IllegalStateException ex) { + log(ex); + } + } + } + } + } + } + + // destroy servlets + destroyAll(defaultRegistry); + if (virtuals != null) { + Iterator itr = virtuals.values().iterator(); + while (itr.hasNext()) { + destroyAll(itr.next()); + } + } + + // clean access tree + defaultRegistry = new PathTreeDictionary(); + virtuals = null; + } + + /** + * + * @author Rohtash Lakra (rohtash.lakra@devamatre.com) + * @author Rohtash Singh Lakra (rohtash.singh@gmail.com) + * @created 2018-03-20 08:11:08 PM + * @version 1.0.0 + * @since 1.0.0 + */ + private class ServletDestroyer implements Runnable { + /** servletIterator */ + private final Enumeration servletIterator; + + /** + * + * @param servletIterator + */ + ServletDestroyer(final Enumeration servletIterator) { + this.servletIterator = servletIterator; + } + + public void run() { + if (servletIterator != null) { + ((Servlet) servletIterator.nextElement()).destroy(); + } + } + } + + /** + * + * @param registry + */ + private void destroyAll(PathTreeDictionary registry) { + final Enumeration servletIterator = registry.elements(); + int dhc = 0; + while (servletIterator.hasMoreElements()) { + Thread destroyThread = new Thread(new ServletDestroyer(servletIterator), "Destroy"); + destroyThread.setDaemon(true); + destroyThread.start(); + try { + destroyThread.join(DESTROY_TIME_SEC * 1000); + } catch (InterruptedException e) { + } + + if (destroyThread.isAlive()) { + log("TJWS: Destroying thread didn't terminate in " + DESTROY_TIME_SEC); + destroyThread.setName("Destroying took too long " + (dhc++)); + } + } + } + + protected void setMappingTable(PathTreeDictionary mappingtable) { + this.mappingtable = mappingtable; + } + + protected void setRealms(PathTreeDictionary realms) { + this.realms = realms; + } + + AcmeSession getSession(String id) { + return (AcmeSession) sessions.get(id); + } + + HttpSession createSession() { + Integer maxActiveSessions = ((Integer) this.arguments.get(ARG_MAX_ACTIVE_SESSIONS)); + if (maxActiveSessions != null && maxActiveSessions.intValue() < sessions.size()) { + return null; + } + + HttpSession result = new AcmeSession(generateSessionId(), Math.abs(expiredIn) * 60, this, sessions); + synchronized (sessions) { + sessions.put(result.getId(), result); + } + + return result; + } + + void removeSession(String id) { + synchronized (sessions) { + sessions.remove(id); + } + } + + /** + * Writes logs information in the servet logs. + * + * @param message + * @param logInAllLoggers + */ + public void log(String message, final boolean logInAllLoggers) { + message = "[" + new Date().toString() + "] " + message; + if (logInAllLoggers) { + System.out.println(message); + } + logStream.println(message); + } + + /** + * @see javax.servlet.ServletContext#log(java.lang.String) + */ + public void log(final String message) { + log(message, true); + } + + public void log(String message, Throwable throwable) { + if (throwable != null) { + message += LINE_SEP + IOHelper.toString(throwable); + } + log(message); + } + + // / Write a stack trace to the servlet log. + // @param exception where to get the stack trace + // @param message the message to log + public void log(Exception exception, String message) { + log(message, exception); + } + + /** + * + * @param throwable + */ + public void log(Throwable throwable) { + if (throwable != null) { + log(LINE_SEP + IOHelper.toString(throwable)); + } + } + + // / Applies alias rules to the specified virtual path and returns the + // corresponding real path. It returns null if the translation + // cannot be performed. + // @param path the path to be translated + public String getRealPath(String path) { + // System.err.print("[" + path + "]->["); + path = Utils.canonicalizePath(path); + if (path != null && mappingtable != null) { + // try find first sub-path + Object[] os = mappingtable.get(path); + // System.err.println("Searching for path: "+path+" found: "+os[0]); + if (os[0] == null) { + return null; + } + + int slpos = ((Integer) os[1]).intValue(); + int pl = path.length(); + if (slpos > 0) { + if (path.length() > slpos) { + path = path.substring(slpos + 1); + } else { + path = ""; + } + } else if (pl > 0) { + for (int i = 0; i < pl; i++) { + char s = path.charAt(i); + if (s == '/' || s == '\\') { + continue; + } else { + if (i > 0) { + path = path.substring(i); + } + break; + } + } + } + // System.err.println("Path after processing :"+path+" slash was at + // "+slpos); + return new File((File) os[0], path).getPath(); + } + + return path; + } + + /** + * + * @return + */ + public String getContextPath() { + return ""; + } + + // / Returns the MIME type of the specified file. + // @param file file name whose MIME type is required + public String getMimeType(String file) { + int dp = file.lastIndexOf('.'); + if (dp > 0) { + return mime.getProperty(file.substring(dp + 1).toUpperCase()); + } + + return null; + } + + // / Returns the name and version of the web server under which the servlet + // is running. + // Same as the CGI variable SERVER_SOFTWARE. + public String getServerInfo() { + return Serve.Identification.serverName + " " + Serve.Identification.serverVersion + " (" + Serve.Identification.serverUrl + ")"; + } + + // / Returns the value of the named attribute of the network service, or + // null if the attribute does not exist. This method allows access to + // additional information about the service, not already provided by + // the other methods in this interface. + public Object getAttribute(String name) { + return attributes.get(name); + } + + // ///////////////// JSDK 2.1 extensions ////////////////////////// + public void removeAttribute(String name) { + attributes.remove(name); + } + + public void setAttribute(String name, Object object) { + if (object != null) { + attributes.put(name, object); + } else { + attributes.remove(name); + } + } + + public Enumeration getAttributeNames() { + return attributes.keys(); + } + + // TODO check webapp servlets to find out conexts for uri + public ServletContext getContext(String uripath) { + // only root context supported + return this; + } + + public int getMajorVersion() { + // support 2.x + return 2; + } + + public int getMinorVersion() { + // support 2.5 + return 5; + } + + // 2.3 + + /** + * Returns a directory-like listing of all the paths to resources within the + * web application whose longest sub-path matches the supplied path + * argument. Paths indicating subdirectory paths end with a '/'. The + * returned paths are all relative to the root of the web application and + * have a leading '/'. For example, for a web application containing + *

+ * /welcome.html
+ * /catalog/index.html
+ * /catalog/products.html
+ * /catalog/offers/books.html
+ * /catalog/offers/music.html
+ * /customer/login.jsp
+ * /WEB-INF/web.xml
+ * /WEB-INF/classes/com.acme.OrderServlet.class, + *

+ * getResourcePaths("/") returns {"/welcome.html", "/catalog/", + * "/customer/", "/WEB-INF/"}
+ * getResourcePaths("/catalog/") returns {"/catalog/index.html", + * "/catalog/products.html", "/catalog/offers/"}. + *

+ * + * @param the + * - partial path used to match the resources, which must start + * with a / + * @return a Set containing the directory listing, or null if there are no + * resources in the web application whose path begins with the + * supplied path. + * @since Servlet 2.3 + * + */ + public Set getResourcePaths(String path) { + String realPath = getRealPath(path); + if (realPath != null) { + String[] dirPaths = new File(realPath).list(); + if (dirPaths.length > 0) { + Set dirPathSet = new HashSet(dirPaths.length); + for (int i = 0; i < dirPaths.length; i++) { + dirPathSet.add(dirPaths[i]); + } + + return dirPathSet; + } + } + + return null; + } + + /** + * Returns the name of this web application corresponding to this + * ServletContext as specified in the deployment descriptor for this web + * application by the display-name element. + * + * @return The name of the web application or null if no name has been + * declared in the deployment descriptor. + * + * @since Servlet 2.3 + */ + public String getServletContextName() { + return null; + } + + /** + * Returns a URL to the resource that is mapped to a specified path. The + * path must begin with a "/" and is interpreted as relative to the current + * context root. + * + *

+ * This method allows the servlet container to make a resource available to + * servlets from any source. Resources can be located on a local or remote + * file system, in a database, or in a .war file. + * + *

+ * The servlet container must implement the URL handlers and + * URLConnection objects that are necessary to access the + * resource. + * + *

+ * This method returns null if no resource is mapped to the + * pathname. + * + *

+ * Some containers may allow writing to the URL returned by this method + * using the methods of the URL class. + * + *

+ * The resource content is returned directly, so be aware that requesting a + * .jsp page returns the JSP source code. Use a + * RequestDispatcher instead to include results of an + * execution. + * + *

+ * This method has a different purpose than + * java.lang.Class.getResource, which looks up resources based + * on a class loader. This method does not use class loaders. + * + * @param path + * a String specifying the path to the resource + * + * @return the resource located at the named path, or null if + * there is no resource at that path + * + * @exception MalformedURLException + * if the pathname is not given in the correct form + * + * + */ + public URL getResource(String path) throws MalformedURLException { + if (path == null || path.length() == 0 || path.charAt(0) != '/') { + throw new MalformedURLException("Path " + path + " is not in acceptable form."); + } + + File resFile = new File(getRealPath(path)); + if (resFile.exists()) {// TODO get canonical path is more robust + return new URL("file", "localhost", resFile.getPath()); + } + + return null; + } + + /** + * Returns the resource located at the named path as an + * InputStream object. + * + *

+ * The data in the InputStream can be of any type or length. + * The path must be specified according to the rules given in + * getResource. This method returns null if no + * resource exists at the specified path. + * + *

+ * Meta-information such as content length and content type that is + * available via getResource method is lost when using this + * method. + * + *

+ * The servlet container must implement the URL handlers and + * URLConnection objects necessary to access the resource. + * + *

+ * This method is different from + * java.lang.Class.getResourceAsStream, which uses a class + * loader. This method allows servlet containers to make a resource + * available to a servlet from any location, without using a class loader. + * + * + * @param path + * a String specifying the path to the resource + * + * @return the InputStream returned to the servlet, or + * null if no resource exists at the specified path + * + * + */ + public InputStream getResourceAsStream(String path) { + try { + return getResource(path).openStream(); + } catch (Exception ex) { + log(ex); + } + + return null; + } + + public RequestDispatcher getRequestDispatcher(String urlpath) { + if (urlpath == null || urlpath.length() == 0 || urlpath.charAt(0) != '/') { + return null; + } + + try { + return new SimpleRequestDispatcher(urlpath); + } catch (NullPointerException ex) { + log(ex); + return null; + } + } + + // no way to specify parameters for context + public String getInitParameter(String param) { + return null; + } + + public Enumeration getInitParameterNames() { + return Utils.EMPTY_ENUMERATION; + } + + public RequestDispatcher getNamedDispatcher(String name) { + // named resources are not supported + return null; + } + + /** + * + * @return + */ + public synchronized String generateSessionId() { + secureRandom.nextBytes(uniqer); + // TODO swap randomly bytes + return Utils.base64Encode(uniqer); + } + + /** + * + * @author Rohtash Lakra (rohtash.lakra@devamatre.com) + * @author Rohtash Singh Lakra (rohtash.singh@gmail.com) + * @created 2018-03-20 07:45:28 PM + * @version 1.0.0 + * @since 1.0.0 + */ + protected class ServletRequestWrapper extends HttpServletRequestWrapper { + + /** requestDispatcher */ + private final SimpleRequestDispatcher requestDispatcher; + + /** + * + * @param servletRequest + * @param requestDispatcher + */ + public ServletRequestWrapper(final HttpServletRequest servletRequest, final SimpleRequestDispatcher requestDispatcher) { + super(servletRequest); + this.requestDispatcher = requestDispatcher; + } + + public String getPathInfo() { + return requestDispatcher.dispatchLen >= requestDispatcher.dispatchPath.length() ? null : requestDispatcher.dispatchPath.substring(requestDispatcher.dispatchLen); + } + + public String getRequestURI() { + return requestDispatcher.dispatchPath; + } + + public String getQueryString() { + return requestDispatcher.dispatchQuery; + } + + public String getPathTranslated() { + // System.out.println("Path t path i: "+getPathInfo()+", dp: + // "+dispatchPath); + return getRequest().getRealPath(getPathInfo()); + } + + // TODO implement getPathInfo + + public String getServletPath() { + return requestDispatcher.dispatchLen <= 0 ? "" : requestDispatcher.dispatchPath.substring(0, requestDispatcher.dispatchLen); + } + + public synchronized Enumeration getAttributeNames() { + if (super.getAttribute("javax.servlet.forward.request_uri") == null) { + setAttribute("javax.servlet.forward.request_uri", super.getRequestURI()); + setAttribute("javax.servlet.forward.context_path", this.getContextPath()); + setAttribute("javax.servlet.forward.servlet_path", super.getServletPath()); + setAttribute("javax.servlet.forward.path_info", super.getPathInfo()); + setAttribute("javax.servlet.forward.query_string", super.getQueryString()); + } + return super.getAttributeNames(); + } + + public Object getAttribute(String name) { + getAttributeNames(); // here is some overhead + return super.getAttribute(name); + } + + public String[] getParameterValues(String name) { + Map params = createParameters(); + String[] result = (String[]) params.get(name); + if (result != null) + return result; + return super.getParameterValues(name); + } + + public String getParameter(String name) { + Map params = createParameters(); + String[] result = (String[]) params.get(name); + if (result != null) { + return result[0]; + } + return super.getParameter(name); + } + + public Map getParameterMap() { + HashMap result = new HashMap(); + result.putAll(super.getParameterMap()); + result.putAll(createParameters()); + return result; + } + + public Enumeration getParameterNames() { + Map params = getParameterMap(); + Hashtable result = new Hashtable(); + result.putAll(params); + return result.keys(); + } + + /** + * + * @return + */ + synchronized protected Map createParameters() { + if (requestDispatcher.parameters == null) { + String query = getQueryString(); + if (query != null) { + requestDispatcher.parameters = Utils.parseQueryString(query, null); + } else { + requestDispatcher.parameters = new Hashtable(); + } + } + + return requestDispatcher.parameters; + } + } + + protected class SimpleRequestDispatcher implements RequestDispatcher { + HttpServlet servlet; + String dispatchPath; + String dispatchQuery; + int dispatchLen; + Map parameters; + + SimpleRequestDispatcher(String path) { + PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); + if (registry == null) { + registry = defaultRegistry; + } + Object[] os = registry.get(path); + servlet = (HttpServlet) os[0]; + // log("Dispatch to: " + path + ", servlet "+servlet); + if (servlet == null) { + throw new NullPointerException(); + } + dispatchLen = ((Integer) os[1]).intValue(); + int qmp = path.indexOf('?'); + + if (qmp < 0 || qmp >= path.length() - 1) { + dispatchPath = path; + } else { + dispatchPath = path.substring(0, qmp); + dispatchQuery = path.substring(qmp + 1); + } + } + + /** + * + * @param _request + * @param _response + * @throws ServletException + * @throws java.io.IOException + * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, + * javax.servlet.ServletResponse) + */ + public void forward(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException { + // reset in case of nested + request.removeAttribute("javax.servlet.forward.request_uri"); + response.reset(); + servlet.service(new ServletRequestWrapper((HttpServletRequest) request, this), response); + // TODO think when response isn't actual response ServeConnection + // ((ServeConnection) _response).closeStreams(); + // do not allow to continue + } + + /** + * + * @param request + * @param response + * @throws ServletException + * @throws IOException + * @see javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, + * javax.servlet.ServletResponse) + */ + public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { + request.removeAttribute("javax.servlet.include.request_uri"); // reset + // in case of nested + ((Serve.ServeConnection) response).setInInclude(true); + try { + servlet.service(new HttpServletRequestWrapper((HttpServletRequest) request) { + public synchronized Enumeration getAttributeNames() { + if (super.getAttribute("javax.servlet.include.request_uri") == null) { + setAttribute("javax.servlet.include.request_uri", dispatchPath); + setAttribute("javax.servlet.include.context_path", this.getContextPath()); + setAttribute("javax.servlet.include.servlet_path", dispatchLen <= 0 ? "" : dispatchPath.substring(0, dispatchLen)); + setAttribute("javax.servlet.include.path_info", dispatchLen >= dispatchPath.length() ? null : dispatchPath.substring(dispatchLen)); + setAttribute("javax.servlet.include.query_string", dispatchQuery); + } + return super.getAttributeNames(); + } + + /** + * + * @param name + * @return + * @see javax.servlet.ServletRequestWrapper#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) { + // here is some overhead + getAttributeNames(); + return super.getAttribute(name); + } + + }, response); + } finally { + ((Serve.ServeConnection) response).setInInclude(false); + } + } + + } + + /** + * Keep Alive supporter, JDK 1.4 based for backward compatibility + * + * @author Rohtash Singh Lakra + * @date 03/16/2018 12:02:56 PM + */ + class KeepAliveCleaner extends Thread { + protected List connections; + protected List ingoings; + protected boolean stopped; + private boolean noCheckClose; + + KeepAliveCleaner() { + super("KeepAlive cleaner"); + connections = new LinkedList(); + ingoings = new LinkedList(); + setDaemon(true); + } + + /** + * + * @param serveConnection + */ + void addConnection(ServeConnection serveConnection) { + synchronized (ingoings) { + if (stopped == false) { + ingoings.add(serveConnection); + } + } + } + + void clear() { + if (stopped == false) { + new IllegalStateException("Can't clear running cleaner"); + } + clear(ingoings); + clear(connections); + } + + /** + * Clears the server connections. + * + * @param serveConnections + */ + private void clear(List serveConnections) { + Iterator itr = serveConnections.iterator(); + while (itr.hasNext()) { + ServeConnection serveConnection = itr.next(); + itr.remove(); + serveConnection.close(); + } + } + + public void run() { + // int maxUse = getMaxTimesConnectionUse(); + while (true) { + synchronized (ingoings) { + Iterator itr = ingoings.iterator(); + while (itr.hasNext()) { + connections.add(itr.next()); + itr.remove(); + } + } + + Iterator itr = connections.iterator(); + long ct = System.currentTimeMillis(); + long keepAliveDuration = getKeepAliveDuration(); + // System.err.println("===> keep alive time"+d); + while (itr.hasNext()) { + ServeConnection serveConnection = itr.next(); + boolean closed = serveConnection.socket == null; + if (noCheckClose == false) { + synchronized (serveConnection) { + if (serveConnection.socket != null) { + try { + closed = ((Boolean) serveConnection.socket.getClass().getMethod("isClosed", Utils.EMPTY_CLASSES).invoke(serveConnection.socket, Utils.EMPTY_OBJECTS)).booleanValue(); + } catch (NoSuchMethodException e) { + noCheckClose = true; + } catch (Exception e) { + } + } + } + } + + if (serveConnection.lastRun < serveConnection.lastWait && (closed || serveConnection.keepAlive == false || (ct - serveConnection.lastWait > keepAliveDuration)) || stopped) { + itr.remove(); + synchronized (serveConnection) { + if (serveConnection.socket != null) { + try { + // System.err.println("Closing + // socket:"+conn.socket.getClass().getName()); + // // !!! + // conn.socket.close(); + serveConnection.socket.getInputStream().close(); + } catch (IOException ioe) { + // ignore + } + // System.err.println("done"); + } + } + // System.err.println("===> Removing and closing + // con"+conn+" of "+conn.keepAlive); + } + + if (serveConnection.asyncTimeout > 0) { + if (ct >= serveConnection.asyncTimeout) { + if (serveConnection.asyncMode != null) { + serveConnection.asyncMode.notifyTimeout(); + serveConnection.keepAlive = false; + if (serveConnection.webSocketUpgrade) { + serveConnection.asyncMode = null; + } + serveConnection.joinAsync(); + } + + /* + * else if (conn.websocketUpgrade) { + * try { + * conn.keepAlive = false; + * //conn.socket.getChannel().close(); // TODO + * perhaps use normal close call + * //conn.socket = null; + * } catch(Exception e) { + * } + * } + */ + } else { + long nd = serveConnection.asyncTimeout - ct; + if (nd < keepAliveDuration) { + keepAliveDuration = nd; + } + } + } + } + + // TODO stopped can be enough, since clear method + if (stopped && connections.size() == 0) { + break; + } + + try { + sleep(keepAliveDuration); + } catch (InterruptedException ie) { + // not thread safe + stopped = true; + } + } + } + } + + public static interface Identification { + public static final String serverName = "D. Rogatkin's TJWS (+Android, JSR340, JSR356) https://github.com/drogatkin/TJWS2.git or https://github.com/rslakra/TJWS2.git"; + public static final String serverVersion = "Version 1.115 (nightly)"; + public static final String serverUrl = "http://tjws.sourceforge.net"; + public static final String serverIdHtml = "

" + serverName + " " + serverVersion + "
"; + } + + // //////////////////////////////////////////////////////////////// + + protected static class ServeConfig implements ServletConfig { + + private ServletContext context; + private Hashtable initParams; + private String servletName; + + /** + * + * @param context + */ + public ServeConfig(ServletContext context) { + this(context, null, "undefined"); + } + + /** + * + * @param context + * @param initParams + * @param servletName + */ + public ServeConfig(ServletContext context, Hashtable initParams, String servletName) { + this.context = context; + this.initParams = initParams; + this.servletName = servletName; + } + + // Methods from ServletConfig. + + /** + * Returns the context for the servlet. + * + * @return + * @see javax.servlet.ServletConfig#getServletContext() + */ + public ServletContext getServletContext() { + return context; + } + + // / Gets an initialization parameter of the servlet. + // @param name the parameter name + public String getInitParameter(String name) { + // This server supports servlet init params. :) + if (initParams != null) { + return (String) initParams.get(name); + } + + return null; + } + + // / Gets the names of the initialization parameters of the servlet. + // @param name the parameter name + public Enumeration getInitParameterNames() { + // This server does:) support servlet init params. + if (initParams != null) { + return initParams.keys(); + } + + return new Vector().elements(); + } + + // 2.2 + public String getServletName() { + return servletName; + } + } + + // ///////////////////////////////////////////////////////////////////// + /** + * provides request/response + */ + public static class ServeConnection implements Runnable, HttpServletRequest, HttpServletResponse { + + public final static String WWWFORMURLENCODE = "application/x-www-form-urlencoded"; + public final static String TRANSFERENCODING = "transfer-encoding".toLowerCase(); + public final static String KEEPALIVE = "Keep-Alive".toLowerCase(); + public final static String CONTENT_ENCODING = "Content-Encoding".toLowerCase(); + public final static String CONNECTION = "Connection".toLowerCase(); + public final static String CHUNKED = "chunked"; + public final static String CONTENTLENGTH = "Content-Length".toLowerCase(); + public final static String CONTENTTYPE = "Content-Type".toLowerCase(); + public final static String SETCOOKIE = "Set-Cookie".toLowerCase(); + public final static String HOST = "Host".toLowerCase(); + public final static String COOKIE = "Cookie".toLowerCase(); + public final static String UPGRADE = "Upgrade".toLowerCase(); + public final static String WEBSOCKET = "websocket".toLowerCase(); + public final static String ACCEPT_LANGUAGE = "Accept-Language".toLowerCase(); + public final static String SESSION_COOKIE_NAME = "JSESSIONID"; + public final static String SESSION_URL_NAME = ";$sessionid$"; // ;jsessionid= + public final static String FORWARDED_FOR = "x-Forwarded-for".toLowerCase(); + public final static String FORWARDED_HOST = "X-Forwarded-Host".toLowerCase(); + public final static String FORWARDED_SERVER = "X-Forwarded-Server".toLowerCase(); + + private static final Map EMPTYHASHTABLE = new Hashtable(); + + private Socket socket; + private Hashtable sslAttributes; + private Serve serve; + private ServletInputStream inputStream; + private ServletOutputStream outputStream; + private String scheme; + private AsyncCallback asyncMode; + private Thread requestThread; + private long asyncTimeout; + private String reqMethod; // == null by default + private String reqUriPath, reqUriPathUn; + private String reqProtocol; + private String charEncoding; // req and resp + private String remoteUser; + private String authType; + + // HTTP/1.1 or better + private boolean oneOne; + private boolean reqMime; + private boolean webSocketUpgrade; + private Vector reqHeaderNames = new Vector(); + private Vector reqHeaderValues = new Vector(); + private Locale locale; + private int uriLen; + private HttpServlet servlet; + + protected boolean keepAlive = true; + protected int keepAliveRequestedTime; + protected long lastRun, lastWait; + private Vector outCookies; + private Vector inCookies; + private String sessionCookieValue, sessionUrlValue, sessionValue, reqSessionValue; + protected String reqQuery; + private PrintWriter printWriter; + private ServletOutputStream servletOutput; + private Map formParameters; + private Hashtable attributes = new Hashtable(); + private int resCode = -1; + private String resMessage; + + private Hashtable resHeaderNames = new Hashtable(); + private String[] postCache; + private boolean headersWritten; + private MessageFormat accessLogFormat; + private Object[] logPlaceHolders; + + /* + * TODO consider creation an instance per thread in a pool, thread + * memory can be used + */ + + // used for cookie + private final SimpleDateFormat expdatefmt = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss 'GMT'", Locale.US); + + // rfc850-date + private final SimpleDateFormat rfc850DateFmt = new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss 'GMT'", Locale.US); + + // rfc1123-date + private final SimpleDateFormat headerdateformat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US); + + // ASCII date, used in headers + private final SimpleDateFormat asciiDateFmt = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", Locale.US); + private static final TimeZone timeZone = TimeZone.getTimeZone("GMT"); + static { + timeZone.setID("GMT"); + } + + /** + * Constructor. + * + * @param socket + * @param serve + */ + public ServeConnection(Socket socket, Serve serve) { + LogManager.debug("ServeConnection(" + socket + ", " + serve + ")"); + // serve.log("+++++++"+this); + // Save arguments. + this.socket = socket; + this.serve = serve; + expdatefmt.setTimeZone(timeZone); + headerdateformat.setTimeZone(timeZone); + rfc850DateFmt.setTimeZone(timeZone); + asciiDateFmt.setTimeZone(timeZone); + if (serve.isAccessLogged()) { + // note format string must be not null + accessLogFormat = new MessageFormat((String) serve.arguments.get(ARG_ACCESS_LOG_FMT)); + logPlaceHolders = new Object[12]; + } + try { + // start handshake + if (this.socket instanceof SSLSocket) { + final SSLSocket sslSocket = ((SSLSocket) this.socket); + // LogManager.debug("EnabledCipherSuites:" + + // IOHelper.toString(sslSocket.getEnabledCipherSuites())); + sslSocket.setEnabledCipherSuites(sslSocket.getEnabledCipherSuites()); + // LogManager.debug("EnabledProtocols:" + + // IOHelper.toString(sslSocket.getEnabledProtocols())); + sslSocket.setEnabledProtocols(sslSocket.getEnabledProtocols()); + // LogManager.debug("startHandshake() ..."); + sslSocket.startHandshake(); + } + + // initialize streams + inputStream = new ServeInputStream(socket.getInputStream(), this); + outputStream = new ServeOutputStream(socket.getOutputStream(), this); + } catch (IOException ex) { + serve.log(ex); + close(); + return; + } + serve.threadPool.executeThread(this); + } + + private void initSSLAttrs() { + if (isSSLSocket() && sslAttributes == null) { + try { + sslAttributes = new Hashtable(); + Object sslSession = socket.getClass().getMethod("getSession", Utils.EMPTY_CLASSES).invoke(socket, Utils.EMPTY_OBJECTS); + if (sslSession != null) { + sslAttributes.put("javax.net.ssl.session", sslSession); + Method m = sslSession.getClass().getMethod("getCipherSuite", Utils.EMPTY_CLASSES); + m.setAccessible(true); + sslAttributes.put("javax.net.ssl.cipher_suite", m.invoke(sslSession, Utils.EMPTY_OBJECTS)); + m = sslSession.getClass().getMethod("getPeerCertificates", Utils.EMPTY_CLASSES); + m.setAccessible(true); + sslAttributes.put("javax.net.ssl.peer_certificates", m.invoke(sslSession, Utils.EMPTY_OBJECTS)); + } + } catch (IllegalAccessException iae) { + sslAttributes = null; + // iae.printStackTrace(); + } catch (NoSuchMethodException nsme) { + sslAttributes = null; + // nsme.printStackTrace(); + } catch (InvocationTargetException ite) { + // note we do not clear attributes, because + // SSLPeerUnverifiedException + // happens in the last call, when no client sertificate + // sslAttributes = null; + // ite.printStackTrace(); + } catch (IllegalArgumentException iae) { + // sslAttributes = null; + // iae.printStackTrace(); + } + // System.err.println("Socket SSL attrs: "+sslAttributes); + } // else TODO take attributes from SSLEngine when used + } + + /** + * it closes stream awaring of keep -alive + * + * @throws IOException + */ + private void closeStreams() throws IOException { + // System.err.println("===>CLOSE()"); + IOException ioe = null; + try { + if (printWriter != null) { + printWriter.flush(); + } else { + outputStream.flush(); + } + } catch (IOException io1) { + ioe = io1; + } + + try { + outputStream.close(); + } catch (IOException io1) { + if (ioe != null) { + ioe = (IOException) ioe.initCause(io1); + } else { + ioe = io1; + } + } + try { + inputStream.close(); + } catch (IOException io1) { + if (ioe != null) { + ioe = (IOException) ioe.initCause(io1); + } else { + ioe = io1; + } + } + + if (ioe != null) { + serve.log(ioe); + throw ioe; + } + } + + /* + * open for debug only + * protected void finalize() throws Throwable { + * System.err.println("Connection object gone"); // !!! + * super.finalize(); + * } + */ + + /** + * + * @throws IOException + */ + private void restart() throws IOException { + // new Exception("RESTART").printStackTrace(); + reqMethod = null; + reqUriPath = reqUriPathUn = null; + reqProtocol = null; + charEncoding = null; + remoteUser = null; + authType = null; + servlet = null; + oneOne = false; + reqMime = false; + + // considering that clear() works faster than new + if (reqHeaderNames == null) { + reqHeaderNames = new Vector(); + } else { + reqHeaderNames.clear(); + } + + if (reqHeaderValues == null) { + reqHeaderValues = new Vector(); + } else { + reqHeaderValues.clear(); + } + + locale = null; + uriLen = 0; + outCookies = null; + inCookies = null; + // requested + sessionCookieValue = null; + // requested + sessionUrlValue = null; + // actual used + sessionValue = null; + // requested and used + reqSessionValue = null; + reqQuery = null; + printWriter = null; + servletOutput = null; + formParameters = null; + + if (attributes == null) { + attributes = new Hashtable(); + } else { + attributes.clear(); + } + + if (sslAttributes != null) { + attributes.putAll(sslAttributes); + } + + resCode = -1; + resMessage = null; + resHeaderNames.clear(); + headersWritten = false; + webSocketUpgrade = false; + postCache = null; + if (asyncMode != null) { + serve.log("TJWS: debug", new Exception("Restarting without clean async mode")); + asyncMode = null; + } + requestThread = Thread.currentThread(); + ((ServeInputStream) inputStream).refresh(); + outputStream = new ServeOutputStream(socket.getOutputStream(), this); + // stream can be still used asyncronously, so + // ((ServeOutputStream) out).refresh(); + } + + // Methods from Runnable. + public void run() { + if (socket == null) { + return; + } + + try { + do { + restart(); + // Get the streams. + parseRequest(); + // serve.log("A>"+asyncMode); + if (asyncMode != null) { + asyncTimeout = asyncMode.getTimeout(); + if (asyncTimeout > 0) { + asyncTimeout += System.currentTimeMillis(); + } + return; + } + + finalizeRequest(); + if (webSocketUpgrade) { + outputStream.flush(); + try { + serve.websocketProvider.upgrade(socket, reqUriPath, servlet, this, this); + return; + } catch (Exception ex) { + serve.log("TJWS: websocket upgrade protocol error: " + ex, ex); + webSocketUpgrade = false; + } + } + } while (keepAlive && serve.isKeepAlive() && keepAliveRequestedTime < serve.getMaxTimesConnectionUse()); + } catch (IOException ex) { + /* Print if required in future. */ + // serve.log(ioe); + if (ex instanceof SocketTimeoutException) { + /* Keep commented, if running as Android embedded server. */ + if (!IOHelper.isAndroid()) { + serve.log("Keepalive timeout, asyncMode:" + asyncMode, ex); + } + } else { + String errMsg = ex.getMessage(); + if ((errMsg == null || errMsg.indexOf("ocket closed") < 0) && ex instanceof java.nio.channels.AsynchronousCloseException == false) { + if (socket != null) { + serve.log("TJWS: IO error: " + ex + " in processing a request " + (reqUriPathUn == null ? "(NULL)" : reqUriPathUn) + " from " + socket.getInetAddress() + ":" + socket.getLocalPort() + " / " + socket.getClass().getName()); + } else { + serve.log("TJWS: IO error: " + ex + "(socket NULL)"); + } + } else { + synchronized (this) { + socket = null; + } + } + } + } finally { + if (asyncMode == null && !webSocketUpgrade) { + close(); + } + } + } + + synchronized final void close() { + IOHelper.closeSilently(socket); + socket = null; + } + + private void parseRequest() throws IOException { + byte[] lineBytes = new byte[4096]; + // TODO put time mark here for start waiting for receiving requests + lastWait = System.currentTimeMillis(); + // Read the first line of the request. + socket.setSoTimeout(serve.timeoutKeepAlive); + int length = inputStream.readLine(lineBytes, 0, lineBytes.length); + if (length <= 0) { + if (keepAlive) { + keepAlive = false; + // connection seems be closed + } else { + problem("Status-Code 400: Bad Request(empty)", SC_BAD_REQUEST); + } + + return; + } + + if (length >= lineBytes.length) { + problem("Status-Code 414: Request-URI Too Long", SC_REQUEST_URI_TOO_LONG); + return; + } + + String line = new String(lineBytes, 0, length, IOHelper.UTF_8); + // serve.log("R>"+line); + final StringTokenizer lineTokens = new StringTokenizer(line); + if (lineTokens.hasMoreTokens()) { + reqMethod = lineTokens.nextToken(); + if (lineTokens.hasMoreTokens()) { + reqUriPathUn = lineTokens.nextToken(); + // TODO make it only when URL overwrite enabled + int uop = reqUriPathUn.indexOf(SESSION_URL_NAME); + if (uop > 0) { + sessionUrlValue = reqUriPathUn.substring(uop + SESSION_URL_NAME.length()); + reqUriPathUn = reqUriPathUn.substring(0, uop); + try { + serve.getSession(sessionUrlValue).userTouch(); + } catch (NullPointerException npe) { + } catch (IllegalStateException ise) { + } + } + + if (lineTokens.hasMoreTokens()) { + reqProtocol = lineTokens.nextToken(); + oneOne = !reqProtocol.toUpperCase().equals("HTTP/1.0"); + reqMime = true; + + // Read the rest of the lines. + String lineSegment; + while ((lineSegment = ((ServeInputStream) inputStream).readLine(HTTP_MAX_HDR_LEN)) != null) { + // serve.log("H>"+s); + if (lineSegment.length() == 0) { + break; + } + int c = lineSegment.indexOf(':', 0); + if (c > 0) { + String key = lineSegment.substring(0, c).trim().toLowerCase(); + String value = lineSegment.substring(c + 1).trim(); + reqHeaderNames.addElement(key); + reqHeaderValues.addElement(value); + } else { + serve.log("TJWS: header field '" + lineSegment + "' without ':'"); + } + } + } else { + reqProtocol = "HTTP/0.9"; + oneOne = false; + reqMime = false; + // keep alive supposes to be false already + } + } + } + + if (reqProtocol == null) { + problem("Status-Code 400: Malformed request line:" + line, SC_BAD_REQUEST); + return; + } + // Check Host: header in HTTP/1.1 requests. + if (oneOne) { + String strHeader = getHeader(HOST); + if (strHeader == null) { + problem("Status-Code 400: 'Host' header is missing in HTTP/1.1 request", SC_BAD_REQUEST); + return; + } + strHeader = getHeader(CONNECTION); + if (strHeader != null) { + strHeader = strHeader.toLowerCase(); + } + + webSocketUpgrade = strHeader != null && strHeader.indexOf(UPGRADE) >= 0 && WEBSOCKET.equalsIgnoreCase(getHeader(UPGRADE)); + keepAlive = "close".equalsIgnoreCase(strHeader) == false; + if (keepAlive) { + strHeader = getHeader(KEEPALIVE); + // serve.log("upgrading protocol:" + strHeader); + /* + * FF specific ? parse value to extract the connection + * specific timeoutKeepAlive and maxAliveConnUse todo that + * introduce the value in req/resp and copy defaults from + * Serve + */ + } + } else { + keepAlive = false; + } + + // Split off query string, if any. + int mark = reqUriPathUn.indexOf('?'); + if (mark > -1) { + if (mark < reqUriPathUn.length() - 1) { + reqQuery = reqUriPathUn.substring(mark + 1); + } + reqUriPathUn = reqUriPathUn.substring(0, mark); + } + reqUriPath = Utils.decode(reqUriPathUn, IOHelper.UTF_8); + // TDOD check if reqUriPathUn starts with http://host:port + if (CHUNKED.equalsIgnoreCase(getHeader(TRANSFERENCODING))) { + setHeader(CONTENTLENGTH, null); + ((ServeInputStream) inputStream).chunking(true); + } + String contentEncoding = extractEncodingFromContentType(getHeader(CONTENTTYPE)); + // TODO: encoding in request can be invalid, then do default + setCharacterEncoding(contentEncoding != null ? contentEncoding : IOHelper.UTF_8); + String contentLength = getHeader(CONTENTLENGTH); + if (contentLength != null) { + try { + ((ServeInputStream) inputStream).setContentLength(Long.parseLong(contentLength)); + } catch (NumberFormatException nfe) { + serve.log("TJWS: Invalid value of input content-length: " + contentLength); + } + } + + // the code was originally in processing headers loop, however hhas + // been moved here + String encoding = getHeader(CONTENT_ENCODING); + if (encoding != null) { + if ((encoding.equalsIgnoreCase("gzip") || encoding.equalsIgnoreCase("compressed")) && null != serve.gzipInStreamConstr && ((ServeInputStream) inputStream).compressed(true)) { + } else { + problem("Status-Code 415: Unsupported media type:" + encoding, SC_UNSUPPORTED_MEDIA_TYPE); + return; + } + } + + if (assureHeaders() && socket.getKeepAlive() == false) { + socket.setKeepAlive(true); + } + + socket.setSoTimeout(0); + serve.setHost(getHeader(HOST)); + PathTreeDictionary registry = (PathTreeDictionary) currentRegistry.get(); + lastRun = System.currentTimeMillis(); + try { + // TODO new + // SimpleRequestDispatcher(reqUriPathUn).forward((ServletRequest) + // this, (ServletResponse) this); + Object[] os = registry.get(reqUriPath); + if (webSocketUpgrade) { + webSocketUpgrade = false; + if (serve.websocketProvider != null) { + try { + serve.websocketProvider.handshake(socket, reqUriPath, servlet = (HttpServlet) os[0], this, this); + webSocketUpgrade = (resCode == SC_SWITCHING_PROTOCOLS); + // System.err.println("hs code:"+resCode); + } catch (Exception wse) { + problem("Can't handshake " + wse, SC_INTERNAL_SERVER_ERROR, wse); + } + } else { + problem("Websocket support is not configured", SC_NOT_IMPLEMENTED); + } + } else { + if (os[0] != null) { // note, os always not null + // / TODO put time mark here to monitor actual servicing + + // System.err.println("Servlet "+os[0]+" for path + // "+reqUriPath); + uriLen = ((Integer) os[1]).intValue(); + initSSLAttrs(); + runServlet((HttpServlet) os[0]); + } else { + problem("No any servlet found for serving " + reqUriPath, SC_BAD_REQUEST); + } + } + } finally { + currentRegistry.set(null); // remove + } + } + + /** + * + * @throws IOException + */ + private void finalizeRequest() throws IOException { + if (reqMethod != null && serve.isAccessLogged()) { + // TODO avoid hardcoded indecies, give them name as LOG_IP = 0, + // LOG_IDENT = 1, LOG_REMOTE_USER = 2 + // consider caching socket stuff for faster logging + // {0} {1} {2} [{3,date,dd/MMM/yyyy:HH:mm:ss Z}] \"{4} {5} {6}\" + // {7,number,#} {8,number} {9} {10} + // ARG_ACCESS_LOG_FMT + logPlaceHolders[0] = socket.getInetAddress(); // IP + logPlaceHolders[1] = "-"; // the RFC 1413 identity of the + // client, TODO get it from BASIC auth + logPlaceHolders[2] = remoteUser == null ? "-" : remoteUser; // remote + // user + logPlaceHolders[3] = new Date(lastRun); // time stamp + // {3,date,dd/MMM/yyyy:HH:mm:ss Z} {3,time,} + logPlaceHolders[4] = reqMethod; // method + logPlaceHolders[5] = reqUriPathUn; // resource + logPlaceHolders[6] = reqProtocol; // protocol + logPlaceHolders[7] = new Integer(resCode); // res code + logPlaceHolders[8] = new Long(((ServeOutputStream) outputStream).lengthWritten()); + logPlaceHolders[9] = new Integer(socket.getLocalPort()); + logPlaceHolders[10] = serve.isShowReferer() ? getHeader("Referer") : "-"; + logPlaceHolders[11] = serve.isShowUserAgent() ? getHeader("User-Agent") : "-"; + serve.logStream.println(accessLogFormat.format(logPlaceHolders)); + } + + if (!webSocketUpgrade) { + lastRun = 0; + keepAliveRequestedTime++; + closeStreams(); + } + } + + private boolean assureHeaders() { + if (reqMime) { + setHeader("MIME-Version", "1.0"); + } + + setDateHeader("Date", System.currentTimeMillis()); + setHeader("Server", Serve.Identification.serverName + "/" + Serve.Identification.serverVersion); + if (keepAlive && serve.isKeepAlive() && !webSocketUpgrade) { + if (reqMime) { + // set for 1.1 too, because some client do not follow a + // standard + setHeader(CONNECTION, KEEPALIVE); + if (oneOne) { + setHeader(KEEPALIVE, serve.getKeepAliveParamStr()); + } + } + return true; + } else if (webSocketUpgrade) { + setHeader(CONNECTION, UPGRADE); + return true; + } else { + setHeader(CONNECTION, "close"); + } + + return false; + } + + /** + * Runs the current servlet + * + * @param servlet + * @throws IOException + */ + private void runServlet(HttpServlet servlet) throws IOException { + // Set default response fields. + setStatus(SC_OK); + try { + parseCookies(); + if (reqSessionValue == null) {// not from cookie + reqSessionValue = sessionUrlValue; + } + + sessionValue = reqSessionValue; + if (authenificate()) { + if (servlet instanceof SingleThreadModel) { + synchronized (servlet) { + servlet.service((ServletRequest) this, (ServletResponse) this); + } + } else { + servlet.service((ServletRequest) this, (ServletResponse) this); + } + } + // old close + } catch (UnavailableException ex) { + if (ex.isPermanent()) { + serve.unloadServlet(servlet); + servlet.destroy(); + } else if (ex.getUnavailableSeconds() > 0) { + serve.log("TJWS: Temporary unavailability feature is not supported " + servlet); + } + problem(ex.getMessage(), SC_SERVICE_UNAVAILABLE); + } catch (ServletException e) { + serve.log("TJWS: Servlet exception", e); + Throwable rootCause = e.getRootCause(); + while (rootCause != null) { + serve.log("Caused by", rootCause); + if (rootCause instanceof ServletException) { + rootCause = ((ServletException) rootCause).getRootCause(); + } else { + /* 1.4 */ + rootCause = rootCause.getCause(); + } + } + problem(e.toString(), SC_INTERNAL_SERVER_ERROR); + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + serve.log("TJWS: Unexpected problem running servlet", e); + problem("Unexpected problem running servlet: " + e.toString(), SC_INTERNAL_SERVER_ERROR); + } finally { + // closeStreams(); + // socket will be closed by a caller if no keep-alive + } + } + + /** + * + * @return + * @throws IOException + */ + private boolean authenificate() throws IOException { + final Object[] o = serve.realms.get(reqUriPath); // by Niel Markwick + BasicAuthRealm realm = null; + if (o != null) { + realm = (BasicAuthRealm) o[0]; + } + + // System.err.println("looking for realm for path "+getPathInfo()+" + // in "+serve.realms+" found "+realm); + if (realm == null) { + return true; + } + + String credentials = getHeader("Authorization"); + if (credentials != null) { + credentials = Utils.base64Decode(credentials.substring(credentials.indexOf(' ') + 1), getCharacterEncoding()); + int i = credentials.indexOf(':'); + String user = credentials.substring(0, i); + String password = credentials.substring(i + 1); + remoteUser = user; + authType = "BASIC"; // support only basic authenification (FORM, + // CLIENT_CERT, DIGEST ) + String realPassword = (String) realm.get(user); + // System.err.println("User "+user+" Password "+password+" real + // "+realPassword); + if (realPassword != null && realPassword.equals(password)) { + return true; + } + } + + setStatus(SC_UNAUTHORIZED); + setHeader("WWW-Authenticate", "basic realm=\"" + realm.name() + '"'); + // writeHeaders(); // because sendError() is used + realSendError(); + return false; + } + + private void problem(String logMessage, int resCode, Throwable t) { + serve.log("TJWS: " + logMessage, t); + try { + sendError(resCode, logMessage); + } catch (IllegalStateException e) { /* ignore */ + } catch (IOException e) { /* ignore */ + } + } + + private void problem(String logMessage, int resCode) { + problem(logMessage, resCode, null); + } + + public void setInInclude(boolean set) { + ((ServeOutputStream) outputStream).setInInclude(set); + } + + public void spawnAsync(AsyncCallback setAsync) { + // System.err.println("SPAWN=="); + asyncMode = setAsync; + } + + public void joinAsync() { + // System.err.println("JOIN=="); + // new Exception("JOIN==").printStackTrace(); + synchronized (this) { + if (asyncMode == null) { + return; + } + asyncMode = null; + } + // System.err.println("Comparing request with current "+ + // requestThread+" "+ Thread.currentThread()); + if (requestThread == Thread.currentThread()) { + // detecting if called within request processing thread + return; + } + + try { + finalizeRequest(); + if (keepAlive && serve.isKeepAlive() && keepAliveRequestedTime < serve.getMaxTimesConnectionUse()) { + serve.threadPool.executeThread(this); + } else { + close(); + } + } catch (IOException ioe) { + serve.log("TJWS: " + ioe); + } + } + + public void extendAsyncTimeout(long period) { + if (period > 0) { + asyncTimeout = System.currentTimeMillis() + period; + } else if (period < 0) { + asyncTimeout = 0; + } + } + + private static final int MAYBEVERSION = 1; + private static final int INVERSION = 2; + private static final int OLD_INNAME = 3; + private static final int OLD_INVAL = 4; + private static final int INVERSIONNUM = 5; + private static final int RECOVER = 6; + private static final int NEW_INNAME = 7; + private static final int NEW_INVAL = 8; + private static final int INPATH = 9; + private static final int MAYBEINPATH = 10; + private static final int INPATHVALUE = 11; + private static final int MAYBEPORT = 12; + private static final int INDOMAIN = 13; + private static final int MAYBEDOMAIN = 14; + private static final int INPORT = 15; + private static final int INDOMAINVALUE = 16; + private static final int INPORTVALUE = 17; + + // TODO see if it can be simplified + // TODO check if HTTPOnly can be transfered back + private void parseCookies() throws IOException { + if (inCookies == null) { + inCookies = new Vector(); + } + + String cookies = getHeader(COOKIE); + if (LogManager.isDebugEnabled()) { + serve.log("cookies:" + cookies); + } + + if (cookies == null) { + return; + } + + try { + String cookieName = null; + String cookieValue = null; + String cookiePath = null; + String cookieDomain = null; + // boolean httpOnly = false; + if (cookies.length() > 300 * 4096) { + throw new IOException("Cookie string too long:" + cookies.length()); + } + + // System.err.println("We received:" + cookies); + char[] cookiesChars = cookies.toCharArray(); + int state = MAYBEVERSION; + StringBuffer token = new StringBuffer(256); + boolean quoted = false; + for (int i = 0; i < cookiesChars.length; i++) { + char c = cookiesChars[i]; + switch (state) { + case MAYBEVERSION: + if (c != ' ') { + token.append(c); + if (c == '$') { + // RFC 2965 + state = INVERSION; + } else { + // RFC 2109 + state = OLD_INNAME; + } + } + break; + case OLD_INNAME: + if (c == '=') { + state = OLD_INVAL; + cookieName = token.toString(); + token.setLength(0); + } else if (c != ' ' || token.length() > 0) { + token.append(c); + } + break; + // TODO introduce val_start. then quoted value and value + case OLD_INVAL: + if (quoted == false) { + if (c == ';') { + state = OLD_INNAME; + cookieValue = token.toString(); + token.setLength(0); + addCookie(cookieName, cookieValue, null, null); + } else if (c == '"' && token.length() == 0) { + quoted = true; + } else { + token.append(c); + } + } else { + if (c == '"') { + quoted = false; + } else { + token.append(c); + } + } + break; + case INVERSION: + if (c == '=') { + if ("$Version".equals(token.toString())) { + state = INVERSIONNUM; + } else { + // consider name starts with $ + state = OLD_INVAL; + cookieName = token.toString(); + } + token.setLength(0); + } else { + token.append(c); + } + break; + case INVERSIONNUM: + if (c == ',' || c == ';') { + token.setLength(0); + state = NEW_INNAME; + } else if (Character.isDigit(c) == false) { + state = RECOVER; + } else { + token.append(c); + } + break; + case NEW_INNAME: + if (c == '=') { + state = NEW_INVAL; + cookieName = token.toString(); + token.setLength(0); + } else if (c != ' ' || token.length() > 0) { + token.append(c); + } + break; + case NEW_INVAL: + if (c == ';') { + state = MAYBEINPATH; + cookieValue = token.toString(); + token.setLength(0); + cookiePath = null; + } else if (c == ',') { + state = NEW_INNAME; + cookieValue = token.toString(); + token.setLength(0); + addCookie(cookieName, cookieValue, null, null); + } else { + token.append(c); + } + break; + case MAYBEINPATH: + if (c != ' ') { + token.append(c); + if (c == '$') { + state = INPATH; + } else { + addCookie(cookieName, cookieValue, null, null); + state = NEW_INNAME; + } + } + break; + case INPATH: + if (c == '=') { + if ("$Path".equals(token.toString())) + state = INPATHVALUE; + else { + addCookie(cookieName, cookieValue, null, null); + // consider name starts with $ + state = NEW_INVAL; + cookieName = token.toString(); + } + token.setLength(0); + } else { + token.append(c); + } + break; + case INPATHVALUE: + if (c == ',') { + cookiePath = token.toString(); + state = NEW_INNAME; + addCookie(cookieName, cookieValue, cookiePath, null); + token.setLength(0); + } else if (c == ';') { + state = MAYBEDOMAIN; + cookiePath = token.toString(); + token.setLength(0); + } else { + token.append(c); + } + break; + case MAYBEDOMAIN: + if (c != ' ') { + token.append(c); + if (c == '$') { + state = INDOMAIN; + } else { + addCookie(cookieName, cookieValue, cookiePath, null); + state = NEW_INNAME; + } + } + break; + case INDOMAIN: + if (c == '=') { + if ("$Domain".equals(token.toString())) { + state = INDOMAINVALUE; + } else { + addCookie(cookieName, cookieValue, cookiePath, null); + // consider name starts with $ + state = NEW_INVAL; + cookieName = token.toString(); + } + token.setLength(0); + } + break; + case INDOMAINVALUE: + if (c == ',') { + state = NEW_INNAME; + addCookie(cookieName, cookieValue, cookiePath, token.toString()); + token.setLength(0); + } else if (c == ';') { + cookieDomain = token.toString(); + state = MAYBEPORT; + } else { + token.append(c); + } + break; + case MAYBEPORT: + if (c != ' ') { + token.append(c); + if (c == '$') { + state = INPORT; + } else { + addCookie(cookieName, cookieValue, cookiePath, cookieDomain); + state = NEW_INNAME; + } + } + break; + case INPORT: + if (c == '=') { + if ("$Port".equals(token.toString())) + state = INPORTVALUE; + else { + addCookie(cookieName, cookieValue, cookiePath, cookieDomain); + // consider name starts with $ + state = NEW_INVAL; + cookieName = token.toString(); + } + token.setLength(0); + } + break; + case INPORTVALUE: + if (c == ',' || c == ';') { + int port = Integer.parseInt(token.toString()); + state = NEW_INNAME; + addCookie(cookieName, cookieValue, cookiePath, cookieDomain); + token.setLength(0); + } else if (Character.isDigit(c) == false) { + state = RECOVER; + } else { + token.append(c); + } + break; + case RECOVER: + serve.log("TJWS: Parsing recover of cookie string " + cookies, null); + if (c == ';' || c == ',') { + token.setLength(0); + state = NEW_INNAME; + } + break; + } + } + + if (state == OLD_INVAL || state == NEW_INVAL) { + cookieValue = token.toString(); + addCookie(cookieName, cookieValue, null, null); + } else if (state == INPATHVALUE) { + addCookie(cookieName, cookieValue, token.toString(), null); + } else if (state == INDOMAINVALUE) { + addCookie(cookieName, cookieValue, cookiePath, token.toString()); + } else if (state == INPORTVALUE) { + addCookie(cookieName, cookieValue, cookiePath, cookieDomain); + } + } catch (Error ex) { + serve.log("TJWS: Error in parsing cookies: " + cookies, ex); + } catch (Exception ex) { + serve.log("TJWS: An exception in parsing cookies: " + cookies, ex); + } + } + + /** + * + * @param name + * @param value + * @param path + * @param domain + */ + private void addCookie(String name, String value, String path, String domain) { + if (LogManager.isDebugEnabled()) { + serve.log("addCookie(" + name + ", " + value + ", " + path + ", " + domain + ")"); + } + if (SESSION_COOKIE_NAME.equals(name) && sessionCookieValue == null) { + sessionCookieValue = value; + try { + serve.getSession(sessionCookieValue).userTouch(); + reqSessionValue = sessionCookieValue; + } catch (IllegalStateException ex) { + if (LogManager.isDebugEnabled()) { + serve.log(ex); + } + } catch (NullPointerException ex) { + if (LogManager.isDebugEnabled()) { + serve.log(ex); + } + } + } else { + final Cookie mCookie = new Cookie(name, value); + inCookies.addElement(mCookie); + if (path != null) { + mCookie.setPath(path); + if (domain != null) { + mCookie.setDomain(domain); + } + } + } + } + + // Methods from ServletRequest. + + // / Returns the size of the request entity data, or -1 if not known. + // Same as the CGI variable CONTENT_LENGTH. + public int getContentLength() { + try { + return getIntHeader(CONTENTLENGTH); + } catch (NumberFormatException nfe) { + + } + return -1; + } + + // / Returns the MIME type of the request entity data, or null if + // not known. + // Same as the CGI variable CONTENT_TYPE. + public String getContentType() { + return getHeader(CONTENTTYPE); + } + + // / Returns the protocol and version of the request as a string of + // the form /.. + // Same as the CGI variable SERVER_PROTOCOL. + public String getProtocol() { + return reqProtocol; + } + + // / Returns the scheme of the URL used in this request, for example + // "http", "https", or "ftp". Different schemes have different rules + // for constructing URLs, as noted in RFC 1738. The URL used to create + // a request may be reconstructed using this scheme, the server name + // and port, and additional information such as URIs. + public String getScheme() { + if (scheme == null) { + // lazy stuf dlc + synchronized (this) { + if (scheme == null) { + scheme = isSSLSocket() || (serve.proxySSL) ? "https" : "http"; + } + } + } + + return scheme; + } + + boolean isSSLSocket() { + return socket.getClass().getName().indexOf("SSLSocket") > 0 || socket.getClass().getName().indexOf("SSLChannel") > 0; + } + + // / Returns the host name of the server as used in the part of + // the request URI. + // Same as the CGI variable SERVER_NAME. + public String getServerName() { + String serverName = getHeader(HOST); + if (serverName != null && serverName.length() > 0) { + int colon = serverName.lastIndexOf(':'); + if (colon >= 0) { + if (colon < serverName.length()) { + serverName = serverName.substring(0, colon); + } + } + } + + if (serverName == null) { + if (serve.proxyConfig) + serverName = getHeader(FORWARDED_SERVER); + if (serverName == null) { + try { + serverName = InetAddress.getLocalHost().getHostName(); + } catch (java.net.UnknownHostException ignore) { + serverName = "localhost"; + } + } + } + + int slash = serverName.indexOf("/"); + if (slash >= 0) { + serverName = serverName.substring(slash + 1); + } + return serverName; + } + + // / Returns the port number on which this request was received as used + // in + // the part of the request URI. + // Same as the CGI variable SERVER_PORT. + public int getServerPort() { + final String serverName = getHeader(HOST); + if (!IOHelper.isNullOrEmpty(serverName)) { + int colon = serverName.indexOf(':'); + if (colon >= 0) { + try { + return Integer.parseInt(serverName.substring(colon + 1).trim()); + } catch (NumberFormatException ex) { + if (LogManager.isDebugEnabled()) { + serve.log(ex); + } + } + } else { + if ("https".equals(getScheme())) { + return 443; + } + + return 80; + } + } + + return socket.getLocalPort(); + } + + // / Returns the Internet Protocol (IP) address of the client or last + // proxy that sent the request. + // Same as the CGI variable REMOTE_ADDR. + public String getRemoteAddr() { + if (serve.proxyConfig && getHeader(FORWARDED_FOR) != null) { + return getHeader(FORWARDED_FOR); + } + + return socket.getInetAddress().getHostAddress(); + } + + // / Returns the fully qualified name of the client or the last proxy + // that sent the request. + // + // Same as the CGI variable REMOTE_HOST. + public String getRemoteHost() { + if (serve.proxyConfig && getHeader(FORWARDED_FOR) != null) { + // TODO resolve name by IP address from X-Forwarded-For + return getHeader(FORWARDED_FOR); + } + + String result = socket.getInetAddress().getHostName(); + return result != null ? result : getRemoteAddr(); + } + + // / Applies alias rules to the specified virtual path and returns the + // corresponding real path, or null if the translation can not be + // performed for any reason. For example, an HTTP servlet would + // resolve the path using the virtual docroot, if virtual hosting is + // enabled, and with the default docroot otherwise. Calling this + // method with the string "/" as an argument returns the document root. + public String getRealPath(String path) { + return serve.getRealPath(path); + } + + // / Returns an input stream for reading request data. + // @exception IllegalStateException if getReader has already been called + // @exception IOException on other I/O-related errors + public ServletInputStream getInputStream() throws IOException { + synchronized (inputStream) { + if (((ServeInputStream) inputStream).isReturnedAsReader()) { + throw new IllegalStateException("Already returned as a reader."); + } + ((ServeInputStream) inputStream).setReturnedAsStream(true); + } + + return inputStream; + } + + // / Returns a buffered reader for reading request data. + // @exception UnsupportedEncodingException if the character set encoding + // isn't supported + // @exception IllegalStateException if getInputStream has already been + // called + // @exception IOException on other I/O-related errors + public BufferedReader getReader() { + synchronized (inputStream) { + if (((ServeInputStream) inputStream).isReturnedAsStream()) { + throw new IllegalStateException("Already returned as a stream."); + } + ((ServeInputStream) inputStream).setReturnedAsReader(true); + } + + if (charEncoding != null) { + try { + return new BufferedReader(new InputStreamReader(inputStream, charEncoding)); + } catch (UnsupportedEncodingException ex) { + if (LogManager.isDebugEnabled()) { + serve.log(ex); + } + } + } + + return new BufferedReader(new InputStreamReader(inputStream)); + } + + private Map assureParametersFromRequest() { + synchronized (resHeaderNames) { // supposes to not be null + if (formParameters == null) { + if ("GET".equals(reqMethod) || "HEAD".equals(reqMethod)) { + if (reqQuery != null) { + try { + formParameters = Utils.parseQueryString(reqQuery, charEncoding); + } catch (IllegalArgumentException ex) { + serve.log("TJWS: Exception " + ex + " at parsing 'get|head' data " + reqQuery); + } + } + } else if ("POST".equals(reqMethod)) { + String contentType = getContentType(); + if (contentType != null && WWWFORMURLENCODE.regionMatches(true, 0, contentType, 0, WWWFORMURLENCODE.length())) { + if (postCache == null) { + postCache = new String[1]; + try { + final InputStream is = getInputStream(); + formParameters = Utils.parsePostData(getContentLength(), is, charEncoding, postCache); + } catch (Exception ex) { + serve.log("TJWS: Exception " + ex + " at parsing 'POST' data of length " + getContentLength()); + // TODO propagate the exception ? + formParameters = EMPTYHASHTABLE; + } + } else { + formParameters = Utils.parseQueryString(postCache[0], charEncoding); + } + + if (!IOHelper.isNullOrEmpty(reqQuery)) { + formParameters.putAll(Utils.parseQueryString(reqQuery, charEncoding)); + } + } else if (reqQuery != null) { + formParameters = Utils.parseQueryString(reqQuery, charEncoding); + } + } else { + throw new IllegalArgumentException("Request parameters are not supported for method:" + reqMethod); + } + } + } + + if (formParameters == null) { + formParameters = EMPTYHASHTABLE; + } + + return formParameters; + } + + // / Returns the parameter names for this request. + public Enumeration getParameterNames() { + assureParametersFromRequest(); + return ((Hashtable) formParameters).keys(); + } + + // / Returns the value of the specified query string parameter, or null + // if not found. + // @param name the parameter name + public String getParameter(String name) { + String[] params = getParameterValues(name); + if (params == null || params.length == 0) { + return null; + } + + return params[0]; + } + + // / Returns the values of the specified parameter for the request as an + // array of strings, or null if the named parameter does not exist. + public String[] getParameterValues(String name) { + assureParametersFromRequest(); + return (String[]) formParameters.get(name); + } + + // / Returns the value of the named attribute of the request, or null if + // the attribute does not exist. This method allows access to request + // information not already provided by the other methods in this + // interface. + public Object getAttribute(String name) { + // System.err.println("!!!Get att + // orig:"+name+"="+attributes.get(name)); + return attributes.get(name); + } + + // Methods from HttpServletRequest. + + // / Gets the array of cookies found in this request. + public Cookie[] getCookies() { + Cookie[] cookieArray = new Cookie[inCookies.size()]; + inCookies.copyInto(cookieArray); + return cookieArray; + } + + /** + * Returns the method with which the request was made. This can be + * "GET", "HEAD", "POST", or an extension method. + * Same as the CGI variable REQUEST_METHOD. + * + * @see javax.servlet.http.HttpServletRequest#getMethod() + */ + public String getMethod() { + return reqMethod; + } + + /*********************************************************************** + * Returns the part of this request's URL from the protocol name up to + * the query string in the first line of the HTTP request. To + * reconstruct an URL with a scheme and host, use + * HttpUtils.getRequestURL(javax.servlet.http.HttpServletRequest). + ************************************************************************/ + // Returns the full request URI. + public String getRequestURI() { + return reqUriPathUn; + } + + /** + * Reconstructs the URL the client used to make the request. The + * returned URL contains a protocol, server name, port number, and + * server path, but it does not include query string parameters.
+ * Because this method returns a StringBuffer, not a string, you can + * modify the URL easily, for example, to append query parameters. + *

+ * This method is useful for creating redirect messages and for + * reporting errors. + * + * @return a StringBuffer object containing the reconstructed URL + * @since 2.3 + */ + public java.lang.StringBuffer getRequestURL() { + int port = getServerPort(); + return new StringBuffer().append(getScheme()).append("://").append(getServerName()).append("https".equals(getScheme()) && port == 443 || port == 80 ? "" : ":" + String.valueOf(port)).append(getRequestURI()); + } + + // / Returns the part of the request URI that referred to the servlet + // being + // invoked. + // Analogous to the CGI variable SCRIPT_NAME. + public String getServletPath() { + // In this server, the entire path is regexp-matched against the + // servlet pattern, so there's no good way to distinguish which + // part refers to the servlet. + return uriLen > 0 ? reqUriPath.substring(0, uriLen) : ""; + } + + // / Returns optional extra path information following the servlet path, + // but + // immediately preceding the query string. Returns null if not + // specified. + // Same as the CGI variable PATH_INFO. + public String getPathInfo() { + // In this server, the entire path is regexp-matched against the + // servlet pattern, so there's no good way to distinguish which + // part refers to the servlet. + return uriLen >= reqUriPath.length() ? null : reqUriPath.substring(uriLen); + } + + // / Returns extra path information translated to a real path. Returns + // null if no extra path information was specified. + // Same as the CGI variable PATH_TRANSLATED. + public String getPathTranslated() { + // In this server, the entire path is regexp-matched against the + // servlet pattern, so there's no good way to distinguish which + // part refers to the servlet. + return getRealPath(getPathInfo()); + } + + // / Returns the query string part of the servlet URI, or null if not + // known. + // Same as the CGI variable QUERY_STRING. + public String getQueryString() { + return reqQuery; + } + + // / Returns the name of the user making this request, or null if not + // known. + // Same as the CGI variable REMOTE_USER. + public String getRemoteUser() { + return remoteUser; + } + + // / Returns the authentication scheme of the request, or null if none. + // Same as the CGI variable AUTH_TYPE. + public String getAuthType() { + return authType; + } + + /** + * Returns the value of a header field, or null if not known. + * Same as the information passed in the CGI variabled HTTP_*. + * + * @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String) + */ + public String getHeader(String name) { + name = name.toLowerCase(); + int i = -1; + if (serve.proxyConfig && HOST.equals(name)) { + i = reqHeaderNames.indexOf(FORWARDED_HOST); + } + if (i < 0) { + i = reqHeaderNames.indexOf(name); + } + if (i < 0) { + return null; + } + return (String) reqHeaderValues.elementAt(i); + } + + /** + * @see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String) + */ + public int getIntHeader(String name) { + String val = getHeader(name); + if (val == null) { + return -1; + } + + return Integer.parseInt(val); + } + + /** + * @see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String) + */ + public long getDateHeader(String name) { + String val = getHeader(name); + if (val == null) { + return -1; + } + + try { + return headerdateformat.parse(val).getTime(); + } catch (ParseException pe) { + try { + return rfc850DateFmt.parse(val).getTime(); + } catch (ParseException pe1) { + try { + return asciiDateFmt.parse(val).getTime(); + } catch (ParseException pe3) { + throw new IllegalArgumentException("Value " + val + " can't be converted to Date using any of formats: [" + headerdateformat.toPattern() + "][ " + rfc850DateFmt.toPattern() + "][" + asciiDateFmt.toPattern()); + } + } + } + } + + /** + * Returns the request headers for the given header. + * + * @param header + * @return + */ + public Enumeration getRequestHeaders(String header) { + Vector result = new Vector(); + int i = -1; + while ((i = reqHeaderNames.indexOf(header.toLowerCase(), i + 1)) >= 0) { + result.addElement(reqHeaderValues.elementAt(i)); + } + return result.elements(); + } + + /** + * Returns the request header names. + * + * @return + */ + public Enumeration getRequestHeaderNames() { + return reqHeaderNames.elements(); + } + + // / Gets the current valid session associated with this request, if + // create is false or, if necessary, creates a new session for the + // request, if create is true. + //

+ // Note: to ensure the session is properly maintained, the servlet + // developer must call this method (at least once) before any output + // is written to the response. + //

+ // Additionally, application-writers need to be aware that newly + // created sessions (that is, sessions for which HttpSession.isNew + // returns true) do not have any application-specific state. + public synchronized HttpSession getSession(boolean create) { + HttpSession result = null; + if (sessionValue != null) { + result = serve.getSession(sessionValue); + if (result != null && ((AcmeSession) result).isValid() == false) { + serve.removeSession(sessionValue); + result = null; + } + // System.err.println("^^^^^^^req sess: "+sessionValue+", + // found:"+result); + } + + if (result == null && create) { + result = serve.createSession(); + if (result != null) { + sessionValue = result.getId(); + } else { + throw new RuntimeException("A session can't be created"); + } + // System.err.println("^~~~~~created: "+sessionValue); + } + return result; + } + + // JSDK 2.1 + public HttpSession getSession() { + return getSession(true); + } + + public boolean isRequestedSessionIdFromURL() { + return isRequestedSessionIdFromUrl(); + } + + // from ServletRequest + public Enumeration getAttributeNames() { + return attributes.keys(); + } + + /** + * Stores an attribute in this request. Attributes are reset between + * requests. This method is most often used in conjunction with + * RequestDispatcher. + *

+ * Attribute names should follow the same conventions as package names. + * Names beginning with java.*, javax.*, and com.sun.*, are reserved for + * use by Sun Microsystems. If the object passed in is null, the effect + * is the same as calling removeAttribute(java.lang.String). + *

+ * It is warned that when the request is dispatched from the servlet + * resides in a different web application by RequestDispatcher, the + * object set by this method may not be correctly retrieved in the + * caller servlet. + * + * @param name + * - a String specifying the name of the attribute + * @param o + * - the Object to be stored + */ + public void setAttribute(String key, Object value) { + // System.err.println("!!!Set att orig:"+key+"="+o); + // if ("javax.servlet.jsp.jspException".equals(key) && o instanceof + // Throwable) + // ((Throwable)o).printStackTrace(); + + if (value != null) { + attributes.put(key, value); + } else { + attributes.remove(key); + } + } + + // / Gets the session id specified with this request. This may differ + // from the actual session id. For example, if the request specified + // an id for an invalid session, then this will get a new session with + // a new id. + public String getRequestedSessionId() { + return reqSessionValue; + } + + // / Checks whether this request is associated with a session that is + // valid in the current session context. If it is not valid, the + // requested session will never be returned from the getSession + // method. + public boolean isRequestedSessionIdValid() { + if (reqSessionValue != null) { + AcmeSession session = serve.getSession(reqSessionValue); + return (session != null && session.isValid()); + } + return false; + } + + /** + * Checks whether the session id specified by this request came in as a + * cookie. (The requested session may not be one returned by the + * getSession method.) + */ + public boolean isRequestedSessionIdFromCookie() { + return sessionCookieValue != null; + } + + // / Checks whether the session id specified by this request came in as + // part of the URL. (The requested session may not be the one returned + // by the getSession method.) + public boolean isRequestedSessionIdFromUrl() { + return sessionUrlValue != null && sessionCookieValue == null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse) + */ + @Override + public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { + // TODO Auto-generated method stub + return false; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String) + */ + @Override + public Part getPart(String arg0) throws IOException, ServletException { + // TODO Auto-generated method stub + return null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServletRequest#getParts() + */ + @Override + public Collection getParts() throws IOException, ServletException { + // TODO Auto-generated method stub + return null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, + * java.lang.String) + */ + @Override + public void login(String arg0, String arg1) throws ServletException { + // TODO Auto-generated method stub + + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServletRequest#logout() + */ + @Override + public void logout() throws ServletException { + // TODO Auto-generated method stub + + } + + // Methods from ServletResponse. + + /** + * Sets the content length for this response. + * + * @see javax.servlet.ServletResponse#setContentLength(int) + */ + public void setContentLength(int length) { + if (length >= 0) { + setIntHeader(CONTENTLENGTH, length); + } else { + setHeader(CONTENTLENGTH, null); + } + } + + /** + * Sets the content type for this response. + * + * @see javax.servlet.ServletResponse#setContentType(java.lang.String) + */ + public void setContentType(String type) { + setHeader(CONTENTTYPE, type); + } + + /** + * Returns an output stream for writing response data. + * + * @see javax.servlet.ServletResponse#getOutputStream() + */ + public ServletOutputStream getOutputStream() { + synchronized (outputStream) { + if (servletOutput == null) { + if (printWriter != null) { + throw new IllegalStateException("Already returned as a writer"); + } + servletOutput = outputStream; + } + } + + return servletOutput; + } + + // / Returns a print writer for writing response data. The MIME type of + // the response will be modified, if necessary, to reflect the character + // encoding used, through the charset=... property. This means that the + // content type must be set before calling this method. + // @exception UnsupportedEncodingException if no such encoding can be + // provided + // @exception IllegalStateException if getOutputStream has been called + // @exception IOException on other I/O errors + public PrintWriter getWriter() throws IOException { + synchronized (outputStream) { + if (printWriter == null) { + if (servletOutput != null) { + throw new IllegalStateException("Already was returned as servlet output stream"); + } + + String encoding = getCharacterEncoding(); + if (encoding != null) { + printWriter = new PrintWriter(new OutputStreamWriter(outputStream, encoding)); + } else { + printWriter = new PrintWriter(outputStream); + } + } + } + + return printWriter; + } + + // / Returns the character set encoding used for this MIME body. The + // character encoding is either the one specified in the assigned + // content type, or one which the client understands. If no content + // type has yet been assigned, it is implicitly set to text/plain. + public String getCharacterEncoding() { + final String contenType = (String) resHeaderNames.get(CONTENTTYPE.toLowerCase()); + if (contenType != null) { + String encoding = extractEncodingFromContentType(contenType); + if (encoding != null) { + return encoding; + } + } + + return charEncoding; + } + + /** + * + * @param contenType + * @return + */ + private String extractEncodingFromContentType(String contenType) { + if (contenType == null) { + return null; + } + + int index = contenType.indexOf(';'); + if (index > 0) { + index = contenType.toLowerCase().indexOf("charset=", index); + if (index >= 0) { + contenType = contenType.substring(index + "charset=".length()).trim(); + index = contenType.indexOf(';'); + if (index > 0) { + contenType = contenType.substring(0, index); + } + + int lenContenType = contenType.length(); + if (lenContenType > 2 && contenType.charAt(0) == '"') { + return contenType.substring(1, lenContenType - 1); + } + return contenType; + } + } + + return null; + } + + // 2.2 - do not use buffer + public void flushBuffer() throws java.io.IOException { + ((ServeOutputStream) outputStream).flush(); + } + + /** + * Clears the content of the underlying buffer in the response without + * clearing headers or status code. If the response has been committed, + * this method throws an IllegalStateException. + * + * @since 2.3 + */ + public void resetBuffer() { + ((ServeOutputStream) outputStream).reset(); + synchronized (this) { + // TODO check if stream was flushed + headersWritten = false; + } + } + + public int getBufferSize() { + return ((ServeOutputStream) outputStream).getBufferSize(); + } + + public void setBufferSize(int size) { + ((ServeOutputStream) outputStream).setBufferSize(size); + } + + /** + * Returns a boolean indicating if the response has been committed. A + * commited response has already had its status code and headers + * written. + * + * @return a boolean indicating if the response has been committed + * @see setBufferSize(int), getBufferSize(), flushBuffer(), reset() + */ + // a caller should think about syncronization + public boolean isCommitted() { + return headersWritten && ((ServeOutputStream) outputStream).lengthWritten() > 0; + } + + /** + * Clears any data that exists in the buffer as well as the status code + * and headers. If the response has been committed, this method throws + * an IllegalStateException. + * + * @throws java.lang.IllegalStateException + * - if the response has already been committed + * @see setBufferSize(int), getBufferSize(), flushBuffer(), + * isCommitted() + */ + public void reset() throws IllegalStateException { + // new Exception("RESET").printStackTrace(); + if (!isCommitted()) { + if (outCookies != null) { + outCookies.clear(); + } + resHeaderNames.clear(); + printWriter = null; + servletOutput = null; + ((ServeOutputStream) outputStream).reset(); + assureHeaders(); + } else { + throw new IllegalStateException("Header have already been committed."); + } + } + + /** + * Sets the locale of the response, setting the headers (including the + * Content-Type's charset) as appropriate. This method should be called + * before a call to getWriter(). By default, the response locale is the + * default locale for the server. + * + * @param loc + * - the locale of the response + * @see getLocale() + */ + public void setLocale(java.util.Locale locale) { + this.locale = locale; + } + + /** + * For request: Returns the preferred Locale that the client will accept + * content in, based on the Accept-Language header. If the client + * request doesn't provide an Accept-Language header, this method + * returns the default locale for the server. + * + * For response: Returns the locale specified for this response using + * the setLocale(java.util.Locale) method. Calls made to setLocale after + * the response is committed have no effect. If no locale has been + * specified, the container's default locale is returned. + */ + public java.util.Locale getLocale() { + if (locale != null) { + return locale; + } + + Enumeration itr = getLocales(); + if (itr.hasMoreElements()) { + return (Locale) itr.nextElement(); + } + + return Locale.getDefault(); + } + + /** + * Returns an Enumeration of Locale objects indicating, in decreasing + * order starting with the preferred locale, the locales that are + * acceptable to the client based on the Accept-Language header. If the + * client request doesn't provide an Accept-Language header, this method + * returns an Enumeration containing one Locale, the default locale for + * the server. + */ + public Enumeration getLocales() { + // TODO: cache result + final String acceptLanguage = getHeader(ACCEPT_LANGUAGE); + if (LogManager.isDebugEnabled()) { + serve.log("acceptLanguage:" + acceptLanguage); + } + + final TreeSet localeWithWeights = new TreeSet(); + if (acceptLanguage != null) { + final StringTokenizer sTokenizer = new StringTokenizer(acceptLanguage, ";", false); + try { + while (sTokenizer.hasMoreTokens()) { + final String languages = sTokenizer.nextToken(";"); + // System.err.println("Langs:"+langs); + String strEqual = sTokenizer.nextToken(";="); + // System.err.println("q:"+q); + strEqual = sTokenizer.nextToken("=,"); + // System.err.println("q:"+q); + float weight = 0; + try { + weight = Float.valueOf(strEqual).floatValue(); + } catch (NumberFormatException ex) { + if (LogManager.isDebugEnabled()) { + serve.log(ex); + } + } + + if (weight > 0) { + final StringTokenizer langTokenizer = new StringTokenizer(languages, ", ", false); + while (langTokenizer.hasMoreTokens()) { + final String lan = langTokenizer.nextToken(); + int dIndex = lan.indexOf('-'); + if (dIndex < 0) { + // 1. 4 + localeWithWeights.add(new LocaleWithWeight(new Locale(lan.trim()), weight)); + } else { + localeWithWeights.add(new LocaleWithWeight(new Locale(lan.substring(0, dIndex), lan.substring(dIndex + 1).trim().toUpperCase()), weight)); + } + } + } + } + } catch (NoSuchElementException ex) { + // can't parse + if (LogManager.isDebugEnabled()) { + serve.log(ex); + } + } + } + + if (localeWithWeights.size() == 0) { + localeWithWeights.add(new LocaleWithWeight(Locale.getDefault(), 1)); + } + + return new AcceptLocaleEnumeration(localeWithWeights); + } + + /** + * Overrides the name of the character encoding used in the body of this + * request. This method must be called prior to reading request + * parameters or reading input using getReader(). + * + * @param a + * - String containing the name of the chararacter encoding. + * @throws java.io.UnsupportedEncodingException + * - if this is not a valid encoding + * @since JSDK 2.3 + */ + public void setCharacterEncoding(String _enc) { + // TODO: check if encoding is valid + // TODO separate encoding came from page and set programatically + charEncoding = _enc; + synchronized (this) { + formParameters = null; + } + } + + public void addDateHeader(String header, long date) { + addHeader(header, headerdateformat.format(new Date(date))); + } + + /** + * Add headers in the request. + * + * @see javax.servlet.http.HttpServletResponse#addHeader(java.lang.String, + * java.lang.String) + */ + public void addHeader(String header, String value) { + header = header.trim().toLowerCase(); + Object object = resHeaderNames.get(header); + if (object == null) { + setHeader(header, value); + } else { + if (object instanceof String[]) { + String[] oldVal = (String[]) object; + String[] newVal = new String[oldVal.length + 1]; + System.arraycopy(oldVal, 0, newVal, 0, oldVal.length); + newVal[oldVal.length] = value; + resHeaderNames.put(header, newVal); + } else if (object instanceof String) { + String[] newVal = new String[2]; + newVal[0] = (String) object; + newVal[1] = value; + resHeaderNames.put(header, newVal); + } else + throw new RuntimeException("Invalid content of header hash - " + object.getClass().getName()); + } + } + + /** + * @see javax.servlet.http.HttpServletResponse#addIntHeader(java.lang.String, + * int) + */ + public void addIntHeader(String header, int value) { + addHeader(header, Integer.toString(value)); + } + + public RequestDispatcher getRequestDispatcher(String urlpath) { + if (urlpath.length() > 0 && urlpath.charAt(0) != '/') { + String dispatchPath = getContextPath(); + String pathInfo = getPathInfo(); + String servletPath = getServletPath(); + ; + if (pathInfo != null) { + dispatchPath += servletPath; + int slp = pathInfo.indexOf('/', 1); + if (slp > 0) // can it ever happen? + dispatchPath += pathInfo.substring(0, slp - 1); + } else { + int spsp = servletPath.lastIndexOf('/'); + if (spsp >= 0) + dispatchPath += servletPath.substring(0, spsp); + } + // serve.log("Dispatch path:"+dispatchPath); + urlpath = dispatchPath + '/' + urlpath; + } + return serve.getRequestDispatcher(urlpath); + } + + /** + * Returns true if the scheme is https otherwise false. + * + * @see javax.servlet.ServletRequest#isSecure() + */ + public boolean isSecure() { + return "https".equals(getScheme()); + } + + /** + * @see javax.servlet.ServletRequest#removeAttribute(java.lang.String) + */ + public void removeAttribute(String name) { + attributes.remove(name); + } + + // only root context supported + public String getContextPath() { + return ""; + } + + public Principal getUserPrincipal() { + return null; + } + + public boolean isUserInRole(String user) { + return false; + } + + /** + * Returns a java.util.Map of the parameters of this request. Request + * parameters are extra information sent with the request. For HTTP + * servlets, parameters are contained in the query string or posted form + * data. + * + * @return an immutable java.util.Map containing parameter names as keys + * and parameter values as map values. The keys in the parameter + * map are of type String. The values in the parameter map are + * of type String array. + * @since 2.3 + */ + public Map getParameterMap() { + assureParametersFromRequest(); + return formParameters; + } + + // Methods from HttpServletResponse. + + // / Adds the specified cookie to the response. It can be called + // multiple times to set more than one cookie. + public void addCookie(Cookie cookie) { + if (outCookies == null) { + outCookies = new Vector(); + } + + outCookies.addElement(cookie); + } + + // / Checks whether the response message header has a field with the + // specified name. + public boolean containsHeader(String name) { + return resHeaderNames.contains(name); + } + + /** + * JSDK 2.1 extension. + * + * @see javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String) + */ + public String encodeURL(String url) { + int uop = url.indexOf(SESSION_URL_NAME); + // TODO not robust enough + if (uop > 0) { + url = url.substring(0, uop); + } + + if (sessionValue == null || isRequestedSessionIdFromCookie()) { + return url; + } + + try { + new URL(url); // for testing syntac + int ehp = url.indexOf('/'); + if (ehp < 0) { + ehp = url.indexOf('?'); + } + if (ehp < 0) { + ehp = url.indexOf('#'); + } + if (ehp < 0) { + ehp = url.length(); + } + if (url.regionMatches(true, 0, getRequestURL().toString(), 0, ehp) == false) { + return url; + } + } catch (MalformedURLException e) { + } + + return url + SESSION_URL_NAME + sessionValue; + } + + public String encodeRedirectURL(String url) { + return encodeURL(url); + } + + /** + * Returns the Internet Protocol (IP) source port of the client or last + * proxy that sent the request. + * + * @return an integer specifying the port number + * + * @since 2.4 + */ + public int getRemotePort() { + // TODO not quite robust + return getServerPort(); + } + + /** + * Returns the host name of the Internet Protocol (IP) interface on + * which the request was received. + * + * @return a String containing the host name of the IP on + * which the request was received. + * + * @since 2.4 + */ + public String getLocalName() { + InetAddress localAddress = socket.getLocalAddress(); + /* 1.4 */ + return (localAddress == null ? null : localAddress.getCanonicalHostName()); + } + + /** + * Returns the Internet Protocol (IP) address of the interface on which + * the request was received. + * + * @return a String containing the IP address on which the + * request was received. + * + * @since 2.4 + * + */ + public String getLocalAddr() { + InetAddress localAddress = socket.getLocalAddress(); + return (localAddress == null ? null : localAddress.getHostAddress()); + } + + /** + * Returns the Internet Protocol (IP) port number of the interface on + * which the request was received. + * + * @return an integer specifying the port number + * + * @since 2.4 + */ + public int getLocalPort() { + return socket.getLocalPort(); + } + + // / Sets the status code and message for this response. + // @param resCode the status code + // @param resMessage the status message + public void setStatus(int resCode, String resMessage) { + // if (((ServeOutputStream) out).isInInclude()) + // return; + this.resCode = resCode; + this.resMessage = resMessage; + } + + // / Sets the status code and a default message for this response. + // @param resCode the status code + public void setStatus(int resCode) { + switch (resCode) { + case SC_CONTINUE: + setStatus(resCode, "Continue"); + break; + case SC_SWITCHING_PROTOCOLS: + setStatus(resCode, "Switching protocols"); + break; + case SC_OK: + setStatus(resCode, "Ok"); + break; + case SC_CREATED: + setStatus(resCode, "Created"); + break; + case SC_ACCEPTED: + setStatus(resCode, "Accepted"); + break; + case SC_NON_AUTHORITATIVE_INFORMATION: + setStatus(resCode, "Non-authoritative"); + break; + case SC_NO_CONTENT: + setStatus(resCode, "No content"); + break; + case SC_RESET_CONTENT: + setStatus(resCode, "Reset content"); + break; + case SC_PARTIAL_CONTENT: + setStatus(resCode, "Partial content"); + break; + case SC_MULTIPLE_CHOICES: + setStatus(resCode, "Multiple choices"); + break; + case SC_MOVED_PERMANENTLY: + setStatus(resCode, "Moved permanentently"); + break; + case SC_MOVED_TEMPORARILY: + setStatus(resCode, "Moved temporarily"); + break; + case SC_SEE_OTHER: + setStatus(resCode, "See other"); + break; + case SC_NOT_MODIFIED: + setStatus(resCode, "Not modified"); + break; + case SC_USE_PROXY: + setStatus(resCode, "Use proxy"); + break; + case SC_BAD_REQUEST: + setStatus(resCode, "Bad request"); + break; + case SC_UNAUTHORIZED: + setStatus(resCode, "Unauthorized"); + break; + case SC_PAYMENT_REQUIRED: + setStatus(resCode, "Payment required"); + break; + case SC_FORBIDDEN: + setStatus(resCode, "Forbidden"); + break; + case SC_NOT_FOUND: + setStatus(resCode, "Not found"); + break; + case SC_METHOD_NOT_ALLOWED: + setStatus(resCode, "Method not allowed"); + break; + case SC_NOT_ACCEPTABLE: + setStatus(resCode, "Not acceptable"); + break; + case SC_PROXY_AUTHENTICATION_REQUIRED: + setStatus(resCode, "Proxy auth required"); + break; + case SC_REQUEST_TIMEOUT: + setStatus(resCode, "Request timeout"); + break; + case SC_CONFLICT: + setStatus(resCode, "Conflict"); + break; + case SC_GONE: + setStatus(resCode, "Gone"); + break; + case SC_LENGTH_REQUIRED: + setStatus(resCode, "Length required"); + break; + case SC_PRECONDITION_FAILED: + setStatus(resCode, "Precondition failed"); + break; + case SC_REQUEST_ENTITY_TOO_LARGE: + setStatus(resCode, "Request entity too large"); + break; + case SC_REQUEST_URI_TOO_LONG: + setStatus(resCode, "Request URI too long"); + break; + case SC_UNSUPPORTED_MEDIA_TYPE: + setStatus(resCode, "Unsupported media type"); + break; + case SC_INTERNAL_SERVER_ERROR: + setStatus(resCode, "Internal server error"); + break; + case SC_NOT_IMPLEMENTED: + setStatus(resCode, "Not implemented"); + break; + case SC_BAD_GATEWAY: + setStatus(resCode, "Bad gateway"); + break; + case SC_SERVICE_UNAVAILABLE: + setStatus(resCode, "Service unavailable"); + break; + case SC_GATEWAY_TIMEOUT: + setStatus(resCode, "Gateway timeout"); + break; + case SC_HTTP_VERSION_NOT_SUPPORTED: + setStatus(resCode, "HTTP version not supported"); + break; + case 207: + setStatus(resCode, "Multi Status"); + break; + default: + setStatus(resCode, ""); + break; + } + } + + // / Sets the value of a header field. + // @param name the header field name + // @param value the header field value + public void setHeader(String header, String value) { + header = header.trim().toLowerCase(); // normilize header + if (value == null) { + resHeaderNames.remove(header); + } else { + resHeaderNames.put(header, value); + // if (header.equals(CONTENTTYPE)) { + // String enc = extractEncodingFromContentType(value); + // if (enc != null) + // setCharacterEncoding(enc); + // } + } + } + + // / Sets the value of an integer header field. + // @param name the header field name + // @param value the header field integer value + public void setIntHeader(String header, int value) { + setHeader(header, Integer.toString(value)); + } + + // / Sets the value of a long header field. + // @param name the header field name + // @param value the header field long value + public void setLongHeader(String header, long value) { + setHeader(header, Long.toString(value)); + } + + // / Sets the value of a date header field. + // @param name the header field name + // @param value the header field date value + public void setDateHeader(String header, long value) { + setHeader(header, headerdateformat.format(new Date(value))); + } + + // / Writes the status line and message headers for this response to the + // output stream. + // @exception IOException if an I/O error has occurred + void writeHeaders() throws IOException { + synchronized (this) { + // TODO: possible to write trailer when chunked out, + // so chunked out should be global flag + if (headersWritten) + return; + // new Exception("headers").printStackTrace(); + headersWritten = true; + } + + if (reqMime) { + boolean chunked_out = false; + long contentLen = -1; + if (resMessage.length() < 256) { + outputStream.println(reqProtocol + " " + resCode + " " + resMessage.replace('\r', '/').replace('\n', '/')); + } else { + outputStream.println(reqProtocol + " " + resCode + " " + resMessage.substring(0, 255).replace('\r', '/').replace('\n', '/')); + } + + final Enumeration headerNames = resHeaderNames.keys(); + while (headerNames.hasMoreElements()) { + final String name = headerNames.nextElement(); + // skip header until make decision + if (CONNECTION.equals(name) || KEEPALIVE.equals(name)) { + continue; + } + + final Object headerValue = resHeaderNames.get(name); + if (headerValue instanceof String) { + String value = (String) headerValue; + if (value != null) {// just in case + if (CONTENTTYPE.equals(name)) { + if (charEncoding != null && value.startsWith("text/")) { + int p = value.indexOf(';'); + if (p > 0) { + value = value.substring(0, p); + } + value += "; charset=" + charEncoding; + } + + // TODO check locale and can take from it as + // well based on mapping locale charset + } + // some overhead can be here for checking every + // header, so possibly do checks after loop + if (CONTENTLENGTH.equals(name)) { + if (contentLen < 0) + try { + contentLen = Long.parseLong(value); + } catch (NumberFormatException nfe) { + } + } else + outputStream.println(name + ": " + value); + if (chunked_out == false) { + if (TRANSFERENCODING.equals(name) && CHUNKED.equals(value)) { + chunked_out = true; + } + } + } + } else if (headerValue instanceof String[]) { + String[] values = (String[]) headerValue; + if ("set-cookie".equals(name)) { + for (int i = 0; i < values.length; i++) { + outputStream.print(name); + outputStream.print(": "); + outputStream.println(values[i]); + } + } else { + outputStream.print(name + ": " + values[0]); + for (int i = 1; i < values.length; i++) { + outputStream.print("," + values[i]); + } + outputStream.println(); + } + } + } + + StringBuffer setCookieBuilder = null; + StringBuffer cookieBuilderVersion1 = null; + Cookie cookie = null; + // add session cookie + if (sessionValue != null) { + HttpSession session = serve.getSession(sessionValue); + if (session != null) { + if (((AcmeSession) session).isValid()) { + if (session.isNew()) { + cookie = new AcmeCookie(SESSION_COOKIE_NAME, sessionValue); + if (serve.expiredIn < 0) { + cookie.setMaxAge(Math.abs(serve.expiredIn) * 60); + } + + ((AcmeCookie) cookie).setHttpOnly(serve.httpSessCookie); + if (serve.secureSessCookie) { + ((AcmeCookie) cookie).setSecure(true); + } + + ServletContext sc = ((AcmeSession) session).getServletContext(); + try { + String cp = (String) sc.getClass().getMethod("getContextPath", Utils.EMPTY_CLASSES).invoke(sc, Utils.EMPTY_OBJECTS); + if (cp.length() == 0) { + cp = "/"; + } + cookie.setPath(cp); + } catch (Exception e) { + + } + addCookie(cookie); + } + } else { + cookie = new AcmeCookie(SESSION_COOKIE_NAME, ""); + cookie.setMaxAge(0); + ((AcmeCookie) cookie).setHttpOnly(serve.httpSessCookie); + addCookie(cookie); + } + } + } + + // how to remove a cookie + // cc = new Cookie(cookieName, ""); + // cc.setMaxAge(0); + // + for (int i = 0; outCookies != null && i < outCookies.size(); i++) { + cookie = (Cookie) outCookies.elementAt(i); + if (cookie.getSecure() && isSecure() == false) { + continue; + } + + int version = cookie.getVersion(); + boolean httpOnly = false; + try { + httpOnly = Boolean.TRUE.equals(cookie.getClass().getMethod("isHttpOnly", Utils.EMPTY_CLASSES).invoke(cookie, Utils.EMPTY_OBJECTS)); + } catch (Exception ex) { + // ignore me! + } + + String token; + if (version > 1) { + if (cookieBuilderVersion1 == null) { + cookieBuilderVersion1 = new StringBuffer(SETCOOKIE + "2: "); + } else { + cookieBuilderVersion1.append(','); + } + cookieBuilderVersion1.append(cookie.getName()); + cookieBuilderVersion1.append("=\""); + cookieBuilderVersion1.append(cookie.getValue()).append('"'); + token = cookie.getComment(); + if (token != null) { + cookieBuilderVersion1.append("; Comment=\"").append(token).append('"'); + } + token = cookie.getDomain(); + if (token != null) { + cookieBuilderVersion1.append("; Domain=\"").append(token).append('"'); + } + if (cookie.getMaxAge() >= 0) { + cookieBuilderVersion1.append("; Max-Age=\"").append(cookie.getMaxAge()).append('"'); + } + token = cookie.getPath(); + if (token != null) { + cookieBuilderVersion1.append("; Path=\"").append(token).append('"'); + } + if (cookie.getSecure()) { + cookieBuilderVersion1.append("; Secure"); + } + if (httpOnly) { + cookieBuilderVersion1.append("; HttpOnly"); + } + cookieBuilderVersion1.append("; Version=\"").append(version).append('"'); + } else { + if (setCookieBuilder == null) { + setCookieBuilder = new StringBuffer(SETCOOKIE + ": "); + } else { + // for IE not + setCookieBuilder.append("\r\n" + SETCOOKIE + ": "); + } + setCookieBuilder.append(cookie.getName()); + setCookieBuilder.append('='); + setCookieBuilder.append(cookie.getValue());// .append('"'); + if (!IOHelper.isNullOrEmpty(cookie.getDomain())) { + setCookieBuilder.append("; domain=" + cookie.getDomain()); + } + if (cookie.getMaxAge() >= 0) { + setCookieBuilder.append("; expires="); + setCookieBuilder.append(expdatefmt.format(new Date(new Date().getTime() + 1000l * cookie.getMaxAge()))); + } + + if (!IOHelper.isNullOrEmpty(cookie.getPath())) { + setCookieBuilder.append("; path=" + cookie.getPath()); + } + if (cookie.getSecure()) { + setCookieBuilder.append("; secure"); + } + + if (httpOnly) { + setCookieBuilder.append("; HttpOnly"); + } + } + } + if (setCookieBuilder != null) { + outputStream.println(setCookieBuilder.toString()); + // System.err.println("We sent cookies: " + sb); + } + + if (cookieBuilderVersion1 != null) { + outputStream.println(cookieBuilderVersion1.toString()); + // System.err.println("We sent cookies 2: " + sb2); + } + + if (!webSocketUpgrade) + // setHeader(KEEPALIVE, "timeout=30000"); + if (chunked_out == false) { + if (contentLen < 0) + if (serve.isKeepAlive() && oneOne) { + if ((resCode != SC_NO_CONTENT && !"HEAD".equals(reqMethod)) || resCode != SC_NOT_MODIFIED) { + outputStream.println(TRANSFERENCODING + ": " + CHUNKED); + chunked_out = true; + } + } else { + keepAlive = false; + setHeader(CONNECTION, "close"); + setHeader(KEEPALIVE, null); + } + else { + outputStream.print(CONTENTLENGTH); + outputStream.print(": "); + outputStream.println(String.valueOf(contentLen)); + } + } + // process keep alive headers + Object object = resHeaderNames.get(CONNECTION); + if (object instanceof String) { + outputStream.println(CONNECTION + ": " + object); + } + object = resHeaderNames.get(KEEPALIVE); + if (object instanceof String) { + outputStream.println(KEEPALIVE + ": " + object); + } + outputStream.println(); + outputStream.flush(); + if (resCode == SC_NO_CONTENT || resCode == SC_NOT_MODIFIED || "HEAD".equals(reqMethod)) { + outputStream.close(); + } else { + ((ServeOutputStream) outputStream).setChunked(chunked_out); + } + } + } + + // / Writes an error response using the specified status code and + // message. + // @param resCode the status code + // @param resMessage the status message + // @exception IOException if an I/O error has occurred + public void sendError(int resCode, String resMessage) throws IOException { + setStatus(resCode, resMessage); + realSendError(); + } + + // / Writes an error response using the specified status code and a + // default + // message. + // @param resCode the status code + // @exception IOException if an I/O error has occurred + public void sendError(int resCode) throws IOException { + setStatus(resCode); + realSendError(); + } + + private void realSendError() throws IOException { + if (isCommitted()) + throw new IllegalStateException("Can not send an error (" + resCode + ") - " + resMessage + ", headers have been already written"); + // if (((ServeOutputStream) out).isInInclude()) // ignore + // return; + setContentType("text/html"); + StringBuffer sb = new StringBuffer(100); + int lsp = resMessage.indexOf('\n'); + sb.append("").append("" + resCode + " " + (lsp < 0 ? resMessage : resMessage.substring(0, lsp)) + "").append("

" + resCode + " " + (lsp < 0 ? resMessage : resMessage.substring(0, lsp)) + "

"); + if (lsp > 0) + sb.append("
").append(Utils.htmlEncode(resMessage.substring(lsp), false)).append("
"); + sb.append("
"); + sendEnd(sb); + } + + // / Sends a redirect message to the client using the specified redirect + // location URL. + // @param location the redirect location URL + // @exception IOException if an I/O error has occurred + public void sendRedirect(String location) throws IOException { + if (isCommitted()) + throw new IllegalStateException("Can not redirect, headers have been already written"); + if (location.indexOf(":/") < 0) { // relative + String portString = ""; + if ("https".equalsIgnoreCase(getScheme())) { + if (getServerPort() != 443) + portString = ":" + getServerPort(); + } else if (getServerPort() != 80) + portString = ":" + getServerPort(); + + if (location.length() > 0 && location.charAt(0) == '/') { + location = getScheme() + "://" + getServerName() + portString + location; + } else { + int sp = reqUriPathUn.lastIndexOf('/'); + String uri; + if (sp < 0) { + uri = reqUriPathUn + '/'; + sp = uri.length(); + } else { + uri = reqUriPathUn; + sp++; + } + location = getScheme() + "://" + getServerName() + portString + uri.substring(0, sp) + location; + } + } + // serve.log("location:"+location); + setHeader("Location", location); + setStatus(SC_MOVED_TEMPORARILY); + setContentType("text/html"); + StringBuffer sb = new StringBuffer(200); + sb.append("" + "" + SC_MOVED_TEMPORARILY + " Moved" + "

" + SC_MOVED_TEMPORARILY + " Moved

" + "This document has moved here.
"); + sendEnd(sb); + } + + private void sendEnd(StringBuffer sendContent) throws IOException { + sendContent.append(Identification.serverIdHtml); + sendContent.append(""); + setContentLength(sendContent.length()); + // to avoid further out + if (!oneOne) { + keepAlive = false; + setHeader(CONNECTION, "close"); + setHeader(KEEPALIVE, null); + } + outputStream.print(sendContent.toString()); + outputStream.close(); + } + + // URL rewriting + // http://www.myserver.com/catalog/index.html;jsessionid=mysession1928 + // like: + // http://www.sun.com/2001-0227/sunblade/;$sessionid$AD5RQ0IAADJAZAMTA1LU5YQ + + // / Encodes the specified URL by including the session ID in it, or, if + // encoding is not needed, returns the URL unchanged. The + // implementation of this method should include the logic to determine + // whether the session ID needs to be encoded in the URL. For example, + // if the browser supports cookies, or session tracking is turned off, + // URL encoding is unnecessary. + //

+ // All URLs emitted by a Servlet should be run through this method. + // Otherwise, URL rewriting cannot be used with browsers which do not + // support cookies. + // @deprecated + public String encodeUrl(String url) { + return encodeURL(url); + } + + // / Encodes the specified URL for use in the sendRedirect method or, if + // encoding is not needed, returns the URL unchanged. The + // implementation of this method should include the logic to determine + // whether the session ID needs to be encoded in the URL. Because the + // rules for making this determination differ from those used to + // decide whether to encode a normal link, this method is seperate + // from the encodeUrl method. + //

+ // All URLs sent to the sendRedirect method should + // be + // run through this method. Otherwise, URL rewriting cannot be used with + // browsers which do not support cookies. + public String encodeRedirectUrl(String url) { + return encodeRedirectURL(url); + } + + public Socket getSocket() { + // TODO apply security check + return socket; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.ServletRequest#getAsyncContext() + */ + @Override + public AsyncContext getAsyncContext() { + // TODO Auto-generated method stub + return null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.ServletRequest#getDispatcherType() + */ + @Override + public DispatcherType getDispatcherType() { + return null; + } + + /** + * @see javax.servlet.ServletRequest#getServletContext() + */ + @Override + public ServletContext getServletContext() { + return null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.ServletRequest#isAsyncStarted() + */ + @Override + public boolean isAsyncStarted() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see javax.servlet.ServletRequest#isAsyncSupported() + */ + @Override + public boolean isAsyncSupported() { + return false; + } + + /** + * @see javax.servlet.ServletRequest#startAsync() + */ + @Override + public AsyncContext startAsync() throws IllegalStateException { + return null; + } + + /** + * @see javax.servlet.ServletRequest#startAsync(javax.servlet.ServletRequest, + * javax.servlet.ServletResponse) + */ + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { + return null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServletResponse#getStatus() + */ + public int getStatus() { + return 0; + } + + /** + * Returns the request header names. + * Note: If it does not work, return null here. + * + * @see javax.servlet.http.HttpServletRequest#getHeaderNames() + */ + @Override + public Enumeration getHeaderNames() { +// return this.getRequestHeaderNames(); + return null; + } + + /** + * Returns the request headers for the given header. + * Note: If it does not work, return null here. + * + * @see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String) + */ + @Override + public Enumeration getHeaders(String header) { + return getRequestHeaders(header); + } + } + + public static class BasicAuthRealm extends Hashtable { + private String name; + + public BasicAuthRealm(String name) { + this.name = name; + } + + String name() { + return name; + } + } + + public static class ServeInputStream extends ServletInputStream { + private final static boolean STREAM_DEBUG = false; + + /** + * The actual input stream (buffered). + */ + private InputStream inStream, origInStream; + private ServeConnection serveConnection; + private int chunksize = 0; + private boolean chunking = false, compressed; + private boolean returnedAsReader, returnedAsStream; + private long contentLength = -1; + private long readCount; + private byte[] oneReadBuffer = new byte[1]; + private boolean closed; + + /* ------------------------------------------------------------ */ + /** + * Constructor + */ + public ServeInputStream(InputStream inStream, final ServeConnection serveConnection) { + this.serveConnection = serveConnection; + this.inStream = inStream; + } + + void refresh() { + returnedAsReader = false; + returnedAsStream = false; + contentLength = -1; + readCount = 0; + chunksize = 0; + closed = false; + compressed(false); + } + + /* ------------------------------------------------------------ */ + /** + * @param chunking + */ + public void chunking(boolean chunking) { + if (contentLength == -1) { + this.chunking = chunking; + } + } + + boolean compressed(boolean on) { + if (on) { + if (compressed == false) { + origInStream = inStream; + try { + ServeInputStream serveInputStream = new ServeInputStream(inStream, serveConnection); + if (chunking) { + serveInputStream.chunking(true); + chunking(false); + } + inStream = (InputStream) serveConnection.serve.gzipInStreamConstr.newInstance(new Object[] { serveInputStream }); + compressed = true; + // conn.serve.log("Compressed stream was created with + // success", + // null); + } catch (Exception ex) { + if (ex instanceof InvocationTargetException) { + serveConnection.serve.log("TJWS: Problem in compressed stream creation", ((InvocationTargetException) ex).getTargetException()); + } else { + serveConnection.serve.log("TJWS: Problem in compressed stream obtaining", ex); + } + } + } + } else if (compressed) { + compressed = false; + inStream = origInStream; + } + + return compressed; + } + + /** + * sets max read byte in input + */ + void setContentLength(long contentLength) { + if (this.contentLength == -1 && contentLength >= 0 && chunking == false) { + // if (STREAM_DEBUG) { + // new Exception("Set content + // length:"+contentLength).printStackTrace(); + // } + this.contentLength = contentLength; + readCount = 0; + } + + // else if (STREAM_DEBUG || true) { + // new Exception("Igonore Set content length:"+contentLength+" + // for "+this.contentLength).printStackTrace(); + // } + } + + /* ------------------------------------------------------------ */ + /** + * Read a line ended by CRLF, used internally only for reading headers. + * No char encoding, ASCII only + */ + protected String readLine(int maxLen) throws IOException { + if (maxLen <= 0) { + throw new IllegalArgumentException("Max len:" + maxLen); + } + + final StringBuffer lineBuffer = new StringBuffer(Math.min(8192, maxLen)); + + int c; + boolean newLine = false; + int i = 0; + while ((c = inStream.read()) != -1) { + if (c == 10) { // LF + if (newLine) { + break; + } + break; + // throw new IOException ("LF without CR"); + } else if (c == 13) { // CR + newLine = true; + } else { + // if (cr) throw new IOException ("CR without LF"); + // see + // http://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/draft-lafon-rfc2616bis-03.html#tolerant.applications + newLine = false; + if (i >= maxLen) { + throw new IOException("Line lenght exceeds " + maxLen); + } + + lineBuffer.append((char) c); + i++; + } + } + + if (STREAM_DEBUG) { + System.err.println(lineBuffer); + } + + if (c == -1 && lineBuffer.length() == 0) { + return null; + } + + return lineBuffer.toString(); + } + + /** + * Reads the stream bytes. + * + * @see java.io.InputStream#read() + */ + public int read() throws IOException { + int result = read(oneReadBuffer, 0, 1); + if (result == 1) { + return 255 & oneReadBuffer[0]; + } + + return -1; + } + + /** + * Reads the stream bytes. + * + * @see java.io.InputStream#read(byte[]) + */ + public int read(byte b[]) throws IOException { + return read(b, 0, b.length); + } + + /** + * Reads the stream bytes. + * + * @see java.io.InputStream#read(byte[], int, int) + */ + public synchronized int read(byte[] dataBytes, int offset, int length) throws IOException { + if (closed) { + throw new IOException("The stream is already closed"); + } + + if (chunking) { + if (chunksize <= 0 && getChunkSize() <= 0) { + return -1; + } + if (length > chunksize) { + length = chunksize; + } + length = inStream.read(dataBytes, offset, length); + chunksize = (length < 0) ? -1 : (chunksize - length); + } else { + if (contentLength >= 0) { + if (readCount >= contentLength) { + if (STREAM_DEBUG) { + System.err.print("EOF at " + contentLength); + } + return -1; + } + + if (contentLength - length < readCount) { + length = (int) (contentLength - readCount); + } + + length = inStream.read(dataBytes, offset, length); + if (length > 0) { + readCount += length; + } + } else { + // to avoid extra if + length = inStream.read(dataBytes, offset, length); + } + } + + if (STREAM_DEBUG && length > 0) { + System.err.print(new String(dataBytes, offset, length)); + } + + return length; + } + + /* ------------------------------------------------------------ */ + public long skip(long length) throws IOException { + if (STREAM_DEBUG) { + System.err.println("instream.skip() :" + length); + } + if (closed) { + throw new IOException("The stream is already closed"); + } + + if (chunking) { + if (chunksize <= 0 && getChunkSize() <= 0) { + return -1; + } + + if (length > chunksize) { + length = chunksize; + } + length = inStream.skip(length); + chunksize = (length < 0) ? -1 : (chunksize - (int) length); + } else { + if (contentLength >= 0) { + length = Math.min(length, contentLength - readCount); + if (length <= 0) { + return -1; + } + length = inStream.skip(length); + readCount += length; + } else { + length = inStream.skip(length); + } + } + + return length; + } + + /* ------------------------------------------------------------ */ + /** + * Available bytes to read without blocking. If you are unlucky may + * return 0 when there are more + */ + public int available() throws IOException { + if (STREAM_DEBUG) { + System.err.println("instream.available()"); + } + + if (closed) { + // throw new IOException("The stream is already closed"); + return 0; + } + + if (chunking) { + int len = inStream.available(); + if (len <= chunksize) { + return len; + } + return chunksize; + } + + if (contentLength >= 0) { + int len = inStream.available(); + if (contentLength - readCount < Integer.MAX_VALUE) { + return Math.min(len, (int) (contentLength - readCount)); + } + + return len; + } else { + return inStream.available(); + } + } + + /* ------------------------------------------------------------ */ + public void close() throws IOException { + // keep alive, will be closed by socket + // in.close(); + if (STREAM_DEBUG) { + System.err.println("instream.close() " + closed); + } + // new Exception("instream.close()").printStackTrace(); + if (closed) { + return; + } + // throw new + // IOException("The stream is already closed"); + // read until end of chunks or content length + if (chunking) { + while (read() >= 0) { + ; + } + } else if (contentLength < 0) { + ; + } else { + long skipCount = contentLength - readCount; + while (skipCount > 0) { + long skipped = skip(skipCount); + if (skipped <= 0) { + break; + } + skipCount -= skipped; + } + } + + if (serveConnection.keepAlive == false) { + inStream.close(); + } + closed = true; + } + + /* ------------------------------------------------------------ */ + /** + * Mark is not supported + * + * @return false + */ + public boolean markSupported() { + return false; + } + + /* ------------------------------------------------------------ */ + /** + * + */ + public void reset() throws IOException { + // no buffering, so not possible + if (closed) { + throw new IOException("The stream is already closed"); + } + if (STREAM_DEBUG) { + System.err.println("instream.reset()"); + } + inStream.reset(); + } + + /* ------------------------------------------------------------ */ + /** + * Not Implemented + * + * @param readlimit + */ + public void mark(int readlimit) { + // not supported + if (STREAM_DEBUG) + System.err.println("instream.mark(" + readlimit + ")"); + } + + /* ------------------------------------------------------------ */ + private int getChunkSize() throws IOException { + if (chunksize < 0) + return -1; + + chunksize = -1; + + // Get next non blank line + chunking = false; + String line = readLine(60); + while (line != null && line.length() == 0) + line = readLine(60); + chunking = true; + + // Handle early EOF or error in format + if (line == null) + return -1; + + // Get chunksize + int i = line.indexOf(';'); + if (i > 0) + line = line.substring(0, i).trim(); + try { + chunksize = Integer.parseInt(line, 16); + } catch (NumberFormatException nfe) { + throw new IOException("Chunked stream is broken, " + line); + } + + // check for EOF + if (chunksize == 0) { + chunksize = -1; + // Look for footers + readLine(60); + chunking = false; + } + return chunksize; + } + + boolean isReturnedAsStream() { + return returnedAsStream; + } + + void setReturnedAsStream(boolean _on) { + returnedAsStream = _on; + } + + boolean isReturnedAsReader() { + return returnedAsReader; + } + + void setReturnedAsReader(boolean _on) { + returnedAsReader = _on; + } + } + + public static class ServeOutputStream extends ServletOutputStream { + + private static final boolean STREAM_DEBUG = false; + private boolean chunked; + private boolean closed; + + // TODO: predefine as static byte[] used by chunked + // underneath stream + private OutputStream outputStream; + // private BufferedWriter writer; // for top speed + private ServeConnection serveConnection; + private int inInclude; + private String encoding; + private long longBytes; + private Utils.SimpleBuffer buffer; + + public ServeOutputStream(final OutputStream outputStream, ServeConnection serveConnection) { + this.outputStream = outputStream; + this.serveConnection = serveConnection; + buffer = new Utils.SimpleBuffer(); + encoding = serveConnection.getCharacterEncoding(); + if (encoding == null) { + encoding = IOHelper.ISO_8859_1; + } + } + + /* + * void refresh() { chunked = false; closed = false; inInclude = 0; + * lbytes = 0; buffer.reset(); encoding = conn.getCharacterEncoding(); + * if (encoding == null) encoding = Utils.ISO_8859_1; } + */ + + protected void reset() { + if (longBytes == 0) { + buffer.reset(); + } else { + throw new IllegalStateException("Result was already committed"); + } + } + + protected int getBufferSize() { + return buffer.getSize(); + } + + protected void setBufferSize(int size) { + if (longBytes > 0) { + throw new IllegalStateException("Bytes already written in response"); + } + buffer.setSize(size); + } + + protected void setChunked(boolean set) { + chunked = set; + } + + public void print(String s) throws IOException { + write(s.getBytes(encoding)); + } + + public void write(int b) throws IOException { + write(new byte[] { (byte) b }, 0, 1); + } + + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + /** + * + * @param dataBytes + * @param off + * @param len + * @throws IOException + * @see java.io.OutputStream#write(byte[], int, int) + */ + public void write(byte[] dataBytes, int off, int len) throws IOException { + if (closed) { + if (STREAM_DEBUG) { + System.err.println((dataBytes == null ? "null" : new String(dataBytes, off, len)) + "\n won't be written, stream closed."); + } + throw new IOException("An attempt of writing " + len + " bytes to a closed out."); + } + + if (len == 0) { + return; + } + + // write connection headers. + serveConnection.writeHeaders(); + dataBytes = buffer.put(dataBytes, off, len); + len = dataBytes.length; + if (len == 0) { + return; + } + + off = 0; + if (chunked) { + String hexl = Integer.toHexString(len); + // no encoding Ok + outputStream.write((hexl + "\r\n").getBytes()); + longBytes += 2 + hexl.length(); + outputStream.write(dataBytes, off, len); + longBytes += len; + outputStream.write("\r\n".getBytes()); + longBytes += 2; + } else { + outputStream.write(dataBytes, off, len); + longBytes += len; + } + + if (STREAM_DEBUG) { + if (chunked) { + System.err.println(Integer.toHexString(len)); + } + System.err.print(new String(dataBytes, off, len)); + if (chunked) { + System.err.println(); + } + } + } + + public void flush() throws IOException { + // boolean cl = closed; + if (closed) { + return; + } + + // throw new IOException("An attempt of flushig closed out."); + serveConnection.writeHeaders(); + if (closed) { + return; + } + + byte[] b = buffer.get(); + if (b.length > 0) { + if (chunked) { + String hexl = Integer.toHexString(b.length); + // no encoding Ok + outputStream.write((hexl + "\r\n").getBytes()); + longBytes += 2 + hexl.length(); + outputStream.write(b); + longBytes += b.length; + outputStream.write("\r\n".getBytes()); + longBytes += 2; + if (STREAM_DEBUG) { + System.err.println(hexl); + System.err.print(new String(b)); + System.err.println(); + } + } else { + outputStream.write(b); + longBytes += b.length; + if (STREAM_DEBUG) { + System.err.print(new String(b)); + } + } + } + + // System.err.println("Was "+cl+" now "+closed); + outputStream.flush(); + } + + public void close() throws IOException { + if (closed) { + return; + } + + // throw new IOException("Stream is already closed."); + // new IOException("Stream closing").printStackTrace(); + try { + flush(); + if (inInclude == 0) { + if (chunked) { + outputStream.write("0\r\n\r\n".getBytes()); + longBytes += 5; + if (STREAM_DEBUG) { + System.err.print("0\r\n\r\n"); + } + + // TODO: here is possible to write trailer headers + outputStream.flush(); + } + + if (serveConnection.keepAlive == false) { + outputStream.close(); + } else { + outputStream = null; + // the stream has to be recreated after closing + serveConnection = null; + } + } + } finally { + closed = true; + } + } + + private long lengthWritten() { + return longBytes; + } + + boolean isInInclude() { + return inInclude == 0; + } + + void setInInclude(boolean _set) { + inInclude = _set ? 1 : 0; + /* + * if (_set) inInclude++; else inInclude--; if (inInclude < 0) throw + * new IllegalStateException("Not matching include set"); + */ + } + } + + /** + * Class PathTreeDictionary - this class allows to put path elements in + * format n1/n2/n2[/*.ext] and get match to a pattern and a unmatched tail + */ + public static class PathTreeDictionary { + Node rootNode; + Node ext; + Object ctx; + + public PathTreeDictionary() { + rootNode = new Node(); + } + + /** + * Manages a tree of web path entries with the following cases + *

    + *
  • /path1/path2... - exact match entry + *
  • anything ending by /* + *
  • *.ext - extension entry applied only for last part + *
  • - empty entry context root servicing only /contextpath/ + *
  • / - default servlet when nothing else is matching + *
+ * + * @param path + * @param value + */ + public synchronized Object[] put(String path, Object value) { + // TODO make returning Object[] for cconsitency + if (path.length() == 0) { // context + if (ctx == null) { + ctx = new Node(); + } + + Object result = ctx; + ctx = value; + return new Object[] { result, INT_ZERO }; + } + if (path.charAt(0) == '*') { + String ext_str = null; + if (path.length() > 2 && path.charAt(1) == '.') { + ext_str = path.substring(1); + } else { + throw new IllegalArgumentException("No extension specified for * starting pattern:" + path); + } + + if (ext == null) { + ext = new Node(); + } + return new Object[] { ext.put(ext_str, value), INT_ZERO }; + } + // System.out.println("==>PUT path : "+path); + StringTokenizer st = new StringTokenizer(path, "\\/"); + Node curNode = rootNode; + while (st.hasMoreTokens()) { + String nodename = st.nextToken(); + // System.out.println("PUT curr node : "+nodename); + int wci = nodename.indexOf('*'); + if (wci == 0) { + if (nodename.length() > 1 || st.hasMoreTokens()) { + throw new IllegalArgumentException("Using * in other than ending /* for path:" + path); + } + + nodename = ""; + } else if (wci > 0) { + throw new IllegalArgumentException("Using * in other than ending /* for path:" + path); + } + + Node node = (Node) curNode.get(nodename); + if (node == null) { + node = new Node(); + curNode.put(nodename, node); + } + curNode = node; + } + + Object result = curNode.object; + curNode.object = value; + return new Object[] { result, INT_ZERO }; + } + + /** + * + * @param value + * @return + */ + public synchronized Object[] remove(Object value) { + Object[] result = remove(rootNode, value); + if (result[0] == null) { + result = remove(null, value); + } + if (result[0] == null) { + return remove(ext, value); + } + + return result; + } + + /** + * + * @param path + * @return + */ + public synchronized Object[] remove(String path) { + Object[] result = get(path); + if (result[0] != null) { + return remove(result[0]); + } + + return result; + } + + /** + * + * @param node + * @param value + * @return + */ + public Object[] remove(Node node, Object value) { + // TODO make full path, not only last element + if (node == null) { + if (ctx == value) { + ctx = null; + return new Object[] { value, new Integer(0) }; + } + return new Object[] { null, null }; + } + + if (node == ext) { + // TODO potential bug since look for first entry + Enumeration e = ext.keys(); + while (e.hasMoreElements()) { + Object key = e.nextElement(); + if (ext.get(key) == value) { + return new Object[] { ext.remove(key), new Integer(0) }; + } + } + return new Object[] { null, null }; + } + + if (node.object == value) { + node.object = null; + return new Object[] { value, new Integer(0) }; + } + Enumeration e = node.keys(); + while (e.hasMoreElements()) { + Object[] result = remove((Node) node.get((String) e.nextElement()), value); + if (result[0] != null) { + return result; + } + } + return new Object[] { null, null }; + } + + /** + * This function looks up in the directory to find the perfect match and + * remove matching part from path, so if you need to keep original path, + * save it somewhere + */ + public Object[] get(String path) { + // System.out.println("==>GET " + path); + // new Exception("GET " + path).printStackTrace(); + Object[] result = new Object[2]; + if (path == null) + return result; + if ((path.length() == 0 || path.equals("/")) && ctx != null) { + result[0] = ctx; + result[1] = INT_ZERO; + return result; + } + char[] ps = path.toCharArray(); + Node curNode = rootNode; // default servlet + int p0 = 0, lm = 0; // last match + + boolean div_state = true; + for (int i = 0; i < ps.length; i++) { + // System.out.println("GET "+ps[i]); + if (ps[i] == '/' || ps[i] == '\\') { // next divider + if (div_state) { + continue; + } + Node node = (Node) curNode.get(new String(ps, p0, i - p0)); + // System.out.println("GET Node " + node + " for " + new + // String(ps, p0, i - p0)); + + if (node == null) { // exact + node = (Node) curNode.get(""); // for * + if (node != null && node.object != null) { + result[0] = node.object; + // System.out.println("GET * for " + node); + } + break; + } + curNode = node; + div_state = true; + p0 = i + 1; + } else { + if (div_state) { + p0 = i; + div_state = false; + } + } + } + + String last_part = new String(ps, p0, ps.length - p0); + Node lastNode = (Node) curNode.get(last_part); + // System.out.println("GET cur node : " + last_node + " for: " + + // last_part + " root ext:" + ext+" and pos:"+p0); + if (lastNode != null) { + if (lastNode.object == null) { + lastNode = (Node) lastNode.get(""); // check for * + } + if (lastNode != null && lastNode.object != null) { + result[0] = lastNode.object; + lm = last_part.length() > 0 ? ps.length : p0 - 1; + } + } else { + lastNode = (Node) curNode.get(""); + if (lastNode != null && lastNode.object != null) { + result[0] = lastNode.object; + lm = p0 > 0 ? p0 - 1 : 0; + } + } + + // try ext + if (result[0] == null) { + lm = ps.length; + if (ext != null) { + int ldi = last_part.lastIndexOf('.'); + if (ldi > 0) { // ignoring cases /.extension + result[0] = ext.get(last_part.substring(ldi)); + // System.out.println("GET ext node: " + + // last_part.substring(ldi)); + } + } + if (result[0] == null) { // look for default servlet + lastNode = (Node) rootNode.get(""); + if (lastNode != null) + result[0] = lastNode.object; + if (result[0] == null) { + result[0] = rootNode.object; + } + } + } + // System.out.println("GET pos: "+lm); + result[1] = new Integer(lm); + return result; + } + + public Enumeration keys() { + Vector result = new Vector(); + if (ctx != null) { + result.addElement(""); + } + if (rootNode.object != null) { + result.addElement("/"); + } + addSiblingNames(rootNode, result, ""); + if (ext != null) { + Enumeration itr = ext.keys(); + while (itr.hasMoreElements()) { + result.addElement("*" + itr.nextElement()); + } + } + + return result.elements(); + } + + /** + * + * @param node + * @param result + * @param path + */ + public void addSiblingNames(Node node, Vector result, String path) { + Enumeration itr = node.keys(); + while (itr.hasMoreElements()) { + String pc = (String) itr.nextElement(); + Node childNode = (Node) node.get(pc); + pc = path + '/' + (pc.length() == 0 ? "*" : pc); + if (childNode.object != null) { + result.addElement(pc); + } + + addSiblingNames(childNode, result, pc); + } + } + + public Enumeration elements() { + Vector result = new Vector(); + if (rootNode.object != null) { + result.add(rootNode.object); + } + + addSiblingObjects(rootNode, result); + return result.elements(); + } + + /** + * + * @param node + * @param result + */ + public void addSiblingObjects(Node node, Vector result) { + Enumeration itr = node.keys(); + while (itr.hasMoreElements()) { + Node childNode = (Node) node.get(itr.nextElement()); + if (childNode.object != null) { + result.addElement(childNode.object); + } + addSiblingObjects(childNode, result); + } + } + + class Node extends Hashtable { + Object object; + String name; + } + } + + /** + * Http session support + * + * TODO: provide lazy session restoring, it should allow to load classes + * from wars 1st step it read serialization data and store under session + * attribute 2nd when the session requested, it tries to deserialize all + * session attributes considered that all classes available + */ + public static class AcmeSession extends Hashtable implements HttpSession { + private long createTime; + private long lastAccessTime; + private String id; + private int inactiveInterval; // in seconds + private boolean expired; + private transient ServletContext servletContext; + private transient HttpSessionContext sessionContext; + private transient List listeners; + + /** + * TODO: check in documentation what is default inactive interval and + * what means 0 and what is mesurement unit + * + * @param id + * @param servletContext + * @param sessionContext + */ + AcmeSession(String id, ServletContext servletContext, HttpSessionContext sessionContext) { + this(id, 0, servletContext, sessionContext); + } + + /** + * + * @param id + * @param inactiveInterval + * @param servletContext + * @param sessionContext + */ + AcmeSession(String id, int inactiveInterval, ServletContext servletContext, HttpSessionContext sessionContext) { + // new + // Exception("Session created with: + // "+servletContext).printStackTrace(); + // //!!! + createTime = System.currentTimeMillis(); + this.id = id; + this.inactiveInterval = inactiveInterval; + this.servletContext = servletContext; + this.sessionContext = sessionContext; + } + + public long getCreationTime() { + return createTime; + } + + public String getId() { + return id; + } + + public long getLastAccessedTime() { + return lastAccessTime; + } + + public void setMaxInactiveInterval(int interval) { + inactiveInterval = interval; + } + + public int getMaxInactiveInterval() { + return inactiveInterval; + } + + /** + * @deprecated + */ + public HttpSessionContext getSessionContext() { + return sessionContext; + } + + /** + * Returns the ServletContext to which this session belongs. + * + * @return The ServletContext object for the web application + * @ince 2.3 + */ + public ServletContext getServletContext() { + // System.err.println("ctx from:"+servletContext); //!!! + return servletContext; + } + + public Object getAttribute(String name) throws IllegalStateException { + if (expired) { + throw new IllegalStateException(); + } + return get((Object) name); + } + + public Object getValue(String name) throws IllegalStateException { + return getAttribute(name); + } + + public Enumeration getAttributeNames() throws IllegalStateException { + if (expired) { + throw new IllegalStateException(); + } + + return keys(); + } + + public String[] getValueNames() throws IllegalStateException { + Enumeration e = getAttributeNames(); + Vector names = new Vector(); + while (e.hasMoreElements()) { + names.addElement(e.nextElement()); + } + String[] result = new String[names.size()]; + names.copyInto(result); + return result; + } + + public void setAttribute(String name, Object value) throws IllegalStateException { + if (expired) { + throw new IllegalStateException(); + } + + Object oldValue = value != null ? put((Object) name, value) : remove(name); + if (oldValue != null) { + if (oldValue instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) oldValue).valueUnbound(new HttpSessionBindingEvent(this, name)); + } + } + + if (value != null) { + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name)); + } + notifyListeners(name, oldValue, value); + } else { + notifyListeners(name, oldValue); + } + } + + public void putValue(String name, Object value) throws IllegalStateException { + setAttribute(name, value); + } + + public void removeAttribute(String name) throws IllegalStateException { + if (expired) { + throw new IllegalStateException(); + } + + Object value = remove((Object) name); + if (value != null) { + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name)); + } + notifyListeners(name, value); + } + } + + public void removeValue(String name) throws IllegalStateException { + removeAttribute(name); + } + + public synchronized void invalidate() throws IllegalStateException { + if (expired) { + throw new IllegalStateException(); + } + + notifyListeners(); + Enumeration e = getAttributeNames(); + while (e.hasMoreElements()) { + removeAttribute((String) e.nextElement()); + } + listeners = null; + setExpired(true); + // would be nice remove it from hash table also + } + + public boolean isNew() throws IllegalStateException { + if (expired) { + throw new IllegalStateException(); + } + + return (lastAccessTime == 0); + } + + /** + * + * @param listeners + */ + public synchronized void setListeners(List listeners) { + if (this.listeners == null) { + this.listeners = listeners; + if (this.listeners != null) { + HttpSessionEvent localHttpSessionEvent = new HttpSessionEvent(this); + for (int i = 0; i < this.listeners.size(); i++) { + try { + ((HttpSessionListener) this.listeners.get(i)).sessionCreated(localHttpSessionEvent); + } catch (ClassCastException ex) { + // servletContext.log("Wrong session listener type:" + // + classCastException, classCastException); + } catch (NullPointerException ex) { + // servletContext.log("Null session listener!", + // nullPointerException); + } + } + } + } + } + + /** + * something hack, to update servlet context since session created out + * of scope + * + * @param servletContext + */ + public synchronized void setServletContext(ServletContext servletContext) { + // System.err.println("ctx to:"+servletContext); //!!! + this.servletContext = servletContext; + } + + private void notifyListeners() { + if (listeners != null) { + HttpSessionEvent event = new HttpSessionEvent(this); + for (int i = 0; i < listeners.size(); i++) { + try { + ((HttpSessionListener) listeners.get(i)).sessionDestroyed(event); + } catch (ClassCastException ex) { + // servletContext.log("Wrong session listener + // type."+cce); + } catch (NullPointerException ex) { + // servletContext. log("Null session listener."); + } + } + } + } + + /** + * + * @param name + * @param value + */ + private void notifyListeners(String name, Object value) { + if (listeners != null) { + HttpSessionBindingEvent event = new HttpSessionBindingEvent(this, name, value); + for (int i = 0, n = listeners.size(); i < n; i++) { + try { + ((HttpSessionAttributeListener) listeners.get(i)).attributeRemoved(event); + } catch (ClassCastException ex) { + // ignore me! + } catch (NullPointerException ex) { + // ignore me! + } + } + } + } + + /** + * + * @param name + * @param oldValue + * @param value + */ + private void notifyListeners(String name, Object oldValue, Object value) { + if (listeners != null) { + HttpSessionBindingEvent event = new HttpSessionBindingEvent(this, name, value); + HttpSessionBindingEvent oldEvent = oldValue == null ? null : new HttpSessionBindingEvent(this, name, oldValue); + for (int i = 0, n = listeners.size(); i < n; i++) { + try { + HttpSessionAttributeListener sessionListener = (HttpSessionAttributeListener) listeners.get(i); + if (oldEvent != null) { + sessionListener.attributeReplaced(oldEvent); + } + + sessionListener.attributeAdded(event); + } catch (ClassCastException ex) { + // ignore me! + } catch (NullPointerException ex) { + // ignore me! + } + } + } + } + + private void setExpired(boolean expired) { + this.expired = expired; + } + + boolean isValid() { + return !expired; + } + + boolean checkExpired() { + return (inactiveInterval > 0 && (inactiveInterval * 1000 < System.currentTimeMillis() - lastAccessTime)); + } + + void userTouch() { + if (isValid()) { + lastAccessTime = System.currentTimeMillis(); + } else { + throw new IllegalStateException(); + } + } + + // storing session in format + // id:latency:contextname:tttt + // entry:base64 ser data + // entry:base64 ser data + void save(Writer w) throws IOException { + if (expired) { + return; + } + + // can't use append because old JDK + w.write(id); + w.write(':'); + w.write(Integer.toString(inactiveInterval)); + w.write(':'); + w.write(servletContext == null || servletContext.getServletContextName() == null ? "" : servletContext.getServletContextName()); + w.write(':'); + w.write(Long.toString(lastAccessTime)); + w.write("\r\n"); + + Enumeration e = getAttributeNames(); + ByteArrayOutputStream os = new ByteArrayOutputStream(1024 * 16); + while (e.hasMoreElements()) { + String aname = (String) e.nextElement(); + Object so = get(aname); + if (so instanceof Serializable) { + os.reset(); + ObjectOutputStream outputStream = new ObjectOutputStream(os); + try { + outputStream.writeObject(so); + w.write(aname); + w.write(":"); + w.write(Utils.base64Encode(os.toByteArray())); + w.write("\r\n"); + } catch (IOException ioe) { + servletContext.log("TJWS: Can't replicate/store a session value of '" + aname + "' class:" + so.getClass().getName(), ioe); + } + } else { + servletContext.log("TJWS: Non serializable session object has been " + so.getClass().getName() + " skiped in storing of " + aname, null); + } + + if (so instanceof HttpSessionActivationListener) { + ((HttpSessionActivationListener) so).sessionWillPassivate(new HttpSessionEvent(this)); + } + } + w.write("$$\r\n"); + } + + /** + * + * @param r + * @param inactiveInterval + * @param servletContext + * @param sessionContext + * @return + * @throws IOException + */ + static AcmeSession restore(BufferedReader r, int inactiveInterval, ServletContext servletContext, HttpSessionContext sessionContext) throws IOException { + String s = r.readLine(); + if (s == null) { + // eos + return null; + } + + int cp = s.indexOf(':'); + if (cp < 0) { + throw new IOException("Invalid format for a session header, no session id: " + s); + } + + String id = s.substring(0, cp); + int cp2 = s.indexOf(':', cp + 1); + if (cp2 < 0) + throw new IOException("Invalid format for a session header, no latency: " + s); + try { + inactiveInterval = Integer.parseInt(s.substring(cp + 1, cp2)); + } catch (NumberFormatException nfe) { + servletContext.log("TJWS: Session latency is invalid:" + s.substring(cp + 1, cp2) + " " + nfe); + } + cp = s.indexOf(':', cp2 + 1); + if (cp < 0) + throw new IOException("TJWS: Invalid format for a session header, context name: " + s); + String contextName = s.substring(cp2 + 1, cp); + // consider servletContext.getContext("/"+contextName) + AcmeSession result = new AcmeSession(id, inactiveInterval, contextName.length() == 0 ? servletContext : null, sessionContext); + try { + result.lastAccessTime = Long.parseLong(s.substring(cp + 1)); + } catch (NumberFormatException nfe) { + servletContext.log("TJWS: Last access time is invalid:" + s.substring(cp + 1) + " " + nfe); + } + do { + s = r.readLine(); + if (s == null) { + throw new IOException("Unexpected end of a stream."); + } + if ("$$".equals(s)) { + return result; + } + + cp = s.indexOf(':'); + if (cp < 0) { + throw new IOException("Invalid format for a session entry: " + s); + } + + String aname = s.substring(0, cp); + // if (lazyRestore) + // result.put(aname, s.substring(cp+1)); + ObjectInputStream oInputStream = new ObjectInputStream(new ByteArrayInputStream(Utils.decode64(s.substring(cp + 1)))); + Throwable restoreError; + try { + Object so = oInputStream.readObject(); + result.put(aname, so); + restoreError = null; + if (so instanceof HttpSessionActivationListener) { + ((HttpSessionActivationListener) so).sessionDidActivate(new HttpSessionEvent(result)); + } + + } catch (ClassNotFoundException cnfe) { + restoreError = cnfe; + } catch (NoClassDefFoundError ncdfe) { + restoreError = ncdfe; + } catch (IOException ioe) { + restoreError = ioe; + } + + if (restoreError != null) { + servletContext.log("TJWS: Can't restore :" + aname + ", " + restoreError); + } + + } while (true); + } + } + + protected static class AcmeCookie extends Cookie { + private boolean httpOnly; + + public AcmeCookie(String name, String value) { + super(name, value); + } + + public boolean isHttpOnly() { + return httpOnly; + } + + public void setHttpOnly(boolean isHttpOnly) { + httpOnly = isHttpOnly; + } + } + + protected static class LocaleWithWeight implements Comparable { + // should be int + protected float weight; + protected Locale locale; + + LocaleWithWeight(final Locale locale, float weight) { + this.locale = locale; + this.weight = weight; + } + + public int compareTo(Object object) { + if (object instanceof LocaleWithWeight) { + return (int) (((LocaleWithWeight) object).weight - weight) * 100; + } + + throw new IllegalArgumentException(); + } + + public Locale getLocale() { + return locale; + } + } + + protected static class AcceptLocaleEnumeration implements Enumeration { + private Iterator itr; + + public AcceptLocaleEnumeration(TreeSet treeSet) { + itr = treeSet.iterator(); + } + + public boolean hasMoreElements() { + return itr.hasNext(); + } + + public Object nextElement() { + return ((LocaleWithWeight) itr.next()).getLocale(); + } + } + + /** + * TODO: reconsider implementation by providing inner class implementing + * HttpSessionContext and returning it on request to avoid casting this + * class to Hashtable. + */ + protected static class HttpSessionContextImpl extends Hashtable implements HttpSessionContext { + + public Enumeration getIds() { + return keys(); + } + + public HttpSession getSession(final String sessionId) { + return (HttpSession) get(sessionId); + } + + void save(final Writer writer) throws IOException { + Enumeration itr = elements(); + while (itr.hasMoreElements()) { + ((AcmeSession) itr.nextElement()).save(writer); + } + } + + static HttpSessionContextImpl restore(final BufferedReader bReader, int inactiveInterval, ServletContext servletContext) throws IOException { + HttpSessionContextImpl result = new HttpSessionContextImpl(); + AcmeSession session; + while ((session = AcmeSession.restore(bReader, inactiveInterval, servletContext, result)) != null) { + if (session.checkExpired() == false) { + result.put(session.getId(), session); + } + } + + return result; + } + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getEffectiveMajorVersion() + */ + @Override + public int getEffectiveMajorVersion() { + return 0; + } + + /** + * @see javax.servlet.ServletContext#getEffectiveMinorVersion() + */ + @Override + public int getEffectiveMinorVersion() { + return 0; + } + + /** + * @see javax.servlet.ServletContext#setInitParameter(java.lang.String, + * java.lang.String) + */ + @Override + public boolean setInitParameter(String paramString1, String paramString2) { + return false; + } + + /** + * @see javax.servlet.ServletContext#addServlet(java.lang.String, + * java.lang.Class) + */ + @Override + public Dynamic addServlet(String paramString, Class paramClass) { + return null; + } + + /** + * @see javax.servlet.ServletContext#createServlet(java.lang.Class) + */ + @Override + public T createServlet(Class paramClass) throws ServletException { + return null; + } + + /** + * @see javax.servlet.ServletContext#getServletRegistration(java.lang.String) + */ + @Override + public ServletRegistration getServletRegistration(String paramString) { + return null; + } + + /** + * @see javax.servlet.ServletContext#getServletRegistrations() + */ + @Override + public Map getServletRegistrations() { + return null; + } + + /** + * @see javax.servlet.ServletContext#addFilter(java.lang.String, + * java.lang.String) + */ + @Override + public javax.servlet.FilterRegistration.Dynamic addFilter(String paramString1, String paramString2) { + return null; + } + + /** + * @see javax.servlet.ServletContext#addFilter(java.lang.String, + * javax.servlet.Filter) + */ + @Override + public javax.servlet.FilterRegistration.Dynamic addFilter(String paramString, Filter paramFilter) { + return null; + } + + /** + * @see javax.servlet.ServletContext#addFilter(java.lang.String, + * java.lang.Class) + */ + @Override + public javax.servlet.FilterRegistration.Dynamic addFilter(String paramString, Class paramClass) { + return null; + } + + /** + * @see javax.servlet.ServletContext#createFilter(java.lang.Class) + */ + @Override + public T createFilter(Class paramClass) throws ServletException { + return null; + } + + /** + * @see javax.servlet.ServletContext#getFilterRegistration(java.lang.String) + */ + @Override + public FilterRegistration getFilterRegistration(String paramString) { + return null; + } + + /** + * @see javax.servlet.ServletContext#getFilterRegistrations() + */ + @Override + public Map getFilterRegistrations() { + return null; + } + + /** + * @see javax.servlet.ServletContext#getSessionCookieConfig() + */ + @Override + public SessionCookieConfig getSessionCookieConfig() { + return null; + } + + /** + * @see javax.servlet.ServletContext#setSessionTrackingModes(java.util.Set) + */ + @Override + public void setSessionTrackingModes(Set paramSet) { + } + + /** + * @see javax.servlet.ServletContext#getDefaultSessionTrackingModes() + */ + @Override + public Set getDefaultSessionTrackingModes() { + return null; + } + + /** + * @see javax.servlet.ServletContext#getEffectiveSessionTrackingModes() + */ + @Override + public Set getEffectiveSessionTrackingModes() { + return null; + } + + /** + * @see javax.servlet.ServletContext#addListener(java.lang.String) + */ + @Override + public void addListener(String paramString) { + } + + /** + * @see javax.servlet.ServletContext#addListener(java.util.EventListener) + */ + @Override + public void addListener(T paramT) { + } + + /** + * @see javax.servlet.ServletContext#addListener(java.lang.Class) + */ + @Override + public void addListener(Class paramClass) { + } + + /** + * @see javax.servlet.ServletContext#createListener(java.lang.Class) + */ + @Override + public T createListener(Class paramClass) throws ServletException { + return null; + } + + /** + * (non-Javadoc) + * + * @see javax.servlet.ServletContext#getJspConfigDescriptor() + */ + @Override + public JspConfigDescriptor getJspConfigDescriptor() { + return null; + } + + /** + * @see javax.servlet.ServletContext#getClassLoader() + */ + @Override + public ClassLoader getClassLoader() { + return null; + } + + /** + * + * @see javax.servlet.ServletContext#declareRoles(java.lang.String[]) + */ + @Override + public void declareRoles(String... paramVarArgs) { + } +} \ No newline at end of file diff --git a/src/Acme/Serve/SimpleAcceptor.java b/src/Acme/Serve/SimpleAcceptor.java new file mode 100755 index 0000000..8376f7a --- /dev/null +++ b/src/Acme/Serve/SimpleAcceptor.java @@ -0,0 +1,110 @@ +/* + * tjws - SimpleAcceptor.java + * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: SimpleAcceptor.java,v 1.9 2012/08/16 02:50:15 dmitriy Exp $ + * Created on Jun 12, 2007 + * @author dmitriy + * @author Rohtash Singh Lakra + */ +package Acme.Serve; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Map; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; + +/** + * SimpleAcceptor.java + */ +public class SimpleAcceptor implements Serve.Acceptor { + + /** socket */ + private ServerSocket socket; + + /** + * @see Acme.Serve.Serve.Acceptor#accept() + */ + public Socket accept() throws IOException { + return socket.accept(); + } + + /** + * @see Acme.Serve.Serve.Acceptor#destroy() + */ + public void destroy() throws IOException { + if (socket == null) { + throw new IOException("Socket already destroyed!"); + } + + IOHelper.closeSilently(socket); + socket = null; + } + + /** + * @see Acme.Serve.Serve.Acceptor#init(java.util.Map, java.util.Map) + */ + public void init(Map inProperties, Map outProperties) throws IOException { + int port = inProperties.get(Serve.ARG_PORT) != null ? ((Integer) inProperties.get(Serve.ARG_PORT)).intValue() : Serve.DEF_PORT; + String bindAddrStr = (String) inProperties.get(Serve.ARG_BINDADDRESS); + LogManager.debug("bindAddrStr:" + bindAddrStr); + InetSocketAddress bindAddr = bindAddrStr != null ? new InetSocketAddress(InetAddress.getByName(bindAddrStr), port) : null; + String backlogStr = (String) inProperties.get(Serve.ARG_BACKLOG); + int backlog = backlogStr != null ? Integer.parseInt(backlogStr) : -1; + if (bindAddr != null) { + socket = new ServerSocket(); + if (backlog < 0) { + socket.bind(bindAddr); + } else { + socket.bind(bindAddr, backlog); + } + } else { + if (backlog < 0) { + socket = new ServerSocket(port); + } else { + socket = new ServerSocket(port, backlog); + } + } + + if (outProperties != null) { + if (socket.isBound()) { + outProperties.put(Serve.ARG_BINDADDRESS, socket.getInetAddress().getHostName()); + } else { + outProperties.put(Serve.ARG_BINDADDRESS, InetAddress.getLocalHost().getHostName()); + } + } + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + return "SimpleAcceptor - " + (socket != null ? socket.toString() : "Uninitialized!"); + } +} \ No newline at end of file diff --git a/1.x/src/Acme/Serve/ThrottleItem.java b/src/Acme/Serve/ThrottleItem.java old mode 100644 new mode 100755 similarity index 75% rename from 1.x/src/Acme/Serve/ThrottleItem.java rename to src/Acme/Serve/ThrottleItem.java index 1389172..66c1b3c --- a/1.x/src/Acme/Serve/ThrottleItem.java +++ b/src/Acme/Serve/ThrottleItem.java @@ -1,20 +1,20 @@ // ThrottleItem - data item for ThrottledOutputStream // -// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. +// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. +// notice, this list of conditions and the following disclaimer. // 2. Redistributions 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. +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -30,20 +30,24 @@ /// Data item for ThrottledOutputStream. //

-// Fetch the software.
+// Fetch the +/// software.
// Fetch the entire Acme package. - public class ThrottleItem { - - private long maxBps; - + + private final long maxBps; + // / Constructor. public ThrottleItem(long maxBps) { this.maxBps = maxBps; } - + + /** + * + * @return + */ public long getMaxBps() { return maxBps; } - + } diff --git a/1.x/src/Acme/Serve/ThrottledOutputStream.java b/src/Acme/Serve/ThrottledOutputStream.java old mode 100644 new mode 100755 similarity index 72% rename from 1.x/src/Acme/Serve/ThrottledOutputStream.java rename to src/Acme/Serve/ThrottledOutputStream.java index f026e7c..fca523d --- a/1.x/src/Acme/Serve/ThrottledOutputStream.java +++ b/src/Acme/Serve/ThrottledOutputStream.java @@ -6,15 +6,15 @@ // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. +// notice, this list of conditions and the following disclaimer. // 2. Redistributions 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. +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -35,16 +35,19 @@ import java.io.IOException; import java.io.OutputStream; +import Acme.Utils; + /// Output stream with throttling. //

-// Restricts output to a specified rate. Also includes a static utility +// Restricts output to a specified rate. Also includes a static utility // routine for parsing a file of throttle settings. //

-// Fetch the software.
+// Fetch the +/// software.
// Fetch the entire Acme package. public class ThrottledOutputStream extends FilterOutputStream { - + // / Parses a standard throttle file. //

// A throttle file lets you set maximum byte rates on filename patterns. @@ -71,41 +74,54 @@ public class ThrottledOutputStream extends FilterOutputStream { // The routine returns a WildcardDictionary. Do a lookup in this // dictionary using a filename, and you'll get back a ThrottleItem // containing the corresponding byte rate. - public static Acme.WildcardDictionary parseThrottleFile(String filename) throws IOException { - Acme.WildcardDictionary wcd = new Acme.WildcardDictionary(); + public static Acme.WildcardDictionary parseThrottleFile(String filename) throws IOException { + Acme.WildcardDictionary wildCardDictionary = new Acme.WildcardDictionary(); File thFile = new File(filename); - if (thFile.isAbsolute() == false) + if (thFile.isAbsolute() == false) { thFile = new File(System.getProperty("user.dir", "."), thFile.getName()); - BufferedReader br = new BufferedReader(new FileReader(thFile)); - while (true) { - String line = br.readLine(); - if (line == null) - break; - int i = line.indexOf('#'); - if (i != -1) - line = line.substring(0, i); - line = line.trim(); - if (line.length() == 0) - continue; - String[] words = Acme.Utils.splitStr(line); - if (words.length != 2) - throw new IOException("malformed throttle line: " + line); - try { - wcd.put(words[0], new ThrottleItem(Long.parseLong(words[1]))); - } catch (NumberFormatException e) { - throw new IOException("malformed number in throttle line: " + line); + } + + BufferedReader bReader = new BufferedReader(new FileReader(thFile)); + try { + + while (true) { + String line = bReader.readLine(); + if (line == null) { + break; + } + + int i = line.indexOf('#'); + if (i != -1) { + line = line.substring(0, i); + } + line = line.trim(); + if (line.length() == 0) { + continue; + } + + final String[] words = Utils.splitStr(line); + if (words.length != 2) { + throw new IOException("malformed throttle line: " + line); + } + + try { + wildCardDictionary.put(words[0], new ThrottleItem(Long.parseLong(words[1]))); + } catch (NumberFormatException ex) { + throw new IOException("malformed number in throttle line:" + line); + } } + } finally { + bReader.close(); } - br.close(); - return wcd; + + return wildCardDictionary; } - + private long maxBps; - private long bytes; - private long start; - + private byte[] oneByte = new byte[1]; + // / Constructor. public ThrottledOutputStream(OutputStream out, long maxBps) { super(out); @@ -113,9 +129,7 @@ public ThrottledOutputStream(OutputStream out, long maxBps) { bytes = 0; start = System.currentTimeMillis(); } - - private byte[] oneByte = new byte[1]; - + // / Writes a byte. This method will block until the byte is actually // written. // @param b the byte to be written @@ -124,7 +138,7 @@ public void write(int b) throws IOException { oneByte[0] = (byte) b; write(oneByte, 0, 1); } - + // / Writes a subarray of bytes. // @param b the data to be written // @param off the start offset in the data @@ -134,7 +148,7 @@ public void write(byte b[], int off, int len) throws IOException { // Check the throttle. bytes += len; long elapsed = Math.max(System.currentTimeMillis() - start, 1); - + long bps = bytes * 1000L / elapsed; if (bps > maxBps) { // Oops, sending too fast. @@ -144,9 +158,9 @@ public void write(byte b[], int off, int len) throws IOException { } catch (InterruptedException ignore) { } } - + // Write the bytes. out.write(b, off, len); } - + } diff --git a/src/Acme/Serve/WarDeployer.java b/src/Acme/Serve/WarDeployer.java new file mode 100755 index 0000000..c1dadc3 --- /dev/null +++ b/src/Acme/Serve/WarDeployer.java @@ -0,0 +1,40 @@ +/* + * tjws - WarDeployer.java + * Copyright (C) 1999-2004 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * $Id: WarDeployer.java,v 1.1 2006/05/10 05:45:21 rogatkin Exp $ + * Created on Dec 13, 2004 + */ + +package Acme.Serve; + +/** + * @author dmitriy + * @author Rohtash Singh Lakra + */ +public interface WarDeployer { + + /** + * + * @param server + */ + void deploy(Serve server); +} diff --git a/src/Acme/ThreadPoolFactory.java b/src/Acme/ThreadPoolFactory.java new file mode 100644 index 0000000..284a5f1 --- /dev/null +++ b/src/Acme/ThreadPoolFactory.java @@ -0,0 +1,47 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package Acme; + +/** + * @author Rohtash Singh Lakra (rohtash.singh@gmail.com) + * @created 2018-03-20 07:32:10 PM + * @version 1.0.0 + * @since 1.0.0 + */ +public interface ThreadPoolFactory { + /** + * + * @param runnable + * @return + */ + Thread create(Runnable runnable); +} \ No newline at end of file diff --git a/src/Acme/Utils.java b/src/Acme/Utils.java new file mode 100755 index 0000000..e68ec39 --- /dev/null +++ b/src/Acme/Utils.java @@ -0,0 +1,1607 @@ +// Utils - assorted static utility routines +// +// Copyright (C)1996,1998 by Jef Poskanzer . All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// +// Base64 code borrowed from public domain supported by Robert Harder +// Please visit http://iharder.net/base64 +// periodically to check for updates or to contribute improvements. +// +// All enhancements Copyright (C)1998-2010 by Dmitriy Rogatkin +// +// $Id: Utils.java,v 1.39 2013/08/10 02:47:26 cvs Exp $ + +package Acme; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.Provider; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +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.Properties; +import java.util.StringTokenizer; + +import javax.net.ssl.SSLParameters; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.rslakra.logger.LogManager; + +/// Assorted static utility routines. +//

+// Whenever I come up with a static routine that might be of general use, +// I put it here. So far the class includes: +//

    +//
  • some string routines that were left out of java.lang.String +//
  • a general array-to-string routine +//
  • a fixed version of java.io.InputStream's byte-array read routine +//
  • a bunch of URL-hacking routines +//
  • some easy-to-use wrappers for Runtime.exec +//
  • a debugging routine to dump the current call stack +//
  • a URLDecoder to match java.net.URLEncoder +//
+// and lots more. +//

+// Fetch the software.
+// Fetch the entire Acme package. + +public class Utils { + /* + * Returns a date string formatted in Unix ls style - if it's within six + * months of now, Mmm dd hh:ss, else Mmm dd yyyy. + */ + static final SimpleDateFormat SHORT_DATE_FORMAT = new SimpleDateFormat("MMM dd HH:mm"); + static final SimpleDateFormat LONG_DATE_FORMAT = new SimpleDateFormat("MMM dd yyyy"); + + public static final int COPY_BUF_SIZE = 4096 * 2; + + public static final Class[] EMPTY_CLASSES = {}; + public static final Object[] EMPTY_OBJECTS = {}; + + /** + * EMPTY_ENUMERATION + */ + public static final Enumeration EMPTY_ENUMERATION = new Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public Object nextElement() { + return null; + } + }; + + /** + * + * @param date + * @return + */ + public static String lsDateStr(Date date) { + if (Math.abs(System.currentTimeMillis() - date.getTime()) < 183L * 24L * 60L * 60L * 1000L) { + return SHORT_DATE_FORMAT.format(date); + } else { + return LONG_DATE_FORMAT.format(date); + } + } + + /** + * + * @param query + * @param encoding + * @return + */ + public static Hashtable parseQueryString(final String query, String encoding) { + Hashtable parsedQueryString = new Hashtable(); + if (IOHelper.isNullOrEmpty(encoding)) { + encoding = IOHelper.UTF_8; + } + + final StringTokenizer stringTokens = new StringTokenizer(query, "&"); + while (stringTokens.hasMoreTokens()) { + String pair = stringTokens.nextToken(); + int ep = pair.indexOf('='); + String key = ep > 0 ? pair.substring(0, ep) : pair; + String value = ep > 0 ? pair.substring(ep + 1) : ""; + try { + key = decode(key, encoding); + if (value != null) { + value = decode(value, encoding); + } + } catch (UnsupportedEncodingException ex) { + } + + String[] values = parsedQueryString.get(key); + String[] newValues; + if (values == null) { + newValues = new String[1]; + newValues[0] = value; + } else { + newValues = new String[values.length + 1]; + System.arraycopy(values, 0, newValues, 0, values.length); + newValues[values.length] = value; + } + + parsedQueryString.put(key, newValues); + } + + return parsedQueryString; + } + + /** + * + * @param length + * @param inputStream + * @param encoding + * @param cachedStream + * @return + * @throws IOException + */ + public static Map parsePostData(long length, InputStream inputStream, String encoding, String[] cachedStream) throws IOException { + // TODO: handle parsing data over 2 GB + if (length > Integer.MAX_VALUE) { + throw new RuntimeException("Can't process POST data over " + Integer.MAX_VALUE + ", requested: " + length); + } + + byte[] buffer = new byte[(int) length]; + int filePointer = 0; + while (filePointer < length) { + int readBytes = inputStream.read(buffer, filePointer, buffer.length - filePointer); + if (readBytes < 0) { + break; + } + filePointer += readBytes; + } + + // System.err.println("====>"+new String( buf)); + if (cachedStream != null && cachedStream.length > 0) { + return parseQueryString(cachedStream[0] = new String(buffer, 0, filePointer, IOHelper.ISO_8859_1), encoding); + } else { + return parseQueryString(new String(buffer, 0, filePointer, IOHelper.ISO_8859_1), encoding); + } + } + + /** + * Decodes URL encoded string including newly introduced JavaScript encoding + * with %uxxxx chars + * + * @param s + * encoded string + * @param enc + * source encoding + * @return decoded string or original if no decoding required + * @throws UnsupportedEncodingException + */ + public static String decode(String s, String enc) throws UnsupportedEncodingException { + if (enc == null || enc.length() == 0) { + throw new UnsupportedEncodingException("decode: no source char encoding provided."); + } + + if (s == null) { + return null; + } + + boolean decoded = false; + int l = s.length(); + StringBuffer sBuffer = new StringBuffer(l > 1024 ? l / 3 : l); + + int state = sText; + int i = 0; + int code = 0; + char c; + int pos = 0; + int ofs = 0; + byte[] buf = null; + boolean processDig = false; + while (i < l) { + c = s.charAt(i); + switch (c) { + case '+': + decoded = true; + if (state == sText) { + sBuffer.append(' '); + } else if (state == s2Dig) { + sBuffer.append(new String(buf, 0, pos + 1, enc)); + state = sText; + sBuffer.append(' '); + } else { + new IllegalArgumentException("decode: unexpected + at pos: " + i + ", of : " + s); + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ofs = '0'; + processDig = true; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + ofs = 'a' - 10; + processDig = true; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + ofs = 'A' - 10; + processDig = true; + break; + case '%': + decoded = true; + if (state == sText) { + state = sEscape; + if (buf == null) { + buf = new byte[(l - i) / 3]; + } + pos = 0; + } else if (state == s2Dig) { + state = sEscape; + pos++; + } else { + new IllegalArgumentException("decode: unexpected escape % at pos: " + i + ", of : " + s); + } + break; + case 'u': + if (state == sEscape) { + if (pos > 0) { + sBuffer.append(new String(buf, 0, pos, enc)); + pos = 0; + } + state = sU1; + } else if (state == sText) { + sBuffer.append(c); + } else if (state == s2Dig) { + sBuffer.append(new String(buf, 0, pos + 1, enc)); + state = sText; + sBuffer.append(c); + } else { + new IllegalArgumentException("decode: unexpected char in hex at pos: " + i + ", of : " + s); + } + break; + default: + if (state == sText) { + sBuffer.append(c); + } else if (state == s2Dig) { + sBuffer.append(new String(buf, 0, pos + 1, enc)); + state = sText; + sBuffer.append(c); + } else { + new IllegalArgumentException("decode: unexpected char in hex at pos: " + i + ", of : " + s); + } + + break; + } + i++; + + if (processDig) { + if (state == sEscape) { + code = c - ofs; + state = s1Dig; + } else if (state == s1Dig) { + buf[pos] = (byte) (code * 16 + (c - ofs)); + state = s2Dig; + } else if (state == s2Dig) { // escape finished + sBuffer.append(new String(buf, 0, pos + 1, enc)); + state = sText; + sBuffer.append(c); + } else if (state == sU1) { + code = c - ofs; + state = sU2; + } else if (state == sU2) { + code = code * 16 + c - ofs; + state = sU3; + } else if (state == sU3) { + code = code * 16 + c - ofs; + state = sU4; + } else if (state == sU4) { + sBuffer.append((char) (code * 16 + c - ofs)); + state = sText; + } else { + sBuffer.append(c); + } + processDig = false; + } + } + + if (state == s2Dig) { + sBuffer.append(new String(buf, 0, pos + 1, enc)); + } + + return (decoded ? sBuffer.toString() : s); + } + + private static final int sText = 0; + private static final int s1Dig = 1; + private static final int s2Dig = 2; + private static final int sEscape = 3; + private static final int sU1 = 4; + private static final int sU2 = 5; + private static final int sU3 = 6; + private static final int sU4 = 7; + + /** + * + * @param s + * @param encodeWS + * @return + */ + public static String htmlEncode(String s, boolean encodeWS) { + if (s == null) { + return null; + } + + char[] ca = s.toCharArray(); + StringBuffer res = new StringBuffer(ca.length); + int ls = 0; + boolean blankMet = true; + for (int i = 0; i < ca.length; i++) { + switch (ca[i]) { + case '<': + res.append(ca, ls, i - ls); + res.append("<"); + ls = i + 1; + break; + case '>': + res.append(ca, ls, i - ls); + res.append(">"); + ls = i + 1; + break; + case '"': + res.append(ca, ls, i - ls); + res.append("""); + ls = i + 1; + break; + case '&': + res.append(ca, ls, i - ls); + res.append("&"); + ls = i + 1; + break; + case ' ': + if (blankMet && encodeWS) { + res.append(ca, ls, i - ls); + res.append(" "); + ls = i + 1; + } else + blankMet = true; + break; + case '\n': + if (encodeWS) { + res.append(ca, ls, i - ls); + res.append("
"); + ls = i + 1; + } + break; + case '\r': + if (encodeWS) { + res.append(ca, ls, i - ls); + ls = i + 1; + } + break; + default: + if (ca[i] > 127) { // no unicode + res.append(ca, ls, i - ls); + res.append("&#").append((int) ca[i]).append(';'); + ls = i + 1; + } + blankMet = false; + } + } + + if (ls < ca.length) { + res.append(ca, ls, ca.length - ls); + } + + return res.toString(); + } + + /** + * + * @param contentEncoding + * @return + */ + public static float isGzipAccepted(String contentEncoding) { + float result = 0f; + if (contentEncoding != null) { + int gzsl = "gzip;".length(); + int zp = contentEncoding.indexOf("gzip"); + if (zp >= 0) { + if (contentEncoding.length() > (zp + gzsl) && contentEncoding.charAt(zp + gzsl) == ';') { + zp = contentEncoding.indexOf("q=", zp + gzsl); + if (zp > 0) { + int qe = contentEncoding.indexOf(",", zp); + if (qe < 0) + qe = contentEncoding.length(); + try { + result = Float.parseFloat(contentEncoding.substring(zp + 2, qe)); + } catch (NumberFormatException e) { + } + } + } else + result = 1f; + } + } + return result; + } + + // / Checks whether a string matches a given wildcard pattern. + // Only does ? and *, and multiple patterns separated by |. + public static boolean match(String pattern, String string) { + for (int p = 0;; ++p) { + for (int s = 0;; ++p, ++s) { + boolean sEnd = (s >= string.length()); + boolean pEnd = (p >= pattern.length() || pattern.charAt(p) == '|'); + if (sEnd && pEnd) { + return true; + } + if (sEnd || pEnd) { + break; + } + if (pattern.charAt(p) == '?') { + continue; + } + if (pattern.charAt(p) == '*') { + int i; + ++p; + for (i = string.length(); i >= s; --i) { + if (match(pattern.substring(p), string.substring(i))) { + // not quite right + return true; + } + } + break; + } + + if (pattern.charAt(p) != string.charAt(s)) { + break; + } + } + + p = pattern.indexOf('|', p); + if (p == -1) { + return false; + } + } + } + + /* + * Finds the maximum length of a string that matches a given wildcard + * pattern. Only does ? and *, and multiple patterns separated by |. + */ + public static int matchSpan(String pattern, String string) { + int result = 0; + final StringTokenizer stringTokenizer = new StringTokenizer(pattern, "|"); + while (stringTokenizer.hasMoreTokens()) { + final int length = matchSpan1(stringTokenizer.nextToken(), string); + if (length > result) { + result = length; + } + } + + return result; + } + + static int matchSpan1(String pattern, String string) { + int p = 0; + for (; p < string.length() && p < pattern.length(); p++) { + if (pattern.charAt(p) == string.charAt(p)) { + continue; + } + + if (pattern.charAt(p) == '*') { + return p - 1; + } + + return 0; + } + + return p < (pattern.length() - 1) ? -1 : p; + } + + // / Turns a String into an array of Strings, by using StringTokenizer + // to split it up at whitespace. + public static String[] splitStr(String str) { + StringTokenizer st = new StringTokenizer(str); + int n = st.countTokens(); + String[] strs = new String[n]; + for (int i = 0; i < n; ++i) { + strs[i] = st.nextToken(); + } + + return strs; + } + + // / Turns a String into an array of Strings, by splitting it at + // the specified character. This does not use StringTokenizer, + // and therefore can handle empty fields. + public static String[] splitStr(String str, char delim) { + int n = 1; + int index = -1; + while (true) { + index = str.indexOf(delim, index + 1); + if (index == -1) { + break; + } + ++n; + } + String[] strs = new String[n]; + index = -1; + for (int i = 0; i < n - 1; ++i) { + int nextIndex = str.indexOf(delim, index + 1); + strs[i] = str.substring(index + 1, nextIndex); + index = nextIndex; + } + strs[n - 1] = str.substring(index + 1); + return strs; + } + + public static String[] splitStr(String str, String quotes) { + char[] ca = str.toCharArray(); + // List result = new ArrayList(10); + String[] result = new String[0]; + boolean inArg = false; + boolean quoted = false; + int argStart = -1; + for (int i = 0; i < ca.length; i++) { + char c = ca[i]; + if (inArg) { + if (quoted) { + if (quotes.indexOf(c) >= 0) { + result = copyOf(result, result.length + 1); + result[result.length - 1] = new String(ca, argStart, i - argStart); + argStart = -1; + quoted = false; + inArg = false; + } + } else { + if (c == ' ') { + result = copyOf(result, result.length + 1); + result[result.length - 1] = new String(ca, argStart, i - argStart); + argStart = -1; + inArg = false; + } + } + } else { + if (c != ' ') { + inArg = true; + if (quotes.indexOf(c) >= 0) { + quoted = true; + argStart = i + 1; + } else + argStart = i; + } + } + } + + if (argStart > 0) { + result = copyOf(result, result.length + 1); + result[result.length - 1] = new String(ca, argStart, ca.length - argStart); + } + // for(int i=0;i 0) { + pathElements.remove(pathElements.size() - 1); + } else { + lev--; + } + // else exception ? + } else if (element.equals(".") == false) + if (lev >= 0) { + pathElements.add(element); + } else { + lev++; + } + + if (found) { + startIndex = i; + break; + } + startIndex = -1; + } + } + } + + if (startIndex > 0) { + String el = new String(pathChars, startIndex, n - startIndex); + if (el.equals("..")) { + if (pathElements.size() > 0) { + pathElements.remove(pathElements.size() - 1); + } + // else exception ? + } else if (el.equals(".") == false) { + if (lev >= 0) { + pathElements.add(el); + } + } + } else { + pathElements.add(""); + } + + if (pathElements.size() == 0) { + return lev >= 0 ? "" : null; + } + + StringBuffer result = new StringBuffer(n); + result.append(pathElements.get(0)); + n = pathElements.size(); + for (int i = 1; i < n; i++) { + result.append('/').append(pathElements.get(i)); + } + + // System.err.println("Before "+path+" after "+result); + return result.toString(); + } + + // / Copy the input to the output until EOF. + public static long copyStream(InputStream in, OutputStream out, long maxLen) throws IOException { + byte[] buf = new byte[COPY_BUF_SIZE]; + int len; + long total = 0; + if (maxLen <= 0) { + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + total += len; + } + } else { + while ((len = in.read(buf)) > 0) { + if (len <= maxLen) { + out.write(buf, 0, len); + maxLen -= len; + total += len; + } else { + out.write(buf, 0, (int) maxLen); + total += maxLen; + break; + } + } + } + + return total; + } + + // / Copy the input to the output until EOF. + public static void copyStream(Reader in, Writer out) throws IOException { + char[] buf = new char[COPY_BUF_SIZE]; + int len; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + } + + // / Copy the input to the output until EOF. + public static void copyStream(Reader in, OutputStream out, String charSet) throws IOException { + char[] buf = new char[4096]; + int len; + if (charSet == null) { + while ((len = in.read(buf)) != -1) { + out.write(new String(buf, 0, len).getBytes()); + } + } else { + while ((len = in.read(buf)) != -1) { + out.write(new String(buf, 0, len).getBytes(charSet)); + } + } + } + + protected final static char BASE64ARRAY[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; + + /** + * base 64 encoding, string converted to bytes using specified encoding + * + * @param String + * textString original string to encode + * @param String + * encoding, can be null, then iso-8859-1 used + * @return String result of encoding as iso-8859-1 string
+ * return null in case of invalid encoding or original string null + * @exception no + * exceptions + */ + public final static String base64Encode(String textString, String encoding) { + if (IOHelper.isNull(textString)) { + return null; + } else if (!IOHelper.isNullOrEmpty(textString)) { + if (IOHelper.isNullOrEmpty(encoding)) { + encoding = IOHelper.ISO_8859_1; + } + try { + return base64Encode(textString.getBytes(encoding)); + } catch (Exception ex) { + LogManager.error(ex); + } + } + + return null; + } + + /** + * base 64 encoding, array of bytes converted to bytes using specified + * encoding + * + * @param String + * _s original string to encode + * @param String + * encoding, can be null, then iso-8859-1 used + * @return String result of encoding as iso-8859-1 string
+ * + * @exception NullPointerException + * if input parameter is null + */ + public final static String base64Encode(byte[] _bytes) { + StringBuffer encodedBuffer = new StringBuffer((int) (_bytes.length * 1.5)); + int i = 0; + int pad = 0; + while (i < _bytes.length) { + int b1 = (0xFF & _bytes[i++]); + int b2; + int b3; + if (i >= _bytes.length) { + b2 = 0; + b3 = 0; + pad = 2; + } else { + b2 = 0xFF & _bytes[i++]; + if (i >= _bytes.length) { + b3 = 0; + pad = 1; + } else { + b3 = (0xFF & _bytes[i++]); + } + } + byte c1 = (byte) (b1 >> 2); + byte c2 = (byte) (((b1 & 0x3) << 4) | (b2 >> 4)); + byte c3 = (byte) (((b2 & 0xf) << 2) | (b3 >> 6)); + byte c4 = (byte) (b3 & 0x3f); + encodedBuffer.append(BASE64ARRAY[c1]).append(BASE64ARRAY[c2]); + switch (pad) { + case 0: + encodedBuffer.append(BASE64ARRAY[c3]).append(BASE64ARRAY[c4]); + break; + case 1: + encodedBuffer.append(BASE64ARRAY[c3]).append('='); + break; + case 2: + encodedBuffer.append("=="); + break; + } + } + + return encodedBuffer.toString(); + } + + /** + * Translates a Base64 value to either its 6-bit reconstruction value or a + * negative number indicating some other meaning. + */ + protected final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal + // 0 + // - + // 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal + // 14 - + // 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero + // through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' + // through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters + // 'O' + // through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters + // 'a' + // through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters + // 'n' + // through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + }; + + // Indicates white space in encoding + protected final static byte WHITE_SPACE_ENC = -5; + + // Indicates equals sign in encoding + protected final static byte EQUALS_SIGN_ENC = -1; + + /** The equals sign (=) as a byte. */ + protected final static byte EQUALS_SIGN = (byte) '='; + + /** + * base 64 decoding + * + * @param encoded + * string + * @param encoding + * used to get string bytes + * @return result of encoding, or null if encoding invalid or string null, + * or string is invalid base 64 encoding + */ + public final static String base64Decode(String base64Encoded, String encoding) { + if (IOHelper.isNull(base64Encoded)) { + return null; + } else if (!IOHelper.isNullOrEmpty(base64Encoded)) { + if (IOHelper.isNullOrEmpty(encoding)) { + encoding = IOHelper.ISO_8859_1; + } + try { + return new String(decode64(base64Encoded), encoding); + } catch (UnsupportedEncodingException ex) { + LogManager.error(ex); + } + } + + return null; + } + + /** + * Decodes four bytes from array source and writes the resulting + * bytes (up to three of them) to destination. The source and + * destination arrays can be manipulated anywhere along their length by + * specifying srcOffset and destOffset. This method + * does not + * check to make sure your arrays are large enough to accomodate + * srcOffset + 4 for the source array or + * destOffset + 3 + * for the destination array. This method returns the actual + * number of bytes that were converted from the Base64 encoding. + * + * + * @param source + * the array to convert + * @param srcOffset + * the index where conversion begins + * @param destination + * the array to hold the conversion + * @param destOffset + * the index where output will be put + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset) { + // Example: Dk== + if (source[srcOffset + 2] == EQUALS_SIGN) { + // Two ways to do the same thing. Don't know which way I like best. + // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 + // ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); + + destination[destOffset] = (byte) (outBuff >>> 16); + return 1; + } + + // Example: DkL= + else if (source[srcOffset + 3] == EQUALS_SIGN) { + // Two ways to do the same thing. Don't know which way I like best. + // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 + // ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); + + destination[destOffset] = (byte) (outBuff >>> 16); + destination[destOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } + + // Example: DkLE + else { + try { + // Two ways to do the same thing. Don't know which way I like + // best. + // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) + // >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF)); + + destination[destOffset] = (byte) (outBuff >> 16); + destination[destOffset + 1] = (byte) (outBuff >> 8); + destination[destOffset + 2] = (byte) (outBuff); + + return 3; + } catch (Exception e) { + System.out.println("" + source[srcOffset] + ": " + (DECODABET[source[srcOffset]])); + System.out.println("" + source[srcOffset + 1] + ": " + (DECODABET[source[srcOffset + 1]])); + System.out.println("" + source[srcOffset + 2] + ": " + (DECODABET[source[srcOffset + 2]])); + System.out.println("" + source[srcOffset + 3] + ": " + (DECODABET[source[srcOffset + 3]])); + return -1; + } // e nd catch + } + } // end decodeToBytes + + /** + * Very low-level access to decoding ASCII characters in the form of a byte + * array. Does not support automatically gunzipping or any other "fancy" + * features. + * + * @param source + * The Base64 encoded data + * @param off + * The offset of where to begin decoding + * @param len + * The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode(byte[] source, int off, int len) { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[len34]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for (i = off; i < off + len; i++) { + sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[sbiCrop]; + + if (sbiDecode >= WHITE_SPACE_ENC) // Whitesp ace,Eq ualssi gnor be + // tter + { + if (sbiDecode >= EQUALS_SIGN_ENC) { + b4[b4Posn++] = sbiCrop; + if (b4Posn > 3) { + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if (sbiCrop == EQUALS_SIGN) { + break; + } + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else { + System.err.println("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); + return null; + } // end else: + } // each input character + + byte[] out = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, out, 0, outBuffPosn); + return out; + } // end decode + + /** + * Decodes data from Base64 notation, automatically detecting + * gzip-compressed data and decompressing it. + * + * @param s + * the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode64(String string) { + byte[] bytes; + try { + bytes = string.getBytes(IOHelper.ISO_8859_1); + } catch (java.io.UnsupportedEncodingException uee) { + bytes = string.getBytes(); + } + + // + + // Decode + bytes = decode(bytes, 0, bytes.length); + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + if (bytes != null && bytes.length >= 4) { + + int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); + if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) { + java.io.ByteArrayInputStream bais = null; + java.util.zip.GZIPInputStream gzis = null; + java.io.ByteArrayOutputStream baos = null; + byte[] buffer = new byte[2048]; + int length = 0; + + try { + baos = new java.io.ByteArrayOutputStream(); + bais = new java.io.ByteArrayInputStream(bytes); + gzis = new java.util.zip.GZIPInputStream(bais); + + while ((length = gzis.read(buffer)) >= 0) { + baos.write(buffer, 0, length); + } + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } catch (java.io.IOException e) { + // Just return originally-decoded bytes + } finally { + IOHelper.closeSilently(baos); + IOHelper.closeSilently(gzis); + IOHelper.closeSilently(bais); + } + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } + + /** + * calculate local file based class path for class loader if possible + * (servlet classes must be located there) + * + * @param cl + * class loader + * @return class path in string + */ + static public String calculateClassPath(ClassLoader classLoader) { + // scan cl chain to find + StringBuffer classPath = new StringBuffer(); + boolean jspFound = false, servletFound = false; + while (classLoader != null) { + if (classLoader instanceof URLClassLoader) { + boolean addClasses = false; + if (jspFound == false) { + jspFound = ((URLClassLoader) classLoader).findResource("javax/servlet/jsp/JspPage.class") != null; + addClasses |= jspFound; + } + if (servletFound == false) { + servletFound = ((URLClassLoader) classLoader).findResource("javax/servlet/http/HttpServlet.class") != null; + addClasses |= servletFound; + } + if (addClasses) { + URL[] urls = ((URLClassLoader) classLoader).getURLs(); + for (int i = 0; i < urls.length; i++) { + String classFile = toFile(urls[i]); + if (classFile == null) { + continue; + } + if (classPath.length() > 0) { + classPath.append(File.pathSeparatorChar).append(classFile); + } else { + classPath.append(classFile); + } + } + } + + if (jspFound && servletFound) { + return classPath.toString(); + } + } + classLoader = classLoader.getParent(); + } + + return System.getProperty("java.class.path"); + } + + /** + * + * @param numObject + * @param defValue + * @return + */ + public static int parseInt(Object numObject, int defValue) { + if (numObject instanceof Number) { + return ((Number) numObject).intValue(); + } + try { + return Integer.parseInt(numObject.toString()); + } catch (Exception ex) { + return defValue; + } + } + + public static final String toFile(URL url) { + if (url.getProtocol().indexOf("file") < 0) { + return null; + } + + String result = url.getPath(); + if (result.charAt(0) == '/' && File.separatorChar == '\\') { + result = result.substring(1); + } + + try { + return decode(result, IOHelper.UTF_8); + } catch (UnsupportedEncodingException ex) { + return result; + } + } + + /** + * ThreadPool + */ + public static final class ThreadPool { + static final int DEF_MAX_POOLED_THREAD = 20; + static final String ID = "Acme.Utils.ThreadPool"; + public static final String MAXNOTHREAD = ID + ".maxpooledthreads"; + + protected static int counter; + protected ArrayList freeThreads; + protected HashMap busyThreads; + protected int maxThreads; + protected ThreadPoolFactory threadFactory; + + /** + * Creates a thread pool not queued with max number of threads defined + * in properties or DEF_MAX_POOLED_THREAD = 20 + * + * @param Properties + * where property THREADSINPOOL gives max threads Note if + * THREADSINPOOL not integers, or negative then + * DEF_MAX_POOLED_THREAD used + */ + public ThreadPool(Properties properties, ThreadPoolFactory threadfactory) { + maxThreads = parseInt(properties.getProperty(MAXNOTHREAD), DEF_MAX_POOLED_THREAD); + if (maxThreads < 0) { + maxThreads = DEF_MAX_POOLED_THREAD; + } + + freeThreads = new ArrayList(maxThreads); + busyThreads = new HashMap(maxThreads); + this.threadFactory = threadfactory; + } + + /** + * Assigns a new value for max threads + * + * @param int + * new value of max threads, can't be less than 2, but can be + * 0 If current number threads exceed the value, then extra + * thread will be + * discarded gracefully + */ + public void setMaxThreads(int newSize) { + if (newSize > 2 || newSize == 0) { + maxThreads = newSize; + } + } + + /** + * Returns setting for max number of threads + * + * @return int setting for max number of threads, doesn't reflect actual + * number of threads though + */ + public int getMaxThreads() { + return maxThreads; + } + + /** + * Takes a new task for execution by a threads in pool will wait until + * free threads if number of threads reached max + * + * @param Runnable + * task for execution + */ + public void executeThread(Runnable runnable) { + PooledThread pooledThread = null; + do { + synchronized (freeThreads) { + if (freeThreads.size() > 0) { + pooledThread = freeThreads.remove(0); + } + } + + if (pooledThread != null && !pooledThread.isAlive()) { + pooledThread = null; + } + + if (pooledThread == null) { + synchronized (busyThreads) { + if (busyThreads.size() < maxThreads || maxThreads == 0) + pooledThread = new PooledThread(); + } + } + + if (pooledThread == null) { + synchronized (freeThreads) { + try { + freeThreads.wait(); + } catch (InterruptedException ex) { + // ignore me! + } + } + } + } while (pooledThread == null); + pooledThread.setName("-PooledThread: " + runnable); + pooledThread.setRunner(runnable); + synchronized (busyThreads) { + busyThreads.put(pooledThread, pooledThread); + } + } + + protected void finalize() throws Throwable { + synchronized (freeThreads) { + Iterator itr = freeThreads.iterator(); + while (itr.hasNext()) { + itr.next().interrupt(); + } + } + + synchronized (busyThreads) { + Iterator itr = freeThreads.iterator(); + while (itr.hasNext()) { + itr.next().interrupt(); + } + } + super.finalize(); + } + + /** + * Returns the string representation of this object. + * + * @return + * @see java.lang.Object#toString() + */ + public String toString() { + if (freeThreads != null && busyThreads != null) { + return ID + ": free threads:" + freeThreads.size() + " busy threads:" + busyThreads.size(); + } else { + return ID + ": not initialized yet. " + super.toString(); + } + } + + final class PooledThread implements Runnable { + Runnable runner; + boolean quit; + Thread delegateThread; + String id = ID + "(" + (counter++) + ")"; + + PooledThread() { + if (threadFactory != null) { + delegateThread = threadFactory.create(this); + } else { + delegateThread = new Thread(this); + } + setName("-PooledThread: CREATED"); + delegateThread.start(); + } + + public void setName(String name) { + delegateThread.setName(id + name); + } + + public boolean isAlive() { + return delegateThread.isAlive(); + } + + synchronized public void run() { + do { + if (runner == null) { + try { + this.wait(); + } catch (InterruptedException ie) { + // ignore me! + } + } + + if (runner != null) { + try { + runner.run(); + } catch (Throwable ex) { + if (ex instanceof ThreadDeath) { + throw (ThreadDeath) ex; + } + ex.printStackTrace(); + } finally { + runner = null; + } + + int activeThreads = 0; + synchronized (busyThreads) { + busyThreads.remove(this); + activeThreads = busyThreads.size(); + } + + synchronized (freeThreads) { + if (freeThreads.size() + activeThreads > maxThreads) { + // discard this thread + break; + } + freeThreads.add(this); + delegateThread.setName(ID + "-PooledThread: FREE"); + freeThreads.notify(); + } + } + } while (!quit); + } + + synchronized public void interrupt() { + quit = true; + delegateThread.interrupt(); + } + + /** + * + * @param runnable + */ + synchronized void setRunner(Runnable runnable) { + if (runner != null) { + throw new RuntimeException("Invalid worker thread state, current runner not null."); + } + runner = runnable; + this.notifyAll(); + } + } + } + + public static class SimpleBuffer { + byte[] buffer; + int fillPosition; + byte[] emptyBuffer; + + public SimpleBuffer() { + fillPosition = 0; + setSize(COPY_BUF_SIZE); + } + + public synchronized void setSize(int size) { + if (size < 0) { + throw new IllegalArgumentException("Size can't be negative"); + } + + if (fillPosition <= 0) { + buffer = new byte[size]; + } else { + throw new IllegalStateException("Can't resize buffer containing data"); + } + } + + public synchronized int getSize() { + return buffer.length; + } + + public synchronized byte[] put(byte[] data, int off, int len) { + // System.err.println("put in buff:" + len+", fp:"+fillPos); + if (buffer.length > fillPosition + len) { + System.arraycopy(data, off, buffer, fillPosition, len); + fillPosition += len; + return getEmptyBuffer(); + } + byte[] result = new byte[Math.max(fillPosition + len - buffer.length, buffer.length)]; + // System.err.println("fp:" + fillPos + ",bl:" + buffer.length + + // ",rl:" + result.length + ",l:" + len); + // fill result + int rfilled = 0; + if (fillPosition < result.length) { + System.arraycopy(buffer, 0, result, 0, fillPosition); + rfilled = result.length - fillPosition; + System.arraycopy(data, off, result, fillPosition, rfilled); + fillPosition = 0; + // System.err.println("1rf:"+rfilled); + } else { + System.arraycopy(buffer, 0, result, 0, result.length); + System.arraycopy(buffer, result.length, buffer, 0, fillPosition - result.length); + fillPosition -= result.length; + rfilled = 0; + // System.err.println("qrf: 0"); + } + + if (rfilled < len) { + System.arraycopy(data, off + rfilled, buffer, fillPosition, len - rfilled); + fillPosition += len - rfilled; + // System.err.println("added to buf:"+(len - rfilled)); + } + + return result; + } + + public synchronized byte[] get() { + // System.err.println("get fp: "+fillPos); + if (fillPosition <= 0) { + return getEmptyBuffer(); + } + byte[] result = new byte[fillPosition]; + System.arraycopy(buffer, 0, result, 0, fillPosition); + fillPosition = 0; + return result; + } + + public synchronized void reset() { + // System.err.println("reset buf"); + fillPosition = 0; + } + + private synchronized byte[] getEmptyBuffer() { + if (emptyBuffer == null) { + emptyBuffer = new byte[0]; + } + + return emptyBuffer; + } + } + + /** + * Converts the request headers to map. + * + * @param request + * @return + */ + public static HashMap> getRequestHeaders(HttpServletRequest request) { + HashMap> requestHeaders = new HashMap>(); + for (Enumeration itr = request.getHeaderNames(); itr.hasMoreElements();) { + String name = itr.nextElement(); + requestHeaders.put(name, Collections.list(request.getHeaders(name))); + } + + return requestHeaders; + } + + /** + * Converts the request parameters as map. + * + * @param request + * @return + */ + public static HashMap> getRequestParameters(HttpServletRequest request) { + HashMap> requestParameters = new HashMap>(); + for (Map.Entry entry : request.getParameterMap().entrySet()) { + requestParameters.put(entry.getKey(), Arrays.asList(entry.getValue())); + } + + return requestParameters; + } + + /** + * Converts the request headers to map. + * + * @param request + * @return + */ + public static HashMap> getResponseHeaders(final HttpServletResponse response) { + HashMap> responseHeaders = new HashMap>(); + if (response.getHeaderNames() instanceof Collections) { + /* TODO - Implement it later. */ + // for (String name : response.getHeaderNames()) { + // responseHeaders.put(name, new + // ArrayList(response.getHeaders(name))); + // } + } else { + for (Enumeration itr = response.getHeaderNames(); itr.hasMoreElements();) { + String name = itr.nextElement(); + responseHeaders.put(name, Collections.list(response.getHeaders(name))); + } + } + + return responseHeaders; + } + + /** + * Logs the provider information. + * + * @param provider + */ + public static String toString(final Provider provider) { + return (provider == null ? "" : new StringBuilder("Provider - Info:").append(provider.getInfo()).append(", Name:").append(provider.getName()).append(", Services:").append(provider.getServices()).append(", Version:").append(provider.getVersion()).toString()); + } + + /** + * Logs the provider information. + * + * @param sslParameters + */ + public static String toString(final SSLParameters sslParameters) { + return (sslParameters == null ? "" : new StringBuilder("SSLParameters - CipherSuites:").append(IOHelper.toString(sslParameters.getCipherSuites())).append(", Protocols:").append(IOHelper.toString(sslParameters.getProtocols())).append(", WantClientAuth:").append(sslParameters.getWantClientAuth()).append(", NeedClientAuth:").append(sslParameters.getNeedClientAuth()).toString()); + } + + public static void main(String[] args) { + try { + System.out.println(args[0]); + System.out.println(canonicalizePath(args[0])); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/1.x/src/Acme/WildcardDictionary.java b/src/Acme/WildcardDictionary.java old mode 100644 new mode 100755 similarity index 63% rename from 1.x/src/Acme/WildcardDictionary.java rename to src/Acme/WildcardDictionary.java index edfe764..053800f --- a/1.x/src/Acme/WildcardDictionary.java +++ b/src/Acme/WildcardDictionary.java @@ -1,20 +1,20 @@ // WildcardDictionary - a dictionary with wildcard lookups // -// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. +// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. +// notice, this list of conditions and the following disclaimer. // 2. Redistributions 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. +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -26,7 +26,7 @@ // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ // -// http://tjws.sourceforge.net +// http://tjws.sourceforge.net // $Id: WildcardDictionary.java,v 1.3 2006/06/16 08:40:04 rogatkin Exp $ package Acme; @@ -37,76 +37,103 @@ /// A dictionary with wildcard lookups. //

-// The keys in this dictionary are wildcard patterns. When you do a get(), +// The keys in this dictionary are wildcard patterns. When you do a get(), // the string you pass in is matched against all the patterns, and the // first match is returned. //

// The wildcard matcher is fairly simple, it implements * meaning any // string, ? meaning any single character, and | separating multiple -// patterns. All other characters must match literally. +// patterns. All other characters must match literally. //

-// Fetch the software.
+// Fetch the +/// software.
// Fetch the entire Acme package. //

// @see Acme.Utils#match - -public class WildcardDictionary extends Dictionary { - - private Vector keys; - - private Vector elements; - +public class WildcardDictionary extends Dictionary { + + private Vector keys; + private Vector elements; + // / Constructor. public WildcardDictionary() { - keys = new Vector(); - elements = new Vector(); + keys = new Vector(); + elements = new Vector(); } - - // / Returns the number of elements contained within the dictionary. + + /** + * Returns the number of elements contained within the dictionary. + * + * @return + * @see java.util.Dictionary#size() + */ public int size() { return elements.size(); } - - // / Returns true if the dictionary contains no elements. + + /** + * Returns true if the dictionary contains no elements. + * + * @return + * @see java.util.Dictionary#isEmpty() + */ public boolean isEmpty() { return size() == 0; } - - // / Returns an enumeration of the dictionary's keys. - public Enumeration keys() { + + /** + * Returns an enumeration of the dictionary's keys. + * + * @return + * @see java.util.Dictionary#keys() + */ + public Enumeration keys() { return keys.elements(); } - - // / Returns an enumeration of the elements. Use the Enumeration methods - // on the returned object to fetch the elements sequentially. - public Enumeration elements() { + + /** + * Returns an enumeration of the elements. Use the Enumeration methods on + * the returned object to fetch the elements sequentially. + * + * @return + * @see java.util.Dictionary#elements() + */ + public Enumeration elements() { return elements.elements(); } - - // / Gets the object associated with the specified key in the dictionary. - // The key is assumed to be a String, which is matched against - // the wildcard-pattern keys in the dictionary. - // @param key the string to match - // @returns the element for the key, or null if there's no match - // @see Acme.Utils#match - public synchronized Object get(Object key) { + + /* + * Gets the object associated with the specified key in the dictionary. + * The key is assumed to be a String, which is matched against + * the wildcard-pattern keys in the dictionary. + * + * @param key the string to match + * + * @returns the element for the key, or null if there's no match + * + * @see Acme.Utils#match + */ + public synchronized V get(Object key) { String sKey = (String) key; int matching_len = 0, found = -1; // to optimize speed, keys should be sorted by length // TODO: above for (int i = keys.size() - 1; i > -1; i--) { String thisKey = (String) keys.elementAt(i); - int current = Acme.Utils.matchSpan(thisKey, sKey); + int current = Utils.matchSpan(thisKey, sKey); if (current > matching_len) { found = i; matching_len = current; } } - if (found > -1) + + if (found > -1) { return elements.elementAt(found); + } + return null; } - + public static String trimPathSeparators(String src) { StringBuffer result = new StringBuffer(src.length()); boolean ms = false; @@ -124,7 +151,7 @@ public static String trimPathSeparators(String src) { } return result.toString(); } - + // / Puts the specified element into the Dictionary, using the specified // key. The element may be retrieved by doing a get() with the same // key. The key and the element cannot be null. @@ -133,10 +160,10 @@ public static String trimPathSeparators(String src) { // @return the old value of the key, or null if it did not have one. // @exception NullPointerException If the value of the specified // element is null. - public synchronized Object put(Object key, Object element) { + public synchronized V put(K key, V element) { int i = keys.indexOf(key); if (i != -1) { - Object oldElement = elements.elementAt(i); + V oldElement = elements.elementAt(i); elements.setElementAt(element, i); return oldElement; } else { @@ -145,19 +172,20 @@ public synchronized Object put(Object key, Object element) { return null; } } - + // / Removes the element corresponding to the key. Does nothing if the // key is not present. // @param key the key that needs to be removed // @return the value of key, or null if the key was not found. - public synchronized Object remove(Object key) { + public synchronized V remove(Object key) { int i = keys.indexOf(key); if (i != -1) { - Object oldElement = elements.elementAt(i); + V oldElement = elements.elementAt(i); keys.removeElementAt(i); elements.removeElementAt(i); return oldElement; - } else + } else { return null; + } } } diff --git a/1.x/src/appserver.mf b/src/appserver.mf similarity index 100% rename from 1.x/src/appserver.mf rename to src/appserver.mf diff --git a/src/com/rslakra/logger/LogManager.java b/src/com/rslakra/logger/LogManager.java new file mode 100644 index 0000000..d458cd2 --- /dev/null +++ b/src/com/rslakra/logger/LogManager.java @@ -0,0 +1,348 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the https://github.com/rslakra/TJWS2 page for up-to-date versions of +// this and other fine Java utilities. +// +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// https://github.com/rslakra/TJWS2 +package com.rslakra.logger; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.PatternLayout; + +/** + * @author Rohtash Singh Lakra (Rohtash.Lakra@nasdaq.com) + * @date 03/21/2018 10:48:44 AM + */ +public final class LogManager { + + /* LOG_PATTERN */ + private static final String LOG_PATTERN = "[%d{MM-dd-yyyy hh:mm:ss.S a}] %5p [%t] [%c{1}(%L)] - %m%n"; + + /* consoleAppender */ + private static final ConsoleAppender consoleAppender = new ConsoleAppender(); + + /* mCachedLoggers. */ + private static final Map mCachedLoggers = new ConcurrentHashMap(); + + /** mRootLogger */ + private static Logger mRootLogger; + + /** sEnableServerLogs */ + private static boolean sEnableServerLogs; + + /** singleton instance. */ + private LogManager() { + throw new RuntimeException("Object creation is not allowed for this object!"); + } + + /** + * Returns the singleton instance of the root logger. + * + * @return + */ + private static final Logger getRootLogger() { + if (mRootLogger == null) { + synchronized (LogManager.class) { + if (mRootLogger == null) { + mRootLogger = Logger.getRootLogger(); + mRootLogger.getLoggerRepository().resetConfiguration(); + // configure the appender + consoleAppender.setLayout(new PatternLayout(LOG_PATTERN)); + consoleAppender.activateOptions(); + // add appender to any Logger (here is root) + mRootLogger.addAppender(consoleAppender); + /* DEFAULT LOG LEVEL. */ + mRootLogger.setLevel(Level.WARN); + } + } + } + + return mRootLogger; + } + + /** + * Returns the sEnableServerLogs value. + * + * @return + */ + public static boolean isEnableServerLogs() { + return sEnableServerLogs; + } + + /** + * The sEnableServerLogs to be set. + * + * @param enableServerLogs + */ + public static void setEnableServerLogs(boolean enableServerLogs) { + sEnableServerLogs = enableServerLogs; + } + + /** + * Return the log level of the root logger + * + * @return Log level of the root logger + */ + private static Level getLogLevel() { + return getRootLogger().getLevel(); + } + + /** + * Sets log level for the root logger + * + * @param logLevel + * Log level for the root logger + */ + public static void setLogLevel(final Level logLevel) { + getRootLogger().setLevel(logLevel); + consoleAppender.setThreshold(logLevel); + } + + /** + * Returns true if the current logLevel is >= the given logLevel otherwise + * false. + * + * @param logLevel + * @return + */ + public static boolean isLogEnabledFor(final Level logLevel) { + return (logLevel != null && logLevel.toInt() >= getLogLevel().toInt()); + } + + /** + * Returns the Logger object for the specified + * logClass class. + * + * @param logClass + * @return + */ + public static Logger getLogger(Class logClass) { + Logger logger = null; + if (logClass == null) { + throw new IllegalArgumentException("logClass is NULL! it must provide!"); + } + + logger = mCachedLoggers.get(logClass.getName()); + if (logger == null) { + synchronized (mCachedLoggers) { + if (logger == null) { + logger = Logger.getLogger(logClass.getName()); + /* cache this class logger to reuse */ + mCachedLoggers.put(logClass.getName(), logger); + } + } + } + + return logger; + } + + /** + * Returns the Logger object for the specified + * logClassName class name. + *

+ * + * @param logClassName + * @return + */ + public static Logger getLogger(final String logClassName) { + Logger logger = null; + if (logClassName == null || logClassName.trim().length() == 0) { + throw new IllegalArgumentException("logClass is NULL! it must provide!"); + } + + logger = mCachedLoggers.get(logClassName); + if (logClassName == null || logClassName.trim().length() == 0) { + synchronized (mCachedLoggers) { + if (logClassName == null || logClassName.trim().length() == 0) { + logger = Logger.getLogger(logClassName); + /* cache this class logger to reuse */ + mCachedLoggers.put(logClassName, logger); + } + } + } + + return logger; + } + + /** + * Returns the string representation of the specified object + * object, if it's not + * null otherwise empty string. + * + * @param object + * @return + */ + public static final String toString(final Object object) { + return (object == null ? "".intern() : object.toString()); + } + + /** + * Returns the string representation of the throwable object. + * + * @param throwable + * @return + */ + public static final String toString(final Throwable throwable) { + if (throwable == null) { + return "".intern(); + } else { + final StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + throwable.printStackTrace(printWriter); + printWriter.close(); + return stringWriter.toString(); + } + } + + /** + * Returns the value of the sDebugEnabled property. + * + * @return + */ + public static boolean isDebugEnabled() { + return (isEnableServerLogs() && isLogEnabledFor(Level.DEBUG)); + } + + /** + * Returns the value of the sDebugEnabled property. + * + * @return + */ + public static boolean isInfoEnabled() { + return (isEnableServerLogs() && isLogEnabledFor(Level.INFO)); + } + + /** + * + * @param object + */ + public static void fatal(final Object object) { + getRootLogger().fatal(toString(object)); + } + + /** + * + * @param object + * @param throwable + */ + public static void fatal(final Object object, final Throwable throwable) { + getRootLogger().fatal(toString(object), throwable); + } + + /** + * + * @param object + * @return + */ + public static void error(final Object object) { + getRootLogger().error(((object instanceof Throwable) ? toString((Throwable) object) : toString(object))); + } + + /** + * + * @param object + * @param throwable + */ + public static void error(final Throwable throwable) { + getRootLogger().error(toString(throwable)); + } + + /** + * + * @param object + * @param throwable + */ + public static void error(final Object object, final Throwable throwable) { + getRootLogger().error(toString(object), throwable); + } + + /** + * + * @param object + */ + public static void warn(final Object object) { + getRootLogger().warn(toString(object)); + } + + /** + * + * @param object + * @param throwable + */ + public static void warn(final Object object, final Throwable throwable) { + getRootLogger().warn(toString(object), throwable); + } + + /** + * + * @param object + */ + public static void info(final Object object) { + if (isInfoEnabled()) { + getRootLogger().info(toString(object)); + } + } + + /** + * + * @param object + * @param throwable + */ + public static void info(final Object object, final Throwable throwable) { + if (isInfoEnabled()) { + getRootLogger().info(toString(object), throwable); + } + } + + /** + * + * @param object + */ + public static void debug(final Object object) { + if (isDebugEnabled()) { + getRootLogger().debug(toString(object)); + } + } + + /** + * + * @param object + * @param throwable + */ + public static void debug(final Object object, final Throwable throwable) { + if (isDebugEnabled()) { + getRootLogger().debug(toString(object), throwable); + } + } +} diff --git a/src/javax/servlet/http/HttpServletResponse.java b/src/javax/servlet/http/HttpServletResponse.java new file mode 100644 index 0000000..554786f --- /dev/null +++ b/src/javax/servlet/http/HttpServletResponse.java @@ -0,0 +1,141 @@ +// Serve - minimal Java servlet container class +// +// Copyright (C)2018 by Rohtash Singh Lakra . All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net + +package javax.servlet.http; + +import java.io.IOException; +import java.util.Enumeration; + +import javax.servlet.ServletResponse; + +/** + * @author Rohtash Lakra (rohtash.lakra@devamatre.com) + * @author Rohtash Singh Lakra (rohtash.singh@gmail.com) + * @created 2018-03-18 11:40:14 AM + * @version 1.0.0 + * @since 1.0.0 + */ +public abstract interface HttpServletResponse extends ServletResponse { + public static final int SC_CONTINUE = 100; + public static final int SC_SWITCHING_PROTOCOLS = 101; + public static final int SC_OK = 200; + public static final int SC_CREATED = 201; + public static final int SC_ACCEPTED = 202; + public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; + public static final int SC_NO_CONTENT = 204; + public static final int SC_RESET_CONTENT = 205; + public static final int SC_PARTIAL_CONTENT = 206; + public static final int SC_MULTIPLE_CHOICES = 300; + public static final int SC_MOVED_PERMANENTLY = 301; + public static final int SC_MOVED_TEMPORARILY = 302; + public static final int SC_FOUND = 302; + public static final int SC_SEE_OTHER = 303; + public static final int SC_NOT_MODIFIED = 304; + public static final int SC_USE_PROXY = 305; + public static final int SC_TEMPORARY_REDIRECT = 307; + public static final int SC_BAD_REQUEST = 400; + public static final int SC_UNAUTHORIZED = 401; + public static final int SC_PAYMENT_REQUIRED = 402; + public static final int SC_FORBIDDEN = 403; + public static final int SC_NOT_FOUND = 404; + public static final int SC_METHOD_NOT_ALLOWED = 405; + public static final int SC_NOT_ACCEPTABLE = 406; + public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; + public static final int SC_REQUEST_TIMEOUT = 408; + public static final int SC_CONFLICT = 409; + public static final int SC_GONE = 410; + public static final int SC_LENGTH_REQUIRED = 411; + public static final int SC_PRECONDITION_FAILED = 412; + public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; + public static final int SC_REQUEST_URI_TOO_LONG = 414; + public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; + public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + public static final int SC_EXPECTATION_FAILED = 417; + public static final int SC_INTERNAL_SERVER_ERROR = 500; + public static final int SC_NOT_IMPLEMENTED = 501; + public static final int SC_BAD_GATEWAY = 502; + public static final int SC_SERVICE_UNAVAILABLE = 503; + public static final int SC_GATEWAY_TIMEOUT = 504; + public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; + + public abstract void addCookie(Cookie paramCookie); + + public abstract boolean containsHeader(String paramString); + + public abstract String encodeURL(String paramString); + + public abstract String encodeRedirectURL(String paramString); + + /** + * @deprecated + */ + public abstract String encodeUrl(String paramString); + + /** + * @deprecated + */ + public abstract String encodeRedirectUrl(String paramString); + + public abstract void sendError(int paramInt, String paramString) throws IOException; + + public abstract void sendError(int paramInt) throws IOException; + + public abstract void sendRedirect(String paramString) throws IOException; + + public abstract void setDateHeader(String paramString, long paramLong); + + public abstract void addDateHeader(String paramString, long paramLong); + + public abstract void setHeader(String paramString1, String paramString2); + + public abstract void addHeader(String paramString1, String paramString2); + + public abstract void setIntHeader(String paramString, int paramInt); + + public abstract void addIntHeader(String paramString, int paramInt); + + public abstract void setStatus(int paramInt); + + /** + * @deprecated + */ + public abstract void setStatus(int paramInt, String paramString); + + public abstract int getStatus(); + + public abstract String getHeader(String paramString); + + public abstract Enumeration getHeaders(String paramString); + + public abstract Enumeration getHeaderNames(); +} diff --git a/1.x/src/manifest.mf b/src/manifest.mf similarity index 100% rename from 1.x/src/manifest.mf rename to src/manifest.mf diff --git a/1.x/src/mysql/ConnectionChecker.java b/src/mysql/ConnectionChecker.java old mode 100644 new mode 100755 similarity index 55% rename from 1.x/src/mysql/ConnectionChecker.java rename to src/mysql/ConnectionChecker.java index f6d17a8..79658fd --- a/1.x/src/mysql/ConnectionChecker.java +++ b/src/mysql/ConnectionChecker.java @@ -7,12 +7,12 @@ public class ConnectionChecker { public static boolean validate(SQLException se, Connection conn) { for (; se != null; se = se.getNextException()) try { - //System.err.println("Checking: " + se.getClass().getName() + ", for " + conn + ", closed:" - // + conn.isClosed()); - return "com.mysql.jdbc.exceptions.jdbc4.CommunicationsException".equals(se.getClass().getName()) == false - && conn.isClosed() == false; + // System.err.println("Checking: " + se.getClass().getName() + + // ", for " + conn + ", closed:" + // + conn.isClosed()); + return "com.mysql.jdbc.exceptions.jdbc4.CommunicationsException".equals(se.getClass().getName()) == false && conn.isClosed() == false; } catch (SQLException e) { - }//System.err.println("Connection "+conn+" is bad"); + }// System.err.println("Connection "+conn+" is bad"); return false; } } diff --git a/1.x/src/oracle/ConnectionChecker.java b/src/oracle/ConnectionChecker.java similarity index 100% rename from 1.x/src/oracle/ConnectionChecker.java rename to src/oracle/ConnectionChecker.java diff --git a/src/rogatkin/app/Main.java b/src/rogatkin/app/Main.java new file mode 100755 index 0000000..bb12223 --- /dev/null +++ b/src/rogatkin/app/Main.java @@ -0,0 +1,209 @@ +/* + * tjws - Main.java + * Copyright (C) 1999-2010 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: Main.java,v 1.16 2013/03/20 03:49:46 cvs Exp $ + * Created on Mar 27, 2007 + * @author Dmitriy + */ +package rogatkin.app; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.HashSet; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import Acme.Utils; +import rogatkin.web.WebApp; +import rogatkin.web.WebAppServlet; + +public class Main { + public static final String APP_MAIN_CLASS = "tjws.app.main"; + public static final String APP_MAIN_CLASSPATH = "tjws.app.main.classpath"; + public static final String APP_MAIN_STRIP_PARAM_RIGHT = "tjws.app.main.striprightparam"; + public static final String APP_MAIN_STRIP_PARAM_LEFT = "tjws.app.main.stripleftparam"; + + /** + * @param args + */ + public static void main(String[] args) { + String mainClass = System.getProperty(APP_MAIN_CLASS); + if (mainClass == null) { + Acme.Serve.Main.main(initAppServer(args)); + } else { + URLClassLoader classLoader = null; + try { + final String classPath = System.getProperty(APP_MAIN_CLASSPATH); + if (classPath != null) { + final String[] classPathTokens = classPath.split(File.pathSeparator); + final URL urls[] = new URL[classPathTokens.length]; + for (int i = 0; i < classPathTokens.length; i++) { + if (classPathTokens[i].startsWith("file:") == false && classPathTokens[i].startsWith("http") == false) { + urls[i] = new URL("file:/" + classPathTokens[i]); + } else { + urls[i] = new URL(classPathTokens[i]); + } + } + classLoader = new URLClassLoader(urls); + } + + Class main = (classLoader == null ? Class.forName(mainClass) : Class.forName(mainClass, true, classLoader)); + if (classLoader != null) { + Thread.currentThread().setContextClassLoader(classLoader); + } + main.getDeclaredMethod("main", String[].class).invoke(null, new Object[] { rangeParam(initAppServer(args)) }); + } catch (Exception ex) { + System.err.printf("Can't launch a user app %s (%s) due: %s", mainClass, Arrays.toString(classLoader == null ? new URL[] {} : classLoader.getURLs()), ex); + ex.printStackTrace(); + } + } + } + + /** + * + * @param params + * @return + */ + protected static String[] rangeParam(String... params) { + String range = System.getProperty(APP_MAIN_STRIP_PARAM_RIGHT); + if (range != null) { + return Utils.copyOf(params, Integer.parseInt(range)); + } + range = System.getProperty(APP_MAIN_STRIP_PARAM_LEFT); + if (range != null) { + return Utils.copyOfRange(params, Integer.parseInt(range), params.length); + } + + return params; + } + + /** + * + * @param args + * @return + */ + protected static String[] initAppServer(String... args) { + // defaulting JNDI + if (System.getProperty(Context.INITIAL_CONTEXT_FACTORY) == null) { + System.getProperties().setProperty(Context.INITIAL_CONTEXT_FACTORY, SimpleJndi.class.getName()); + } + if (System.getProperty(Context.PROVIDER_URL) == null) { + System.getProperties().setProperty(Context.PROVIDER_URL, "http://localhost:1221"); + } + + try { + final Context namingContext = new InitialContext(); + WebAppServlet.setAppContextDelegator(new WebAppServlet.AppContextDelegator() { + public Object lookup(String name) { + try { + return namingContext.lookup(name); + } catch (NamingException ex) { + throw new RuntimeException("Can't delegate naming context operation", ex); + } + } + + public Object lookupLink(String name) { + try { + return namingContext.lookupLink(name); + } catch (NamingException ex) { + throw new RuntimeException("Can't delegate naming context operation", ex); + } + } + + public void add(String name, Object object) { + + try { + if (object instanceof WebApp.MetaContext) { + SimpleDataSource sds = new SimpleDataSource(((WebApp.MetaContext) object).getPath(), ((WebApp.MetaContext) object).getClassLoader()); + // TODO all data sources created form App class path + // have to be destroyed at the app destroy + if (sds.isScopeApp()) { + HashSet simpleDataSource = (HashSet) namingContext.getEnvironment().get(name); + if (simpleDataSource == null) { + simpleDataSource = new HashSet(); + namingContext.addToEnvironment(name, simpleDataSource); + } + // System.err.printf("Adding %s for %s%n", sds, + // name); + simpleDataSource.add(sds); + } + } else { + namingContext.addToEnvironment(name, object); + } + } catch (NamingException ex) { + throw new RuntimeException("Can't delegate naming context operation", ex); + } + } + + /** + * + * @param name + * @return + * @see rogatkin.web.WebAppServlet.AppContextDelegator#remove(java.lang.String) + */ + @Override + public Object remove(String name) { + Object result = null; + try { + result = namingContext.removeFromEnvironment(name); + if (result instanceof HashSet) { + for (SimpleDataSource sds : (HashSet) result) // { + sds.invalidate(); // System.err.printf("Invalidating + // %s for %s%n", sds, + // name);} + } + return result; + } catch (NamingException ex) { + // throw new RuntimeException("Can't resolve context in + // environment"); + } + return result; + } + + }); + } catch (NamingException nce) { + System.err.printf("Can not obtain initial naming context (%s) because %s%n", System.getProperty(Context.INITIAL_CONTEXT_FACTORY), nce); + } + // Perhaps it should be set Context.URL_PKG_PREFIXES + // System.out.println("Xmx set "+Runtime.getRuntime().maxMemory()); + if (args.length == 0) { + args = Acme.Serve.Main.readArguments(System.getProperty("user.dir", "."), Acme.Serve.Main.CLI_FILENAME); + } + if (args != null) + for (int i = 0; i < args.length; i++) { + if ("-dataSource".equals(args[i])) { + try { + new SimpleDataSource(args[++i], null); + } catch (IllegalArgumentException e) { + System.err.printf("Data source %s wasn't created because %s%n", args[i], e); + } + } + } + return args; + } +} diff --git a/src/rogatkin/app/ObjectPool.java b/src/rogatkin/app/ObjectPool.java new file mode 100755 index 0000000..abcc95f --- /dev/null +++ b/src/rogatkin/app/ObjectPool.java @@ -0,0 +1,203 @@ +/* + * tjws - ObjectPool.java + * Copyright (C) 2010 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: ObjectPool.java,v 1.15 2012/06/23 06:59:29 dmitriy Exp $ + * Created on Mar 5, 2008 + * @author Dmitriy + */ +package rogatkin.app; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +public abstract class ObjectPool { + + protected String[] descardMethods = { "destroy", "close" }; + protected BlockingQueue pool; + protected ArrayList borrowed; + protected int timeout; + private boolean monitor; + public static Class Wrapper; + + static { + try { + Wrapper = Class.forName("java.sql.Wrapper"); + } catch (ClassNotFoundException e) { + System.err.printf("Your Java runtime doesn't support JDBC 3.0 (%s), some functionality can be supressed.", e); + } + } + + /** + * + * @return + */ + protected abstract O create(); + + /** + * + * @param object + */ + protected void discard(O object) { + // System.err.printf("Discard %s%n", obj); + if (Wrapper != null && Wrapper.isAssignableFrom(object.getClass())) + try { + // obj = (O)((Wrapper)obj).unwrap(obj.getClass()); + object = (O) object.getClass().getMethod("unwrap", Class.class).invoke(object, object.getClass()); + } catch (Exception e1) { + } + for (int i = 0; i < descardMethods.length; i++) { + try { + object.getClass().getMethod(descardMethods[i], new Class[] {}).invoke(object, new Object[] {}); + break; + } catch (IllegalArgumentException e) { + } catch (SecurityException e) { + } catch (IllegalAccessException e) { + } catch (InvocationTargetException e) { + } catch (NoSuchMethodException e) { + } + } + } + + public ObjectPool(BlockingQueue blockingQueue) { + if (blockingQueue != null) { + pool = blockingQueue; + borrowed = new ArrayList(blockingQueue.size()); + } else { + throw new NullPointerException(); + } + } + + public O get() { + O result = get1(); + if (result != null) { + assert (borrowed.contains(result) == false); + synchronized (borrowed) { + borrowed.add(result); + // new Exception(String.format("Added in used %s size %d", + // result, borrowed.size())).printStackTrace(); + } + if (monitor) { + // get stack trace for identifying a caller and store the + // information among with request time + if (result instanceof Monitor) + ((Monitor) result).putMark(getClass().getName()); + } + } + return result; + } + + private O get1() { + if (pool.isEmpty() && borrowed.size() < getCapacity()) { + return create(); + // System.err.printf("get %s%n", o); + } + + try { + if (timeout > 0) { + return pool.poll(timeout, TimeUnit.MILLISECONDS); + } + return pool.take(); + } catch (InterruptedException e) { + } + return null; + } + + public void put(O obj) { + assert borrowed.contains(obj); + synchronized (borrowed) { + if (borrowed.remove(obj) == false) { + return; // connection already removed + } + } + + /* + * no synchronization between increasing limit and offering the + * connection for consumption is considered + * as acceptable, offering connection first and then decreasing limit + * can issue objects starvation, + * it will also require using set for borrowing list + * new Exception(String.format("returned %s, still in use: %d", obj, + * borrowed.size())).printStackTrace(); + */ + if (pool.offer(obj) == false) { + // no room, discard the object + discard(obj); + } + } + + public void remove(O obj) { + if (borrowed.contains(obj)) { + synchronized (borrowed) { + if (borrowed.remove(obj) == false) { + System.err.println("Object " + obj + " wasn't removed"); + } + } + } else { + if (pool.remove(obj) == false) { + System.err.println("Object " + obj + " wasn't removed from pool"); + } + } + + // TODO generally discard can have side effect + discard(obj); + } + + public void setTimeout(int to) { + timeout = to; + } + + /** + * resizes the pool + * + * @param newSize + */ + public abstract int getCapacity(); + + public void invalidate() { + ArrayList forDiscard = new ArrayList(); + pool.drainTo(forDiscard); + for (O o : forDiscard) + discard(o); + if (borrowed.size() > 0) + throw new IllegalStateException("Pool invalidate with borrowed objects"); + } + + /** + * The interface is used for marking pooled object by requester id + * and access time + * + * @author dmitriy + * + */ + public static interface Monitor { + void putMark(String boundaryClassName); + + String getMarkCaller(); + + long getMarkTime(); + } + +} diff --git a/src/rogatkin/app/SimpleDataSource.java b/src/rogatkin/app/SimpleDataSource.java new file mode 100755 index 0000000..251b490 --- /dev/null +++ b/src/rogatkin/app/SimpleDataSource.java @@ -0,0 +1,563 @@ +/* + * tjws - SimpleDataSource.java + * Copyright (C) 1999-2010 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: SimpleDataSource.java,v 1.30 2013/03/20 03:49:46 cvs Exp $ + * Created on Mar 25, 2007 + * @author Dmitriy + */ +package rogatkin.app; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Properties; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.logging.Logger; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import javax.sql.RowSet; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +/** + * The class presents data source, which is created based on a property file + *

+ * The following properties are allowed:
+ *

    + *
  • jndi-name - under this name the data source will be registered in + * JNDI if name starts with jdbc, then prefix + * java:comp/env/ will be added. + *
  • driver-class - class name of JDBC driver + *
  • url - JDBC connection URL + *
  • user - connection user + *
  • password - connection password + *
  • pool-size - max number of allocated connections, 0 = no size + * limitation, -1 = no pool used + *
  • access-timeout - timeout in ms before getting an exception on + * connection request when no connections are available, 0 means wait forever + *
  • driver-class-path - defines class path to driver archive, unless + * it is already in boot classpath + *
  • prob-query defines a query to verify that given connection is + * valid, executed at time getting a connection from pool. If + * isValid is specified as value, then isValid() method of SQL + * connection is used (note that it is available only in Java 6 drivers). If + * isClosed is specified, then isClosed() method used for a + * connection validation. + *
  • exception-handler - a name of class implementing static public + * method boolean validate(SQLException, Connection). This class is used to + * verify if SQLException indicates that the connection isn't valid anymore and + * has to be removed from the pool. The method returns true, if the connection + * still good for further use. + *
  • pool-shrink-size - max available connections in pool (not + * implemented yet) + *
+ * + * @author dmitriy + * + */ +public class SimpleDataSource extends ObjectPool implements DataSource { + + public final static String RW_ISVALID = "isValid"; + public final static String RW_ISCLOSED = "isClosed"; + public final static String CP_DEFAULT = "application"; + protected final static int DEFAULT_CAPACITY = 20; + protected Properties dataSourceProperties, conectionProperties; + protected Driver driver; + private int capacity; + private PrintWriter logWriter; + private Method connectionValidateMethod; + private String validateQuery; + private boolean appClassPath; + + /** + * + * @param definitionPropertiesLocation + * @param classLoader + */ + public SimpleDataSource(String definitionPropertiesLocation, ClassLoader classLoader) { + super(new ArrayBlockingQueue(DEFAULT_CAPACITY)); + logWriter = new PrintWriter(System.out); + InputStream propertiesStream = null; + File file = new File(definitionPropertiesLocation); + try { + if (file.exists()) { + propertiesStream = new FileInputStream(file); + } else { + propertiesStream = new URL(definitionPropertiesLocation).openStream(); + } + dataSourceProperties = new Properties(); + if (definitionPropertiesLocation.toLowerCase().endsWith("context.xml")) { + contextToProperties(propertiesStream); + } else if (definitionPropertiesLocation.toLowerCase().endsWith(".xml")) { + dataSourceProperties.loadFromXML(propertiesStream); + } else { + dataSourceProperties.load(propertiesStream); + } + init(classLoader); + } catch (FileNotFoundException e) { + throw new IllegalArgumentException(e); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Data source properties file doesn't exist, and can't be resolved as URL", e); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Connection validator class problem", e); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } finally { + if (propertiesStream != null) { + try { + propertiesStream.close(); + } catch (IOException e) { + } + } + } + } + + /** + * + * @param classLoader + * @throws Exception + */ + protected void init(ClassLoader classLoader) throws Exception { + String classPath = dataSourceProperties.getProperty("driver-class-path"); + if (classPath == null) { + // if (classLoader != null) + // Class.forName(dataSourceProperties.getProperty("driver-class"), + // true, classLoader); + // else + String driverClass = dataSourceProperties.getProperty("driver-class"); + if (driverClass == null) { + return; // no data source + } + Class.forName(driverClass); + driver = DriverManager.getDriver(dataSourceProperties.getProperty("url")); + } else { + String[] classPaths = classPath.split(File.pathSeparator); + URL[] urls = new URL[classPaths.length]; + for (int i = 0; i < urls.length; i++) { + urls[i] = new URL("file:" + classPaths[i]); + } + if (CP_DEFAULT.equalsIgnoreCase(classPath)) { + driver = (Driver) Class.forName(dataSourceProperties.getProperty("driver-class"), true, classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader).newInstance(); + appClassPath = true; + } else { + driver = (Driver) Class.forName(dataSourceProperties.getProperty("driver-class"), true, classLoader = new URLClassLoader(urls, DriverManager.class.getClassLoader())).newInstance(); + } + } + conectionProperties = new Properties(); + if (dataSourceProperties.getProperty("user") != null) { + conectionProperties.setProperty("user", dataSourceProperties.getProperty("user")); + if (dataSourceProperties.getProperty("password") != null) { + conectionProperties.setProperty("password", dataSourceProperties.getProperty("password")); + } + } + try { + setTimeout(Integer.parseInt(dataSourceProperties.getProperty("access-timeout"))); + } catch (Exception e) { + } + + try { + capacity = Integer.parseInt(dataSourceProperties.getProperty("pool-size")); + this.pool = new ArrayBlockingQueue(capacity, true); + this.borrowed = new ArrayList(capacity); + } catch (Exception e) { + capacity = DEFAULT_CAPACITY; + } + validateQuery = dataSourceProperties.getProperty("prob-query"); + String conValClass = dataSourceProperties.getProperty("exception-handler"); + if (conValClass != null) { + connectionValidateMethod = (classLoader == null ? Class.forName(conValClass) : Class.forName(conValClass, true, classLoader)).getMethod("validate", SQLException.class, Connection.class); + } + + String jndiName = dataSourceProperties.getProperty("jndi-name"); + if (jndiName != null) { + if (jndiName.startsWith("jdbc/")) { + jndiName = "java:comp/env/" + jndiName; + } + + InitialContext ic = new InitialContext(); + try { + ic.lookup(jndiName); + ic.rebind(jndiName, this); + } catch (NamingException ne) { + ic.bind(jndiName, this); + } + } + } + + public Connection getConnection() throws SQLException { + Connection realConn = validateQuery == null ? get() : getValidated(); + return (Connection) Proxy.newProxyInstance(realConn.getClass().getClassLoader(), Wrapper != null ? new Class[] { Connection.class, Wrapper } : new Class[] { Connection.class }, new ConnectionWrapperHandler(realConn)); + } + + @Override + public String toString() { + Properties masked = (Properties) dataSourceProperties.clone(); + masked.setProperty("password", "*******"); + Properties maskedConn = (Properties) conectionProperties.clone(); + maskedConn.setProperty("password", "*******"); + return "Pooled data source : " + masked + "\n" + maskedConn + "\n capacity:" + capacity + ", available: " + pool.size() + ", borrowed: " + borrowed.size(); + } + + public boolean isScopeApp() { + return appClassPath; + } + + private Connection getValidated() { + boolean bad = true; + do { + Connection result = get(); + Statement statement = null; + try { + if (validateQuery.equals(RW_ISVALID)) + try { + if ((Boolean) result.getClass().getMethod("isValid", int.class).invoke(10)) { + return result; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + else if (validateQuery.equals(RW_ISCLOSED)) { + if (result.isClosed() == false) { + return result; + } + } else { + /* + * TODO it can be reasonable to execute the query in a + * thread and join in millis + * because dropped connection can hung a query + */ + statement = result.createStatement(); + statement.execute(validateQuery); + return result; + } + } catch (SQLException ex) { + log("Discarding connection %s because %s%n", null, result, ex); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + } + } + } + remove(result); + } while (bad); + + throw new IllegalStateException(); + } + + public Connection getConnection(String user, String password) throws SQLException { + conectionProperties.setProperty("user", user); + conectionProperties.setProperty("password", password); + return getConnection(); + } + + public PrintWriter getLogWriter() throws SQLException { + return logWriter; + } + + public int getLoginTimeout() throws SQLException { + return timeout; + } + + public void setLogWriter(PrintWriter timeout) throws SQLException { + logWriter = timeout; + } + + public void setLoginTimeout(int timeout) throws SQLException { + // not quite what it is + setTimeout(timeout); + } + + public boolean isWrapperFor(Class _class) throws SQLException { + return DataSource.class.equals(_class) || ObjectPool.class.equals(_class); + } + + public T unwrap(Class _class) throws SQLException { + if (isWrapperFor(_class)) { + return (T) this; + } + + return null; + } + + /** + * + * @param message + * @param ex + * @param args + */ + protected void log(String message, Throwable ex, Object... args) { + if (args == null || args.length == 0) { + logWriter.write(message + "\n"); // ?? lineSeparator? + } else { + logWriter.write(String.format(message, args)); + } + if (ex != null) { + ex.printStackTrace(logWriter); + } + + logWriter.flush(); + } + + @Override + protected void discard(Connection obj) { + Connection unwrapped = null; + try {// System.err.printf("Discarding %s%n", obj); + unwrapped = (Connection) obj.getClass().getMethod("unwrap", Class.class).invoke(obj, Connection.class); + unwrapped.close(); + } catch (Exception e) {// e.printStackTrace(); + if (unwrapped == null) { + try { + obj.close(); + } catch (SQLException e1) { + // e1.printStackTrace(); + } + } + } + } + + @Override + protected Connection create() { + try { + return driver.connect(dataSourceProperties.getProperty("url"), conectionProperties); + } catch (SQLException e) { + log("Can't create connection for %s%n", e, dataSourceProperties.getProperty("url")); + throw new IllegalArgumentException("Can't create connection, check connection parameters and class path for JDBC driver", e); + } + } + + private Throwable processException(InvocationTargetException ite, Connection conn, Connection proxyConn) throws IllegalArgumentException, IllegalAccessException { + if (connectionValidateMethod != null) { + Throwable se = ite.getCause(); + // System.err.println("Cause*********"+se+" instance sql:"+(se + // instanceof SQLException)); + try { + if (se instanceof SQLException && connectionValidateMethod.invoke(null, se, conn).equals(Boolean.FALSE)) { + remove(conn); + } + } catch (InvocationTargetException e) { + } + + return se; + } + return ite.getCause(); + } + + @Override + public int getCapacity() { + return capacity; + } + + // @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException(); + } + + private void contextToProperties(InputStream contextXmlStream) throws XPathExpressionException { + XPath xp = XPathFactory.newInstance().newXPath(); + Node document = (Node) xp.evaluate("/Context", new InputSource(contextXmlStream), XPathConstants.NODE); + NodeList nodes = (NodeList) xp.evaluate("Resource", document, XPathConstants.NODESET); + int nodesLen = nodes.getLength(); + if (nodesLen > 1) { + throw new IllegalArgumentException("Only one resource is supported"); + } + + for (int p = 0; p < nodesLen; p++) { + NamedNodeMap attrs = nodes.item(p).getAttributes(); + Node metadataAttr = attrs.getNamedItem("name"); + dataSourceProperties.setProperty("jndi-name", "java:comp/env/" + metadataAttr.getTextContent()); + metadataAttr = attrs.getNamedItem("type"); + if ("javax.sql.DataSource".equals(metadataAttr.getTextContent()) == false) { + throw new IllegalArgumentException("Only SQL data sources are supported"); + } + + metadataAttr = attrs.getNamedItem("auth"); + metadataAttr = attrs.getNamedItem("username"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("user", metadataAttr.getTextContent()); + } + + metadataAttr = attrs.getNamedItem("password"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("password", metadataAttr.getTextContent()); + } + + metadataAttr = attrs.getNamedItem("driverClassName"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("driver-class", metadataAttr.getTextContent()); + } + + metadataAttr = attrs.getNamedItem("url"); + if (metadataAttr == null) { + throw new IllegalArgumentException("Data source URL is required"); + } + + dataSourceProperties.setProperty("url", metadataAttr.getTextContent()); + metadataAttr = attrs.getNamedItem("driverClassPath"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("driver-class-path", metadataAttr.getTextContent()); + } + + metadataAttr = attrs.getNamedItem("validationQuery"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("prob-query", metadataAttr.getTextContent()); + } + + metadataAttr = attrs.getNamedItem("maxActive"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("pool-size", metadataAttr.getTextContent()); + } + + metadataAttr = attrs.getNamedItem("maxIdle"); + if (metadataAttr != null) { + dataSourceProperties.setProperty("pool-shrink-size", metadataAttr.getTextContent()); + } + } + } + + class ConnectionWrapperHandler implements InvocationHandler { + + /* realConnection */ + private Connection realConnection; + + ConnectionWrapperHandler(Connection realConnection) { + this.realConnection = realConnection; + } + + public Object invoke(final Object proxyConn, Method methd, Object[] params) throws Throwable { + if (realConnection == null) { + throw new SQLException("The connection is closed"); + } + + if (methd.getName().equals("close")) { + // log("Closing %s%n", null, proxyConn); + if (realConnection.getAutoCommit() == false) { + try { + realConnection.rollback(); + } catch (SQLException se) { + + } + } + + put(realConnection); + realConnection = null; + } else if (methd.getName().equals("unwrap")) { // && + return realConnection; + } else if (methd.getName().equals("isWrapperFor")) { + return ((Class) params[0]).isInstance(realConnection); + } else if (methd.getName().equals("equals")) { + return proxyConn == params[0]; + } else { + try { + final Object realStmt = methd.invoke(realConnection, params); + if (realStmt instanceof Statement == false) { + return realStmt; + } + + // wrap statement + return Proxy.newProxyInstance(realStmt.getClass().getClassLoader(), Wrapper != null ? new Class[] { CallableStatement.class, PreparedStatement.class, Statement.class, Wrapper } : new Class[] { CallableStatement.class, PreparedStatement.class, Statement.class }, new InvocationHandler() { + public Object invoke(final Object proxyStmt, Method methd, Object[] params) throws Throwable { + if (methd.getName().equals("getConnection")) { + return proxyConn; + } else if (methd.getName().equals("unwrap")) { + return realStmt; // real statement + } else if (methd.getName().equals("isWrapperFor")) { + return ((Class) params[0]).isInstance(realStmt); + } + + try { + final Object realRS = methd.invoke(realStmt, params); + if (realRS instanceof ResultSet == false) { + return realRS; + } + + return Proxy.newProxyInstance(realRS.getClass().getClassLoader(), Wrapper != null ? new Class[] { RowSet.class, ResultSet.class, Wrapper } : new Class[] { RowSet.class, ResultSet.class }, new InvocationHandler() { + public Object invoke(final Object proxyRS, Method methd, Object[] params) throws Throwable { + if (methd.getName().equals("getStatement")) { + return proxyStmt; + } else if (methd.getName().equals("unwrap")) { + return realRS; // resultset + } else if (methd.getName().equals("isWrapperFor")) { + return ((Class) params[0]).isInstance(realRS); + } + + try { + return methd.invoke(realRS, params); + } catch (InvocationTargetException ite) { + throw processException(ite, realConnection, (Connection) proxyConn); + } + } + }); + } catch (InvocationTargetException ite) { + throw processException(ite, realConnection, (Connection) proxyConn); + } + } + }); + } catch (InvocationTargetException ite) { + throw processException(ite, realConnection, (Connection) proxyConn); + } + } + + return null; + } + } + + @Override + protected void finalize() throws Throwable { + // System.err.printf("finilize%s%n", dataSourceProperties); + invalidate(); + super.finalize(); + } + +} diff --git a/1.x/src/rogatkin/app/SimpleJndi.java b/src/rogatkin/app/SimpleJndi.java old mode 100644 new mode 100755 similarity index 78% rename from 1.x/src/rogatkin/app/SimpleJndi.java rename to src/rogatkin/app/SimpleJndi.java index 5c63444..24c250a --- a/1.x/src/rogatkin/app/SimpleJndi.java +++ b/src/rogatkin/app/SimpleJndi.java @@ -1,30 +1,30 @@ -/* tjws - SimpleJndi.java - * Copyright (C) 1999-2010 Dmitriy Rogatkin. All rights reserved. +/* + * tjws - SimpleJndi.java + * Copyright (C) 1999-2010 Dmitriy Rogatkin. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions 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. - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Visit http://tjws.sourceforge.net to get the latest information - * about Rogatkin's products. - * $Id: SimpleJndi.java,v 1.21 2013/03/12 07:58:20 cvs Exp $ - * Created on Mar 25, 2007 - * @author Dmitriy + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: SimpleJndi.java,v 1.21 2013/03/12 07:58:20 cvs Exp $ + * Created on Mar 25, 2007 + * @author Dmitriy */ package rogatkin.app; @@ -73,57 +73,55 @@ import org.omg.CORBA.ORB; import org.omg.CORBA.SystemException; +import Acme.Serve.Serve; import rogatkin.app.remote.bind; import rogatkin.app.remote.bind_listHolder; import rogatkin.app.remote.naming_exception; import rogatkin.app.remote.simple_naming; import rogatkin.app.remote.simple_namingHelper; import rogatkin.app.remote.simple_namingPOA; -import Acme.Serve.Serve; + /** - * Simple JNDI naming service + * Simple JNDI naming service + * + * more details: + * http://download.java.net/jdk8/docs/technotes/guides/jndi/jndi-cos.html#OTHERPROP * - * more details: http://download.java.net/jdk8/docs/technotes/guides/jndi/jndi-cos.html#OTHERPROP * @author Dmitriy * */ public class SimpleJndi implements InitialContextFactory { public static final char NAME_SEP_CHAR = '/'; - public static final String NAME_SEP = "" + NAME_SEP_CHAR; // can be "\\." - public static final String NAME_SEP_REGEXP = NAME_SEP; - + static ORB orb; - + static org.omg.PortableServer.POA rootPoa; - + protected static SimpleContext mainContext; - + protected static simple_naming remoteContext; - + static volatile boolean intitalized; - + public Context getInitialContext(Hashtable arg0) throws NamingException { return initMainContext(new SimpleContext(arg0)); } - + private SimpleContext initMainContext(SimpleContext context) { if (intitalized == false) synchronized (SimpleJndi.class) { if (intitalized == false) { try { - URL provUrl = new URL(System.getProperty(Context.PROVIDER_URL) == null ? (String) context - .getEnvironment().get(Context.PROVIDER_URL) : System.getProperty(Context.PROVIDER_URL)); + URL provUrl = new URL(System.getProperty(Context.PROVIDER_URL) == null ? (String) context.getEnvironment().get(Context.PROVIDER_URL) : System.getProperty(Context.PROVIDER_URL)); if (true || "tjws".equals(provUrl.getProtocol())) { // try to connect try { if (__debug) - System.err.printf("Url %s to connect%n", new URL("http", provUrl.getHost(), provUrl - .getPort(), "getRootContext")); - String ior = readUrltoString(new URL("http", provUrl.getHost(), provUrl.getPort(), - "getRootContext")); + System.err.printf("Url %s to connect%n", new URL("http", provUrl.getHost(), provUrl.getPort(), "getRootContext")); + String ior = readUrltoString(new URL("http", provUrl.getHost(), provUrl.getPort(), "getRootContext")); if (__debug) System.err.printf("==========>>>>Read IOR: %s%n", ior); if (ior == null) @@ -148,36 +146,64 @@ private SimpleContext initMainContext(SimpleContext context) { } return context; } - + + /** + * + * @author Rohtash Singh Lakra + * @date 03/19/2018 05:33:35 PM + */ + static class RootContextServlet extends HttpServlet { + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException { + if (mainContext != null) { + try { + resp.setContentType("text/plain"); + resp.getWriter().write(orb.object_to_string(rootPoa.servant_to_reference(mainContext))); + } catch (org.omg.CORBA.UserException ce) { + ce.printStackTrace(); + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } else + resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + } + } + + /** + * + * @author Rohtash Singh Lakra + * @date 03/19/2018 05:37:46 PM + */ + static class ShutdownHook implements Runnable { + final Serve serve; + + public ShutdownHook(final Serve serve) { + this.serve = serve; + } + + /** + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + if (serve != null) { + serve.notifyStop(); + serve.destroyAllServlets(); + } + } + } + private SimpleContext exposeContext(SimpleContext context, String host, int port) { final Serve srv = new Acme.Serve.Serve(); Properties properties = new java.util.Properties(); properties.put(Serve.ARG_PORT, port); properties.put(Serve.ARG_NOHUP, Serve.ARG_NOHUP); - if (host != null && host.length() > 0 && "localhost".equals(host) == false) + if (host != null && host.length() > 0 && "localhost".equals(host) == false) { properties.put(Serve.ARG_BINDADDRESS, host); + } srv.arguments = properties; - srv.addServlet("/getRootContext", new HttpServlet() { - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, - java.io.IOException { - if (mainContext != null) { - try { - resp.setContentType("text/plain"); - resp.getWriter().write(orb.object_to_string(rootPoa.servant_to_reference(mainContext))); - } catch (org.omg.CORBA.UserException ce) { - ce.printStackTrace(); - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } else - resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); - } - }); - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - public void run() { - srv.notifyStop(); - srv.destroyAllServlets(); - } - })); + srv.addServlet("/getRootContext", new RootContextServlet()); + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(srv))); Thread exposerThread = new Thread("ContextExposer") { public void run() { srv.serve(); @@ -188,7 +214,13 @@ public void run() { exposerThread.start(); return context; } - + + /** + * + * @param url + * @return + * @throws IOException + */ private byte[] readUrl(URL url) throws IOException { URLConnection uc = url.openConnection(); uc.setRequestProperty("connection", "close"); @@ -220,19 +252,19 @@ private byte[] readUrl(URL url) throws IOException { System.err.printf("Respose code %d%n", ((HttpURLConnection) uc).getResponseCode()); return null; } - + private String readUrltoString(URL url) throws IOException { byte[] bytes = readUrl(url); if (bytes != null) return new String(bytes); return null; } - + public static void main(String... args) { try { System.getProperties().setProperty(Context.INITIAL_CONTEXT_FACTORY, SimpleJndi.class.getName()); new SimpleDataSource(args[0], null); - + Connection con = ((DataSource) new InitialContext().lookup("jdbc/access/MediaChest")).getConnection(); System.out.printf("Connection taken %s\n", con); con.close(); @@ -244,12 +276,12 @@ public static void main(String... args) { e.printStackTrace(); } } - + static class SimpleContext extends simple_namingPOA implements Context { private static Hashtable environment = new Hashtable(); - + private static HashMap directory = new HashMap(); - + SimpleContext(Hashtable env) { if (rootPoa == null) synchronized (SimpleContext.class) { @@ -258,12 +290,11 @@ static class SimpleContext extends simple_namingPOA implements Context { String orbArgs = System.getProperty("tjws.app.orb.arguments"); // TODO: add properties if (orbArgs == null) - orb = ORB.init(new String[]{}, new Properties()); + orb = ORB.init(new String[] {}, new Properties()); else { orb = ORB.init(orbArgs.split(","), new Properties()); } - rootPoa = org.omg.PortableServer.POAHelper - .narrow(orb.resolve_initial_references("RootPOA")); + rootPoa = org.omg.PortableServer.POAHelper.narrow(orb.resolve_initial_references("RootPOA")); rootPoa.the_POAManager().activate(); } catch (SystemException se) { se.printStackTrace(); @@ -276,19 +307,19 @@ static class SimpleContext extends simple_namingPOA implements Context { environment.put(key.toString(), env.get(key)); } } - + public Object addToEnvironment(String arg0, Object arg1) throws NamingException { return environment.put(arg0, arg1); } - + public void bind(Name arg0, Object arg1) throws NamingException { bind(arg0.toString(), arg1); } - + public void bind(String arg0, Object arg1) throws NamingException { if (__debug) System.err.printf("===== Binding: %s at %s%n", arg0, arg1); /////////////////////// - + arg0 = arg0.trim(); try { if (lookup(arg0) != null) @@ -298,15 +329,14 @@ public void bind(String arg0, Object arg1) throws NamingException { System.err.printf("Remote ctx %s%n", remoteContext); if (remoteContext != null) if (arg1 instanceof org.omg.CORBA.Object) - try {//System.err.printf("-->Bind%s%n", arg1); + try {// System.err.printf("-->Bind%s%n", arg1); remoteContext.bind1(arg0, (org.omg.CORBA.Object) arg1); } catch (naming_exception ne1) { throw new javax.naming.NameNotFoundException("Can't bind in remote repository"); } else if (arg1 instanceof org.omg.PortableServer.Servant) - try {//System.err.printf("!-->Bind%s%n", arg1); - remoteContext.bind1(arg0, rootPoa - .servant_to_reference((org.omg.PortableServer.Servant) arg1)); + try {// System.err.printf("!-->Bind%s%n", arg1); + remoteContext.bind1(arg0, rootPoa.servant_to_reference((org.omg.PortableServer.Servant) arg1)); } catch (naming_exception ne1) { throw new javax.naming.NameNotFoundException("Can't bind in remote repository"); } catch (org.omg.CORBA.UserException ce) { @@ -314,60 +344,61 @@ else if (arg1 instanceof org.omg.PortableServer.Servant) throw new NamingException(); } else - synchronized (directory) {//System.err.printf("++-->Bind%s%n", arg1); + synchronized (directory) {// System.err.printf("++-->Bind%s%n", + // arg1); directory.put(arg0, arg1); } else - synchronized (directory) {//System.err.printf("~~-->Bind%s%n", arg1); + synchronized (directory) {// System.err.printf("~~-->Bind%s%n", + // arg1); directory.put(arg0, arg1); } } } - + public void close() throws NamingException { - + // TODO disconnect all remote objects if (remoteContext != null) { // deactivate orb.disconnect(remoteContext); } } - + public Name composeName(Name arg0, Name arg1) throws NamingException { return new SimpleName(composeName(arg0.toString(), arg1.toString())); } - + public String composeName(String arg0, String arg1) throws NamingException { return arg0 + NAME_SEP + arg1; } - + public Context createSubcontext(Name arg0) throws NamingException { return createSubcontext(arg0.toString()); } - + public Context createSubcontext(String arg0) throws NamingException { final String subcontextName = arg0.endsWith(NAME_SEP) ? arg0 : arg0 + NAME_SEP; - return (Context) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Context.class }, - new InvocationHandler() { - public Object invoke(Object conn, Method methd, Object[] params) throws Throwable { - for (int i = 0; i < params.length; i++) - if (params[i] instanceof String) - params[i] = subcontextName + (String) params[i]; - else if (params[i] instanceof Name) - params[i] = new SimpleName(subcontextName + params[i].toString()); - try { - return methd.invoke(SimpleContext.this, params); - } catch (InvocationTargetException ite) { - throw ite.getCause(); - } - } - }); + return (Context) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Context.class }, new InvocationHandler() { + public Object invoke(Object conn, Method methd, Object[] params) throws Throwable { + for (int i = 0; i < params.length; i++) + if (params[i] instanceof String) + params[i] = subcontextName + (String) params[i]; + else if (params[i] instanceof Name) + params[i] = new SimpleName(subcontextName + params[i].toString()); + try { + return methd.invoke(SimpleContext.this, params); + } catch (InvocationTargetException ite) { + throw ite.getCause(); + } + } + }); } - + public void destroySubcontext(Name arg0) throws NamingException { destroySubcontext(arg0.toString()); } - + public void destroySubcontext(String arg0) throws NamingException { String subcontextName = arg0.endsWith(NAME_SEP) ? arg0 : arg0 + NAME_SEP; synchronized (directory) { @@ -376,59 +407,59 @@ public void destroySubcontext(String arg0) throws NamingException { directory.remove(key); } } - + public Hashtable getEnvironment() throws NamingException { return environment; } - + public String getNameInNamespace() throws NamingException { throw new OperationNotSupportedException(); } - + public NameParser getNameParser(Name arg0) throws NamingException { return new SimpleNameParser(arg0.toString()); } - + public NameParser getNameParser(String arg0) throws NamingException { return new SimpleNameParser(arg0); } - + public NamingEnumeration list(Name arg0) throws NamingException { return list(arg0.toString()); } - + public NamingEnumeration list(final String arg0) throws NamingException { return new SimpleNamingEnumeration(narrowLocal(arg0)) { public NameClassPair createEntry(String name, Object v) { return new NameClassPair(name, v == null ? null : v.getClass().getName()); } - + public bind[] getRemoteDinds() { bind_listHolder h = new bind_listHolder(); try { remoteContext.list1(arg0, h); return h.value; } catch (naming_exception ne) { - + } catch (COMM_FAILURE cfe) { // Can't connect to remote JNDI server: } return null; } }; - + } - + public NamingEnumeration listBindings(Name arg0) throws NamingException { return listBindings(arg0.toString()); } - + public NamingEnumeration listBindings(final String arg0) throws NamingException { return new SimpleNamingEnumeration(narrowLocal(arg0)) { public Binding createEntry(String name, Object v) { return new Binding(name, v); } - + public bind[] getRemoteDinds() { if (remoteContext != null) try { @@ -436,19 +467,19 @@ public bind[] getRemoteDinds() { remoteContext.list1(arg0, h); return h.value; } catch (naming_exception ne) { - - } catch (COMM_FAILURE cfe) { + + } catch (COMM_FAILURE cfe) { // Can't connect to remote JNDI server: } return null; } }; } - + public Object lookup(Name arg0) throws NamingException { return lookup(arg0.toString()); } - + public Object lookup(String arg0) throws NamingException { if (__debug) System.err.printf("Requested %s = %s%n", arg0, directory.get(arg0)); /////////////// @@ -468,54 +499,54 @@ public Object lookup(String arg0) throws NamingException { throw new NameNotFoundException(arg0 + " not found"); return result; } - + public Object lookupLink(Name arg0) throws NamingException { return lookupLink(arg0.toString()); } - + public Object lookupLink(String arg0) throws NamingException { // links not supported, only local and remote objects return lookup(arg0); } - + public void rebind(Name arg0, Object arg1) throws NamingException { rebind(arg0.toString(), arg1); } - + public void rebind(String arg0, Object arg1) throws NamingException { unbind(arg0); bind(arg0, arg1); } - + public Object removeFromEnvironment(String arg0) throws NamingException { return environment.remove(arg0); } - + public void rename(Name arg0, Name arg1) throws NamingException { rename(arg0.toString(), arg1.toString()); } - + public void rename(String arg0, String arg1) throws NamingException { Object o = lookup(arg0); unbind(arg0); bind(arg1, o); } - + public void unbind(Name arg0) throws NamingException { unbind(arg0.toString()); } - + public void unbind(String arg0) throws NamingException { - if (remoteContext != null) - try { - remoteContext.unbind1(arg0); - return; // success - } catch (naming_exception e) { - } + if (remoteContext != null) + try { + remoteContext.unbind1(arg0); + return; // success + } catch (naming_exception e) { + } if (directory.remove(arg0) == null) throw new NamingException("Not found: " + arg0); } - + private Iterator> narrowLocal(String prefix) { ArrayList> result = new ArrayList>(directory.size()); synchronized (directory) { @@ -530,8 +561,8 @@ private Iterator> narrowLocal(String prefix) { } return result.iterator(); } - - ///////////////////////// CORBA methods ////////////////////////////// + + ///////////////////////// CORBA methods ////////////////////////////// public org.omg.CORBA.Object lookup1(String name) throws naming_exception { name = name.trim(); if (__debug) @@ -542,7 +573,7 @@ public org.omg.CORBA.Object lookup1(String name) throws naming_exception { return (org.omg.CORBA.Object) result; throw new naming_exception(); } - + public void unbind1(String name) throws naming_exception { Object result = lookup1(name); if (result instanceof org.omg.CORBA.Object) { @@ -552,12 +583,12 @@ public void unbind1(String name) throws naming_exception { try { rootPoa.deactivate_object(rootPoa.reference_to_id((org.omg.CORBA.Object) result)); } catch (org.omg.CORBA.UserException ce) { - + } } else throw new naming_exception(); } - + public void bind1(String name, org.omg.CORBA.Object o) throws naming_exception { if (__debug) System.err.printf("Remote bind %s%n", name); @@ -568,7 +599,7 @@ public void bind1(String name, org.omg.CORBA.Object o) throws naming_exception { throw new naming_exception(); } } - + public void list1(String filter, bind_listHolder binds) { if (__debug) System.err.printf("list1 called!!!!!!%n"); @@ -583,28 +614,28 @@ public void list1(String filter, bind_listHolder binds) { } ////////////////////////////////////////////////////////////////////////////////////////////////// } - + protected static abstract class SimpleNamingEnumeration implements NamingEnumeration { Iterator> i; - - //simple_naming r; - + + // simple_naming r; + bind[] remoteBinds; - + int bi; - + SimpleNamingEnumeration(Iterator> ei) { i = ei; } - + abstract T createEntry(String name, Object v); - + abstract bind[] getRemoteDinds(); - + public void close() { i = null; } - + public boolean hasMore() { boolean result = false; if (i != null) { @@ -620,11 +651,11 @@ public boolean hasMore() { return remoteBinds.length > bi; return result; } - + public boolean hasMoreElements() { return hasMore(); } - + public T next() { if (hasMore()) { if (i != null) { @@ -639,42 +670,42 @@ public T next() { } throw new NoSuchElementException(); } - + public T nextElement() { return next(); } } - + protected static class SimpleNameParser implements NameParser { String parent; - + public SimpleNameParser(String name) { parent = name; } - + public Name parse(String arg0) throws NamingException { return new SimpleName(parent + NAME_SEP + arg0); } } - + static class SimpleName implements Name { private String name; - + public SimpleName(String n) { name = n; } - + public String toString() { return name; } - + public Name add(String arg0) throws InvalidNameException { if (arg0.indexOf(NAME_SEP_CHAR) >= 0) throw new InvalidNameException(); name = name + NAME_SEP + arg0; return this; } - + public Name add(int arg0, String arg1) throws InvalidNameException { if (arg1.indexOf(NAME_SEP_CHAR) >= 0) throw new InvalidNameException(); @@ -682,35 +713,35 @@ public Name add(int arg0, String arg1) throws InvalidNameException { name = connect(cn, 0, arg0) + NAME_SEP + arg1 + NAME_SEP + connect(cn, arg0, cn.length - arg0); return this; } - + public Name addAll(Name arg0) throws InvalidNameException { name = name + NAME_SEP + arg0.toString(); return this; } - + public Name addAll(int arg0, Name arg1) throws InvalidNameException { return add(arg0, arg1.toString()); } - + public int compareTo(Object arg0) { return name.compareTo(arg0.toString()); } - + public boolean endsWith(Name arg0) { return name.endsWith(arg0.toString()); } - + public String get(int arg0) { String[] cn = name.split(NAME_SEP); return cn[arg0]; } - + public Enumeration getAll() { return new Enumeration() { String cn[]; - + int i = 0; - + public boolean hasMoreElements() { if (cn == null) { cn = name.split(""); @@ -718,7 +749,7 @@ public boolean hasMoreElements() { } return i < cn.length; } - + public String nextElement() { if (hasMoreElements()) { return cn[i++]; @@ -727,39 +758,39 @@ public String nextElement() { } }; } - + public Name getPrefix(int arg0) { String[] cn = name.split(NAME_SEP); return new SimpleName(connect(cn, 0, arg0)); } - + public Name getSuffix(int arg0) { String[] cn = name.split(NAME_SEP); return new SimpleName(connect(cn, arg0, cn.length - arg0)); } - + public boolean isEmpty() { return name.length() == 0; } - + public Object remove(int arg0) throws InvalidNameException { String[] cn = name.split(NAME_SEP); name = connect(cn, 0, arg0) + NAME_SEP + connect(cn, arg0, cn.length - arg0); return cn[arg0]; } - + public int size() { return name.split(NAME_SEP).length; } - + public boolean startsWith(Name arg0) { return name.startsWith(arg0.toString()); } - + public Object clone() { return new SimpleName(name); } - + private String connect(String[] parts, int s, int len) throws ArrayIndexOutOfBoundsException { if (parts == null || parts.length == 0) return ""; @@ -771,7 +802,7 @@ private String connect(String[] parts, int s, int len) throws ArrayIndexOutOfBou return result; } } - + final private static boolean __debug = false; - + } diff --git a/src/rogatkin/app/WebAppServ.java b/src/rogatkin/app/WebAppServ.java new file mode 100755 index 0000000..aef802b --- /dev/null +++ b/src/rogatkin/app/WebAppServ.java @@ -0,0 +1,52 @@ +/* + * TJWS WebAppServ + * Copyright (C) 2010 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * Visit http://tjws.sourceforge.net to get the latest information + * about Rogatkin's products. + * $Id: WebAppServ.java,v 1.3 2009/12/31 05:02:13 dmitriy Exp $ + * Created on Mar 5, 2008 + * @author dmitriy + */ +package rogatkin.app; + +import Acme.Utils; +import rogatkin.web.WebApp; + +public class WebAppServ extends Main { + + /** + * launches embedded app with app server settings + * + * @param args + */ + public static void main(String[] args) { + if (args.length == 0) + try { + initAppServer(Utils.splitStr(WebApp.readDescriptor()[0])); + } catch (NullPointerException npe) { + // npe.printStackTrace(); + } + else + initAppServer(args); + WebApp.main(args); + } +} diff --git a/src/rogatkin/app/remote/_simple_namingStub.java b/src/rogatkin/app/remote/_simple_namingStub.java new file mode 100644 index 0000000..24124b3 --- /dev/null +++ b/src/rogatkin/app/remote/_simple_namingStub.java @@ -0,0 +1,141 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/_simple_namingStub.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public class _simple_namingStub extends org.omg.CORBA.portable.ObjectImpl implements rogatkin.app.remote.simple_naming +{ + + public void bind1 (String name, org.omg.CORBA.Object o) throws rogatkin.app.remote.naming_exception + { + org.omg.CORBA.portable.InputStream $in = null; + try { + org.omg.CORBA.portable.OutputStream $out = _request ("bind1", true); + $out.write_string (name); + org.omg.CORBA.ObjectHelper.write ($out, o); + $in = _invoke ($out); + return; + } catch (org.omg.CORBA.portable.ApplicationException $ex) { + $in = $ex.getInputStream (); + String _id = $ex.getId (); + if (_id.equals ("IDL:rogatkin.app.remote/app/naming_exception:1.0")) + throw rogatkin.app.remote.naming_exceptionHelper.read ($in); + else + throw new org.omg.CORBA.MARSHAL (_id); + } catch (org.omg.CORBA.portable.RemarshalException $rm) { + bind1 (name, o ); + } finally { + _releaseReply ($in); + } + } // bind1 + + public void unbind1 (String name) throws rogatkin.app.remote.naming_exception + { + org.omg.CORBA.portable.InputStream $in = null; + try { + org.omg.CORBA.portable.OutputStream $out = _request ("unbind1", true); + $out.write_string (name); + $in = _invoke ($out); + return; + } catch (org.omg.CORBA.portable.ApplicationException $ex) { + $in = $ex.getInputStream (); + String _id = $ex.getId (); + if (_id.equals ("IDL:rogatkin.app.remote/app/naming_exception:1.0")) + throw rogatkin.app.remote.naming_exceptionHelper.read ($in); + else + throw new org.omg.CORBA.MARSHAL (_id); + } catch (org.omg.CORBA.portable.RemarshalException $rm) { + unbind1 (name ); + } finally { + _releaseReply ($in); + } + } // unbind1 + + public org.omg.CORBA.Object lookup1 (String name) throws rogatkin.app.remote.naming_exception + { + org.omg.CORBA.portable.InputStream $in = null; + try { + org.omg.CORBA.portable.OutputStream $out = _request ("lookup1", true); + $out.write_string (name); + $in = _invoke ($out); + org.omg.CORBA.Object $result = org.omg.CORBA.ObjectHelper.read ($in); + return $result; + } catch (org.omg.CORBA.portable.ApplicationException $ex) { + $in = $ex.getInputStream (); + String _id = $ex.getId (); + if (_id.equals ("IDL:rogatkin.app.remote/app/naming_exception:1.0")) + throw rogatkin.app.remote.naming_exceptionHelper.read ($in); + else + throw new org.omg.CORBA.MARSHAL (_id); + } catch (org.omg.CORBA.portable.RemarshalException $rm) { + return lookup1 (name ); + } finally { + _releaseReply ($in); + } + } // lookup1 + + public void list1 (String filter, rogatkin.app.remote.bind_listHolder bindings) throws rogatkin.app.remote.naming_exception + { + org.omg.CORBA.portable.InputStream $in = null; + try { + org.omg.CORBA.portable.OutputStream $out = _request ("list1", true); + $out.write_string (filter); + $in = _invoke ($out); + bindings.value = rogatkin.app.remote.bind_listHelper.read ($in); + return; + } catch (org.omg.CORBA.portable.ApplicationException $ex) { + $in = $ex.getInputStream (); + String _id = $ex.getId (); + if (_id.equals ("IDL:rogatkin.app.remote/app/naming_exception:1.0")) + throw rogatkin.app.remote.naming_exceptionHelper.read ($in); + else + throw new org.omg.CORBA.MARSHAL (_id); + } catch (org.omg.CORBA.portable.RemarshalException $rm) { + list1 (filter, bindings ); + } finally { + _releaseReply ($in); + } + } // list1 + + // Type-specific CORBA::Object operations + private static String[] __ids = { + "IDL:rogatkin.app.remote/app/simple_naming:1.0"}; + + public String[] _ids () + { + return (String[])__ids.clone (); + } + + private void readObject (java.io.ObjectInputStream s) throws java.io.IOException + { + String str = s.readUTF (); + String[] args = null; + java.util.Properties props = null; + org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props); + try { + org.omg.CORBA.Object obj = orb.string_to_object (str); + org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate (); + _set_delegate (delegate); + } finally { + orb.destroy() ; + } + } + + private void writeObject (java.io.ObjectOutputStream s) throws java.io.IOException + { + String[] args = null; + java.util.Properties props = null; + org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props); + try { + String str = orb.object_to_string (this); + s.writeUTF (str); + } finally { + orb.destroy() ; + } + } +} // class _simple_namingStub diff --git a/src/rogatkin/app/remote/bind.java b/src/rogatkin/app/remote/bind.java new file mode 100644 index 0000000..70ed13e --- /dev/null +++ b/src/rogatkin/app/remote/bind.java @@ -0,0 +1,26 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/bind.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public final class bind implements org.omg.CORBA.portable.IDLEntity +{ + public String name = null; + public org.omg.CORBA.Object o = null; + + public bind () + { + } // ctor + + public bind (String _name, org.omg.CORBA.Object _o) + { + name = _name; + o = _o; + } // ctor + +} // class bind diff --git a/src/rogatkin/app/remote/bindHelper.java b/src/rogatkin/app/remote/bindHelper.java new file mode 100644 index 0000000..94949a1 --- /dev/null +++ b/src/rogatkin/app/remote/bindHelper.java @@ -0,0 +1,82 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/bindHelper.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +abstract public class bindHelper +{ + private static String _id = "IDL:rogatkin.app.remote/app/bind:1.0"; + + public static void insert (org.omg.CORBA.Any a, rogatkin.app.remote.bind that) + { + org.omg.CORBA.portable.OutputStream out = a.create_output_stream (); + a.type (type ()); + write (out, that); + a.read_value (out.create_input_stream (), type ()); + } + + public static rogatkin.app.remote.bind extract (org.omg.CORBA.Any a) + { + return read (a.create_input_stream ()); + } + + private static org.omg.CORBA.TypeCode __typeCode = null; + private static boolean __active = false; + synchronized public static org.omg.CORBA.TypeCode type () + { + if (__typeCode == null) + { + synchronized (org.omg.CORBA.TypeCode.class) + { + if (__typeCode == null) + { + if (__active) + { + return org.omg.CORBA.ORB.init().create_recursive_tc ( _id ); + } + __active = true; + org.omg.CORBA.StructMember[] _members0 = new org.omg.CORBA.StructMember [2]; + org.omg.CORBA.TypeCode _tcOf_members0 = null; + _tcOf_members0 = org.omg.CORBA.ORB.init ().create_string_tc (0); + _members0[0] = new org.omg.CORBA.StructMember ( + "name", + _tcOf_members0, + null); + _tcOf_members0 = org.omg.CORBA.ObjectHelper.type (); + _members0[1] = new org.omg.CORBA.StructMember ( + "o", + _tcOf_members0, + null); + __typeCode = org.omg.CORBA.ORB.init ().create_struct_tc (rogatkin.app.remote.bindHelper.id (), "bind", _members0); + __active = false; + } + } + } + return __typeCode; + } + + public static String id () + { + return _id; + } + + public static rogatkin.app.remote.bind read (org.omg.CORBA.portable.InputStream istream) + { + rogatkin.app.remote.bind value = new rogatkin.app.remote.bind (); + value.name = istream.read_string (); + value.o = org.omg.CORBA.ObjectHelper.read (istream); + return value; + } + + public static void write (org.omg.CORBA.portable.OutputStream ostream, rogatkin.app.remote.bind value) + { + ostream.write_string (value.name); + org.omg.CORBA.ObjectHelper.write (ostream, value.o); + } + +} diff --git a/src/rogatkin/app/remote/bindHolder.java b/src/rogatkin/app/remote/bindHolder.java new file mode 100644 index 0000000..483d550 --- /dev/null +++ b/src/rogatkin/app/remote/bindHolder.java @@ -0,0 +1,38 @@ +package rogatkin.app.remote; + +/** +* rogatkin/app/remote/bindHolder.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public final class bindHolder implements org.omg.CORBA.portable.Streamable +{ + public rogatkin.app.remote.bind value = null; + + public bindHolder () + { + } + + public bindHolder (rogatkin.app.remote.bind initialValue) + { + value = initialValue; + } + + public void _read (org.omg.CORBA.portable.InputStream i) + { + value = rogatkin.app.remote.bindHelper.read (i); + } + + public void _write (org.omg.CORBA.portable.OutputStream o) + { + rogatkin.app.remote.bindHelper.write (o, value); + } + + public org.omg.CORBA.TypeCode _type () + { + return rogatkin.app.remote.bindHelper.type (); + } + +} diff --git a/src/rogatkin/app/remote/bind_listHelper.java b/src/rogatkin/app/remote/bind_listHelper.java new file mode 100644 index 0000000..51ef2c4 --- /dev/null +++ b/src/rogatkin/app/remote/bind_listHelper.java @@ -0,0 +1,62 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/bind_listHelper.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +abstract public class bind_listHelper +{ + private static String _id = "IDL:rogatkin.app.remote/app/bind_list:1.0"; + + public static void insert (org.omg.CORBA.Any a, rogatkin.app.remote.bind[] that) + { + org.omg.CORBA.portable.OutputStream out = a.create_output_stream (); + a.type (type ()); + write (out, that); + a.read_value (out.create_input_stream (), type ()); + } + + public static rogatkin.app.remote.bind[] extract (org.omg.CORBA.Any a) + { + return read (a.create_input_stream ()); + } + + private static org.omg.CORBA.TypeCode __typeCode = null; + synchronized public static org.omg.CORBA.TypeCode type () + { + if (__typeCode == null) + { + __typeCode = rogatkin.app.remote.bindHelper.type (); + __typeCode = org.omg.CORBA.ORB.init ().create_sequence_tc (0, __typeCode); + __typeCode = org.omg.CORBA.ORB.init ().create_alias_tc (rogatkin.app.remote.bind_listHelper.id (), "bind_list", __typeCode); + } + return __typeCode; + } + + public static String id () + { + return _id; + } + + public static rogatkin.app.remote.bind[] read (org.omg.CORBA.portable.InputStream istream) + { + rogatkin.app.remote.bind value[] = null; + int _len0 = istream.read_long (); + value = new rogatkin.app.remote.bind[_len0]; + for (int _o1 = 0;_o1 < value.length; ++_o1) + value[_o1] = rogatkin.app.remote.bindHelper.read (istream); + return value; + } + + public static void write (org.omg.CORBA.portable.OutputStream ostream, rogatkin.app.remote.bind[] value) + { + ostream.write_long (value.length); + for (int _i0 = 0;_i0 < value.length; ++_i0) + rogatkin.app.remote.bindHelper.write (ostream, value[_i0]); + } + +} diff --git a/src/rogatkin/app/remote/bind_listHolder.java b/src/rogatkin/app/remote/bind_listHolder.java new file mode 100644 index 0000000..2581df3 --- /dev/null +++ b/src/rogatkin/app/remote/bind_listHolder.java @@ -0,0 +1,39 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/bind_listHolder.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public final class bind_listHolder implements org.omg.CORBA.portable.Streamable +{ + public rogatkin.app.remote.bind value[] = null; + + public bind_listHolder () + { + } + + public bind_listHolder (rogatkin.app.remote.bind[] initialValue) + { + value = initialValue; + } + + public void _read (org.omg.CORBA.portable.InputStream i) + { + value = rogatkin.app.remote.bind_listHelper.read (i); + } + + public void _write (org.omg.CORBA.portable.OutputStream o) + { + rogatkin.app.remote.bind_listHelper.write (o, value); + } + + public org.omg.CORBA.TypeCode _type () + { + return rogatkin.app.remote.bind_listHelper.type (); + } + +} diff --git a/src/rogatkin/app/remote/naming_exception.java b/src/rogatkin/app/remote/naming_exception.java new file mode 100644 index 0000000..7d9aaf9 --- /dev/null +++ b/src/rogatkin/app/remote/naming_exception.java @@ -0,0 +1,25 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/naming_exception.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public final class naming_exception extends org.omg.CORBA.UserException +{ + + public naming_exception () + { + super(naming_exceptionHelper.id()); + } // ctor + + + public naming_exception (String $reason) + { + super(naming_exceptionHelper.id() + " " + $reason); + } // ctor + +} // class naming_exception diff --git a/src/rogatkin/app/remote/naming_exceptionHelper.java b/src/rogatkin/app/remote/naming_exceptionHelper.java new file mode 100644 index 0000000..7b1927d --- /dev/null +++ b/src/rogatkin/app/remote/naming_exceptionHelper.java @@ -0,0 +1,72 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/naming_exceptionHelper.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +abstract public class naming_exceptionHelper +{ + private static String _id = "IDL:rogatkin.app.remote/app/naming_exception:1.0"; + + public static void insert (org.omg.CORBA.Any a, rogatkin.app.remote.naming_exception that) + { + org.omg.CORBA.portable.OutputStream out = a.create_output_stream (); + a.type (type ()); + write (out, that); + a.read_value (out.create_input_stream (), type ()); + } + + public static rogatkin.app.remote.naming_exception extract (org.omg.CORBA.Any a) + { + return read (a.create_input_stream ()); + } + + private static org.omg.CORBA.TypeCode __typeCode = null; + private static boolean __active = false; + synchronized public static org.omg.CORBA.TypeCode type () + { + if (__typeCode == null) + { + synchronized (org.omg.CORBA.TypeCode.class) + { + if (__typeCode == null) + { + if (__active) + { + return org.omg.CORBA.ORB.init().create_recursive_tc ( _id ); + } + __active = true; + org.omg.CORBA.StructMember[] _members0 = new org.omg.CORBA.StructMember [0]; + org.omg.CORBA.TypeCode _tcOf_members0 = null; + __typeCode = org.omg.CORBA.ORB.init ().create_exception_tc (rogatkin.app.remote.naming_exceptionHelper.id (), "naming_exception", _members0); + __active = false; + } + } + } + return __typeCode; + } + + public static String id () + { + return _id; + } + + public static rogatkin.app.remote.naming_exception read (org.omg.CORBA.portable.InputStream istream) + { + rogatkin.app.remote.naming_exception value = new rogatkin.app.remote.naming_exception (); + // read and discard the repository ID + istream.read_string (); + return value; + } + + public static void write (org.omg.CORBA.portable.OutputStream ostream, rogatkin.app.remote.naming_exception value) + { + // write the repository ID + ostream.write_string (id ()); + } + +} diff --git a/src/rogatkin/app/remote/naming_exceptionHolder.java b/src/rogatkin/app/remote/naming_exceptionHolder.java new file mode 100644 index 0000000..1d4bf41 --- /dev/null +++ b/src/rogatkin/app/remote/naming_exceptionHolder.java @@ -0,0 +1,38 @@ +package rogatkin.app.remote; + +/** +* rogatkin/app/remote/naming_exceptionHolder.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public final class naming_exceptionHolder implements org.omg.CORBA.portable.Streamable +{ + public rogatkin.app.remote.naming_exception value = null; + + public naming_exceptionHolder () + { + } + + public naming_exceptionHolder (rogatkin.app.remote.naming_exception initialValue) + { + value = initialValue; + } + + public void _read (org.omg.CORBA.portable.InputStream i) + { + value = rogatkin.app.remote.naming_exceptionHelper.read (i); + } + + public void _write (org.omg.CORBA.portable.OutputStream o) + { + rogatkin.app.remote.naming_exceptionHelper.write (o, value); + } + + public org.omg.CORBA.TypeCode _type () + { + return rogatkin.app.remote.naming_exceptionHelper.type (); + } + +} diff --git a/src/rogatkin/app/remote/simple_naming.java b/src/rogatkin/app/remote/simple_naming.java new file mode 100644 index 0000000..7a3b9bd --- /dev/null +++ b/src/rogatkin/app/remote/simple_naming.java @@ -0,0 +1,13 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/simple_naming.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public interface simple_naming extends simple_namingOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity +{ +} // interface simple_naming diff --git a/src/rogatkin/app/remote/simple_namingHelper.java b/src/rogatkin/app/remote/simple_namingHelper.java new file mode 100644 index 0000000..205164e --- /dev/null +++ b/src/rogatkin/app/remote/simple_namingHelper.java @@ -0,0 +1,85 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/simple_namingHelper.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +abstract public class simple_namingHelper +{ + private static String _id = "IDL:rogatkin.app.remote/app/simple_naming:1.0"; + + public static void insert (org.omg.CORBA.Any a, rogatkin.app.remote.simple_naming that) + { + org.omg.CORBA.portable.OutputStream out = a.create_output_stream (); + a.type (type ()); + write (out, that); + a.read_value (out.create_input_stream (), type ()); + } + + public static rogatkin.app.remote.simple_naming extract (org.omg.CORBA.Any a) + { + return read (a.create_input_stream ()); + } + + private static org.omg.CORBA.TypeCode __typeCode = null; + synchronized public static org.omg.CORBA.TypeCode type () + { + if (__typeCode == null) + { + __typeCode = org.omg.CORBA.ORB.init ().create_interface_tc (rogatkin.app.remote.simple_namingHelper.id (), "simple_naming"); + } + return __typeCode; + } + + public static String id () + { + return _id; + } + + public static rogatkin.app.remote.simple_naming read (org.omg.CORBA.portable.InputStream istream) + { + return narrow (istream.read_Object (_simple_namingStub.class)); + } + + public static void write (org.omg.CORBA.portable.OutputStream ostream, rogatkin.app.remote.simple_naming value) + { + ostream.write_Object ((org.omg.CORBA.Object) value); + } + + public static rogatkin.app.remote.simple_naming narrow (org.omg.CORBA.Object obj) + { + if (obj == null) + return null; + else if (obj instanceof rogatkin.app.remote.simple_naming) + return (rogatkin.app.remote.simple_naming)obj; + else if (!obj._is_a (id ())) + throw new org.omg.CORBA.BAD_PARAM (); + else + { + org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate (); + rogatkin.app.remote._simple_namingStub stub = new rogatkin.app.remote._simple_namingStub (); + stub._set_delegate(delegate); + return stub; + } + } + + public static rogatkin.app.remote.simple_naming unchecked_narrow (org.omg.CORBA.Object obj) + { + if (obj == null) + return null; + else if (obj instanceof rogatkin.app.remote.simple_naming) + return (rogatkin.app.remote.simple_naming)obj; + else + { + org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate (); + rogatkin.app.remote._simple_namingStub stub = new rogatkin.app.remote._simple_namingStub (); + stub._set_delegate(delegate); + return stub; + } + } + +} diff --git a/src/rogatkin/app/remote/simple_namingHolder.java b/src/rogatkin/app/remote/simple_namingHolder.java new file mode 100644 index 0000000..ab3865f --- /dev/null +++ b/src/rogatkin/app/remote/simple_namingHolder.java @@ -0,0 +1,38 @@ +package rogatkin.app.remote; + +/** +* rogatkin/app/remote/simple_namingHolder.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public final class simple_namingHolder implements org.omg.CORBA.portable.Streamable +{ + public rogatkin.app.remote.simple_naming value = null; + + public simple_namingHolder () + { + } + + public simple_namingHolder (rogatkin.app.remote.simple_naming initialValue) + { + value = initialValue; + } + + public void _read (org.omg.CORBA.portable.InputStream i) + { + value = rogatkin.app.remote.simple_namingHelper.read (i); + } + + public void _write (org.omg.CORBA.portable.OutputStream o) + { + rogatkin.app.remote.simple_namingHelper.write (o, value); + } + + public org.omg.CORBA.TypeCode _type () + { + return rogatkin.app.remote.simple_namingHelper.type (); + } + +} diff --git a/src/rogatkin/app/remote/simple_namingOperations.java b/src/rogatkin/app/remote/simple_namingOperations.java new file mode 100644 index 0000000..d5a1774 --- /dev/null +++ b/src/rogatkin/app/remote/simple_namingOperations.java @@ -0,0 +1,17 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/simple_namingOperations.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public interface simple_namingOperations +{ + void bind1 (String name, org.omg.CORBA.Object o) throws rogatkin.app.remote.naming_exception; + void unbind1 (String name) throws rogatkin.app.remote.naming_exception; + org.omg.CORBA.Object lookup1 (String name) throws rogatkin.app.remote.naming_exception; + void list1 (String filter, rogatkin.app.remote.bind_listHolder bindings) throws rogatkin.app.remote.naming_exception; +} // interface simple_namingOperations diff --git a/src/rogatkin/app/remote/simple_namingPOA.java b/src/rogatkin/app/remote/simple_namingPOA.java new file mode 100644 index 0000000..57a0d1c --- /dev/null +++ b/src/rogatkin/app/remote/simple_namingPOA.java @@ -0,0 +1,123 @@ +package rogatkin.app.remote; + + +/** +* rogatkin/app/remote/simple_namingPOA.java . +* Generated by the IDL-to-Java compiler (portable), version "3.2" +* from idl/remotecontext.idl +* Wednesday, February 21, 2018 12:25:09 PM PST +*/ + +public abstract class simple_namingPOA extends org.omg.PortableServer.Servant + implements rogatkin.app.remote.simple_namingOperations, org.omg.CORBA.portable.InvokeHandler +{ + + // Constructors + + private static java.util.Hashtable _methods = new java.util.Hashtable (); + static + { + _methods.put ("bind1", new java.lang.Integer (0)); + _methods.put ("unbind1", new java.lang.Integer (1)); + _methods.put ("lookup1", new java.lang.Integer (2)); + _methods.put ("list1", new java.lang.Integer (3)); + } + + public org.omg.CORBA.portable.OutputStream _invoke (String $method, + org.omg.CORBA.portable.InputStream in, + org.omg.CORBA.portable.ResponseHandler $rh) + { + org.omg.CORBA.portable.OutputStream out = null; + java.lang.Integer __method = (java.lang.Integer)_methods.get ($method); + if (__method == null) + throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE); + + switch (__method.intValue ()) + { + case 0: // app/simple_naming/bind1 + { + try { + String name = in.read_string (); + org.omg.CORBA.Object o = org.omg.CORBA.ObjectHelper.read (in); + this.bind1 (name, o); + out = $rh.createReply(); + } catch (rogatkin.app.remote.naming_exception $ex) { + out = $rh.createExceptionReply (); + rogatkin.app.remote.naming_exceptionHelper.write (out, $ex); + } + break; + } + + case 1: // app/simple_naming/unbind1 + { + try { + String name = in.read_string (); + this.unbind1 (name); + out = $rh.createReply(); + } catch (rogatkin.app.remote.naming_exception $ex) { + out = $rh.createExceptionReply (); + rogatkin.app.remote.naming_exceptionHelper.write (out, $ex); + } + break; + } + + case 2: // app/simple_naming/lookup1 + { + try { + String name = in.read_string (); + org.omg.CORBA.Object $result = null; + $result = this.lookup1 (name); + out = $rh.createReply(); + org.omg.CORBA.ObjectHelper.write (out, $result); + } catch (rogatkin.app.remote.naming_exception $ex) { + out = $rh.createExceptionReply (); + rogatkin.app.remote.naming_exceptionHelper.write (out, $ex); + } + break; + } + + case 3: // app/simple_naming/list1 + { + try { + String filter = in.read_string (); + rogatkin.app.remote.bind_listHolder bindings = new rogatkin.app.remote.bind_listHolder (); + this.list1 (filter, bindings); + out = $rh.createReply(); + rogatkin.app.remote.bind_listHelper.write (out, bindings.value); + } catch (rogatkin.app.remote.naming_exception $ex) { + out = $rh.createExceptionReply (); + rogatkin.app.remote.naming_exceptionHelper.write (out, $ex); + } + break; + } + + default: + throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE); + } + + return out; + } // _invoke + + // Type-specific CORBA::Object operations + private static String[] __ids = { + "IDL:rogatkin.app.remote/app/simple_naming:1.0"}; + + public String[] _all_interfaces (org.omg.PortableServer.POA poa, byte[] objectId) + { + return (String[])__ids.clone (); + } + + public simple_naming _this() + { + return simple_namingHelper.narrow( + super._this_object()); + } + + public simple_naming _this(org.omg.CORBA.ORB orb) + { + return simple_namingHelper.narrow( + super._this_object(orb)); + } + + +} // class simple_namingPOA diff --git a/1.x/src/rogatkin/resource/splash.gif b/src/rogatkin/resource/splash.gif similarity index 100% rename from 1.x/src/rogatkin/resource/splash.gif rename to src/rogatkin/resource/splash.gif diff --git a/1.x/src/rogatkin/resource/systraymenu.properties b/src/rogatkin/resource/systraymenu.properties similarity index 100% rename from 1.x/src/rogatkin/resource/systraymenu.properties rename to src/rogatkin/resource/systraymenu.properties diff --git a/1.x/src/rogatkin/resource/systraymenu_ru.asis b/src/rogatkin/resource/systraymenu_ru.asis similarity index 100% rename from 1.x/src/rogatkin/resource/systraymenu_ru.asis rename to src/rogatkin/resource/systraymenu_ru.asis diff --git a/1.x/src/rogatkin/resource/tjws.gif b/src/rogatkin/resource/tjws.gif similarity index 100% rename from 1.x/src/rogatkin/resource/tjws.gif rename to src/rogatkin/resource/tjws.gif diff --git a/1.x/src/rogatkin/web/AsyncContextImpl.java b/src/rogatkin/web/AsyncContextImpl.java similarity index 100% rename from 1.x/src/rogatkin/web/AsyncContextImpl.java rename to src/rogatkin/web/AsyncContextImpl.java diff --git a/1.x/src/rogatkin/web/DualSocketAcceptor.java b/src/rogatkin/web/DualSocketAcceptor.java old mode 100644 new mode 100755 similarity index 50% rename from 1.x/src/rogatkin/web/DualSocketAcceptor.java rename to src/rogatkin/web/DualSocketAcceptor.java index 2dbea50..272ea23 --- a/1.x/src/rogatkin/web/DualSocketAcceptor.java +++ b/src/rogatkin/web/DualSocketAcceptor.java @@ -31,115 +31,41 @@ import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; -import java.net.Socket; import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; + +import com.rslakra.logger.LogManager; import Acme.Serve.SSLAcceptor; import Acme.Serve.Serve; public class DualSocketAcceptor extends SSLAcceptor { - protected static class TwoHeadServerSocket extends ServerSocket { - protected BlockingQueue requestQueue; - - protected ServerSocket socket1, socket2; - - private Thread currentThread; - - public TwoHeadServerSocket(ServerSocket socket1, ServerSocket socket2) throws IOException { - requestQueue = new LinkedBlockingQueue(1000); // ?? backlog - // ArrayBlockingQueue - Thread thread; - if (socket1 != null) { - thread = new Thread(new AcceptQueuer(socket1), "Accept processor 1"); - thread.setDaemon(true); - thread.start(); - this.socket1 = socket1; - } - if (socket2 != null) { - thread = new Thread(new AcceptQueuer(socket2), "Accept processor 2"); - thread.setDaemon(true); - thread.start(); - this.socket2 = socket2; - } - } - - public Socket accept() throws IOException { - Socket result; - currentThread = Thread.currentThread(); - for (;;) { - try { - result = requestQueue.poll(1000L, TimeUnit.SECONDS); - if (result != null) { - result.setSoTimeout(10*60*1000); // temp 10 mins - return result; - } - } catch (InterruptedException e) { - break; - } - } - throw new IOException(); - } - - public void close() throws IOException { - if (currentThread != null) - currentThread.interrupt(); - IOException ioe = null; - try { - socket1.close(); - } catch (IOException ioe1) { - ioe = ioe1; - } - socket2.close(); - if (ioe != null) - throw ioe; - } - - public String toString() { - return "" + socket1 + "/" + socket2; - } - - class AcceptQueuer implements Runnable { - ServerSocket socket; - - AcceptQueuer(ServerSocket socket) { - this.socket = socket; - } - - public void run() { - for (;;) - try { - requestQueue.put(socket.accept()); - } catch (InterruptedException e) { - return; - } catch (IOException e) { - break; - } - } - } - } - - public void init(Map inProperties, Map outProperties) throws IOException { + + /** + * @see Acme.Serve.SSLAcceptor#init(java.util.Map, java.util.Map) + */ + public void init(Map inProperties, Map outProperties) throws IOException { super.init(inProperties, outProperties); - int port = inProperties.get(Serve.ARG_PORT) != null ? ((Integer) inProperties.get(Serve.ARG_PORT)).intValue() - : Serve.DEF_PORT; + int port = inProperties.get(Serve.ARG_PORT) != null ? ((Integer) inProperties.get(Serve.ARG_PORT)).intValue() : Serve.DEF_PORT; int bl = 50; try { // TODO: consider conversion at getting the argument bl = Integer.parseInt((String) inProperties.get(ARG_BACKLOG)); - if (bl < 2) + if (bl < 2) { bl = 2; - } catch (Exception e) { + } + } catch (Exception ex) { + LogManager.error(ex); } + InetAddress ia = null; - if (inProperties.get(Serve.ARG_BINDADDRESS) != null) + if (inProperties.get(Serve.ARG_BINDADDRESS) != null) { try { ia = InetAddress.getByName((String) inProperties.get(Serve.ARG_BINDADDRESS)); - } catch (Exception e) { + } catch (Exception ex) { + LogManager.error(ex); } - + } + socket = new TwoHeadServerSocket(new ServerSocket(port, bl, ia), socket); } } \ No newline at end of file diff --git a/1.x/src/rogatkin/web/Multipart.java b/src/rogatkin/web/Multipart.java similarity index 67% rename from 1.x/src/rogatkin/web/Multipart.java rename to src/rogatkin/web/Multipart.java index 5a2109e..1cfb2ad 100644 --- a/1.x/src/rogatkin/web/Multipart.java +++ b/src/rogatkin/web/Multipart.java @@ -42,60 +42,67 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Part; -import rogatkin.web.WebAppServlet.ServletAccessDescr; +import Acme.IOHelper; import Acme.Utils; -import Acme.Serve.Serve; +import rogatkin.web.WebAppServlet.ServletAccessDescr; public class Multipart { private LinkedList parts; - private boolean tooLarge; - private IOException ioException; - Multipart(ServletRequest request, String boundary, ServletAccessDescr sad) { + Multipart(ServletRequest request, String boundary, ServletAccessDescr servletAccessDescr) { try { - String scl = ((HttpServletRequest) request).getHeader("content-length"); + String contentLengthHeader = ((HttpServletRequest) request).getHeader("content-length"); long contentLength = -1; - if (scl != null) + if (contentLengthHeader != null) try { - contentLength = Long.parseLong(scl); + contentLength = Long.parseLong(contentLengthHeader); } catch (NumberFormatException nfe) { } - if (contentLength > 0 && sad.multipartMaxRequest > 0 && sad.multipartMaxRequest < contentLength) - throw new IOException(String.format("Request size %d is bigger than limited by %d", contentLength, - sad.multipartMaxRequest)); - String encoding = request.getCharacterEncoding(); // TODO request.getLocale(); and calculate encoding - if (encoding == null) - encoding = Serve.UTF8; + if (contentLength > 0 && servletAccessDescr.multipartMaxRequest > 0 && servletAccessDescr.multipartMaxRequest < contentLength) { + throw new IOException(String.format("Request size %d is bigger than limited by %d", contentLength, servletAccessDescr.multipartMaxRequest)); + } + + // TODO request.getLocale(); and calculate encoding + String encoding = request.getCharacterEncoding(); + if (encoding == null) { + encoding = IOHelper.UTF_8; + } + ServletInputStream sis = request.getInputStream(); - parts = new LinkedList(); long bytesRead = 0; - parts_loop: do { - // read part +// parts_loop: + do { + // read part PartImpl pi = new PartImpl(); - long partSize = pi.readPart(encoding, boundary, sis, sad); - //System.err.printf("Loaded part %s of %d%n", pi, partSize); - if (partSize < 0) - bytesRead -= partSize; - else - bytesRead += partSize; - if ((sad.multipartMaxFile > 0 && pi.fileSize > sad.multipartMaxFile) - || (sad.multipartMaxRequest > 0 && sad.multipartMaxRequest < bytesRead)) + long partSize = pi.readPart(encoding, boundary, sis, servletAccessDescr); + // System.err.printf("Loaded part %s of %d%n", pi, partSize); + if (partSize < 0) { + bytesRead -= partSize; + } else { + bytesRead += partSize; + } + + if ((servletAccessDescr.multipartMaxFile > 0 && pi.fileSize > servletAccessDescr.multipartMaxFile) || (servletAccessDescr.multipartMaxRequest > 0 && servletAccessDescr.multipartMaxRequest < bytesRead)) { tooLarge = true; - else + } else { parts.add(pi); - //System.err.printf("Loaded part too large %b - %d%n", tooLarge, bytesRead); - if (partSize < 0) + } + + // System.err.printf("Loaded part too large %b - %d%n", + // tooLarge, bytesRead); + if (partSize < 0) { break; + } } while (tooLarge == false && (contentLength < 0 || contentLength > 0 && bytesRead < contentLength)); } catch (IOException ioe) { ioException = ioe; } } - + LinkedList getParts() throws IOException { if (ioException != null) throw ioException; @@ -103,7 +110,7 @@ LinkedList getParts() throws IOException { throw new IllegalStateException("Request or its parts too large"); return parts; } - + Part getPart(String n) throws IOException { if (ioException != null) throw ioException; @@ -114,33 +121,32 @@ Part getPart(String n) throws IOException { return p; return null; } - + static class PartImpl implements Part { private static final int BUFF_SIZE = 32; HashMap headers = new HashMap(6); - + ByteArrayOutputStream cos = new ByteArrayOutputStream(1024 * 4); - + String name, filename; - + File partFile; - + long fileSize; - + private final static int no_rn = 1; - + private final static int last_r = 2; - + private final static int last_rn = 3; - - long readPart(String encoding, String boundary, ServletInputStream sis, ServletAccessDescr sad) - throws IOException { + + long readPart(String encoding, String boundary, ServletInputStream sis, ServletAccessDescr sad) throws IOException { long currentPos = 0; byte[] buff = new byte[BUFF_SIZE * 1024]; int boundaryLen = boundary.length(); if (boundaryLen >= (buff.length - 2)) - throw new IOException("Boundary length exceeds allowed:" + boundaryLen+"/"+(buff.length-2)); + throw new IOException("Boundary length exceeds allowed:" + boundaryLen + "/" + (buff.length - 2)); String hl; int ss; // parse part headers @@ -150,18 +156,18 @@ long readPart(String encoding, String boundary, ServletInputStream sis, ServletA throw new IOException("Trying reading parts after EOS"); currentPos += len; if (buff[len - 1] != '\n') - throw new IOException("Part header is over " + buff.length); + throw new IOException("Part header is over " + buff.length); hl = new String(buff, 0, len - 2, "US-ASCII"); - //System.err.println("h:" + hl); + // System.err.println("h:" + hl); if (hl.length() == 0) break; ss = hl.indexOf(boundary); if (ss >= 0) { - if (hl.indexOf("--", boundaryLen+ss) == boundaryLen+ss) + if (hl.indexOf("--", boundaryLen + ss) == boundaryLen + ss) return -currentPos; // continue; // 1st part starts with it } - + hl = new String(buff, 0, len - 2, encoding); ss = hl.indexOf(':'); if (ss < 0) @@ -172,118 +178,128 @@ long readPart(String encoding, String boundary, ServletInputStream sis, ServletA if (header.equals("Content-Disposition".toLowerCase())) { // TODO add real parser as for cookies if (name != null) - throw new IOException("Multiple header 'Content-Disposition' for the same part: "+hl); + throw new IOException("Multiple header 'Content-Disposition' for the same part: " + hl); int ni = value.toLowerCase().indexOf("name=\""); if (ni < 0) throw new IOException("Part name is missed in 'Content-Disposition'" + hl); int eq = value.indexOf('"', ni + "name=\"".length()); - // TODO name can be encoded so right approach is decoding it here + // TODO name can be encoded so right approach is decoding it + // here name = value.substring(ni + "name=\"".length(), eq); ni = value.toLowerCase().indexOf("filename=\""); if (ni >= 0) { - eq = value.indexOf('"', ni + "filename=\"".length()); - filename = value.substring(ni + "filename=\"".length(), eq); + eq = value.indexOf('"', ni + "filename=\"".length()); + filename = value.substring(ni + "filename=\"".length(), eq); } } - // TODO Analyze content-type multipart/mixed defining new boundary, so they need to be stacked + // TODO Analyze content-type multipart/mixed defining new + // boundary, so they need to be stacked } while (true); - // TODO for content type multipart/mixed need another loop for another boundary + // TODO for content type multipart/mixed need another loop for + // another boundary // read part content fileSize = 0; boolean writingInMem = sad.multipartThreshold > 0; OutputStream wos = cos; int state = no_rn; - + try { - read_part: do { + read_part: + do { int len = sis.readLine(buff, 0, buff.length); if (len < 0) - throw new IOException("Unexpected end of multipart data at "+currentPos); - //System.err.println("" + len + "==" + new String(buff, 0, len)); - + throw new IOException("Unexpected end of multipart data at " + currentPos); + // System.err.println("" + len + "==" + new String(buff, 0, + // len)); + switch (state) { - case no_rn: - if (buff[len - 1] == '\n') { - if (len > 1) + case no_rn: + if (buff[len - 1] == '\n') { + if (len > 1) + if (buff[len - 2] == '\r') { + wos.write(buff, 0, len - 2); + fileSize += len - 2; + state = last_rn; + break; + } + } else if (buff[len - 1] == '\r') { + wos.write(buff, 0, len - 1); + fileSize += len - 1; + state = last_r; + break; + } + wos.write(buff, 0, len); + fileSize += len; + break; + case last_r: + if (buff[len - 1] == '\n') { + if (len == 1) { + state = last_rn; + break; + } + if (buff[len - 2] == '\r') { + wos.write('\r'); + fileSize++; wos.write(buff, 0, len - 2); fileSize += len - 2; state = last_rn; break; } - } else if (buff[len - 1] == '\r') { - wos.write(buff, 0, len - 1); - fileSize += len - 1; - state = last_r; - break; - } - wos.write(buff, 0, len); - fileSize += len; - break; - case last_r: - if (buff[len - 1] == '\n') { - if (len == 1) { - state = last_rn; - break; - } - - if (buff[len - 2] == '\r') { + } else if (buff[len - 1] == '\r') { wos.write('\r'); fileSize++; - wos.write(buff, 0, len - 2); - fileSize += len - 2; - state = last_rn; + wos.write(buff, 0, len - 1); + fileSize += len - 1; + state = last_r; break; - } - } else if (buff[len - 1] == '\r') { + } wos.write('\r'); fileSize++; - wos.write(buff, 0, len - 1); - fileSize += len - 1; - state = last_r; + wos.write(buff, 0, len); + fileSize += len; + state = no_rn; break; - } - wos.write('\r'); - fileSize++; - wos.write(buff, 0, len); - fileSize += len; - state = no_rn; - break; - case last_rn: - if (buff[len - 1] == '\n') { - if (len > 1) - if (buff[len - 2] == '\r') { - hl = new String(buff, 0, len - 2, "US-ASCII"); - ss = hl.indexOf(boundary); - if (ss >= 0) { - if (hl.indexOf("--", ss + boundaryLen) == (ss + boundaryLen)) - return -currentPos -fileSize; - else - break read_part; - } else { - wos.write('\r'); - fileSize++; - wos.write('\n'); - fileSize++; - wos.write(buff, 0, len - 2); - fileSize += len - 2; - break; + case last_rn: + if (buff[len - 1] == '\n') { + if (len > 1) + if (buff[len - 2] == '\r') { + hl = new String(buff, 0, len - 2, "US-ASCII"); + ss = hl.indexOf(boundary); + if (ss >= 0) { + if (hl.indexOf("--", ss + boundaryLen) == (ss + boundaryLen)) + return -currentPos - fileSize; + else + break read_part; + } else { + wos.write('\r'); + fileSize++; + wos.write('\n'); + fileSize++; + wos.write(buff, 0, len - 2); + fileSize += len - 2; + break; + } } - } - } else if (buff[len - 1] == '\r') { // can't be boundary limiter since buffer is bigger than boundary - - } - wos.write('\r'); - fileSize++; - wos.write('\n'); - fileSize++; - wos.write(buff, 0, len); - fileSize += len; - state = no_rn; - break; - default: - throw new IllegalStateException(); + } else if (buff[len - 1] == '\r') { // can't be + // boundary + // limiter since + // buffer is + // bigger than + // boundary + + } + wos.write('\r'); + fileSize++; + wos.write('\n'); + fileSize++; + wos.write(buff, 0, len); + fileSize += len; + state = no_rn; + break; + default: + throw new IllegalStateException(); } if (sad.multipartMaxFile > 0 && sad.multipartMaxFile <= fileSize) throw new IOException("File size exceeds limit of " + sad.multipartMaxFile); @@ -299,7 +315,7 @@ long readPart(String encoding, String boundary, ServletInputStream sis, ServletA cos = null; writingInMem = false; } - } while (true); // TODO add condition + } while (true); // TODO add condition } finally { if (wos != null) { // can b e null ? try { @@ -310,7 +326,7 @@ long readPart(String encoding, String boundary, ServletInputStream sis, ServletA } return currentPos + fileSize; } - + @Override public void delete() throws IOException { if (cos != null) { @@ -321,22 +337,22 @@ public void delete() throws IOException { if (partFile.delete() == false) throw new IOException("Can't delete part:" + partFile); } - + @Override public String getContentType() { return getHeader("content-type"); } - + @Override public String getHeader(String header) { return headers.get(header.toLowerCase()); } - + @Override public Collection getHeaderNames() { return headers.keySet(); } - + @Override public Collection getHeaders(String header) { LinkedList result = new LinkedList(); @@ -344,7 +360,7 @@ public Collection getHeaders(String header) { result.add(getHeader(header)); return result; } - + @Override public InputStream getInputStream() throws IOException { if (cos != null) @@ -352,19 +368,19 @@ public InputStream getInputStream() throws IOException { else return new FileInputStream(partFile); } - + @Override public String getName() { return name; } - + @Override public long getSize() { if (cos != null) return cos.size(); return partFile.length(); } - + @Override public void write(String file) throws IOException { if (cos != null) { @@ -387,27 +403,28 @@ public void write(String file) throws IOException { try { in.close(); } catch (IOException e) { - + } if (out != null) try { out.close(); } catch (IOException e) { - + } } } else partFile = targetFile; } } - // no override to kepp 3.0 compatible + + // no override to kepp 3.0 compatible public String getSubmittedFileName() { return filename; } @Override public String toString() { - return "Part '" + name + "' of "+fileSize+" :" + (cos != null ? cos.toString() : partFile); + return "Part '" + name + "' of " + fileSize + " :" + (cos != null ? cos.toString() : partFile); } } } diff --git a/1.x/src/rogatkin/web/SessionCookieConfigImpl.java b/src/rogatkin/web/SessionCookieConfigImpl.java similarity index 95% rename from 1.x/src/rogatkin/web/SessionCookieConfigImpl.java rename to src/rogatkin/web/SessionCookieConfigImpl.java index 6205a15..8b58dd0 100644 --- a/1.x/src/rogatkin/web/SessionCookieConfigImpl.java +++ b/src/rogatkin/web/SessionCookieConfigImpl.java @@ -28,87 +28,81 @@ public class SessionCookieConfigImpl implements SessionCookieConfig { private String comment; - private String domain; - private int maxAge; - private String name; - private String path; - private boolean http; - private boolean secure; - + @Override public String getComment() { return comment; } - + @Override public String getDomain() { return domain; } - + @Override public int getMaxAge() { return maxAge; } - + @Override public String getName() { return name; } - + @Override public String getPath() { return path; } - + @Override public boolean isHttpOnly() { return http; } - + @Override public boolean isSecure() { return secure; } - + @Override public void setComment(String comment) { this.comment = comment; } - + @Override public void setDomain(String domain) { this.domain = domain; } - + @Override public void setHttpOnly(boolean set) { this.http = set; } - + @Override public void setMaxAge(int maxAge) { this.maxAge = maxAge; } - + @Override public void setName(String name) { this.name = name; } - + @Override public void setPath(String path) { this.path = path; } - + @Override public void setSecure(boolean secure) { this.secure = secure; } - + } diff --git a/1.x/src/rogatkin/web/SysTrayControl.java b/src/rogatkin/web/SysTrayControl.java similarity index 100% rename from 1.x/src/rogatkin/web/SysTrayControl.java rename to src/rogatkin/web/SysTrayControl.java diff --git a/src/rogatkin/web/TwoHeadServerSocket.java b/src/rogatkin/web/TwoHeadServerSocket.java new file mode 100644 index 0000000..b354d8a --- /dev/null +++ b/src/rogatkin/web/TwoHeadServerSocket.java @@ -0,0 +1,93 @@ +/** + * + */ +package rogatkin.web; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * @author Rohtash Singh Lakra (Rohtash.Lakra@nasdaq.com) + * @date 03/19/2018 05:15:44 PM + */ +public class TwoHeadServerSocket extends ServerSocket { + protected BlockingQueue requestQueue; + protected ServerSocket socket1, socket2; + private Thread currentThread; + + public TwoHeadServerSocket(ServerSocket socket1, ServerSocket socket2) throws IOException { + requestQueue = new LinkedBlockingQueue(1000); // ?? backlog + // ArrayBlockingQueue + Thread thread; + if (socket1 != null) { + thread = new Thread(new AcceptQueuer(socket1), "Accept processor 1"); + thread.setDaemon(true); + thread.start(); + this.socket1 = socket1; + } + if (socket2 != null) { + thread = new Thread(new AcceptQueuer(socket2), "Accept processor 2"); + thread.setDaemon(true); + thread.start(); + this.socket2 = socket2; + } + } + + public Socket accept() throws IOException { + Socket result; + currentThread = Thread.currentThread(); + for (;;) { + try { + result = requestQueue.poll(1000L, TimeUnit.SECONDS); + if (result != null) { + result.setSoTimeout(10 * 60 * 1000); // temp 10 mins + return result; + } + } catch (InterruptedException e) { + break; + } + } + throw new IOException(); + } + + public void close() throws IOException { + if (currentThread != null) + currentThread.interrupt(); + IOException ioe = null; + try { + socket1.close(); + } catch (IOException ioe1) { + ioe = ioe1; + } + socket2.close(); + if (ioe != null) + throw ioe; + } + + public String toString() { + return "" + socket1 + "/" + socket2; + } + + class AcceptQueuer implements Runnable { + ServerSocket socket; + + AcceptQueuer(ServerSocket socket) { + this.socket = socket; + } + + public void run() { + for (;;) + try { + requestQueue.put(socket.accept()); + } catch (InterruptedException e) { + return; + } catch (IOException e) { + break; + } + } + } +} diff --git a/src/rogatkin/web/WarRoller.java b/src/rogatkin/web/WarRoller.java new file mode 100644 index 0000000..ab54e02 --- /dev/null +++ b/src/rogatkin/web/WarRoller.java @@ -0,0 +1,415 @@ +/* tjws - WarRoller.java + * Copyright (C) 2004-2010 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: WarRoller.java,v 1.30 2013/07/02 07:11:28 cvs Exp $ + * Created on Dec 13, 2004 + */ +package rogatkin.web; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import javax.servlet.ServletException; + +import Acme.Utils; +import Acme.Serve.Serve; +import Acme.Serve.WarDeployer; + +public class WarRoller implements WarDeployer { + + public static final String DEPLOY_ARCH_EXT = ".war"; + + public static final String DEPLOYMENT_DIR_TARGET = ".web-apps-target"; + + public static final String DEF_DEPLOY_DYNAMICALLY = "tjws.wardeploy.dynamically"; + + public static final String DEF_DEPLOY_NOINCREMENTAL = "tjws.wardeploy.noincremental"; + + public static final String DEF_VIRTUAL = "tjws.virtual"; + + public static final String DEPLOY_FAILED_EXT = ".failed"; + + /** + * in deploy mode scans for all wars in war directory (app deployment dir) + * for each war looks in corresponding place of deploy directory and figures + * a difference, like any file in war exists and no corresponding file in + * deploy directory or it's older if difference positive, then delete target + * deploy directory unpack war if run mode process all WEB-INF/web.xml and + * build app descriptor, including context name, servlet names, servlet + * urls, class parameters process every app descriptor as standard servlet + * connection proc dispatch for every context name assigned an app + * dispatcher, it uses the rest to find servlet and do resource mapping + * + */ + + public void deploy(File warDir, final File deployTarDir, final String virtualHost) { + // by list + if (warDir.listFiles(new FileFilter() { + public boolean accept(File pathname) { + if (pathname.isFile() && pathname.getName().toLowerCase().endsWith(DEPLOY_ARCH_EXT)) { + deployWar(pathname, deployTarDir); + return true; + } + return false; + } + }).length == 0) + server.log("No .war packaged web apps found in " + (virtualHost == null ? "default" : virtualHost)); + if (deployTarDir.listFiles(new FileFilter() { + public boolean accept(File file) { + if (file.isDirectory()) + try { + attachApp(WebAppServlet.create(file, file.getName(), server, virtualHost), virtualHost); + markSucceeded(file.getParentFile(), file.getName()); // assumes + // that + // parent + // always + // exists + return true; + } catch (ServletException se) { + server.log("Deployment of aplication " + file.getName() + " failed, reason: " + se.getRootCause(), se.getRootCause()); + } catch (Throwable t) { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + server.log("Unexpected problem in deployment of application " + file.getName(), t); + } + return false; + } + }).length == 0) + server.log("No web apps have been deployed in " + (virtualHost == null ? "default" : virtualHost)); + } + + public boolean deployWar(File warFile, File deployTarDir) { + String context = warFile.getName(); + assert context.toLowerCase().endsWith(DEPLOY_ARCH_EXT); + context = context.substring(0, context.length() - DEPLOY_ARCH_EXT.length()); + File failedMark = new File(deployTarDir, context + DEPLOY_FAILED_EXT); + if (failedMark.exists() && failedMark.lastModified() > warFile.lastModified()) + return false; // skipping deploy failed + + server.log("Deploying " + context); + ZipFile zipFile = null; + File deployDir = new File(deployTarDir, context); + boolean noincremental = System.getProperty(DEF_DEPLOY_NOINCREMENTAL) != null; + if (assureDir(deployDir) == false) { + server.log("Can't reach deployment dir " + deployDir); + return false; + } + Exception lastException = null; + deploy: + do { + try { + // some overhead didn't check that doesn't exist + zipFile = new ZipFile(warFile); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry ze = entries.nextElement(); + String en = ze.getName(); + if (File.separatorChar == '/') + en = en.replace('\\', File.separatorChar); + File outFile = new File(deployDir, en); + if (ze.isDirectory()) { + outFile.mkdirs(); + } else { + OutputStream os = null; + InputStream is = null; + File parentFile = outFile.getParentFile(); + if (parentFile.exists() == false) + parentFile.mkdirs(); + if (outFile.exists() && outFile.lastModified() >= ze.getTime()) { + continue; + } + if (noincremental) { + deleteFiles(deployDir, deployDir.list()); + noincremental = false; + continue deploy; + } + try { + os = new FileOutputStream(outFile); + is = zipFile.getInputStream(ze); + copyStream(is, os); + } catch (IOException ioe2) { + server.log("Problem in extracting " + en + " " + ioe2); + // TODO decide to propagate the exception up and + // stop deployment? + lastException = ioe2; + } finally { + try { + os.close(); + } catch (Exception e2) { + + } + try { + is.close(); + } catch (Exception e2) { + + } + } + outFile.setLastModified(ze.getTime()); + } + } + } catch (ZipException ze) { + server.log("Invalid .war format"); + lastException = ze; + } catch (IOException ioe) { + server.log("Can't read " + warFile + "/ " + ioe); + lastException = ioe; + } finally { + try { + zipFile.close(); + } catch (Exception e) { + + } + zipFile = null; + } + } while (false); + if (lastException == null) { + deployDir.setLastModified(warFile.lastModified()); + return true; + } + deployDir.setLastModified(0); + return false; + } + + protected void attachApp(WebAppServlet appServlet, String virtualHost) { + server.addServlet(appServlet.contextPath + "/*", appServlet, virtualHost); + } + + /** + * Returns auto deployment directory + *

+ * The method can be overriden to give more control of choosing the + * directory + * + * @return autodeployment directory location as local file system string + */ + protected String getDeployDirectory() { + String webapp_dir = System.getProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR); + if (webapp_dir == null) + webapp_dir = System.getProperty("user.dir") + File.separator + "webapps"; + return webapp_dir; + } + + public void deploy(Serve server) { + this.server = server; + final File file_webapp = new File(getDeployDirectory()); + if (assureDir(file_webapp) == false) { + server.log("Deployment source location " + file_webapp + " isn't a directory, deployment is impossible."); + return; + } + final File file_deployDir = new File(file_webapp, DEPLOYMENT_DIR_TARGET); + if (assureDir(file_deployDir) == false) { + server.log("Target deployment location " + file_deployDir + " isn't a directory, deployment is impossible."); + return; + } + deploy(file_webapp, file_deployDir, null); + + int td = 0; + if (System.getProperty(DEF_DEPLOY_DYNAMICALLY) != null) { + td = 20; + try { + td = Integer.parseInt(System.getProperty(DEF_DEPLOY_DYNAMICALLY)); + } catch (NumberFormatException nfe) { + server.log("Default redeployment check interval: " + td + " is used"); + } + } + final int interval = td * 1000; + createWatcherThread(file_webapp, file_deployDir, interval, null); + if (null != System.getProperty(DEF_VIRTUAL)) { + file_webapp.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + String virtualHost; + if (pathname.isDirectory() && (virtualHost = pathname.getName()).equals(DEPLOYMENT_DIR_TARGET) == false) { + + final File file_deployDir = new File(pathname, DEPLOYMENT_DIR_TARGET); + if (assureDir(file_deployDir) == false) { + WarRoller.this.server.log("Target deployment location " + file_deployDir + " isn't a directory, deployment is impossible."); + } else { + deploy(pathname, file_deployDir, virtualHost); + createWatcherThread(pathname, file_deployDir, interval, virtualHost); + return true; + } + } + return false; + } + }); + } + } + + protected void createWatcherThread(final File file_webapp, final File file_deployDir, final int interval, final String virtualHost) { + if (interval <= 0) + return; + Thread watcher = new Thread("Deploy update watcher for " + (virtualHost == null ? "main" : virtualHost)) { + public void run() { + for (;;) + try { + deployWatch(file_webapp, file_deployDir, virtualHost); + } catch (Throwable t) { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + WarRoller.this.server.log("Unhandled " + t, t); + } finally { + try { + Thread.sleep(interval); + } catch (InterruptedException e) { + break; + } + } + } + }; + watcher.setDaemon(true); + watcher.start(); + } + + protected boolean assureDir(File fileDir) { + if (fileDir.exists() == false) + fileDir.mkdirs(); + return fileDir.isDirectory(); + } + + protected synchronized void deployWatch(File warDir, final File deployTarDir, String virtualHost) { + server.setHost(virtualHost); + final HashSet apps = new HashSet(); + warDir.listFiles(new FileFilter() { + public boolean accept(File file) { + if (file.isDirectory() == false) { + String name = file.getName(); + if (name.endsWith(DEPLOY_ARCH_EXT)) + apps.add(name.substring(0, name.length() - DEPLOY_ARCH_EXT.length())); + } + return false; + } + }); + + Enumeration servlets = server.getServlets(); + ArrayList markedServlets = new ArrayList(10); + while (servlets.hasMoreElements()) { + Object servlet = servlets.nextElement(); + if (servlet instanceof WebAppServlet) { + WebAppServlet was = (WebAppServlet) servlet; + String name = was.deployDir.getName(); + File war = new File(warDir, name + DEPLOY_ARCH_EXT); + apps.remove(name); + if (war.exists() && war.lastModified() > was.deployDir.lastModified()) { + // deployWar(new File(warDir, was.deployDir.getName() + + // DEPLOY_ARCH_EXT), deployTarDir); + markedServlets.add(was); + } + } + } + + for (WebAppServlet was : markedServlets) { + redeploy(warDir, deployTarDir, was, virtualHost); + } + + for (String name : apps) { + // remaining not deployed yet apps + try { + if (deployWar(new File(warDir, name + DEPLOY_ARCH_EXT), deployTarDir)) { + WebAppServlet was = WebAppServlet.create(new File(deployTarDir, name), name, server, virtualHost); + attachApp(was, virtualHost); + } + } catch (Throwable t) { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + markFailed(deployTarDir, name); + server.log("Unexpected problem in deployment of aplication " + name, t); + } + } + } + + public void redeploy(File warDir, File deployTarDir, WebAppServlet was, String virtualHost) { + was = (WebAppServlet) server.unloadServlet(was); + if (was == null) + return; + server.unloadSessions(was.getServletContext()); + was.destroy(); + + // TODO use pre-saved war name + if (deployWar(new File(warDir, was.deployDir.getName() + DEPLOY_ARCH_EXT), deployTarDir)) + try { + was = WebAppServlet.create(was.deployDir, was.deployDir.getName(), server, virtualHost); + attachApp(was, virtualHost); + server.restoreSessions(was.getServletContext()); + markSucceeded(deployTarDir, was.deployDir.getName()); + } catch (ServletException sex) { + markFailed(deployTarDir, was.deployDir.getName()); + server.log("Deployment of a web app " + was.contextName + " failed due " + sex.getRootCause(), sex.getRootCause()); + } catch (Throwable t) { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + markFailed(deployTarDir, was.deployDir.getName()); + server.log("Unexpected problem in deployment of aplication " + was.contextName, t); + } + } + + static private boolean markFailed(File deployTarDir, String appName) { + File markFile = new File(deployTarDir, appName + DEPLOY_FAILED_EXT); + + if (markFile.exists()) { + File appDeployDir = new File(deployTarDir, appName); + if (appDeployDir.exists()) + markFile.setLastModified(appDeployDir.lastModified() + 1); + return true; + } + try { + return markFile.createNewFile(); + } catch (IOException e) { + return false; + } + } + + static private boolean markSucceeded(File deployTarDir, String appName) { + if (new File(deployTarDir, appName + DEPLOY_FAILED_EXT).exists()) + return new File(deployTarDir, appName + DEPLOY_FAILED_EXT).delete(); + return true; + } + + static void copyStream(InputStream is, OutputStream os) throws IOException { + Utils.copyStream(is, os, -1); + } + + static void deleteFiles(File folder, String[] files) throws IOException { + for (String fn : files) { + File f = new File(folder, fn); + if (f.isDirectory()) { + deleteFiles(f, f.list()); + if (f.delete() == false) + throw new IOException("Can't delete :" + f); + } else { + if (f.delete() == false) + throw new IOException("Can't delete :" + f); + } + } + } + + protected Serve server; +} \ No newline at end of file diff --git a/1.x/src/rogatkin/web/WebApp.java b/src/rogatkin/web/WebApp.java similarity index 83% rename from 1.x/src/rogatkin/web/WebApp.java rename to src/rogatkin/web/WebApp.java index 85a8fda..7099e1a 100644 --- a/1.x/src/rogatkin/web/WebApp.java +++ b/src/rogatkin/web/WebApp.java @@ -41,26 +41,27 @@ import java.net.URL; import java.net.URLConnection; +import Acme.IOHelper; import Acme.Utils; import Acme.Serve.Main; -public class WebApp { +public class WebApp { Main main; public static final String RUN_DESCRIPTOR = "rundescriptor"; - public static final String DEF_WEBAPP_AUTODEPLOY_DIR = "tjws.webappdir"; - public static final String DEF_WEBAPP_CLASSLOADER = "tjws.webclassloader"; - static boolean restart; - + /** * @param args, - * 1st specifies .war file location others can match standard If no parameters specifies it considered as all in one and takes run descriptor + * 1st specifies .war file location others can match standard If + * no parameters specifies it considered as all in one and takes + * run descriptor * from /app/rundescriptor *

- * rundescriptor file has multiple lines, 1st define command line argument
+ * rundescriptor file has multiple lines, 1st define command line + * argument
* following define names of .wars in /app/ */ public static void main(String[] args) { @@ -71,16 +72,20 @@ public static void main(String[] args) { System.exit(1); // message already printed return; } - //deployDir.deleteOnExit(); // TODO make it more consistent and provide directory deletion in on exit hook + // deployDir.deleteOnExit(); // TODO make it more consistent and + // provide directory deletion in on exit hook System.setProperty(DEF_WEBAPP_AUTODEPLOY_DIR, deployDir.getPath()); - } else + } else { deployDir = new File(System.getProperty(DEF_WEBAPP_AUTODEPLOY_DIR)); + } + ServiceController ctrl = null; try { ctrl = (ServiceController) Class.forName("rogatkin.web.SysTrayControl").newInstance(); } catch (Exception ex) { // ex.printStackTrace(); } + URL warUrl = null; if (args.length == 0) { String[] descr = readDescriptor(); @@ -101,6 +106,7 @@ public static void main(String[] args) { return; } } + if (warUrl != null) try { copyWar(warUrl, deployDir); @@ -114,34 +120,30 @@ public boolean accept(File dir, String name) { webapps[i] = webapps[i].substring(0, webapps[i].length() - WarRoller.DEPLOY_ARCH_EXT.length()); ctrl.attachServe(getStopMethod(), getRestartMethod(), webapps); } + do { restart = false; - if (Main.main1(ctrl.massageSettings(args)) == 3 && ctrl != null) { + if (Main.runMain(ctrl.massageSettings(args)) == 3 && ctrl != null) { if (ctrl.reportError(3, "Port conflict")) restart = true; } - } while(restart); + } while (restart); } catch (IOException ioe) { - System.err.printf("Can't copy war %s file to the deployment directory %s exception %s%n", warUrl, - deployDir, ioe); + System.err.printf("Can't copy war %s file to the deployment directory %s exception %s%n", warUrl, deployDir, ioe); System.exit(2); } } - + public static String[] readDescriptor() { BufferedReader br = null; try { - br = new BufferedReader(new InputStreamReader(WebApp.class.getClassLoader().getResourceAsStream( - RUN_DESCRIPTOR), "utf-8")); + br = new BufferedReader(new InputStreamReader(WebApp.class.getClassLoader().getResourceAsStream(RUN_DESCRIPTOR), "utf-8")); // read CLA String parameters = br.readLine(); // can be loop if more than one war return new String[] { parameters, br.readLine() }; } catch (NullPointerException npe) { - System.err - .printf( - "No .war file argument provided and there is no '%s' descriptor for embedded app in the jar packaging%n", - RUN_DESCRIPTOR); + System.err.printf("No .war file argument provided and there is no '%s' descriptor for embedded app in the jar packaging%n", RUN_DESCRIPTOR); return null; } catch (UnsupportedEncodingException e) { System.err.printf("Unsupported ecoding %s%n", e); @@ -150,24 +152,20 @@ public static String[] readDescriptor() { System.err.printf("IO error (%s) at reading app descriptor%n", ioe); return null; } finally { - if (br != null) - try { - br.close(); - } catch (IOException ioe) { - - } + IOHelper.closeSilently(br); } } - + private static Method getStopMethod() { try { return Main.class.getDeclaredMethod("stop"); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } + return null; } - + private static Method getRestartMethod() { try { return WebApp.class.getDeclaredMethod("setRestart"); @@ -181,56 +179,66 @@ public static void setRestart() { restart = true; } + /** + * + * @param key + * @return + */ public static File getDeployDirectory(String key) { String dirName = System.getProperty("java.io.tmpdir"); if (dirName == null) { dirName = System.getProperty("user.home"); - if (dirName == null) + if (dirName == null) { dirName = "."; + } } + File result = new File(dirName, key); try { result = result.getCanonicalFile(); - result.mkdirs(); // no check because can be existent + // no check because can be existent + result.mkdirs(); return result; } catch (IOException e) { System.err.printf("Can't create a deployment directory: %s %s%n", e, result); } return null; } - + + /** + * + * @param sourceWar + * @param deploymentDir + * @throws IOException + */ public static void copyWar(URL sourceWar, File deploymentDir) throws IOException { File targetWar = new File(deploymentDir, new File(sourceWar.getFile()).getName()); URLConnection uc = sourceWar.openConnection(); - if (targetWar.exists() && targetWar.lastModified() >= uc.getLastModified()) + if (targetWar.exists() && targetWar.lastModified() >= uc.getLastModified()) { return; + } + OutputStream os = null; InputStream is = null; try { Utils.copyStream(is = uc.getInputStream(), os = new FileOutputStream(targetWar), -1); } finally { - try { - os.close(); - } catch (Exception e) { - } - try { - is.close(); - } catch (Exception e) { - } + IOHelper.closeSilently(os); + IOHelper.closeSilently(is); } targetWar.setLastModified(uc.getLastModified()); } - public static interface ServiceController { void attachServe(Method stop, Method restart, String[] contextPaths); - + String[] massageSettings(String[] args); boolean reportError(int code, String message); } - /** provides connection to Context.xml + /** + * provides connection to Context.xml * * @author dmitriy * @@ -238,12 +246,12 @@ public static interface ServiceController { public static class MetaContext { private String path; private ClassLoader appClassLoader; - + public MetaContext(String contextPath, ClassLoader cl) { path = contextPath; appClassLoader = cl; } - + public String getPath() { return path; } @@ -251,5 +259,5 @@ public String getPath() { public ClassLoader getClassLoader() { return appClassLoader; } - } + } } diff --git a/1.x/src/rogatkin/web/WebAppServlet.java b/src/rogatkin/web/WebAppServlet.java old mode 100644 new mode 100755 similarity index 60% rename from 1.x/src/rogatkin/web/WebAppServlet.java rename to src/rogatkin/web/WebAppServlet.java index 2f622e7..37d50bf --- a/1.x/src/rogatkin/web/WebAppServlet.java +++ b/src/rogatkin/web/WebAppServlet.java @@ -61,10 +61,10 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.regex.Pattern; import java.util.zip.GZIPOutputStream; -import java.util.jar.JarFile; -import java.util.jar.JarEntry; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; @@ -102,7 +102,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; @@ -118,6 +117,7 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +import Acme.IOHelper; import Acme.Utils; import Acme.Serve.FileServlet; import Acme.Serve.Serve; @@ -129,81 +129,82 @@ */ public class WebAppServlet extends HttpServlet implements ServletContext { public static final String DEF_DEBUG = "tjws.webapp.debug"; - + public static final String WAR_NAME_AS_CONTEXTPATH = "tjws.wardeploy.warname-as-context"; - + public static final String WAR_DEPLOY_IN_ROOT = "tjws.wardeploy.as-root"; public static final String RUNTIMEENV_ATTR = "##RuntimeEnv"; - + static final String MULTIPART_ERR_MSQ = "Request isn't multipart/form-data type or processing it is not enabled in deplyment descriptor web.xml"; - + protected static final String WEBAPPCLASSLOADER = "rogatkin.webapp.AppClassLoader"; - + protected static final String WEBAPPINITTIMEOUT = "tjws.webapp.%s.init.timeout"; // in // seconds - + List servlets; - + List filters; - + URL[] cpUrls; - + ClassLoader ucl; - + private static AppContextDelegator appContextDelegator; private static Object runtimeEnv; - + File deployDir; - + Serve server; - + int sessionTimeout; - + int initTimeout; - + boolean noAnnot; // ignore @WebServlet @WebFilter and @WebListener - + ThreadPoolExecutor asyncThreads; - + // / context methods protected String contextName; - + protected String contextPath; protected String virtualHost; - - //protected String origContextName, origContextPath; - + + // protected String origContextName, origContextPath; + protected String description; - + protected Hashtable attributes; - + protected Hashtable contextParameters; - + protected List welcomeFiles; - + protected List errorPages; - + protected List listeners; - + protected List sessionListeners; - + protected ArrayList requestListeners; - + protected ArrayList attributeListeners; - + protected Map mimes; - + protected SessionCookieConfig scc; - - protected Set dstm = EnumSet.of(SessionTrackingMode.URL, SessionTrackingMode.COOKIE), stm; - + + protected Set dstm = EnumSet.of(SessionTrackingMode.URL, SessionTrackingMode.COOKIE), + stm; + private boolean applyCompression; - + // ** interface to decouple from J2EE features - + public static interface AppContextDelegator { /** * searches object in context @@ -212,7 +213,7 @@ public static interface AppContextDelegator { * @return */ Object lookup(String name); - + /** * looking for a link with name in context * @@ -220,7 +221,7 @@ public static interface AppContextDelegator { * @return */ Object lookupLink(String name); - + /** * add object to be available from context with name * @@ -229,84 +230,69 @@ public static interface AppContextDelegator { */ void add(String name, Object obj); - /** + /** * remove app object from container + * * @param name * @return stored object or null */ Object remove(String name); } - + protected static interface Openable { Object getOrigin(); } - + protected static class MappingEntry { String servPath; - + Pattern pathPat; - + MappingEntry(String path, String pattern) { servPath = path; pathPat = Pattern.compile(pattern); } - + public String toString() { - return String.format("Mapping of %s with regexp pat %s", servPath, - pathPat); + return String.format("Mapping of %s with regexp pat %s", servPath, pathPat); } } - - protected class ServletAccessDescr implements ServletConfig, - Comparable { + + protected class ServletAccessDescr implements ServletConfig, Comparable { String className; - String name; - Servlet instance; - MappingEntry[] mapping; - Map initParams; - String label; - int loadOnStart; - boolean asyncSupported; - String runAs; - File multipartLocation; - long multipartMaxFile; - long multipartMaxRequest; - int multipartThreshold; - boolean multipartEnabled; - String descr; - - long timeToReactivate; // if servlet suspended - + // if servlet suspended + long timeToReactivate; + @Override public String getServletName() { return name; } - + public Enumeration getInitParameterNames() { return new Enumeration() { Iterator i; { i = initParams.keySet().iterator(); } - + public boolean hasMoreElements() { return i.hasNext(); } - + public String nextElement() { return i.next(); } @@ -317,12 +303,12 @@ public String nextElement() { public ServletContext getServletContext() { return WebAppServlet.this; } - + @Override public String getInitParameter(String name) { return initParams.get(name); } - + public void add(MappingEntry entry) { if (mapping == null) mapping = new MappingEntry[1]; @@ -333,11 +319,11 @@ public void add(MappingEntry entry) { } mapping[mapping.length - 1] = entry; } - + public int compareTo(ServletAccessDescr sad) { return loadOnStart - sad.loadOnStart; } - + int matchPath(String path) { if (mapping == null) return -1; @@ -346,22 +332,19 @@ int matchPath(String path) { return i; return -1; } - + protected Servlet newInstance() throws ServletException { try { // System.err.printf("new instance %s %s%n", descr.className, // Arrays.toString(ucl.getURLs())); - Class servletClass = (Class) ucl - .loadClass(className); + Class servletClass = (Class) ucl.loadClass(className); if (noAnnot == false) { - WebServlet servletAnnot = servletClass - .getAnnotation(WebServlet.class); + WebServlet servletAnnot = servletClass.getAnnotation(WebServlet.class); if (servletAnnot != null) { asyncSupported = servletAnnot.asyncSupported(); } } - MultipartConfig multipartAnnot = servletClass - .getAnnotation(MultipartConfig.class); + MultipartConfig multipartAnnot = servletClass.getAnnotation(MultipartConfig.class); if (multipartAnnot != null) { multipartEnabled = true; if (multipartAnnot.location().length() > 0) @@ -385,10 +368,7 @@ public void run() { initThread.join(initTimeout * 1000); if (exHolder[0] == null) if (initThread.isAlive() == true) - exHolder[0] = new ServletException( - String.format( - "Initialization of %s in context %s exceeded allocated time (%dsecs)", - name, contextName, initTimeout)); + exHolder[0] = new ServletException(String.format("Initialization of %s in context %s exceeded allocated time (%dsecs)", name, contextName, initTimeout)); if (exHolder[0] != null) { instance = null; throw exHolder[0]; @@ -396,73 +376,57 @@ public void run() { return instance; // TODO think about setting back context loader } catch (InstantiationException ie) { - throw new ServletException("Servlet class " + className - + " can't instantiate. ", ie); + throw new ServletException("Servlet class " + className + " can't instantiate. ", ie); } catch (IllegalAccessException iae) { - throw new ServletException("Servlet class " + className - + " can't access. ", iae); + throw new ServletException("Servlet class " + className + " can't access. ", iae); } catch (ClassNotFoundException cnfe) { log("", cnfe); - throw new ServletException("Servlet class " + className - + " not found. ", cnfe); + throw new ServletException("Servlet class " + className + " not found. ", cnfe); } catch (Error e) { - throw new ServletException( - "Servlet class " - + className - + " can't be instantiated or initialized due an error.", - e); + throw new ServletException("Servlet class " + className + " can't be instantiated or initialized due an error.", e); } catch (Throwable t) { if (t instanceof ThreadDeath) throw (ThreadDeath) t; - throw new ServletException( - "Servlet class " - + className - + " can't be instantiated or initialized due an exception.", - t); + throw new ServletException("Servlet class " + className + " can't be instantiated or initialized due an exception.", t); } } - + public String toString() { - return "Servlet " + name + " class " + className + " path/patern " - + Arrays.toString(mapping) + " init" + initParams - + " inst " + instance; + return "Servlet " + name + " class " + className + " path/patern " + Arrays.toString(mapping) + " init" + initParams + " inst " + instance; } } - - protected class FilterAccessDescriptor extends ServletAccessDescr implements - FilterConfig { + + protected class FilterAccessDescriptor extends ServletAccessDescr implements FilterConfig { String[] servletNames; - + Filter filterInstance; - + DispatcherType[] dispatchTypes; - + public java.lang.String getFilterName() { return name; } - + public void add(String name) { // note the local name shadows name as class memeber if (servletNames == null) servletNames = new String[1]; else - servletNames = Utils.copyOf(servletNames, - servletNames.length + 1); + servletNames = Utils.copyOf(servletNames, servletNames.length + 1); servletNames[servletNames.length - 1] = name; } - + public void add(DispatcherType dispatcher) { if (dispatchTypes == null) dispatchTypes = new DispatcherType[1]; else { DispatcherType[] copy = new DispatcherType[dispatchTypes.length + 1]; - System.arraycopy(dispatchTypes, 0, copy, 0, - dispatchTypes.length); + System.arraycopy(dispatchTypes, 0, copy, 0, dispatchTypes.length); dispatchTypes = copy; } dispatchTypes[dispatchTypes.length - 1] = dispatcher; } - + int matchServlet(String servletName) { if (servletNames == null) return -1; @@ -471,7 +435,7 @@ int matchServlet(String servletName) { return i; return -1; } - + boolean matchDispatcher(DispatcherType dispatcher) { if (dispatchTypes == null) if (dispatcher.equals(DispatcherType.REQUEST)) @@ -483,67 +447,60 @@ boolean matchDispatcher(DispatcherType dispatcher) { return true; return false; } - + protected Filter newFilterInstance() throws ServletException { try { - Class filterClass = (Class) ucl - .loadClass(className); + Class filterClass = (Class) ucl.loadClass(className); WebFilter annot = filterClass.getAnnotation(WebFilter.class); if (annot != null) asyncSupported = annot.asyncSupported(); filterInstance = filterClass.newInstance(); filterInstance.init(this); } catch (InstantiationException ie) { - throw new ServletException("Filter class " + className - + " can't instantiate. ", ie); + throw new ServletException("Filter class " + className + " can't instantiate. ", ie); } catch (IllegalAccessException iae) { - throw new ServletException("Filter class " + className - + " can't access. ", iae); + throw new ServletException("Filter class " + className + " can't access. ", iae); } catch (ClassNotFoundException cnfe) { - throw new ServletException("Filter class " + className - + " not found. ", cnfe); + throw new ServletException("Filter class " + className + " not found. ", cnfe); } return filterInstance; } - + public String toString() { - return String.format( - "Filter for servlets %s and types %s based on %s", - Arrays.toString(servletNames), - Arrays.toString(dispatchTypes), super.toString()); + return String.format("Filter for servlets %s and types %s based on %s", Arrays.toString(servletNames), Arrays.toString(dispatchTypes), super.toString()); } } - + protected static class ErrorPageDescr { String errorPage; - - Class exception; - + Class exception; int errorCode; - + ErrorPageDescr(String page, String exClass, String code) { if (page == null || page.length() == 0 || page.charAt(0) != '/') - throw new IllegalArgumentException("Error page path '" + page - + "' must start with '/'"); - if (page.charAt(0) == '/') + throw new IllegalArgumentException("Error page path '" + page + "' must start with '/'"); + if (page.charAt(0) == '/') { errorPage = page; - else + } else { errorPage = "/" + page; + } + try { exception = Class.forName(exClass); } catch (Exception e) { - + } try { errorCode = Integer.parseInt(code); } catch (Exception e) { - + } } } - + protected static class JspForwarder extends HttpServlet { String jsp; + @Override public void init(ServletConfig conf) throws ServletException { super.init(conf); @@ -553,11 +510,12 @@ public void init(ServletConfig conf) throws ServletException { if (jsp.startsWith("/") == false) jsp = "/" + jsp; } - + @Override protected void service(HttpServletRequest hreq, HttpServletResponse hresp) throws ServletException, IOException { // TODO clean forward attributes wrapping request - //System.err.printf("%s-%s%n", hreq.getRequestURI(), hreq.getRequestURL()); + // System.err.printf("%s-%s%n", hreq.getRequestURI(), + // hreq.getRequestURL()); hreq.setAttribute("javax.servlet.tjws.servlet-jsp", true); hreq.getRequestDispatcher(jsp).forward(hreq, hresp); } @@ -567,40 +525,26 @@ protected WebAppServlet(String context) { this.contextPath = "/" + context; attributes = new Hashtable(); contextParameters = new Hashtable(); - applyCompression = System.getProperty("tjws.webapp." + context - + ".compressresponse") != null; + applyCompression = System.getProperty("tjws.webapp." + context + ".compressresponse") != null; if (applyCompression == false) - applyCompression = System - .getProperty(FileServlet.DEF_USE_COMPRESSION) != null; + applyCompression = System.getProperty(FileServlet.DEF_USE_COMPRESSION) != null; // TODO consider // _DEBUG = System.getProperty(getClass().getName() + ".debug") != null; - String threadPoolSets[] = System - .getProperty( - "tjws.webapp." + context + ".threadpoolsets", - System.getProperty("tjws.webapp.*.threadpoolsets", - "20,50,300")).split(","); + String threadPoolSets[] = System.getProperty("tjws.webapp." + context + ".threadpoolsets", System.getProperty("tjws.webapp.*.threadpoolsets", "20,50,300")).split(","); if (threadPoolSets.length != 3) - throw new IllegalArgumentException("Illegal thread pool settings:" - + System.getProperty("tjws.webapp." + context - + ".threadpoolsets")); - asyncThreads = new ThreadPoolExecutor( - Integer.parseInt(threadPoolSets[0]), - Integer.parseInt(threadPoolSets[1]), - Integer.parseInt(threadPoolSets[2]), TimeUnit.SECONDS, - new LinkedBlockingQueue(), new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread result = new Thread(r, "Pooled-t-" + contextPath); - result.setDaemon(true); - // result.setContextClassLoader(ucl); - return result; - } - - }); - System.getProperty("tjws.webapp." + context + ".multipartssets", System - .getProperty("tjws.webapp.*.multipartssets", - "$temp,50m,100m,2m")); + throw new IllegalArgumentException("Illegal thread pool settings:" + System.getProperty("tjws.webapp." + context + ".threadpoolsets")); + asyncThreads = new ThreadPoolExecutor(Integer.parseInt(threadPoolSets[0]), Integer.parseInt(threadPoolSets[1]), Integer.parseInt(threadPoolSets[2]), TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread result = new Thread(r, "Pooled-t-" + contextPath); + result.setDaemon(true); + // result.setContextClassLoader(ucl); + return result; + } + + }); + System.getProperty("tjws.webapp." + context + ".multipartssets", System.getProperty("tjws.webapp.*.multipartssets", "$temp,50m,100m,2m")); } - + /** * Initializes singleton delegator * @@ -610,15 +554,14 @@ public static void setAppContextDelegator(AppContextDelegator acd) { if (appContextDelegator == null) appContextDelegator = acd; } - - public static WebAppServlet create(File deployDir, String context, Serve server, String virtualHost) - throws ServletException { - // TODO add method initFromDeployDirectory and move all static calls - // there, - // so it should look like - // WebAppServlet result = new WebAppServlet(context); - // result.initFromDeployDirectory(deployDir, server); - // TODO split also the method on sections of web.xml + + public static WebAppServlet create(File deployDir, String context, Serve server, String virtualHost) throws ServletException { + // TODO add method initFromDeployDirectory and move all static calls + // there, + // so it should look like + // WebAppServlet result = new WebAppServlet(context); + // result.initFromDeployDirectory(deployDir, server); + // TODO split also the method on sections of web.xml XPath xp = XPathFactory.newInstance().newXPath(); final WebAppServlet result = new WebAppServlet(context); result.server = server; @@ -632,9 +575,7 @@ public static WebAppServlet create(File deployDir, String context, Serve server, if (contextDef.exists()) appContextDelegator.add(context, new WebApp.MetaContext(contextDef.getPath(), result.ucl)); } - Node document = (Node) xp.evaluate("/*", - new InputSource(webxml = new FileInputStream(new File(deployDir, - "WEB-INF/web.xml"))), XPathConstants.NODE); + Node document = (Node) xp.evaluate("/*", new InputSource(webxml = new FileInputStream(new File(deployDir, "WEB-INF/web.xml"))), XPathConstants.NODE); // TODO process "web-fragment.xml" as well final String namespaceURI = document.getNamespaceURI(); String prefix = namespaceURI == null ? "" : "j2ee:"; @@ -642,8 +583,7 @@ public static WebAppServlet create(File deployDir, String context, Serve server, public String getNamespaceURI(String prefix) { // System.err.printf("Resolver called with %s%n", prefix); if (prefix == null) - throw new IllegalArgumentException( - "Namespace prefix is null."); + throw new IllegalArgumentException("Namespace prefix is null."); if (namespaceURI == null) return XMLConstants.NULL_NS_URI; if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) @@ -652,60 +592,44 @@ public String getNamespaceURI(String prefix) { return namespaceURI; return XMLConstants.NULL_NS_URI; } - + public String getPrefix(String arg0) { - throw new UnsupportedOperationException("getPrefix(" + arg0 - + ");"); + throw new UnsupportedOperationException("getPrefix(" + arg0 + ");"); } - + public Iterator getPrefixes(String arg0) { - throw new UnsupportedOperationException("getPrefixes(" - + arg0 + ");"); + throw new UnsupportedOperationException("getPrefixes(" + arg0 + ");"); } }); - document = (Node) xp.evaluate("//" + prefix + "web-app", document, - XPathConstants.NODE); + document = (Node) xp.evaluate("//" + prefix + "web-app", document, XPathConstants.NODE); if ("yes".equals(System.getProperty(WAR_NAME_AS_CONTEXTPATH)) == false) - result.contextName = (String) xp.evaluate(prefix - + "display-name", document, XPathConstants.STRING); + result.contextName = (String) xp.evaluate(prefix + "display-name", document, XPathConstants.STRING); if (result.contextName == null || result.contextName.length() == 0) result.contextName = context; else result.contextPath = "/" + result.contextName; - //result.origContextName = result.contextName; - //result.origContextPath = result.contextPath; - if (result.contextName.equals(System.getProperty(WAR_DEPLOY_IN_ROOT - + (virtualHost == null ? "" : '.' + virtualHost)))) { - result.log(String.format("Conext %s deployed as root ", - result.contextName, virtualHost == null ? "" - : virtualHost == null), null); + // result.origContextName = result.contextName; + // result.origContextPath = result.contextPath; + if (result.contextName.equals(System.getProperty(WAR_DEPLOY_IN_ROOT + (virtualHost == null ? "" : '.' + virtualHost)))) { + result.log(String.format("Conext %s deployed as root ", result.contextName, virtualHost == null ? "" : virtualHost == null), null); result.contextPath = ""; result.contextName = ""; } result.virtualHost = virtualHost; - Node metadataAttr = document.getAttributes().getNamedItem( - "metadata-complete"); + Node metadataAttr = document.getAttributes().getNamedItem("metadata-complete"); if (metadataAttr != null) result.noAnnot = "true".equals(metadataAttr.getTextContent()); - result.description = (String) xp.evaluate(prefix - + "description", document, XPathConstants.STRING); + result.description = (String) xp.evaluate(prefix + "description", document, XPathConstants.STRING); if (result.description == null || result.description.length() == 0) - result.description = "Web application :"+result.contextName; + result.description = "Web application :" + result.contextName; // context parameters - NodeList nodes = (NodeList) xp.evaluate(prefix + "context-param", - document, XPathConstants.NODESET); + NodeList nodes = (NodeList) xp.evaluate(prefix + "context-param", document, XPathConstants.NODESET); int nodesLen = nodes.getLength(); for (int p = 0; p < nodesLen; p++) { - result.contextParameters.put( - (String) xp.evaluate(prefix + "param-name", - nodes.item(p), XPathConstants.STRING), - (String) xp.evaluate(prefix + "param-value", - nodes.item(p), XPathConstants.STRING)); + result.contextParameters.put((String) xp.evaluate(prefix + "param-name", nodes.item(p), XPathConstants.STRING), (String) xp.evaluate(prefix + "param-value", nodes.item(p), XPathConstants.STRING)); } // session-config - Number num = (Number) xp.evaluate(prefix + "session-config/" - + prefix + "session-timeout", document, - XPathConstants.NUMBER); + Number num = (Number) xp.evaluate(prefix + "session-config/" + prefix + "session-timeout", document, XPathConstants.NUMBER); if (num != null) result.sessionTimeout = num.intValue(); if (result.sessionTimeout < 0) @@ -713,128 +637,80 @@ public Iterator getPrefixes(String arg0) { else result.sessionTimeout *= 60; result.initTimeout = 10; - Integer initTimeout = Integer.getInteger(String.format( - WEBAPPINITTIMEOUT, result.contextName)); - + Integer initTimeout = Integer.getInteger(String.format(WEBAPPINITTIMEOUT, result.contextName)); + if (initTimeout == null) - initTimeout = Integer.getInteger(String.format( - WEBAPPINITTIMEOUT, "*")); + initTimeout = Integer.getInteger(String.format(WEBAPPINITTIMEOUT, "*")); if (initTimeout != null) result.initTimeout = initTimeout; - String flag = (String) xp.evaluate(prefix + "session-config/" - + prefix + "cookie-config/" + prefix + "http-only", document, - XPathConstants.STRING); + String flag = (String) xp.evaluate(prefix + "session-config/" + prefix + "cookie-config/" + prefix + "http-only", document, XPathConstants.STRING); if (flag.length() > 0) { - server.httpSessCookie = "YES".equalsIgnoreCase(flag) - || "TRUE".equalsIgnoreCase(flag); + server.httpSessCookie = "YES".equalsIgnoreCase(flag) || "TRUE".equalsIgnoreCase(flag); } - flag = (String) xp.evaluate(prefix + "session-config/" - + prefix + "cookie-config/" + prefix + "secure", document, - XPathConstants.STRING); + flag = (String) xp.evaluate(prefix + "session-config/" + prefix + "cookie-config/" + prefix + "secure", document, XPathConstants.STRING); if (flag.length() > 0) { - server.secureSessCookie = "YES".equalsIgnoreCase(flag) - || "TRUE".equalsIgnoreCase(flag); + server.secureSessCookie = "YES".equalsIgnoreCase(flag) || "TRUE".equalsIgnoreCase(flag); } // TODO decide 1) if it is right place 2) do check for Android Thread.currentThread().setContextClassLoader(result.ucl); try { - nodes = (NodeList) xp.evaluate(prefix + "resource-env-ref", - document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "resource-env-ref", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); - result.log(String.format("Processing env-ref-%s", xp - .evaluate(prefix + "description", n, - XPathConstants.STRING))); - Object link = appContextDelegator == null ? null - : appContextDelegator.lookupLink((String) xp - .evaluate(prefix + "resource-env-ref-name", - n, XPathConstants.STRING)); - if (link == null - || link.getClass() - .getName() - .equals(xp.evaluate(prefix - + "resource-env-ref-type", n, - XPathConstants.STRING)) == false) - result.log(String - .format("Web container doesn't provide an administered object %s of %s", - xp.evaluate(prefix - + "resource-env-ref-name", n, - XPathConstants.STRING), - xp.evaluate(prefix - + "resource-env-ref-type", n, - XPathConstants.STRING))); - } - nodes = (NodeList) xp.evaluate(prefix + "resource-ref", - document, XPathConstants.NODESET); + result.log(String.format("Processing env-ref-%s", xp.evaluate(prefix + "description", n, XPathConstants.STRING))); + Object link = appContextDelegator == null ? null : appContextDelegator.lookupLink((String) xp.evaluate(prefix + "resource-env-ref-name", n, XPathConstants.STRING)); + if (link == null || link.getClass().getName().equals(xp.evaluate(prefix + "resource-env-ref-type", n, XPathConstants.STRING)) == false) + result.log(String.format("Web container doesn't provide an administered object %s of %s", xp.evaluate(prefix + "resource-env-ref-name", n, XPathConstants.STRING), xp.evaluate(prefix + "resource-env-ref-type", n, XPathConstants.STRING))); + } + nodes = (NodeList) xp.evaluate(prefix + "resource-ref", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); - result.log(String.format("Processing resource-ref-%s", xp - .evaluate(prefix + "description", n, - XPathConstants.STRING))); - String name = (String) xp.evaluate(prefix + "res-ref-name", - n, XPathConstants.STRING); - String type = toNormalizedString(xp.evaluate(prefix + "res-type", n, - XPathConstants.STRING)); - String auth = toNormalizedString( xp.evaluate(prefix + "res-auth", n, - XPathConstants.STRING)); - String scope = toNormalizedString(xp.evaluate(prefix - + "res-sharing-scope", n, XPathConstants.STRING)); - Object res = appContextDelegator == null ? null - : appContextDelegator.lookup(name); + result.log(String.format("Processing resource-ref-%s", xp.evaluate(prefix + "description", n, XPathConstants.STRING))); + String name = (String) xp.evaluate(prefix + "res-ref-name", n, XPathConstants.STRING); + String type = toNormalizedString(xp.evaluate(prefix + "res-type", n, XPathConstants.STRING)); + String auth = toNormalizedString(xp.evaluate(prefix + "res-auth", n, XPathConstants.STRING)); + String scope = toNormalizedString(xp.evaluate(prefix + "res-sharing-scope", n, XPathConstants.STRING)); + Object res = appContextDelegator == null ? null : appContextDelegator.lookup(name); if (res == null) - result.log(String.format("No resource %s is available", - name)); + result.log(String.format("No resource %s is available", name)); else { - Class typeClass = null; - if (type != null && type.length() > 0) + Class typeClass = null; + if (type != null && type.length() > 0) { try { typeClass = Class.forName(type); } catch (ClassNotFoundException cne) { - result.log(String - .format("No definition of class %s found, type check is bypassed", - type)); + result.log(String.format("No definition of class %s found, type check is bypassed", type)); // TODO res.getClasses() } - if (typeClass != null - && typeClass.isInstance(res) == false) - result.log(String.format( - "No resource %s of %s is available", name, - type)); - else - result.log(String - .format("Confirmed availability of %s of %s authorized by %s in scope of %s", - name, type, auth, scope)); + } + + if (typeClass != null && typeClass.isInstance(res) == false) { + result.log(String.format("No resource %s of %s is available", name, type)); + } else { + result.log(String.format("Confirmed availability of %s of %s authorized by %s in scope of %s", name, type, auth, scope)); + } } } if (appContextDelegator != null) { - nodes = (NodeList) xp.evaluate(prefix + "env-entry", - document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "env-entry", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); - result.log(String.format("Processing env-entry-%s", xp - .evaluate(prefix + "description", n, - XPathConstants.STRING))); - Object value = xp.evaluate(prefix + "env-entry-value", - n, XPathConstants.STRING); + result.log(String.format("Processing env-entry-%s", xp.evaluate(prefix + "description", n, XPathConstants.STRING))); + Object value = xp.evaluate(prefix + "env-entry-value", n, XPathConstants.STRING); if (value != null) { - String type = (String) xp.evaluate(prefix - + "env-entry-type", n, - XPathConstants.STRING); - if (type != null - && ("java.lang.String".equals(type)) == false) { + String type = (String) xp.evaluate(prefix + "env-entry-type", n, XPathConstants.STRING); + if (type != null && ("java.lang.String".equals(type)) == false) { // TODO can use reflection for shortness, // however we should check allowed types if ("java.lang.Boolean".equals(type)) value = new Boolean((String) value); else if ("java.lang.Byte".equals(type)) value = new Byte((String) value); - else if ("java.lang.Character".equals(type) - && ((String) value).length() == 1) - value = new Character( - ((String) value).charAt(0)); + else if ("java.lang.Character".equals(type) && ((String) value).length() == 1) + value = new Character(((String) value).charAt(0)); else if ("java.lang.Short".equals(type)) value = new Short((String) value); else if ("java.lang.Integer".equals(type)) @@ -846,61 +722,45 @@ else if ("java.lang.Float".equals(type)) else if ("java.lang.Double".equals(type)) value = new Double((String) value); } - appContextDelegator.add((String) xp.evaluate(prefix - + "env-entry-name", n, - XPathConstants.STRING), value); + appContextDelegator.add((String) xp.evaluate(prefix + "env-entry-name", n, XPathConstants.STRING), value); } } } } catch (Exception e) { - result.log( - "A problem in obtaining context, all context related settings will be ignored", - e); + result.log("A problem in obtaining context, all context related settings will be ignored", e); } // bypass EJB stuff if (nodesLen > 0) result.log("EJB references are not supported"); - nodes = (NodeList) xp.evaluate(prefix + "ejb-local-ref", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "ejb-local-ref", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen > 0) result.log("Local EJB references are not supported"); // ///////////////////////////////////////////////////////////////// // listeners listener-class - nodes = (NodeList) xp.evaluate(prefix + "listener/" + prefix - + "listener-class", document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "listener/" + prefix + "listener-class", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen > 0) { result.listeners = new ArrayList(nodesLen); for (int i = 0; i < nodesLen; i++) try { - EventListener eventListener = (EventListener) result.ucl - .loadClass(toNormalizedString( - nodes.item(i).getTextContent())) - .newInstance(); - if (eventListener instanceof HttpSessionListener - || eventListener instanceof HttpSessionAttributeListener) { + EventListener eventListener = (EventListener) result.ucl.loadClass(toNormalizedString(nodes.item(i).getTextContent())).newInstance(); + if (eventListener instanceof HttpSessionListener || eventListener instanceof HttpSessionAttributeListener) { if (result.sessionListeners == null) - result.sessionListeners = new ArrayList( - nodesLen); - result.sessionListeners - .add((EventListener) eventListener); + result.sessionListeners = new ArrayList(nodesLen); + result.sessionListeners.add((EventListener) eventListener); } - + if (eventListener instanceof ServletRequestListener) { if (result.requestListeners == null) - result.requestListeners = new ArrayList( - nodesLen); - result.requestListeners - .add((ServletRequestListener) eventListener); + result.requestListeners = new ArrayList(nodesLen); + result.requestListeners.add((ServletRequestListener) eventListener); } - + if (eventListener instanceof ServletRequestAttributeListener) { if (result.attributeListeners == null) - result.attributeListeners = new ArrayList( - nodesLen); - result.attributeListeners - .add((ServletRequestAttributeListener) eventListener); + result.attributeListeners = new ArrayList(nodesLen); + result.attributeListeners.add((ServletRequestAttributeListener) eventListener); } result.listeners.add(eventListener); // because the same // class can @@ -909,34 +769,26 @@ else if ("java.lang.Double".equals(type)) // listener // interfaces } catch (Exception e) { - result.log("Event listener " - + nodes.item(i).getTextContent() - + " can't be created due an exception.", e); + result.log("Event listener " + nodes.item(i).getTextContent() + " can't be created due an exception.", e); } catch (Error e) { - result.log("Event listener " - + nodes.item(i).getTextContent() - + " can't be created due an error.", e); + result.log("Event listener " + nodes.item(i).getTextContent() + " can't be created due an error.", e); } } // restore sessions for this context // serve.sessions.restore for the current context - + // notify context listeners if (result.listeners != null) for (EventListener listener : result.listeners) { if (listener instanceof ServletContextListener) { final ServletContextListener contListener = (ServletContextListener) listener; - contListener - .contextInitialized(new ServletContextEvent( - result)); + contListener.contextInitialized(new ServletContextEvent(result)); } } // read global multi part - Node mp = (Node)xp.evaluate(prefix + "multipart-form", document, XPathConstants.NODE); - boolean casualMultipart = mp != null && - mp.hasAttributes() && mp.getAttributes().getNamedItem("enable") != null && - "true".equals(mp.getAttributes().getNamedItem("enable").getTextContent() ); + Node mp = (Node) xp.evaluate(prefix + "multipart-form", document, XPathConstants.NODE); + boolean casualMultipart = mp != null && mp.hasAttributes() && mp.getAttributes().getNamedItem("enable") != null && "true".equals(mp.getAttributes().getNamedItem("enable").getTextContent()); long maxUpload = 0; if (casualMultipart) { mp = mp.getAttributes().getNamedItem("upload-max"); @@ -946,85 +798,62 @@ else if ("java.lang.Double".equals(type)) if (maxUpload < 0) maxUpload = 0; } catch (Exception e) { - + } } // process filters - nodes = (NodeList) xp.evaluate(prefix + "filter", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "filter", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); result.filters = new ArrayList(nodesLen); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); FilterAccessDescriptor fad = result.createFilterDescriptor(); - fad.name = (String) xp.evaluate(prefix + "filter-name", n, - XPathConstants.STRING); - fad.className = toNormalizedString(xp.evaluate(prefix + "filter-class", - n, XPathConstants.STRING)); + fad.name = (String) xp.evaluate(prefix + "filter-name", n, XPathConstants.STRING); + fad.className = toNormalizedString(xp.evaluate(prefix + "filter-class", n, XPathConstants.STRING)); if (fad.className == null) - throw new ServletException(String.format( - "Filter %s specified without or empty class.", - fad.name)); - String value = (String) xp.evaluate(prefix + "async-supported", - n, XPathConstants.STRING); + throw new ServletException(String.format("Filter %s specified without or empty class.", fad.name)); + String value = (String) xp.evaluate(prefix + "async-supported", n, XPathConstants.STRING); if (value.length() > 0) { value = value.toUpperCase(); - fad.asyncSupported = "YES".equals(value) - || "TRUE".equals(value); - } - fad.label = (String) xp.evaluate(prefix + "display-name", n, - XPathConstants.STRING); - fad.descr = (String) xp.evaluate(prefix + "description", n, - XPathConstants.STRING); - NodeList params = (NodeList) xp.evaluate(prefix + "init-param", - n, XPathConstants.NODESET); + fad.asyncSupported = "YES".equals(value) || "TRUE".equals(value); + } + fad.label = (String) xp.evaluate(prefix + "display-name", n, XPathConstants.STRING); + fad.descr = (String) xp.evaluate(prefix + "description", n, XPathConstants.STRING); + NodeList params = (NodeList) xp.evaluate(prefix + "init-param", n, XPathConstants.NODESET); fad.initParams = new HashMap(params.getLength()); for (int p = 0; p < params.getLength(); p++) { - fad.initParams.put( - (String) xp.evaluate(prefix + "param-name", - params.item(p), XPathConstants.STRING), - (String) xp.evaluate(prefix + "param-value", - params.item(p), XPathConstants.STRING)); - } - fad.multipartEnabled = casualMultipart; - fad.multipartMaxRequest = maxUpload << 10; + fad.initParams.put((String) xp.evaluate(prefix + "param-name", params.item(p), XPathConstants.STRING), (String) xp.evaluate(prefix + "param-value", params.item(p), XPathConstants.STRING)); + } + fad.multipartEnabled = casualMultipart; + fad.multipartMaxRequest = maxUpload << 10; result.filters.add(fad); } // process filter's mapping for (FilterAccessDescriptor fad : result.filters) { - nodes = (NodeList) xp.evaluate(prefix + "filter-mapping[" - + prefix + "filter-name=\"" + fad.name + "\"]", - document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "filter-mapping[" + prefix + "filter-name=\"" + fad.name + "\"]", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen == 0) - throw new ServletException(String.format( - "No mappings were found for the filter %s", - fad.name)); + throw new ServletException(String.format("No mappings were found for the filter %s", fad.name)); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); - NodeList clarifications = (NodeList) xp.evaluate(prefix - + "url-pattern", n, XPathConstants.NODESET); + NodeList clarifications = (NodeList) xp.evaluate(prefix + "url-pattern", n, XPathConstants.NODESET); int claLen = clarifications.getLength(); for (int j = 0; j < claLen; j++) { String mapUrl = clarifications.item(j).getTextContent(); if (mapUrl == null || mapUrl.length() == 0) continue; - fad.add(new MappingEntry(clearPath(mapUrl), - buildREbyPathPatt(mapUrl))); + fad.add(new MappingEntry(clearPath(mapUrl), buildREbyPathPatt(mapUrl))); } - clarifications = (NodeList) xp.evaluate(prefix - + "dispatcher", n, XPathConstants.NODESET); + clarifications = (NodeList) xp.evaluate(prefix + "dispatcher", n, XPathConstants.NODESET); claLen = clarifications.getLength(); for (int j = 0; j < claLen; j++) { - String filterType = clarifications.item(j) - .getTextContent(); + String filterType = clarifications.item(j).getTextContent(); if (filterType == null || filterType.length() == 0) fad.add(DispatcherType.REQUEST); else fad.add(DispatcherType.valueOf(filterType)); } - clarifications = (NodeList) xp.evaluate(prefix - + "servlet-name", n, XPathConstants.NODESET); + clarifications = (NodeList) xp.evaluate(prefix + "servlet-name", n, XPathConstants.NODESET); claLen = clarifications.getLength(); for (int j = 0; j < claLen; j++) { // adding servlet name @@ -1034,95 +863,67 @@ else if ("java.lang.Double".equals(type)) fad.newFilterInstance(); } // servlets - nodes = (NodeList) xp.evaluate(prefix + "servlet", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "servlet", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); result.servlets = new ArrayList(nodesLen + 1); // +jsp for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); ServletAccessDescr sad = result.createDescriptor(); - sad.name = (String) xp.evaluate(prefix + "servlet-name", n, - XPathConstants.STRING); - sad.className = toNormalizedString(xp.evaluate(prefix + "servlet-class", - n, XPathConstants.STRING)); + sad.name = (String) xp.evaluate(prefix + "servlet-name", n, XPathConstants.STRING); + sad.className = toNormalizedString(xp.evaluate(prefix + "servlet-class", n, XPathConstants.STRING)); String jspFile = null; if (sad.className == null || sad.className.length() == 0) { - jspFile = (String) xp.evaluate(prefix + "jsp-file", - n, XPathConstants.STRING); + jspFile = (String) xp.evaluate(prefix + "jsp-file", n, XPathConstants.STRING); if (jspFile != null) { sad.className = JspForwarder.class.getName(); } else - throw new ServletException( - String.format( - "Servlet %s specified without class or jsp file.", - sad.name)); - } - sad.label = (String) xp.evaluate(prefix + "display-name", n, - XPathConstants.STRING); - sad.descr = (String) xp.evaluate(prefix + "description", n, - XPathConstants.STRING); - String loadOnStartVal = toNormalizedString( xp.evaluate(prefix - + "load-on-startup", n, XPathConstants.STRING)); + throw new ServletException(String.format("Servlet %s specified without class or jsp file.", sad.name)); + } + sad.label = (String) xp.evaluate(prefix + "display-name", n, XPathConstants.STRING); + sad.descr = (String) xp.evaluate(prefix + "description", n, XPathConstants.STRING); + String loadOnStartVal = toNormalizedString(xp.evaluate(prefix + "load-on-startup", n, XPathConstants.STRING)); try { sad.loadOnStart = Integer.parseInt(loadOnStartVal); } catch (NumberFormatException nfe) { loadOnStartVal = loadOnStartVal.toUpperCase(); - sad.loadOnStart = "YES".equals(loadOnStartVal) - || "TRUE".equals(loadOnStartVal) ? 0 : -1; + sad.loadOnStart = "YES".equals(loadOnStartVal) || "TRUE".equals(loadOnStartVal) ? 0 : -1; } - String value = toNormalizedString( xp.evaluate(prefix + "async-supported", - n, XPathConstants.STRING)); + String value = toNormalizedString(xp.evaluate(prefix + "async-supported", n, XPathConstants.STRING)); if (value.length() > 0) { - sad.asyncSupported = "YES".equalsIgnoreCase(value) - || "TRUE".equalsIgnoreCase(value); + sad.asyncSupported = "YES".equalsIgnoreCase(value) || "TRUE".equalsIgnoreCase(value); } - sad.runAs = (String) xp.evaluate(prefix + "run-as", n, - XPathConstants.STRING); - value = (String) xp.evaluate(prefix + "enabled", n, - XPathConstants.STRING); - - NodeList params = (NodeList) xp.evaluate(prefix + "init-param", - n, XPathConstants.NODESET); - sad.initParams = new HashMap(params.getLength()+(jspFile==null?0:1)); + sad.runAs = (String) xp.evaluate(prefix + "run-as", n, XPathConstants.STRING); + value = (String) xp.evaluate(prefix + "enabled", n, XPathConstants.STRING); + + NodeList params = (NodeList) xp.evaluate(prefix + "init-param", n, XPathConstants.NODESET); + sad.initParams = new HashMap(params.getLength() + (jspFile == null ? 0 : 1)); for (int p = 0; p < params.getLength(); p++) { - sad.initParams.put( - (String) xp.evaluate(prefix + "param-name", - params.item(p), XPathConstants.STRING), - (String) xp.evaluate(prefix + "param-value", - params.item(p), XPathConstants.STRING)); + sad.initParams.put((String) xp.evaluate(prefix + "param-name", params.item(p), XPathConstants.STRING), (String) xp.evaluate(prefix + "param-value", params.item(p), XPathConstants.STRING)); } if (jspFile != null) { if (sad.initParams.containsKey("jsp-file")) - throw new ServletException("Conflicting iniit parameter jsp-file for JSP servlet "+sad); + throw new ServletException("Conflicting iniit parameter jsp-file for JSP servlet " + sad); sad.initParams.put("jsp-file", jspFile); } - NodeList multiparts = (NodeList) xp.evaluate(prefix - + "multipart-config", n, XPathConstants.NODESET); + NodeList multiparts = (NodeList) xp.evaluate(prefix + "multipart-config", n, XPathConstants.NODESET); if (multiparts.getLength() == 1) { sad.multipartEnabled = true; Node multipart = (Node) multiparts.item(0); - value = (String) xp.evaluate(prefix + "location", - multipart, XPathConstants.STRING); + value = (String) xp.evaluate(prefix + "location", multipart, XPathConstants.STRING); if (value.length() > 0) sad.multipartLocation = new File(value); - value = toNormalizedString( xp.evaluate(prefix + "max-file-size", - multipart, XPathConstants.STRING)); + value = toNormalizedString(xp.evaluate(prefix + "max-file-size", multipart, XPathConstants.STRING)); if (value.length() > 0) sad.multipartMaxFile = Long.parseLong(value); - value = toNormalizedString( xp.evaluate(prefix + "max-request-size", - multipart, XPathConstants.STRING)); + value = toNormalizedString(xp.evaluate(prefix + "max-request-size", multipart, XPathConstants.STRING)); if (value.length() > 0) sad.multipartMaxRequest = Long.parseLong(value); - value = toNormalizedString( xp.evaluate( - prefix + "file-size-threshold", multipart, - XPathConstants.STRING)); + value = toNormalizedString(xp.evaluate(prefix + "file-size-threshold", multipart, XPathConstants.STRING)); if (value.length() > 0) sad.multipartThreshold = Integer.parseInt(value); } - NodeList securityRoles = (NodeList) xp.evaluate(prefix - + "security-role-ref", n, XPathConstants.NODESET); - NodeList descriptionGroups = (NodeList) xp.evaluate(prefix - + "descriptionGroup", n, XPathConstants.NODESET); + NodeList securityRoles = (NodeList) xp.evaluate(prefix + "security-role-ref", n, XPathConstants.NODESET); + NodeList descriptionGroups = (NodeList) xp.evaluate(prefix + "descriptionGroup", n, XPathConstants.NODESET); result.servlets.add(sad); } // assure order of initialization @@ -1130,42 +931,33 @@ else if ("java.lang.Double".equals(type)) // get mappings ServletAccessDescr wasDefault = null; for (ServletAccessDescr sad : result.servlets) { - nodes = (NodeList) xp.evaluate(prefix + "servlet-mapping[" - + prefix + "servlet-name=\"" + sad.name + "\"]", - document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "servlet-mapping[" + prefix + "servlet-name=\"" + sad.name + "\"]", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); // System.err.printf("Found %d mappings for %s%n", nodesLen, // sad); if (nodesLen == 0) { // no mapping at all String urlPat = "/" + sad.name + "/*"; - sad.add(new MappingEntry(clearPath(urlPat), - buildREbyPathPatt(urlPat))); + sad.add(new MappingEntry(clearPath(urlPat), buildREbyPathPatt(urlPat))); } else for (int i = 0; i < nodesLen; i++) { - NodeList maps = (NodeList) xp.evaluate(prefix - + "url-pattern", nodes.item(i), - XPathConstants.NODESET); + NodeList maps = (NodeList) xp.evaluate(prefix + "url-pattern", nodes.item(i), XPathConstants.NODESET); int mapsLen = maps.getLength(); // System.err.printf("Found %d patterns for %s%n", // mapsLen, sad); if (mapsLen == 0) { // mapping with empty pattern String urlPat = "/" + sad.name + "/*"; - sad.add(new MappingEntry(clearPath(urlPat), - buildREbyPathPatt(urlPat))); + sad.add(new MappingEntry(clearPath(urlPat), buildREbyPathPatt(urlPat))); } else { for (int j = 0; j < mapsLen; j++) { String urlPat = maps.item(j).getTextContent(); if (urlPat.equals("/")) if (wasDefault != null) - throw new ServletException( - "More than one default servlets defined " - + sad); + throw new ServletException("More than one default servlets defined " + sad); else wasDefault = sad; - sad.add(new MappingEntry(clearPath(urlPat), - buildREbyPathPatt(urlPat))); + sad.add(new MappingEntry(clearPath(urlPat), buildREbyPathPatt(urlPat))); } } } @@ -1175,9 +967,7 @@ else if ("java.lang.Double".equals(type)) sad.newInstance(); } // additional jsp mapping - nodes = (NodeList) xp.evaluate(prefix + "jsp-config/" + prefix - + "jsp-property-group/" + prefix + "url-pattern", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "jsp-config/" + prefix + "jsp-property-group/" + prefix + "url-pattern", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); ServletAccessDescr jsp; if (nodesLen > 0) { @@ -1187,7 +977,7 @@ else if ("java.lang.Double".equals(type)) } jsp = result.addJSPServlet(jspPats); } else - jsp =result.addJSPServlet(null); + jsp = result.addJSPServlet(null); jsp.multipartEnabled = casualMultipart; jsp.multipartMaxRequest = maxUpload << 10; @@ -1197,9 +987,7 @@ else if ("java.lang.Double".equals(type)) result.servlets.add(wasDefault); } // welcome files - nodes = (NodeList) xp - .evaluate(prefix + "welcome-file-list/" + prefix - + "welcome-file", document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "welcome-file-list/" + prefix + "welcome-file", document, XPathConstants.NODESET); result.welcomeFiles = new ArrayList(nodes.getLength() + 1); nodesLen = nodes.getLength(); if (nodesLen > 0) @@ -1210,102 +998,89 @@ else if ("java.lang.Double".equals(type)) result.welcomeFiles.add("index.jsp"); } // error pages - nodes = (NodeList) xp.evaluate(prefix + "error-page", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "error-page", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen > 0) { result.errorPages = new ArrayList(nodesLen); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); - result.errorPages.add(new WebAppServlet.ErrorPageDescr( - (String) xp.evaluate(prefix + "location", n, - XPathConstants.STRING), (String) xp - .evaluate(prefix + "exception-type", n, - XPathConstants.STRING), (String) xp - .evaluate(prefix + "error-code", n, - XPathConstants.STRING))); + result.errorPages.add(new WebAppServlet.ErrorPageDescr((String) xp.evaluate(prefix + "location", n, XPathConstants.STRING), (String) xp.evaluate(prefix + "exception-type", n, XPathConstants.STRING), (String) xp.evaluate(prefix + "error-code", n, XPathConstants.STRING))); } } // mime types - nodes = (NodeList) xp.evaluate(prefix + "mime-mapping", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "mime-mapping", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen > 0) { result.mimes = new HashMap(nodesLen); for (int i = 0; i < nodesLen; i++) { Node n = nodes.item(i); - result.mimes.put(((String) xp.evaluate( - prefix + "extension", n, XPathConstants.STRING)) - .toLowerCase(), (String) xp.evaluate(prefix - + "mime-type", n, XPathConstants.STRING)); + result.mimes.put(((String) xp.evaluate(prefix + "extension", n, XPathConstants.STRING)).toLowerCase(), (String) xp.evaluate(prefix + "mime-type", n, XPathConstants.STRING)); } } // bypass security stuff - nodes = (NodeList) xp.evaluate(prefix + "security-constraint", - document, XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "security-constraint", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen > 0) result.log("Security constraints are not supported"); - if (xp.evaluate(prefix + "login-config", document, - XPathConstants.NODE) != null) + if (xp.evaluate(prefix + "login-config", document, XPathConstants.NODE) != null) result.log("Login config is not supported"); - nodes = (NodeList) xp.evaluate(prefix + "security-role", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "security-role", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); if (nodesLen > 0) result.log("Security roles are not supported"); - nodes = (NodeList) xp.evaluate(prefix + "ejb-ref", document, - XPathConstants.NODESET); + nodes = (NodeList) xp.evaluate(prefix + "ejb-ref", document, XPathConstants.NODESET); nodesLen = nodes.getLength(); error = false; } catch (IOException ioe) { throw new ServletException("A problem in reading web.xml.", ioe); } catch (XPathExpressionException xpe) { - //server.log("", xpe); + // server.log("", xpe); throw new ServletException("A problem in parsing web.xml.", xpe); - } finally { - if (webxml != null) + } finally { + if (webxml != null) try { webxml.close(); - } catch(Exception e) {} - if (error) + } catch (Exception e) { + } + if (error) try { result.destroy(); - } catch(Exception e) {} + } catch (Exception e) { + } } result.scc = new SessionCookieConfigImpl(result); return deploywebsocket(result, deployDir, context, server, virtualHost); } - - public static WebAppServlet deploywebsocket(final WebAppServlet webApp, final File deployDir, String context, final Serve server, String virtualHost) - throws ServletException { - if (webApp.server.websocketProvider != null) { - File file = new File(deployDir, "WEB-INF/lib"); - ArrayList result = file.exists() && file.isDirectory()?new ArrayList(Arrays.asList(file.listFiles(new FileFilter() { - - @Override - public boolean accept(File pathname) { - String name = pathname.getName().toLowerCase(); - return pathname.isFile() && (name.endsWith(".jar") || name.endsWith(".zip")); - }}))):new ArrayList(); - file = new File(deployDir, "WEB-INF/classes"); - if (file.exists() && file.isDirectory()) - result.add(file); - if (webApp.listeners == null) - webApp.listeners = new ArrayList(2); - webApp.server.websocketProvider.deploy(webApp, result); - } - return webApp; - } - - static String toNormalizedString(Object o) { - if (o == null) - return ""; - if (o instanceof String) - return ((String)o).trim(); - return o.toString().trim(); - } - + + public static WebAppServlet deploywebsocket(final WebAppServlet webApp, final File deployDir, String context, final Serve server, String virtualHost) throws ServletException { + if (webApp.server.websocketProvider != null) { + File file = new File(deployDir, "WEB-INF/lib"); + ArrayList result = file.exists() && file.isDirectory() ? new ArrayList(Arrays.asList(file.listFiles(new FileFilter() { + + @Override + public boolean accept(File pathname) { + String name = pathname.getName().toLowerCase(); + return pathname.isFile() && (name.endsWith(".jar") || name.endsWith(".zip")); + } + }))) : new ArrayList(); + file = new File(deployDir, "WEB-INF/classes"); + if (file.exists() && file.isDirectory()) + result.add(file); + if (webApp.listeners == null) + webApp.listeners = new ArrayList(2); + webApp.server.websocketProvider.deploy(webApp, result); + } + return webApp; + } + + static String toNormalizedString(Object o) { + if (o == null) + return ""; + if (o instanceof String) + return ((String) o).trim(); + return o.toString().trim(); + } + static public void setRuntimeEnv(Object rte) { runtimeEnv = rte; } @@ -1313,27 +1088,25 @@ static public void setRuntimeEnv(Object rte) { static void addMultiple(NodeList list, D d) { // TODO can be solution for more compact code } - + static public String buildREbyPathPatt(String pathPat) { if (pathPat.length() == 0) return "/"; // context servlet - if (pathPat.equals("/")) // default servlet + if (pathPat.equals("/")) // default servlet return "/.*"; if (pathPat.startsWith("*.")) - return pathPat.replace(".", "\\.").replace("?", ".") - .replace("*", ".*").replace("|", "\\|"); // +"\\??.*"; + return pathPat.replace(".", "\\.").replace("?", ".").replace("*", ".*").replace("|", "\\|"); // +"\\??.*"; // TODO think more int wcp = pathPat.indexOf('*'); // if (wcp > 0 && pathPat.charAt(wcp - 1) == '/') // pathPat = pathPat.substring(0, wcp - 1) + '*'; - pathPat = pathPat.replace(".", "\\.").replace("?", ".") - .replace("*", ".*"); + pathPat = pathPat.replace(".", "\\.").replace("?", ".").replace("*", ".*"); if (wcp < 0) if (pathPat.endsWith("/") == false) pathPat += "/?"; return pathPat; } - + static public String clearPath(String pathMask) { if (pathMask.equals("/")) return pathMask; @@ -1346,20 +1119,28 @@ static public String clearPath(String pathMask) { return ""; return pathMask.substring(0, wcp); } - + + /** + * Converts the proxy object into Serve.ServeConnection class + * object. + * + * @param proxy + * @return + */ protected static Serve.ServeConnection toServeConnection(Object proxy) { - if (proxy instanceof Serve.ServeConnection) + if (proxy instanceof Serve.ServeConnection) { return (Serve.ServeConnection) proxy; - else if (proxy instanceof Openable) { - Object servCon = ((Openable) proxy).getOrigin(); - if (servCon instanceof Serve.ServeConnection) - return (Serve.ServeConnection) servCon; + } else if (proxy instanceof Openable) { + final Object openableServeConnection = ((Openable) proxy).getOrigin(); + if (openableServeConnection instanceof Serve.ServeConnection) { + return (Serve.ServeConnection) openableServeConnection; + } } + return null; } - - public void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException { + + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { // new Exception("call trace").printStackTrace(); // TODO check access rights Thread.currentThread().setContextClassLoader(ucl); @@ -1379,30 +1160,20 @@ public void service(ServletRequest req, ServletResponse res) // which supports relative path, no leading / means relative to // currently called if (_DEBUG) - System.err - .printf("Full req:%s, ContextPath: %s, ServletPath:%s, pathInfo:%s\n", - hreq.getRequestURI(), hreq.getContextPath(), - hreq.getServletPath(), path); + System.err.printf("Full req:%s, ContextPath: %s, ServletPath:%s, pathInfo:%s\n", hreq.getRequestURI(), hreq.getContextPath(), hreq.getServletPath(), path); SimpleFilterChain sfc = new SimpleFilterChain(); if (path != null) { // note a limitation, servlet name can't start with /WEB-INF - if (path.regionMatches(true, 0, "/WEB-INF", 0, - "/WEB-INF".length()) - || path.regionMatches(true, 0, "/META-INF", 0, - "/META-INF".length())) { - ((HttpServletResponse) res) - .sendError(HttpServletResponse.SC_NOT_FOUND); + if (path.regionMatches(true, 0, "/WEB-INF", 0, "/WEB-INF".length()) || path.regionMatches(true, 0, "/META-INF", 0, "/META-INF".length())) { + ((HttpServletResponse) res).sendError(HttpServletResponse.SC_NOT_FOUND); return; } for (FilterAccessDescriptor fad : filters) - if (fad.matchDispatcher(DispatcherType.REQUEST) - && fad.matchPath(path) >= 0) + if (fad.matchDispatcher(DispatcherType.REQUEST) && fad.matchPath(path) >= 0) sfc.add(fad); for (ServletAccessDescr sad : servlets) { if (_DEBUG) - System.err.println("Trying matching " + path + " to " - + Arrays.toString(sad.mapping) + " = " - + sad.matchPath(path)); + System.err.println("Trying matching " + path + " to " + Arrays.toString(sad.mapping) + " = " + sad.matchPath(path)); int patIndex; if ((patIndex = sad.matchPath(path)) >= 0) { if (sad.instance == null) { @@ -1419,43 +1190,30 @@ public void service(ServletRequest req, ServletResponse res) // ban // the // servlet? - ((HttpServletResponse) res) - .sendError( - HttpServletResponse.SC_GONE, - "Servlet " - + sad.name - + " hasn't been instantiated successfully or has been unloaded."); + ((HttpServletResponse) res).sendError(HttpServletResponse.SC_GONE, "Servlet " + sad.name + " hasn't been instantiated successfully or has been unloaded."); return; } } else { if (sad.timeToReactivate > 0) { - if (sad.timeToReactivate > System - .currentTimeMillis()) { - ((HttpServletResponse) res) - .setIntHeader( - "Retry-After", - (int) (sad.timeToReactivate - System - .currentTimeMillis()) / 1000 + 1); + if (sad.timeToReactivate > System.currentTimeMillis()) { + ((HttpServletResponse) res).setIntHeader("Retry-After", (int) (sad.timeToReactivate - System.currentTimeMillis()) / 1000 + 1); // ((HttpServletResponse) // res).setDateHeader("Retry-After", new // Date(sad.timeToReactivate)); - ((HttpServletResponse) res) - .sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + ((HttpServletResponse) res).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } else sad.timeToReactivate = 0; } } for (FilterAccessDescriptor fad : filters) - if (fad.matchDispatcher(DispatcherType.REQUEST) - && fad.matchServlet(sad.name) >= 0) + if (fad.matchDispatcher(DispatcherType.REQUEST) && fad.matchServlet(sad.name) >= 0) sfc.add(fad); // sfc.add(fad.filterInstance); // System.err.println("used:"+ // sad.servPath+", wanted:"+((WebAppServlet) // sad.getServletContext()).contextPath); - sfc.setFilter(new WebAppContextFilter( - sad.mapping[patIndex].servPath)); + sfc.setFilter(new WebAppContextFilter(sad.mapping[patIndex].servPath)); // add servlet in chain sfc.setServlet(sad); sfc.reset(); @@ -1464,20 +1222,16 @@ public void service(ServletRequest req, ServletResponse res) } } } else { - ((HttpServletResponse) res).sendRedirect(hreq.getRequestURI() - + "/"); + ((HttpServletResponse) res).sendRedirect(hreq.getRequestURI() + "/"); return; } - + // no matching, process as file sfc.setFilter(new WebAppContextFilter()); sfc.setServlet(new HttpServlet() { - public void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException { - String path = ((HttpServletRequest) req) - .getPathTranslated(); - returnFileContent(path, (HttpServletRequest) req, - (HttpServletResponse) res); + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { + String path = ((HttpServletRequest) req).getPathTranslated(); + returnFileContent(path, (HttpServletRequest) req, (HttpServletResponse) res); } }); sfc.reset(); @@ -1490,7 +1244,7 @@ public void service(ServletRequest req, ServletResponse res) } } } - + protected void fillSecureAttrs(ServletRequest req) { Serve.ServeConnection scon = toServeConnection(req); if (scon != null) { @@ -1498,8 +1252,7 @@ protected void fillSecureAttrs(ServletRequest req) { SSLSocket ssocket = (SSLSocket) scon.getSocket(); SSLSession ssess = ssocket.getSession(); String cipherSuite = ssess.getCipherSuite(); - req.setAttribute("javax.servlet.request.cipher_suite", - cipherSuite); + req.setAttribute("javax.servlet.request.cipher_suite", cipherSuite); int cipherBits = 0; // TODO cache in session if (cipherSuite.indexOf("128") > 0) @@ -1514,23 +1267,20 @@ else if (cipherSuite.indexOf("DES") > 0) cipherBits = 56; req.setAttribute("javax.servlet.request.key_size", cipherBits); try { - req.setAttribute("javax.servlet.request.X509Certificate", - ssess.getPeerCertificateChain()); + req.setAttribute("javax.servlet.request.X509Certificate", ssess.getPeerCertificateChain()); } catch (SSLPeerUnverifiedException e) { } } } else log("Can't obtain an original request for " + req); } - - protected SimpleFilterChain buildFilterChain(String servletName, - String requestPath, DispatcherType filterType) { + + protected SimpleFilterChain buildFilterChain(String servletName, String requestPath, DispatcherType filterType) { SimpleFilterChain sfc = new SimpleFilterChain(); // add path filters if (requestPath != null) for (FilterAccessDescriptor fad : filters) - if (fad.matchDispatcher(filterType) - && fad.matchPath(requestPath) >= 0) + if (fad.matchDispatcher(filterType) && fad.matchPath(requestPath) >= 0) sfc.add(fad); /* * if (filterType == error) { @@ -1540,18 +1290,16 @@ protected SimpleFilterChain buildFilterChain(String servletName, * ((Throwable)request * .getAttribute("javax.servlet.jsp.jspException")).printStackTrace(); } */ - + // add name filters if (servletName != null) for (FilterAccessDescriptor fad : filters) - if (fad.matchDispatcher(DispatcherType.REQUEST) - && fad.matchServlet(servletName) >= 0) + if (fad.matchDispatcher(DispatcherType.REQUEST) && fad.matchServlet(servletName) >= 0) sfc.add(fad); return sfc; } - - protected void returnFileContent(String path, HttpServletRequest req, - HttpServletResponse res) throws IOException, ServletException { + + protected void returnFileContent(String path, HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { // Note : can't call or forward to file servlet since it can be not // installed File fpath = new File(path); @@ -1579,10 +1327,10 @@ protected void returnFileContent(String path, HttpServletRequest req, res.sendError(res.SC_FORBIDDEN); return; } - + String temp = getMimeType(fpath.getName()); res.setContentType(temp); - + long lastMod = fpath.lastModified(); res.setDateHeader("Last-modified", lastMod); String ifModSinceStr = req.getHeader("If-Modified-Since"); @@ -1592,8 +1340,7 @@ protected void returnFileContent(String path, HttpServletRequest req, if (semi != -1) ifModSinceStr = ifModSinceStr.substring(0, semi); try { - ifModSince = DateFormat.getDateInstance().parse(ifModSinceStr) - .getTime(); + ifModSince = DateFormat.getDateInstance().parse(ifModSinceStr).getTime(); } catch (Exception ignore) { } } @@ -1609,7 +1356,7 @@ protected void returnFileContent(String path, HttpServletRequest req, doCompress = true; } } - + if ("HEAD".equals(req.getMethod())) { res.setHeader("Content-Length", Long.toString(fpath.length())); return; @@ -1632,8 +1379,9 @@ protected void returnFileContent(String path, HttpServletRequest req, PrintWriter pw = res.getWriter(); // TODO decide on encoding/charset used by the reader String charSetName = res.getCharacterEncoding(); - if (charSetName == null) - charSetName = Utils.ISO_8859_1; + if (charSetName == null) { + charSetName = IOHelper.ISO_8859_1; + } Utils.copyStream(new InputStreamReader(is, charSetName), pw); // consider Writer is OK to do not close // consider underneath stream closing OK @@ -1649,63 +1397,56 @@ protected void returnFileContent(String path, HttpServletRequest req, } } } - + protected ServletAccessDescr addJSPServlet(List patterns) { ServletAccessDescr sad = createDescriptor(); // get class name from serve sad.initParams = new HashMap(10); - Map arguments = (Map) server.arguments; - sad.className = arguments.get(Serve.ARG_JSP); + Map arguments = (Map) server.arguments; + sad.className = String.valueOf(arguments.get(Serve.ARG_JSP)); if (sad.className == null) { log("No JSP engine specified, Apache Jasper is assumed by default", null); sad.className = "org.apache.jasper.servlet.JspServlet"; - sad.initParams.put("scratchdir", - new File(deployDir, "META-INF/Jasper").getPath()); - sad.initParams.put("debug", System.getProperty(getClass().getName() - + ".debug") != null ? "yes" : "no"); + sad.initParams.put("scratchdir", new File(deployDir, "META-INF/Jasper").getPath()); + sad.initParams.put("debug", System.getProperty(getClass().getName() + ".debug") != null ? "yes" : "no"); sad.initParams.put("classpath", Utils.calculateClassPath(ucl)); } else { String pnpx = sad.className + '.'; int cnl = pnpx.length(); String classPath = Utils.calculateClassPath(ucl); - for (String ipn : arguments.keySet()) - if (ipn.startsWith(pnpx)) - sad.initParams - .put(ipn.substring(cnl), - arguments - .get(ipn) - .replace("%context%", contextName) - .replace("%deploydir%", - deployDir.getPath()) - .replace("%classloader%", - WEBAPPCLASSLOADER) - .replace("%classpath%", classPath)); + Iterator itr = arguments.keySet().iterator(); + while (itr.hasNext()) { + String ipn = (String) itr.next(); + sad.initParams.put(ipn.substring(cnl), ((String) arguments.get(ipn)).replace("%context%", contextName).replace("%deploydir%", deployDir.getPath()).replace("%classloader%", WEBAPPCLASSLOADER).replace("%classpath%", classPath)); + } } + sad.descr = "JSP support servlet"; sad.label = "JSP"; sad.loadOnStart = -1; sad.name = "jsp"; String jspPat; - if (patterns == null || patterns.size() == 0) + if (patterns == null || patterns.size() == 0) { jspPat = "/.*\\.jsp.*"; - else { + } else { jspPat = buildREbyPathPatt(patterns.get(0)); - for (int i = 1; i < patterns.size(); i++) + for (int i = 1; i < patterns.size(); i++) { jspPat += "|" + buildREbyPathPatt(patterns.get(i)); + } } sad.add(new MappingEntry("/", jspPat)); servlets.add(sad); return sad; } - + protected ServletAccessDescr createDescriptor() { return new ServletAccessDescr(); } - + protected FilterAccessDescriptor createFilterDescriptor() { return new FilterAccessDescriptor(); } - + protected void makeCP(File dd) throws IOException { deployDir = dd.getCanonicalFile(); final List urls = new ArrayList(); @@ -1713,10 +1454,7 @@ protected void makeCP(File dd) throws IOException { ClassLoader cl = getClass().getClassLoader(); while (cl != null) { if (cl instanceof URLClassLoader) { - if (((URLClassLoader) cl) - .findResource("javax/servlet/jsp/JspPage.class") != null - || ((URLClassLoader) cl) - .findResource("javax/servlet/http/HttpServlet.class") != null) { + if (((URLClassLoader) cl).findResource("javax/servlet/jsp/JspPage.class") != null || ((URLClassLoader) cl).findResource("javax/servlet/http/HttpServlet.class") != null) { for (URL url : ((URLClassLoader) cl).getURLs()) urls.add(url); } @@ -1728,7 +1466,7 @@ protected void makeCP(File dd) throws IOException { try { urls.add(classesFile.toURL()); } catch (java.net.MalformedURLException mfe) { - + } File libFile = new File(deployDir, "WEB-INF/lib"); libFile.listFiles(new FileFilter() { @@ -1738,32 +1476,27 @@ public boolean accept(File file) { try { urls.add(file.toURL()); } catch (java.net.MalformedURLException mfe) { - + } return false; } }); cpUrls = urls.toArray(new URL[urls.size()]); - - setAttribute(WEBAPPCLASSLOADER, - ucl = createClassLoader(cpUrls, getClass().getClassLoader())); + + setAttribute(WEBAPPCLASSLOADER, ucl = createClassLoader(cpUrls, getClass().getClassLoader())); // System.err.println("CP "+urls+"\nLoader:"+ucl); } - + ClassLoader createClassLoader(URL[] classPath, ClassLoader parent) { - String classLoaderClassName = System - .getProperty(WebApp.DEF_WEBAPP_CLASSLOADER); //WEBAPPCLASSLOADER + String classLoaderClassName = System.getProperty(WebApp.DEF_WEBAPP_CLASSLOADER); // WEBAPPCLASSLOADER // ClassLoader result = null; if (classLoaderClassName != null) { try { - // TODO consider constructor extra parameter PermissionCollection permissionCollection - return (ClassLoader) Class - .forName(classLoaderClassName, true, parent) - .getConstructor(URL[].class, ClassLoader.class) - .newInstance(classPath, parent); + // TODO consider constructor extra parameter + // PermissionCollection permissionCollection + return (ClassLoader) Class.forName(classLoaderClassName, true, parent).getConstructor(URL[].class, ClassLoader.class).newInstance(classPath, parent); } catch (Exception e) { - log("Creation of custom class loader " + classLoaderClassName - + " failed", e); + log("Creation of custom class loader " + classLoaderClassName + " failed", e); } } return new URLClassLoader(cpUrls, getClass().getClassLoader()) { @@ -1781,27 +1514,25 @@ public URL getResource(String name) { public File getDeploymentDir() { return deployDir; } - - void dispatch(String path, ServletRequest request, ServletResponse response) - throws ServletException, IOException { - ((SimpleDispatcher) request.getRequestDispatcher(path)).dispatch( - request, response, DispatcherType.ASYNC); + + void dispatch(String path, ServletRequest request, ServletResponse response) throws ServletException, IOException { + ((SimpleDispatcher) request.getRequestDispatcher(path)).dispatch(request, response, DispatcherType.ASYNC); } - + /* * protected URL toURL(File file) throws MalformedURLException { * System.err.println * ("file:/"+file.getAbsolutePath()+(file.isDirectory()?"/":"")); return new * URL("file:/"+file.getAbsolutePath()+(file.isDirectory()?"/":"")); } */ - + // ///////////////////////////////////////////////////////////////////////////////// // context methods @Override public String getContextPath() { return contextPath; } - + @Override public String getServletContextName() { return contextName; @@ -1811,7 +1542,7 @@ public String getServletContextName() { public String getServletInfo() { return description; } - + @Override public String getServletName() { return contextName; @@ -1823,11 +1554,9 @@ public void removeAttribute(String name) { if (listeners != null) for (EventListener listener : listeners) if (listener instanceof ServletContextAttributeListener) - ((ServletContextAttributeListener) listener) - .attributeRemoved(new ServletContextAttributeEvent( - this, name, value)); + ((ServletContextAttributeListener) listener).attributeRemoved(new ServletContextAttributeEvent(this, name, value)); } - + @Override public void setAttribute(String name, Object object) { // log("Set attr:"+name+" to "+object); @@ -1840,34 +1569,31 @@ public void setAttribute(String name, Object object) { for (EventListener listener : listeners) { if (listener instanceof ServletContextAttributeListener) if (oldObj == null) - ((ServletContextAttributeListener) listener) - .attributeAdded(new ServletContextAttributeEvent( - this, name, object)); + ((ServletContextAttributeListener) listener).attributeAdded(new ServletContextAttributeEvent(this, name, object)); else - ((ServletContextAttributeListener) listener) - .attributeReplaced(new ServletContextAttributeEvent( - this, name, object)); + ((ServletContextAttributeListener) listener).attributeReplaced(new ServletContextAttributeEvent(this, name, object)); } } - + @Override public Enumeration getAttributeNames() { return attributes.keys(); } - + @Override public Object getAttribute(String name) { - // log("context: "+this+" return attr:"+name+" as "+attributes.get(name)); + // log("context: "+this+" return attr:"+name+" as + // "+attributes.get(name)); if (runtimeEnv != null && RUNTIMEENV_ATTR.equals(name)) return runtimeEnv; return attributes.get(name); } - + @Override public String getServerInfo() { return "TJWS/J2EE container, Copyright © 2010 - 2016 Dmitriy Rogatkin"; } - + @Override public ServletContext getServletContext() { return this; @@ -1891,19 +1617,17 @@ public String getRealPath(String path) { public void log(String msg) { server.log((contextName == null ? "" : contextName) + "> " + msg); } - + @Override public void log(Exception exception, String msg) { - server.log(exception, (contextName == null ? "" : contextName) + "> " - + msg); + server.log(exception, (contextName == null ? "" : contextName) + "> " + msg); } @Override public void log(String message, Throwable throwable) { - server.log((contextName == null ? "" : contextName) + "> " + message, - throwable); + server.log((contextName == null ? "" : contextName) + "> " + message, throwable); } - + @Override public Enumeration getServletNames() { Vector result = new Vector(); @@ -1911,16 +1635,16 @@ public Enumeration getServletNames() { result.add(sad.name); return result.elements(); } - + @Override public Enumeration getServlets() { Vector result = new Vector(); for (ServletAccessDescr sad : servlets) result.add(sad.instance); return result.elements(); - + } - + @Override public Servlet getServlet(String name) throws ServletException { for (ServletAccessDescr sad : servlets) @@ -1928,7 +1652,7 @@ public Servlet getServlet(String name) throws ServletException { return sad.instance; throw new ServletException("No servlet " + name); } - + @Override public RequestDispatcher getNamedDispatcher(String name) { for (ServletAccessDescr sad : servlets) @@ -1945,7 +1669,7 @@ public RequestDispatcher getNamedDispatcher(String name) { } return null; } - + @Override public RequestDispatcher getRequestDispatcher(String path) { if (_DEBUG) @@ -1956,10 +1680,7 @@ public RequestDispatcher getRequestDispatcher(String path) { String clearPath = extractQueryAnchor(path, false); for (ServletAccessDescr sad : servlets) { if (_DEBUG) - System.err.printf( - "For dispatcher trying match %s (%s) %s = %d%n", path, - clearPath, Arrays.toString(sad.mapping), - sad.matchPath(clearPath)); + System.err.printf("For dispatcher trying match %s (%s) %s = %d%n", path, clearPath, Arrays.toString(sad.mapping), sad.matchPath(clearPath)); int patIndex; if ((patIndex = sad.matchPath(clearPath)) >= 0) { if (sad.instance == null && sad.loadOnStart < 0) @@ -1969,16 +1690,12 @@ public RequestDispatcher getRequestDispatcher(String path) { sad.newInstance(); } } catch (ServletException se) { - log(String.format( - "Can't instantiate a %s exception %s", sad, se), - se.getRootCause()); + log(String.format("Can't instantiate a %s exception %s", sad, se), se.getRootCause()); } if (_DEBUG) - System.err.printf("Found processing instance %s of %s%n", - sad.instance, sad); + System.err.printf("Found processing instance %s of %s%n", sad.instance, sad); if (sad.instance != null) - return new SimpleDispatcher(sad.instance, - sad.mapping[patIndex].servPath, path); + return new SimpleDispatcher(sad.instance, sad.mapping[patIndex].servPath, path); else return null; // servlet not working } @@ -1990,29 +1707,22 @@ public RequestDispatcher getRequestDispatcher(String path) { if (getResource(path) == null) throw new MalformedURLException(); // check path is valid return new SimpleDispatcher(new HttpServlet() { - public void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException { + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { String path; if (((HttpServletRequest) req).getAttribute("javax.servlet.include.request_uri") != null) - path = req - .getRealPath((String) req - .getAttribute("javax.servlet.include.path_info")); + path = req.getRealPath((String) req.getAttribute("javax.servlet.include.path_info")); else path = ((HttpServletRequest) req).getPathTranslated(); if (_DEBUG) - System.err - .printf("Dispatched file servlet for %s translated %s%n", - path, ((HttpServletRequest) req) - .getPathTranslated()); - returnFileContent(path, (HttpServletRequest) req, - (HttpServletResponse) res); + System.err.printf("Dispatched file servlet for %s translated %s%n", path, ((HttpServletRequest) req).getPathTranslated()); + returnFileContent(path, (HttpServletRequest) req, (HttpServletResponse) res); } }, path); } catch (MalformedURLException mfe) { } return null; } - + @Override public InputStream getResourceAsStream(String path) { try { @@ -2026,122 +1736,138 @@ public InputStream getResourceAsStream(String path) { } return null; } - + @Override public URL getResource(String path) throws MalformedURLException { - if (path.charAt(0) != '/') - throw new MalformedURLException("Path: " + path - + " has to start with '/'"); + if (path.charAt(0) != '/') { + throw new MalformedURLException("Path: " + path + " has to start with '/'"); + } path = extractQueryAnchor(path, false); - int ji = path.indexOf(".jar!/"); + // int ji = path.indexOf(".jar!/"); try { File resFile = new File(getRealPath(path)).getCanonicalFile(); - if (resFile.exists()) + if (resFile.exists()) { return resFile.toURL(); + } } catch (IOException io) { } + return null; } - + @Override public Set getResourcePaths(String path) { - if (path.charAt(0) != '/') - throw new IllegalArgumentException( - "getResourcePaths: path parameters must begin with '/'"); + if (path.charAt(0) != '/') { + throw new IllegalArgumentException("getResourcePaths: path parameters must begin with '/'"); + } + path = extractQueryAnchor(path, false); - int ji = path.indexOf(".jar!/"); - String jarpath = ""; - if (ji > 0) { - if (path.length() > ji+".jar!/".length()) - jarpath = path.substring(ji+".jar!/".length()); - path = path.substring(0, ji+4); + int jarIndex = path.indexOf(".jar!/"); + String jarPath = ""; + if (jarIndex > 0) { + if (path.length() > jarIndex + ".jar!/".length()) { + jarPath = path.substring(jarIndex + ".jar!/".length()); + } + path = path.substring(0, jarIndex + 4); } + File dir = new File(getRealPath(path)); - if (dir.exists() == false) + if (dir.exists() == false) { return null; - log("Path:"+path+" dir "+dir+" jar p "+jarpath); + } + log("Path:" + path + ", dir:" + dir + ", jarPath:" + jarPath); Set set = null; - if (dir.isDirectory() == false) { - if (ji > 0) { + if (dir.isDirectory() == false) { + if (jarIndex > 0) { set = new TreeSet(); try { - JarFile jarFile = new JarFile(dir); - int cp = jarpath.endsWith("/") ?jarpath.length():jarpath.length()+1; - for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { - JarEntry entry = (JarEntry) entries.nextElement(); - String entryPath = entry.getName(); - - if (cp == 1 || entryPath.startsWith(jarpath)) { - if (entryPath.length() == cp) - continue; - int ns = entryPath.indexOf('/', cp+1); - //log("e Path:"+entryPath+", ns "+ns); - if (ns > 0) - entryPath = entryPath.substring(0, ns+1); - set.add(new URL("jar:file:/"+dir.getPath()+"!/"+entryPath).toString()); - } - } - } catch(Exception e) { - log("Problem: "+e); - } - + JarFile jarFile = new JarFile(dir); + int cp = jarPath.endsWith("/") ? jarPath.length() : jarPath.length() + 1; + for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { + JarEntry entry = (JarEntry) entries.nextElement(); + String entryPath = entry.getName(); + if (cp == 1 || entryPath.startsWith(jarPath)) { + if (entryPath.length() == cp) { + continue; + } + + int ns = entryPath.indexOf('/', cp + 1); + // log("e Path:"+entryPath+", ns "+ns); + if (ns > 0) { + entryPath = entryPath.substring(0, ns + 1); + } + set.add(new URL("jar:file:/" + dir.getPath() + "!/" + entryPath).toString()); + } + } + jarFile.close(); + } catch (Exception ex) { + log("Problem: " + ex); + } + } + return set; } + set = new TreeSet(); String[] els = dir.list(); for (String el : els) { String fp = path + "/" + el; - if (new File(getRealPath(fp)).isDirectory()) + if (new File(getRealPath(fp)).isDirectory()) { fp += "/"; + } set.add("/" + fp); } + return set; } - + @Override public String getMimeType(String file) { if (mimes != null && file != null) { - int p = file.lastIndexOf('.'); - if (p > 0) { - String result = mimes.get(file.substring(p).toLowerCase()); - if (result != null) + int lastIndex = file.lastIndexOf('.'); + if (lastIndex > 0) { + String result = mimes.get(file.substring(lastIndex).toLowerCase()); + if (result != null) { return result; + } } } + return server.getMimeType(file); } - + @Override public int getMinorVersion() { return 0; } - + @Override public int getMajorVersion() { return 3; } - + @Override public ServletContext getContext(String uripath) { Servlet servlet = server.getServlet(uripath); - if (servlet != null) + if (servlet != null) { return servlet.getServletConfig().getServletContext(); + } return null; } - + @Override public String getInitParameter(String name) { return contextParameters.get(name); } - + @Override public Enumeration getInitParameterNames() { return contextParameters.keys(); } - + // ////////////// servlet spec 3.0 /////////////////////// - + /** * Gets the minor version of the Servlet specification that the application * represented by this ServletContext is based on. @@ -2150,7 +1876,7 @@ public Enumeration getInitParameterNames() { public int getEffectiveMinorVersion() { return 0; } - + /** * Gets the major version of the Servlet specification that the application * represented by this ServletContext is based on. @@ -2160,7 +1886,7 @@ public int getEffectiveMinorVersion() { public int getEffectiveMajorVersion() { return 3; } - + /** * Sets the context initialization parameter with the given name and value * on this ServletContext. @@ -2172,35 +1898,32 @@ public int getEffectiveMajorVersion() { * @return true if parameter set */ @Override - public boolean setInitParameter(java.lang.String name, - java.lang.String value) { + public boolean setInitParameter(java.lang.String name, java.lang.String value) { if (contextParameters != null) throw new IllegalStateException(); return false; } - + /** * Adds the servlet with the given name and class name to this servlet * context. * */ @Override - public ServletRegistration.Dynamic addServlet(String servletName, - String className) { + public ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); } - + /** * Registers the given servlet instance with this ServletContext under the * given servletName. * */ @Override - public ServletRegistration.Dynamic addServlet(String servletName, - Servlet servlet) { + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { throw new UnsupportedOperationException(); } - + /** * Adds the servlet with the given name and class type to this servlet * context. @@ -2209,11 +1932,10 @@ public ServletRegistration.Dynamic addServlet(String servletName, * ServletRegistration object. */ @Override - public ServletRegistration.Dynamic addServlet(String servletName, - Class servletClass) { + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { throw new UnsupportedOperationException(); } - + /** * Instantiates the given Servlet class. *

@@ -2222,22 +1944,20 @@ public ServletRegistration.Dynamic addServlet(String servletName, * addServlet(String,Servlet). */ @Override - public T createServlet(Class clazz) - throws ServletException { + public T createServlet(Class clazz) throws ServletException { throw new UnsupportedOperationException(); } - + /** * Gets the ServletRegistration corresponding to the servlet with the given * servletName. * */ @Override - public ServletRegistration getServletRegistration( - java.lang.String servletName) { + public ServletRegistration getServletRegistration(java.lang.String servletName) { throw new UnsupportedOperationException(); } - + /** * Gets a (possibly empty) Map of the ServletRegistration objects (keyed by * servlet name) corresponding to all servlets registered with this @@ -2247,18 +1967,17 @@ public ServletRegistration getServletRegistration( public Map getServletRegistrations() { throw new UnsupportedOperationException(); } - + /** * Adds the filter with the given name and class name to this servlet * context. * */ @Override - public FilterRegistration.Dynamic addFilter(String filterName, - String className) { + public FilterRegistration.Dynamic addFilter(String filterName, String className) { throw new UnsupportedOperationException(); } - + /** * Registers the given filter instance with this ServletContext under the * given filterName. @@ -2268,28 +1987,26 @@ public FilterRegistration.Dynamic addFilter(String filterName, public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { throw new UnsupportedOperationException(); } - + /** * Adds the filter with the given name and class type to this servlet * context. * */ @Override - public FilterRegistration.Dynamic addFilter(String filterName, - Class filterClass) { + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { throw new UnsupportedOperationException(); } - + /** * Instantiates the given Filter class. * */ @Override - public T createFilter(Class clazz) - throws ServletException { + public T createFilter(Class clazz) throws ServletException { throw new UnsupportedOperationException(); } - + /** * Gets the FilterRegistration corresponding to the filter with the given * filterName. @@ -2299,7 +2016,7 @@ public T createFilter(Class clazz) public FilterRegistration getFilterRegistration(String filterName) { throw new UnsupportedOperationException(); } - + /** * Gets a (possibly empty) Map of the FilterRegistration objects (keyed by * filter name) corresponding to all filters registered with this @@ -2310,7 +2027,7 @@ public FilterRegistration getFilterRegistration(String filterName) { public Map getFilterRegistrations() { throw new UnsupportedOperationException(); } - + public String getVirtualServerName() { return virtualHost; } @@ -2328,18 +2045,17 @@ public String getVirtualServerName() { public SessionCookieConfig getSessionCookieConfig() { return scc; } - + /** * Sets the session tracking modes that are to become effective for this * ServletContext * */ @Override - public void setSessionTrackingModes( - Set sessionTrackingModes) { - + public void setSessionTrackingModes(Set sessionTrackingModes) { + } - + /** * Gets the session tracking modes that are supported by default for this * ServletContext. @@ -2349,7 +2065,7 @@ public void setSessionTrackingModes( public Set getDefaultSessionTrackingModes() { return dstm; } - + /** * Gets the session tracking modes that are in effect for this * ServletContext @@ -2359,7 +2075,7 @@ public Set getDefaultSessionTrackingModes() { public Set getEffectiveSessionTrackingModes() { return stm; } - + /** * Adds the listener with the given class name to this ServletContext. * @@ -2368,7 +2084,7 @@ public Set getEffectiveSessionTrackingModes() { public void addListener(String className) { throw new UnsupportedOperationException(); } - + /** * Adds the given listener to this ServletContext. * @@ -2377,7 +2093,7 @@ public void addListener(String className) { public void addListener(T t) { listeners.add(t); } - + /** * Adds a listener of the given class type to this ServletContext. *

@@ -2396,17 +2112,16 @@ public void addListener(T t) { public void addListener(Class listenerClass) { throw new UnsupportedOperationException(); } - + /** * Instantiates the given EventListener class. * */ @Override - public T createListener(Class clazz) - throws ServletException { + public T createListener(Class clazz) throws ServletException { throw new UnsupportedOperationException(); } - + /** * Gets the related configuration that was aggregated from the * web.xml and web-fragment.xml descriptor files of the web application @@ -2417,7 +2132,7 @@ public T createListener(Class clazz) public JspConfigDescriptor getJspConfigDescriptor() { throw new UnsupportedOperationException(); } - + /** * Gets the class loader of the web application represented by this * ServletContext. @@ -2428,7 +2143,7 @@ public ClassLoader getClassLoader() { // TODO figure out when SecurityException should be thrown return ucl; } - + /** * Declares role names that are tested using isUserInRole. * @@ -2437,10 +2152,8 @@ public ClassLoader getClassLoader() { public void declareRoles(String... roleNames) { throw new UnsupportedOperationException(); } - - protected void setErrorAttributes(ServletRequest req, int status, - String msg, String servletName, String requestURI, Throwable t, - Class eclass) { + + protected void setErrorAttributes(ServletRequest req, int status, String msg, String servletName, String requestURI, Throwable t, Class eclass) { req.setAttribute("javax.servlet.error.status_code", status); req.setAttribute("javax.servlet.error.exception_type ", eclass); req.setAttribute("javax.servlet.error.message", msg); @@ -2452,40 +2165,51 @@ protected void setErrorAttributes(ServletRequest req, int status, public static String validatePath(String path) { return Utils.canonicalizePath(path); } - + @Override public void destroy() { Thread.currentThread().setContextClassLoader(ucl); asyncThreads.shutdown(); - if (filters != null) - for (FilterAccessDescriptor fad : filters) + if (filters != null) { + for (FilterAccessDescriptor fad : filters) { try { if (fad.filterInstance != null) fad.filterInstance.destroy(); } catch (Exception e) { log("Exception in filter destroy", e); } - for (ServletAccessDescr sad : servlets) + } + } + + for (ServletAccessDescr sad : servlets) { try { if (sad.instance != null) sad.instance.destroy(); } catch (Exception e) { log("Exception in servlet destroy", e); } - if (requestListeners != null) + } + + if (requestListeners != null) { requestListeners.clear(); - if (sessionListeners != null) // no notification since session can persist + } + + if (sessionListeners != null) { + // no notification since session can persist sessionListeners.clear(); + } if (listeners != null) { for (int i = listeners.size() - 1; i > -1; i--) { EventListener listener = listeners.get(i); - if (listener instanceof ServletContextListener) + if (listener instanceof ServletContextListener) { try { ((ServletContextListener) listener).contextDestroyed(new ServletContextEvent(this)); } catch (Exception e) { log("Exception in context destroy notification", e); } + } } + listeners.clear(); } Enumeration e = getAttributeNames(); @@ -2499,259 +2223,206 @@ public void destroy() { } // log("Destroy"); } - + protected class SimpleDispatcher implements RequestDispatcher { Servlet servlet; - String servletPath; - String path; - String named; - - SimpleDispatcher(Servlet s, String p) { - this(s, null, p); + + SimpleDispatcher(Servlet servlet, String path) { + this(servlet, null, path); } - - SimpleDispatcher(String n, Servlet s) { - this(s, null, null); + + SimpleDispatcher(String n, Servlet servlet) { + this(servlet, null, null); named = n; } - - SimpleDispatcher(Servlet s, String sp, String p) { - servlet = s; - path = p; - servletPath = sp; + + SimpleDispatcher(Servlet servlet, String servletPath, String path) { + this.servlet = servlet; + this.path = path; + this.servletPath = servletPath; // if (servletPath.length() > 1 && servletPath.endsWith("/")) // servletPath = servletPath.substring(0, servletPath.length()-1); // ending '/' adjustment done on demand } - + @Override public String toString() { - return String.format( - "Dispatcher for %s path %s name %s servlet %s", servlet, - path, named, servletPath); + return String.format("Dispatcher for %s path %s name %s servlet %s", servlet, path, named, servletPath); } - + // ////////////////////////////////////////////////////////////////// // interface RequestDispatcher + // ////////////////////////////////////////////////////////////////// + + /** + * + * @param request + * @param response + * @throws ServletException + * @throws IOException + * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, + * javax.servlet.ServletResponse) + */ @Override - public void forward(ServletRequest request, ServletResponse response) - throws ServletException, IOException { + public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { dispatch(request, response, DispatcherType.FORWARD); } - public void dispatch(ServletRequest request, ServletResponse response, - DispatcherType dispType) throws ServletException, IOException { - if (_DEBUG) - System.err.printf("%s path: %s, servlet: %s%n", dispType - .equals(DispatcherType.ASYNC) ? "ASYNC_DISPATCH" - : "FORWARD", path, servlet); + /** + * + * @param request + * @param response + * @param dispType + * @throws ServletException + * @throws IOException + */ + public void dispatch(ServletRequest request, ServletResponse response, DispatcherType dispType) throws ServletException, IOException { + if (_DEBUG) { + System.err.printf("%s path: %s, servlet: %s%n", dispType.equals(DispatcherType.ASYNC) ? "ASYNC_DISPATCH" : "FORWARD", path, servlet); + } + response.reset(); // drop all previously putting data and headers - SimpleFilterChain sfc = buildFilterChain( - named, - path, - request.getAttribute("javax.servlet.error.status_code") == null ? dispType - : DispatcherType.ERROR); + SimpleFilterChain sfc = buildFilterChain(named, path, request.getAttribute("javax.servlet.error.status_code") == null ? dispType : DispatcherType.ERROR); sfc.setServlet(servlet); sfc.reset(); - if (_DEBUG) + if (_DEBUG) { printRequestChain(request); + } // try{Thread.sleep(1000);}catch(Exception e) {} boolean toJsp = request.getAttribute("javax.servlet.tjws.servlet-jsp") != null; - sfc.doFilter(new DispatchedRequest((HttpServletRequest) request, - toJsp?DispatcherType.INCLUDE:dispType), response); + sfc.doFilter(new DispatchedRequest((HttpServletRequest) request, toJsp ? DispatcherType.INCLUDE : dispType), response); // servlet.service(new DispatchedRequest((HttpServletRequest) // request, true), response); } - - void printRequestChain(ServletRequest r) { - if (r instanceof DispatchedRequest) { - ServletRequest sr = r; - while (sr instanceof DispatchedRequest) { - System.err.println("Wrapper req:" + sr); - sr = ((DispatchedRequest) sr).getRequest(); - } - System.err.println("Original request:" + sr); - } else - System.err.println("Just request:" + r); + + void printRequestChain(ServletRequest servletRequest) { + if (servletRequest instanceof DispatchedRequest) { + ServletRequest tempServletRequest = servletRequest; + while (tempServletRequest instanceof DispatchedRequest) { + System.err.println("Wrapper req:" + tempServletRequest); + tempServletRequest = ((DispatchedRequest) tempServletRequest).getRequest(); + } + System.err.println("Original request:" + tempServletRequest); + } else { + System.err.println("Just request:" + servletRequest); + } } @Override - public void include(ServletRequest request, - final ServletResponse response) throws ServletException, - java.io.IOException { - Serve.ServeConnection scon = toServeConnection(response); - if (scon != null) - scon.setInInclude(true); - if (_DEBUG) - System.err - .printf("INCLUDE path: %s, servlet: %s, servlet path %s, name:%s%n", - path, servlet, servletPath, named); + public void include(ServletRequest request, final ServletResponse response) throws ServletException, java.io.IOException { + Serve.ServeConnection serveConnection = toServeConnection(response); + if (serveConnection != null) { + serveConnection.setInInclude(true); + } + if (_DEBUG) { + System.err.printf("INCLUDE path: %s, servlet: %s, servlet path %s, name:%s%n", path, servlet, servletPath, named); + } + try { - SimpleFilterChain sfc = buildFilterChain(named, path, - DispatcherType.INCLUDE); - sfc.setServlet(servlet); - sfc.reset(); - if (_DEBUG) + SimpleFilterChain filterChain = buildFilterChain(named, path, DispatcherType.INCLUDE); + filterChain.setServlet(servlet); + filterChain.reset(); + + if (_DEBUG) { printRequestChain(request); - sfc.doFilter(new DispatchedRequest( - (HttpServletRequest) request, DispatcherType.INCLUDE), - new HttpServletResponseWrapper( - (HttpServletResponse) response) { - // TODO review match to 2.5, some calls are allowed - // now - public void addDateHeader(java.lang.String name, - long date) { - } - - public void setDateHeader(java.lang.String name, - long date) { - } - - public void setHeader(java.lang.String name, - java.lang.String value) { - } - - public void addHeader(java.lang.String name, - java.lang.String value) { - } - - public void setIntHeader(java.lang.String name, - int value) { - } - - public void addIntHeader(java.lang.String name, - int value) { - } - - public void setStatus(int sc) { - } - - public void setStatus(int sc, java.lang.String sm) { - } - - public void sendRedirect(java.lang.String location) - throws java.io.IOException { - } - - public void sendError(int sc) - throws java.io.IOException { - } - - public void sendError(int sc, java.lang.String msg) - throws java.io.IOException { - } - - public void reset() { - } - - public void setLocale(java.util.Locale loc) { - } - - public void resetBuffer() { - } - - public void setContentType(java.lang.String type) { - } - - public void setContentLength(int len) { - } - - public void setCharacterEncoding( - java.lang.String charset) { - } - }); + } + + // send request to next filter, if any. + filterChain.doFilter(new DispatchedRequest((HttpServletRequest) request, DispatcherType.INCLUDE), (HttpServletResponse) response); } finally { - if (scon != null) - scon.setInInclude(false); + if (serveConnection != null) { + serveConnection.setInInclude(false); + } } } - + class DispatchedRequest extends HttpServletRequestWrapper { DispatcherType dispType; - boolean forward; - - DispatchedRequest(HttpServletRequest request, - DispatcherType dispType) { + + DispatchedRequest(HttpServletRequest request, DispatcherType dispType) { super(request); this.dispType = dispType; - forward = dispType.equals(DispatcherType.FORWARD) - || dispType.equals(DispatcherType.ASYNC); + forward = dispType.equals(DispatcherType.FORWARD) || dispType.equals(DispatcherType.ASYNC); // System.err.printf("Created !!!!1 %s%n", dispType); } - + @Override public String getPathInfo() { - if (forward) - return getPathInfo1(); - return super.getPathInfo(); + return (forward ? getPathInfo1() : super.getPathInfo()); } - + public String getPathInfo1() { - if (path == null) + if (path == null) { return super.getPathInfo(); - - if ("/".equals(servletPath)) + } + + if ("/".equals(servletPath)) { return null; - if (servletPath != null && servletPath.length() == 0 - && "/".equals(path)) + } + + if (servletPath != null && servletPath.length() == 0 && "/".equals(path)) { return path; - int qp = path.indexOf('?'); - //if (qp < 0) - //qp = path.indexOf('#'); - int sp = servletPath == null ? -1 : path.indexOf(servletPath); - if (sp >= 0) { - sp += servletPath.length() - - (servletPath.endsWith("/") ? 1 : 0); - if (_DEBUG) - System.err - .printf("FORWARD getPathinfo() path %s, servlet %s, sp %d, res %s%n", - path, servletPath, sp, - path.substring(sp)); - if (qp > sp) - return path.substring(sp, qp); - else - return path.substring(sp); } - if (_DEBUG) + + int qPath = path.indexOf('?'); + // if (qp < 0) + // qp = path.indexOf('#'); + int servletPathIndex = servletPath == null ? -1 : path.indexOf(servletPath); + if (servletPathIndex >= 0) { + servletPathIndex += servletPath.length() - (servletPath.endsWith("/") ? 1 : 0); + if (_DEBUG) { + System.err.printf("FORWARD getPathinfo() path %s, servlet %s, sp %d, res %s%n", path, servletPath, servletPathIndex, path.substring(servletPathIndex)); + } + + if (qPath > servletPathIndex) { + return path.substring(servletPathIndex, qPath); + } else { + return path.substring(servletPathIndex); + } + } + + if (_DEBUG) { System.err.printf("FORWARD get pathinfo ret: %s%n", path); - if (qp > 0) - return path.substring(0, qp); + } + + if (qPath > 0) { + return path.substring(0, qPath); + } + return path; } - + @Override public String getPathTranslated() { return getRealPath(getPathInfo()); } - + @Override public String getRealPath(String path) { return WebAppServlet.this.getRealPath(path); } - + @Override public String getServletPath() { if (forward) return getServletPath1(); return super.getServletPath(); } - + public String getServletPath1() { if (servletPath != null) if (servletPath.equals("/")) return extractQueryAnchor(path, false); else - return servletPath.endsWith("/") ? servletPath - .substring(0, servletPath.length() - 1) - : servletPath; - + return servletPath.endsWith("/") ? servletPath.substring(0, servletPath.length() - 1) : servletPath; + return super.getServletPath(); } - + public String getRequestURI1() { if (path == null) if (servletPath != null) @@ -2760,39 +2431,39 @@ public String getRequestURI1() { return null; return contextPath + extractQueryAnchor(path, false); } - + @Override public String getRequestURI() { - if (forward) - return getRequestURI1(); - return super.getRequestURI(); + return (forward ? getRequestURI1() : super.getRequestURI()); } - + @Override public String getContextPath() { return contextPath; } - + public String getQueryString1() { - if (path == null) - return null; - return extractQueryAnchor(path, true); + return (path == null ? null : extractQueryAnchor(path, true)); } - + @Override public String getQueryString() { - if (forward) + if (forward) { return getQueryString1(); - String q = super.getQueryString(); - if (q == null || q.isEmpty()) - q = getQueryString1(); - else - q += "&"+getQueryString1(); - return q; + } + + String queryString = super.getQueryString(); + if (queryString == null || queryString.isEmpty()) { + queryString = getQueryString1(); + } else { + queryString += "&" + getQueryString1(); + } + + return queryString; } - + @Override - public Enumeration getAttributeNames() { + public Enumeration getAttributeNames() { List attributes = new ArrayList(10); if (named == null) { if (forward) { @@ -2804,13 +2475,10 @@ public Enumeration getAttributeNames() { attributes.add(AsyncContext.ASYNC_SERVLET_PATH); } else { attributes.add("javax.servlet.forward.request_uri"); - attributes - .add("javax.servlet.forward.context_path"); - attributes - .add("javax.servlet.forward.servlet_path"); + attributes.add("javax.servlet.forward.context_path"); + attributes.add("javax.servlet.forward.servlet_path"); attributes.add("javax.servlet.forward.path_info"); - attributes - .add("javax.servlet.forward.query_string"); + attributes.add("javax.servlet.forward.query_string"); } } else { attributes.add("javax.servlet.include.request_uri"); @@ -2820,12 +2488,15 @@ public Enumeration getAttributeNames() { attributes.add("javax.servlet.include.query_string"); } } - Enumeration e = super.getAttributeNames(); - while (e.hasMoreElements()) + + Enumeration e = super.getAttributeNames(); + while (e.hasMoreElements()) { attributes.add((String) e.nextElement()); + } + return Collections.enumeration(attributes); } - + @Override public Object getAttribute(String name) { if (named == null) { @@ -2834,37 +2505,26 @@ public Object getAttribute(String name) { if (dispType.equals(DispatcherType.ASYNC)) { if (AsyncContext.ASYNC_REQUEST_URI.equals(name)) return super.getRequestURI(); - else if (AsyncContext.ASYNC_CONTEXT_PATH - .equals(name)) + else if (AsyncContext.ASYNC_CONTEXT_PATH.equals(name)) return super.getContextPath(); - else if (AsyncContext.ASYNC_SERVLET_PATH - .equals(name)) + else if (AsyncContext.ASYNC_SERVLET_PATH.equals(name)) return super.getServletPath(); else if (AsyncContext.ASYNC_PATH_INFO.equals(name)) return super.getPathInfo(); - else if (AsyncContext.ASYNC_QUERY_STRING - .equals(name)) + else if (AsyncContext.ASYNC_QUERY_STRING.equals(name)) return super.getQueryString(); } else { - if ("javax.servlet.forward.request_uri" - .equals(name)) + if ("javax.servlet.forward.request_uri".equals(name)) return super.getRequestURI(); - else if ("javax.servlet.forward.context_path" - .equals(name)) + else if ("javax.servlet.forward.context_path".equals(name)) return super.getContextPath(); - else if ("javax.servlet.forward.servlet_path" - .equals(name)) + else if ("javax.servlet.forward.servlet_path".equals(name)) return super.getServletPath(); - else if ("javax.servlet.forward.path_info" - .equals(name)) + else if ("javax.servlet.forward.path_info".equals(name)) return super.getPathInfo(); - else if ("javax.servlet.forward.query_string" - .equals(name)) + else if ("javax.servlet.forward.query_string".equals(name)) return super.getQueryString(); - else if ("javax.servlet.include.servlet_path" - .equals(name) - || "javax.servlet.include.request_uri" - .equals(name)) + else if ("javax.servlet.include.servlet_path".equals(name) || "javax.servlet.include.request_uri".equals(name)) return null; } } else { @@ -2872,19 +2532,13 @@ else if ("javax.servlet.include.servlet_path" return getRequestURI1(); else if ("javax.servlet.include.path_info".equals(name)) return getPathInfo1(); - else if ("javax.servlet.include.context_path" - .equals(name)) + else if ("javax.servlet.include.context_path".equals(name)) return getContextPath(); - else if ("javax.servlet.include.query_string" - .equals(name)) + else if ("javax.servlet.include.query_string".equals(name)) return getQueryString1(); - else if ("javax.servlet.include.servlet_path" - .equals(name)) + else if ("javax.servlet.include.servlet_path".equals(name)) return getServletPath1(); - else if ("javax.servlet.forward.request_uri" - .equals(name) - || "javax.servlet.forward.servlet_path" - .equals(name)) + else if ("javax.servlet.forward.request_uri".equals(name) || "javax.servlet.forward.servlet_path".equals(name)) return null; } } @@ -2892,67 +2546,77 @@ else if ("javax.servlet.forward.request_uri" // super.getAttribute(name)); return super.getAttribute(name); } - + @Override public void removeAttribute(String name) { - if (_DEBUG && name.startsWith("javax.servlet.")) - System.err - .printf("An attempt to remove systen ATTR: %s in mode %s = %s%n", - name, forward ? "FORWARD" : "INCLUDE", - getAttribute(name)); + if (_DEBUG && name.startsWith("javax.servlet.")) { + System.err.printf("An attempt to remove systen ATTR: %s in mode %s = %s%n", name, forward ? "FORWARD" : "INCLUDE", getAttribute(name)); + } super.removeAttribute(name); } - + // @Override // public void setAttribute(String name, Object value) { // System.err.printf("!!!Set attr %s=%s%n", name, value); // super.setAttribute(name, value); // } - + @Override public RequestDispatcher getRequestDispatcher(String path) { - if (_DEBUG) - System.err.printf("Request %s processing from %s%n", path, - forward ? "FORWARD" : "INCLUDE"); + if (_DEBUG) { + System.err.printf("Request %s processing from %s%n", path, forward ? "FORWARD" : "INCLUDE"); + } + if (path.charAt(0) != '/') { String sp = getServletPath(); String pi = getPathInfo(); if (pi == null) { int lsp = sp.lastIndexOf('/'); - if (lsp >= 0) + if (lsp >= 0) { path = sp.substring(0, lsp) + '/' + path; - else + } else { path = '/' + path; + } } else { int lsp = pi.lastIndexOf('/'); - if (lsp >= 0) + if (lsp >= 0) { path = sp + pi.substring(0, lsp) + '/' + path; - else + } else { path = sp + '/' + path; + } } + // System.err.printf("DEBUG: sp: %sp, pi: %s, p: %s%n", sp, // pi, path); } return WebAppServlet.this.getRequestDispatcher(path); } - + + /** + * + * @param name + * @return + * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) + */ @Override public String getParameter(String name) { Map params = createParameters(); String[] result = params.get(name); - if (result != null) + if (result != null) { return result[0]; + } + return super.getParameter(name); } - + @Override - public Map getParameterMap() { + public Map getParameterMap() { HashMap result = new HashMap(); result.putAll(super.getParameterMap()); result.putAll(createParameters()); return result; } - + @Override public Enumeration getParameterNames() { Map params = getParameterMap(); @@ -2960,7 +2624,7 @@ public Enumeration getParameterNames() { result.putAll(params); return result.keys(); } - + @Override public String[] getParameterValues(String name) { Map params = createParameters(); @@ -2969,30 +2633,28 @@ public String[] getParameterValues(String name) { return result; return super.getParameterValues(name); } - + // //////////////// servlet spec 3.0 /////////////////// - + /** * Use the container login mechanism configured for the * ServletContext to authenticate the user making this request. * */ - public boolean authenticate(HttpServletResponse response) - throws java.io.IOException, ServletException { + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { return super.authenticate(response); } - + /** * Validate the provided username and password in the password * validation realm used by the web container login mechanism * configured for the ServletContext. * */ - public void login(String username, String password) - throws ServletException { + public void login(String username, String password) throws ServletException { super.login(username, password); } - + /** * Establish null as the value returned when getUserPrincipal, * getRemoteUser, and getAuthType is called on the request. @@ -3001,34 +2663,31 @@ public void login(String username, String password) public void logout() throws ServletException { super.logout(); } - + /** * Gets all the Part components of this request, provided that it is * of type multipart/form-data. */ - public Collection getParts() throws java.io.IOException, - ServletException { + public Collection getParts() throws java.io.IOException, ServletException { return super.getParts(); } - + /** * Gets the Part with the given name. * */ - public Part getPart(String name) throws java.io.IOException, - ServletException { + public Part getPart(String name) throws java.io.IOException, ServletException { return super.getPart(name); } - + /** * Gets the dispatcher type of this request. * */ public DispatcherType getDispatcherType() { - return forward ? DispatcherType.FORWARD - : DispatcherType.INCLUDE; + return forward ? DispatcherType.FORWARD : DispatcherType.INCLUDE; } - + /** * Gets the AsyncContext that was created or reinitialized by the * most recent invocation of startAsync() or @@ -3047,7 +2706,7 @@ public DispatcherType getDispatcherType() { public AsyncContext getAsyncContext() { return super.getAsyncContext(); } - + /** * Puts this request into asynchronous mode, and initializes its * AsyncContext with the original (unwrapped) ServletRequest and @@ -3059,7 +2718,7 @@ public AsyncContext getAsyncContext() { public AsyncContext startAsync() throws IllegalStateException { return super.startAsync(); } - + /** * Puts this request into asynchronous mode, and initializes its * AsyncContext with the given request and response objects. The @@ -3074,12 +2733,10 @@ public AsyncContext startAsync() throws IllegalStateException { * @return * @throws IllegalStateException */ - public AsyncContext startAsync(ServletRequest servletRequest, - ServletResponse servletResponse) - throws IllegalStateException { + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { return super.startAsync(servletRequest, servletResponse); } - + /** * Checks if this request has been put into asynchronous mode. * @@ -3088,18 +2745,19 @@ public AsyncContext startAsync(ServletRequest servletRequest, public boolean isAsyncStarted() { return super.isAsyncStarted(); } - + protected Map createParameters() { String query = getQueryString(); - if (query != null) - return Acme.Utils.parseQueryString(query, null); + if (query != null) { + return Utils.parseQueryString(query, null); + } + return new Hashtable(); } - + @Override public String toString() { - return String.format("Dispatching request attached to %s", - SimpleDispatcher.this); + return String.format("Dispatching request attached to %s", SimpleDispatcher.this); } } } @@ -3107,87 +2765,88 @@ public String toString() { protected static class SessionCookieConfigImpl implements SessionCookieConfig { String comment; WebAppServlet was; + SessionCookieConfigImpl(WebAppServlet s) { was = s; } - + @Override public String getComment() { return comment; } - + @Override public String getDomain() { return null; } - + @Override public int getMaxAge() { if (was.server.expiredIn < 0) return -was.server.expiredIn; return 0; } - + @Override public String getName() { return Serve.ServeConnection.SESSION_COOKIE_NAME; } - + @Override public String getPath() { return was.contextPath; } - + @Override public boolean isHttpOnly() { return was.server.httpSessCookie; } - + @Override public boolean isSecure() { return was.server.secureSessCookie; } - + @Override public void setComment(String arg0) { - throw new IllegalStateException(); + throw new IllegalStateException(); } - + @Override public void setDomain(String arg0) { - throw new IllegalStateException(); + throw new IllegalStateException(); } - + @Override public void setHttpOnly(boolean arg0) { - throw new IllegalStateException(); + throw new IllegalStateException(); } - + @Override public void setMaxAge(int arg0) { - throw new IllegalStateException(); + throw new IllegalStateException(); } - + @Override public void setName(String arg0) { throw new IllegalStateException(); } - + @Override public void setPath(String arg0) { throw new IllegalStateException(); } - + @Override public void setSecure(boolean arg0) { throw new IllegalStateException(); } } - + // ////////////// Filter methods ///////////////////// protected class WebAppContextFilter implements Filter { String servPathHolder; - + WebAppContextFilter(String servletPath) { // TODO move to init() if (servletPath != null) @@ -3195,263 +2854,185 @@ protected class WebAppContextFilter implements Filter { else throw new NullPointerException("Servlet path is null"); } - + WebAppContextFilter() { this("/"); } - + public void init(FilterConfig filterConfig) throws ServletException { // no init for the filter } - + /** * this is mandatory filter converting TJWS base servlet requests to web * application context relative request */ - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws java.io.IOException, ServletException { + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException { final HttpServletRequest hreq = (HttpServletRequest) request; final HttpServletResponse hres = (HttpServletResponse) response; final HttpServletResponse[] proxiedRespHolder = new HttpServletResponse[1]; // TODO a research if request wrapper is more efficient - chain.doFilter( - (HttpServletRequest) Proxy.newProxyInstance( - javax.servlet.http.HttpServletRequest.class - .getClassLoader(), - new Class[] { - javax.servlet.http.HttpServletRequest.class, - Openable.class }, new InvocationHandler() { - AsyncContextImpl asyncCtx; - - boolean asyncEnabled; - - Multipart multiparts; - - public Object invoke(Object proxy, - Method method, Object[] args) - throws Throwable { + chain.doFilter((HttpServletRequest) Proxy.newProxyInstance(javax.servlet.http.HttpServletRequest.class.getClassLoader(), new Class[] { javax.servlet.http.HttpServletRequest.class, Openable.class }, new InvocationHandler() { + AsyncContextImpl asyncCtx; + + boolean asyncEnabled; + + Multipart multiparts; + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String mn = method.getName(); + if (mn.equals("getServletPath")) { + if (_DEBUG) + System.err.println("getServletPath() " + extractPath(hreq.getRequestURI(), contextPath, servPathHolder, false)); + return extractPath(hreq.getRequestURI(), contextPath, servPathHolder, false); + } else if (mn.equals("getPathInfo")) { + if (_DEBUG) + System.err.println("getPathInfo() " + extractPath(hreq.getRequestURI(), contextPath, servPathHolder, true)); + return extractPath(hreq.getRequestURI(), contextPath, servPathHolder, true); + } else if (mn.equals("getRealPath")) { + if (_DEBUG) + System.err.println("Path:" + args[0]); + return getRealPath((String) args[0]); + } else if (mn.equals("getPathTranslated")) { + return getRealPath(hreq.getPathInfo()); + } else if (mn.equals("getRequestDispatcher")) { + String url = (String) args[0]; + if (url.charAt(0) != '/') { + String bp = extractPath(hreq.getRequestURI(), contextPath, servPathHolder, false); + int lsp = bp.lastIndexOf('/'); + if (lsp > 0) + bp = bp.substring(0, lsp); + url = bp + '/' + url; + if (_DEBUG) + System.err.printf("req.getDispatcher(%s), %s %n", url, bp); + } + return getRequestDispatcher(url); + } else if (mn.equals("getContextPath")) { + return contextPath; + } else if (mn.equals("getSession")) { + HttpSession session = (HttpSession) method.invoke(hreq, args); + // System.err.println("getsession:"+session); + // TODO some overhead is here, context + // and listeners will be overloaded each + // time + // time of accessing session while it's + // new + if (session instanceof Serve.AcmeSession && (session.getServletContext() == null || session.isNew())) { + // System.err.println("set listeners & context"); + ((Serve.AcmeSession) session).setListeners(WebAppServlet.this.sessionListeners); + ((Serve.AcmeSession) session).setServletContext(WebAppServlet.this); + if (sessionTimeout > 0) + session.setMaxInactiveInterval(sessionTimeout); + } + return session; + } else if (mn.equals("startAsync")) { + // Async + // System.err.printf("STARTTTTTTTT %b %s %n", + // asyncEnabled, asyncCtx); + if (asyncEnabled == false) + throw new IllegalStateException("Async mode not enabled in app descriptor"); + if (asyncCtx == null) { + if (args == null || args.length == 0) + asyncCtx = new AsyncContextImpl((ServletRequest) proxy, proxiedRespHolder[0], (Serve.ServeConnection) hreq); + else + asyncCtx = new AsyncContextImpl((ServletRequest) args[0], (ServletResponse) args[1], (Serve.ServeConnection) hreq); + } + asyncCtx.notifyStart(); + return asyncCtx; + } else if (mn.equals("getServletContext")) { + return WebAppServlet.this; + } else if (mn.equals("isAsyncSupported")) { + return asyncEnabled; + } else if (mn.equals("isAsyncStarted")) { + return asyncCtx != null; + } else if (mn.equals("getAsyncContext")) { + if (asyncCtx != null) + return asyncCtx; + throw new IllegalStateException("Request has not been set in async mode"); + } else if (mn.equals("getDispatcherType")) { + return DispatcherType.REQUEST; + } else if (mn.equals("getParts")) { // //////////////////// + // Multi + // part + // /////////////////////////// + if (multiparts != null) + return multiparts.getParts(); + throw new ServletException(MULTIPART_ERR_MSQ); + } else if (mn.equals("getPart")) { + if (multiparts != null) + return multiparts.getPart((String) args[0]); + throw new ServletException(MULTIPART_ERR_MSQ); + } else if (attributeListeners != null) { + if (mn.equals("setAttribute")) { + Object av = hreq.getAttribute((String) args[0]); + hreq.setAttribute((String) args[0], args[1]); + if (av == null) { + ServletRequestAttributeEvent e = new ServletRequestAttributeEvent(WebAppServlet.this, hreq, (String) args[0], args[1]); + for (ServletRequestAttributeListener sarl : attributeListeners) + sarl.attributeAdded(e); + } else { + ServletRequestAttributeEvent e = new ServletRequestAttributeEvent(WebAppServlet.this, hreq, (String) args[0], av); + for (ServletRequestAttributeListener sarl : attributeListeners) + sarl.attributeReplaced(e); + } + return null; + } else if (mn.equals("removeAttribute")) { + Object av = hreq.getAttribute((String) args[0]); + hreq.removeAttribute((String) args[0]); + ServletRequestAttributeEvent e = new ServletRequestAttributeEvent(WebAppServlet.this, hreq, (String) args[0], av); + for (ServletRequestAttributeListener sarl : attributeListeners) + sarl.attributeRemoved(e); + return null; + } else if (mn.equals("getOrigin")) { + Object origin = hreq; + while (origin instanceof Openable) + origin = ((Openable) origin).getOrigin(); + return origin; + } + } + try { + return method.invoke(hreq, args); + } catch (InvocationTargetException ite) { + throw ite.getTargetException(); + } + } + }), // response); + proxiedRespHolder[0] = (HttpServletResponse) Proxy.newProxyInstance(javax.servlet.http.HttpServletResponse.class.getClassLoader(), new Class[] { javax.servlet.http.HttpServletResponse.class, Openable.class }, new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String mn = method.getName(); - if (mn.equals("getServletPath")) { - if (_DEBUG) - System.err.println("getServletPath() " - + extractPath(hreq - .getRequestURI(), - contextPath, - servPathHolder, - false)); - return extractPath( - hreq.getRequestURI(), - contextPath, servPathHolder, - false); - } else if (mn.equals("getPathInfo")) { - if (_DEBUG) - System.err.println("getPathInfo() " - + extractPath(hreq - .getRequestURI(), - contextPath, - servPathHolder, - true)); - return extractPath( - hreq.getRequestURI(), - contextPath, servPathHolder, - true); - } else if (mn.equals("getRealPath")) { - if (_DEBUG) - System.err.println("Path:" - + args[0]); - return getRealPath((String) args[0]); - } else if (mn.equals("getPathTranslated")) { - return getRealPath(hreq.getPathInfo()); - } else if (mn - .equals("getRequestDispatcher")) { - String url = (String) args[0]; - if (url.charAt(0) != '/') { - String bp = extractPath( - hreq.getRequestURI(), - contextPath, - servPathHolder, false); - int lsp = bp.lastIndexOf('/'); - if (lsp > 0) - bp = bp.substring(0, lsp); - url = bp + '/' + url; - if (_DEBUG) - System.err - .printf("req.getDispatcher(%s), %s %n", - url, bp); - } - return getRequestDispatcher(url); - } else if (mn.equals("getContextPath")) { - return contextPath; - } else if (mn.equals("getSession")) { - HttpSession session = (HttpSession) method - .invoke(hreq, args); - // System.err.println("getsession:"+session); - // TODO some overhead is here, context - // and listeners will be overloaded each - // time - // time of accessing session while it's - // new - if (session instanceof Serve.AcmeSession - && (session.getServletContext() == null || session - .isNew())) { - // System.err.println("set listeners & context"); - ((Serve.AcmeSession) session) - .setListeners(WebAppServlet.this.sessionListeners); - ((Serve.AcmeSession) session) - .setServletContext(WebAppServlet.this); - if (sessionTimeout > 0) - session.setMaxInactiveInterval(sessionTimeout); - } - return session; - } else if (mn.equals("startAsync")) { - // Async - //System.err.printf("STARTTTTTTTT %b %s %n", asyncEnabled, asyncCtx); - if (asyncEnabled == false) - throw new IllegalStateException( - "Async mode not enabled in app descriptor"); - if (asyncCtx == null) { - if (args == null || args.length == 0) - asyncCtx = new AsyncContextImpl( - (ServletRequest) proxy, - proxiedRespHolder[0], - (Serve.ServeConnection) hreq); - else - asyncCtx = new AsyncContextImpl( - (ServletRequest) args[0], - (ServletResponse) args[1], - (Serve.ServeConnection) hreq); - } - asyncCtx.notifyStart(); - return asyncCtx; - } else if (mn.equals("getServletContext")) { - return WebAppServlet.this; - } else if (mn.equals("isAsyncSupported")) { - return asyncEnabled; - } else if (mn.equals("isAsyncStarted")) { - return asyncCtx != null; - } else if (mn.equals("getAsyncContext")) { - if (asyncCtx != null) - return asyncCtx; - throw new IllegalStateException( - "Request has not been set in async mode"); - } else if (mn.equals("getDispatcherType")) { - return DispatcherType.REQUEST; - } else if (mn.equals("getParts")) { // //////////////////// - // Multi - // part - // /////////////////////////// - if (multiparts != null) - return multiparts.getParts(); - throw new ServletException( - MULTIPART_ERR_MSQ); - } else if (mn.equals("getPart")) { - if (multiparts != null) - return multiparts - .getPart((String) args[0]); - throw new ServletException( - MULTIPART_ERR_MSQ); - } else if (attributeListeners != null) { - if (mn.equals("setAttribute")) { - Object av = hreq - .getAttribute((String) args[0]); - hreq.setAttribute((String) args[0], - args[1]); - if (av == null) { - ServletRequestAttributeEvent e = new ServletRequestAttributeEvent( - WebAppServlet.this, - hreq, (String) args[0], - args[1]); - for (ServletRequestAttributeListener sarl : attributeListeners) - sarl.attributeAdded(e); - } else { - ServletRequestAttributeEvent e = new ServletRequestAttributeEvent( - WebAppServlet.this, - hreq, (String) args[0], - av); - for (ServletRequestAttributeListener sarl : attributeListeners) - sarl.attributeReplaced(e); - } - return null; - } else if (mn.equals("removeAttribute")) { - Object av = hreq - .getAttribute((String) args[0]); - hreq.removeAttribute((String) args[0]); - ServletRequestAttributeEvent e = new ServletRequestAttributeEvent( - WebAppServlet.this, hreq, - (String) args[0], av); - for (ServletRequestAttributeListener sarl : attributeListeners) - sarl.attributeRemoved(e); - return null; - } else if (mn.equals("getOrigin")) { - Object origin = hreq; - while (origin instanceof Openable) - origin = ((Openable) origin) - .getOrigin(); - return origin; - } - } - try { - return method.invoke(hreq, args); - } catch (InvocationTargetException ite) { - throw ite.getTargetException(); - } + if (mn.equals("sendError")) { + if (errorPages != null) + for (ErrorPageDescr epd : errorPages) + if (epd.errorCode == ((Integer) args[0]).intValue()) { + setErrorAttributes(hreq, (Integer) args[0], args.length > 1 ? (String) args[1] : "", getServletName(), hreq.getRequestURI(), null, null); + // System.err.printf("ERROR + // Forwarding to %s for + // %d%n",epd.errorPage, + // args[0]); + getRequestDispatcher(epd.errorPage).forward(hreq, hres); + return null; + } + } else if (mn.equals("getOrigin")) { + Object origin = hres; + while (origin instanceof Openable) + origin = ((Openable) origin).getOrigin(); + return origin; + + } // else if + // (mn.equals("sendRedirect")) { + // System.err.printf("Redirect + // to:%s%n",args[0]); + // } + return method.invoke(hres, args); } - }), // response); - proxiedRespHolder[0] = (HttpServletResponse) Proxy - .newProxyInstance( - javax.servlet.http.HttpServletResponse.class - .getClassLoader(), - new Class[] { - javax.servlet.http.HttpServletResponse.class, - Openable.class }, - new InvocationHandler() { - public Object invoke(Object proxy, - Method method, Object[] args) - throws Throwable { - String mn = method.getName(); - if (mn.equals("sendError")) { - if (errorPages != null) - for (ErrorPageDescr epd : errorPages) - if (epd.errorCode == ((Integer) args[0]) - .intValue()) { - setErrorAttributes( - hreq, - (Integer) args[0], - args.length > 1 ? (String) args[1] - : "", - getServletName(), - hreq.getRequestURI(), - null, null); - // System.err.printf("ERROR Forwarding to %s for %d%n",epd.errorPage, - // args[0]); - getRequestDispatcher( - epd.errorPage) - .forward( - hreq, - hres); - return null; - } - } else if (mn.equals("getOrigin")) { - Object origin = hres; - while (origin instanceof Openable) - origin = ((Openable) origin) - .getOrigin(); - return origin; - - } // else if - // (mn.equals("sendRedirect")) { - // System.err.printf("Redirect to:%s%n",args[0]); - // } - return method.invoke(hres, args); - } - })); + })); } - + public void destroy() { // destroy context filter } } - + /** * This function extract meaningful path or query * @@ -3468,7 +3049,7 @@ public static String extractQueryAnchor(String path, boolean query) { return path.substring(qp + 1); return null; } - int hp = -1;//path.indexOf('#'); + int hp = -1;// path.indexOf('#'); if (qp >= 0) { if (hp >= 0 && hp < qp) return path.substring(0, hp); @@ -3477,7 +3058,7 @@ public static String extractQueryAnchor(String path, boolean query) { return path.substring(0, hp); return path; } - + /** * This function extract certain path from request URI, URI is considered * and not decoded @@ -3491,18 +3072,19 @@ public static String extractQueryAnchor(String path, boolean query) { * @param info * @return */ - static public String extractPath(String uri, String context, - String servlet, boolean info) throws UnsupportedEncodingException { - uri = Utils.decode(uri, Serve.UTF8); - if (_DEBUG) - System.err - .printf("Extract path URI: %s, context: %s, servlet: %s, action: %b\n", - uri, context, servlet, info); + static public String extractPath(String uri, String context, String servlet, boolean info) throws UnsupportedEncodingException { + uri = Utils.decode(uri, IOHelper.UTF_8); + if (_DEBUG) { + System.err.printf("Extract path URI: %s, context: %s, servlet: %s, action: %b\n", uri, context, servlet, info); + } + int cl = context.length(); int sl = servlet.length(); int sp = uri.indexOf(servlet, cl); - if (_DEBUG) + if (_DEBUG) { System.err.printf("servlet pos: %d%n", sp); + } + if (sp < 0) { // if ("/".equals(servlet)) // sp = cl-1; @@ -3510,57 +3092,70 @@ static public String extractPath(String uri, String context, sp = cl; } int pp = uri.indexOf('?', sp); // + sl - pp = -1; // query is already separated and can be only part of forward - int ph = -1;// uri.indexOf('#', sp); // + sl - if (ph >= 0 && ((pp >= 0 && ph < pp) || pp < 0)) + // query is already separated and can be only part of forward + pp = -1; + // uri.indexOf('#', sp); // + sl + int ph = -1; + if (ph >= 0 && ((pp >= 0 && ph < pp) || pp < 0)) { pp = ph; + } + int ip = uri.indexOf('/', sp + sl - (servlet.endsWith("/") ? 1 : 0)); - if (_DEBUG) - System.err.printf("servlet pos %d, info pos: %d, param pos: %d %n", - sp, ip, pp); + if (_DEBUG) { + System.err.printf("servlet pos %d, info pos: %d, param pos: %d %n", sp, ip, pp); + } + if (info == false) { - if (servlet.equals("/") || ip < 0) - if (pp > 0) + if (servlet.equals("/") || ip < 0) { + if (pp > 0) { return uri.substring(sp, pp); - else + } else { return uri.substring(sp); - if (pp < 0) + } + } + + if (pp < 0) { return uri.substring(sp, ip); - + } + return uri.substring(sp, pp); } - if (servlet.equals("/") || ip < 0 || (pp > 0 && ip > pp)) + + if (servlet.equals("/") || ip < 0 || (pp > 0 && ip > pp)) { return null; - if (pp < 0) + } + + if (pp < 0) { return uri.substring(ip); + } + return uri.substring(ip, pp); } - + protected class SimpleFilterChain implements FilterChain { List filters; - + Iterator iterator; - + Servlet servlet; - + Filter filter; - + // FilterAccessDescriptor - + Filter nextFilter; - + ServletAccessDescr sad; - + SimpleFilterChain() { filters = new ArrayList(); } - + public void setFilter(Filter filter) { this.filter = filter; } - - public void doFilter(ServletRequest request, ServletResponse response) - throws IOException, ServletException { + + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // TODO decide if wrap in a object returning isAsyncSupported based // on asyncSupported // for servlet or filter without descriptor asyncSupported = false @@ -3570,9 +3165,7 @@ public void doFilter(ServletRequest request, ServletResponse response) } else if (iterator.hasNext()) { FilterAccessDescriptor fad = iterator.next(); try { - fad.filterInstance.doFilter( - applyAsyncSet(request, fad.asyncSupported), - response, this); + fad.filterInstance.doFilter(applyAsyncSet(request, fad.asyncSupported), response, this); } catch (UnavailableException ue) { if (ue.isPermanent()) { synchronized (fad) { @@ -3582,8 +3175,7 @@ public void doFilter(ServletRequest request, ServletResponse response) } } } else { - fad.timeToReactivate = System.currentTimeMillis() - + ue.getUnavailableSeconds() * 1000l; + fad.timeToReactivate = System.currentTimeMillis() + ue.getUnavailableSeconds() * 1000l; } doFilter(request, response); // iterator.remove(); @@ -3594,10 +3186,7 @@ public void doFilter(ServletRequest request, ServletResponse response) // call sevlet try { // new Exception("==RUN AS SERVLET==").printStackTrace(); - servlet.service( - applyAsyncSet(applyMultipart(request), - sad == null ? false : sad.asyncSupported), - response); + servlet.service(applyAsyncSet(applyMultipart(request), sad == null ? false : sad.asyncSupported), response); } catch (IOException ioe) { if (handleError(ioe, request, response) == false) throw ioe; @@ -3613,13 +3202,10 @@ public void doFilter(ServletRequest request, ServletResponse response) } } } else { - sad.timeToReactivate = System.currentTimeMillis() - + ue.getUnavailableSeconds() * 1000l; + sad.timeToReactivate = System.currentTimeMillis() + ue.getUnavailableSeconds() * 1000l; } } - ((HttpServletResponse) response).sendError( - HttpServletResponse.SC_SERVICE_UNAVAILABLE, - ue.getMessage()); + ((HttpServletResponse) response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, ue.getMessage()); // allowing custom handling? // eating an exception to avoid removing entire webapp // servlet throw ue; @@ -3633,17 +3219,14 @@ public void doFilter(ServletRequest request, ServletResponse response) throw new RuntimeException(re); } } - - protected ServletRequest applyAsyncSet(ServletRequest request, - boolean asyncEnabled) { + + protected ServletRequest applyAsyncSet(ServletRequest request, boolean asyncEnabled) { // TODO decide if add wrapper if (asyncEnabled) { if (Proxy.isProxyClass(request.getClass())) { - InvocationHandler handler = Proxy - .getInvocationHandler(request); + InvocationHandler handler = Proxy.getInvocationHandler(request); try { - handler.getClass().getDeclaredField("asyncEnabled") - .set(handler, Boolean.TRUE); + handler.getClass().getDeclaredField("asyncEnabled").set(handler, Boolean.TRUE); } catch (Exception e) { log("", e); } @@ -3651,12 +3234,11 @@ protected ServletRequest applyAsyncSet(ServletRequest request, } return request; } - - protected ServletRequest applyMultipart(ServletRequest request) - throws IOException { + + protected ServletRequest applyMultipart(ServletRequest request) throws IOException { if (sad == null || sad.multipartEnabled == false) return request; - + String contentType = request.getContentType(); if (contentType != null) { contentType = contentType.toLowerCase(); @@ -3664,100 +3246,78 @@ protected ServletRequest applyMultipart(ServletRequest request) if (pi < 0) return request; if (Proxy.isProxyClass(request.getClass()) == false) { - log(String.format("Request object isn't a proxy class (%s), multipart data can't be added", request.getClass()), null); - return request; + log(String.format("Request object isn't a proxy class (%s), multipart data can't be added", request.getClass()), null); + return request; } - - pi = contentType.indexOf("boundary=", pi - + "multipart/form-data".length()); + + pi = contentType.indexOf("boundary=", pi + "multipart/form-data".length()); if (pi <= 0) // invalid multipart request no boundary - throw new IOException("Boundary attribute is missed in " - + contentType); + throw new IOException("Boundary attribute is missed in " + contentType); int ei = contentType.indexOf(';', pi + "boundary=".length()); contentType = request.getContentType(); // since to lower case // was applied - String boundary = ei < 0 ? contentType.substring(pi - + "boundary=".length()) : contentType.substring(pi - + "boundary=".length(), ei); + String boundary = ei < 0 ? contentType.substring(pi + "boundary=".length()) : contentType.substring(pi + "boundary=".length(), ei); InvocationHandler handler = Proxy.getInvocationHandler(request); try { - handler.getClass() - .getDeclaredField("multiparts") - .set(handler, new Multipart(request, boundary, sad)); + handler.getClass().getDeclaredField("multiparts").set(handler, new Multipart(request, boundary, sad)); } catch (Exception e) { log("", e); } } return request; } - - protected boolean handleError(Throwable t, ServletRequest request, - ServletResponse response) throws java.io.IOException, - ServletException { + + protected boolean handleError(Throwable t, ServletRequest request, ServletResponse response) throws java.io.IOException, ServletException { if (errorPages != null) { - Class eclass = t.getClass(); + Class eclass = t.getClass(); for (ErrorPageDescr epd : errorPages) { if (epd.exception != null && eclass.equals(epd.exception)) { log("forward to " + epd.errorPage, t); - ((HttpServletResponse) response) - .sendRedirect(epd.errorPage); - setErrorAttributes(request, -1, t.getMessage(), - getServletName(), - ((HttpServletRequest) request).getRequestURI(), - t, t.getClass()); - getRequestDispatcher(epd.errorPage).forward(request, - response); + ((HttpServletResponse) response).sendRedirect(epd.errorPage); + setErrorAttributes(request, -1, t.getMessage(), getServletName(), ((HttpServletRequest) request).getRequestURI(), t, t.getClass()); + getRequestDispatcher(epd.errorPage).forward(request, response); return true; } } - Class[] peclasses = eclass.getClasses(); - for (Class peclass : peclasses) + Class[] peclasses = eclass.getClasses(); + for (Class peclass : peclasses) for (ErrorPageDescr epd : errorPages) { - if (epd.exception != null - && peclass.equals(epd.exception)) { + if (epd.exception != null && peclass.equals(epd.exception)) { log("forward to " + epd.errorPage, t); - ((HttpServletResponse) response) - .sendRedirect(epd.errorPage); - setErrorAttributes(request, -1, t.getMessage(), - getServletName(), - ((HttpServletRequest) request) - .getRequestURI(), t, t.getClass()); - getRequestDispatcher(epd.errorPage).forward( - request, response); + ((HttpServletResponse) response).sendRedirect(epd.errorPage); + setErrorAttributes(request, -1, t.getMessage(), getServletName(), ((HttpServletRequest) request).getRequestURI(), t, t.getClass()); + getRequestDispatcher(epd.errorPage).forward(request, response); return true; } } - + } return false; } - + protected void reset() { iterator = filters.iterator(); nextFilter = filter; } - + protected void add(FilterAccessDescriptor fad) { - if (fad.timeToReactivate > 0 - && fad.timeToReactivate > System.currentTimeMillis()) + if (fad.timeToReactivate > 0 && fad.timeToReactivate > System.currentTimeMillis()) return; if (filters.contains(fad) == false) filters.add(fad); } - + protected void setServlet(Servlet servlet) { this.servlet = servlet; sad = null; } - + protected void setServlet(ServletAccessDescr sad) { this.servlet = sad.instance; this.sad = sad; } } - + private final static boolean _DEBUG = false; - - private final static boolean __DEBUG = "yes".equals(System - .getProperty(DEF_DEBUG)) || _DEBUG; + private final static boolean __DEBUG = "yes".equals(System.getProperty(DEF_DEBUG)) || _DEBUG; } \ No newline at end of file diff --git a/1.x/src/rogatkin/wskt/EndPointScanner.java b/src/rogatkin/wskt/EndPointScanner.java similarity index 54% rename from 1.x/src/rogatkin/wskt/EndPointScanner.java rename to src/rogatkin/wskt/EndPointScanner.java index 602f7d2..0677672 100644 --- a/1.x/src/rogatkin/wskt/EndPointScanner.java +++ b/src/rogatkin/wskt/EndPointScanner.java @@ -1,10 +1,5 @@ package rogatkin.wskt; -import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; -import io.github.lukehutch.fastclasspathscanner.matchprocessor.ClassAnnotationMatchProcessor; -import io.github.lukehutch.fastclasspathscanner.matchprocessor.InterfaceMatchProcessor; -import io.github.lukehutch.fastclasspathscanner.matchprocessor.SubclassMatchProcessor; - import java.io.File; import java.io.FileFilter; import java.io.FileWriter; @@ -21,28 +16,41 @@ import javax.websocket.server.ServerApplicationConfig; import javax.websocket.server.ServerEndpoint; -public class EndPointScanner { +import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; +import io.github.lukehutch.fastclasspathscanner.matchprocessor.ClassAnnotationMatchProcessor; +import io.github.lukehutch.fastclasspathscanner.matchprocessor.InterfaceMatchProcessor; +import io.github.lukehutch.fastclasspathscanner.matchprocessor.SubclassMatchProcessor; +public class EndPointScanner { + protected static final char[] CR = { '\r', '\n' }; - + + /** + * + * @param args + */ public static void main(String... args) { if (args.length != 2) { usage(); System.exit(1); } - File web_inf = new File(args[0]); - if (web_inf.exists() == false || web_inf.isAbsolute() == false) { + + File webINFFile = new File(args[0]); + if (webINFFile.exists() == false || webINFFile.isAbsolute() == false) { System.out.printf("Argument %s doesn't point ot valid WEB-INF directory%n", args[0]); System.exit(-1); } - ArrayList cp = new ArrayList<>(); - File classes = new File(web_inf, "classes"); - if (classes.exists() && classes.isDirectory()) - cp.add(classes); - File lib = new File(web_inf, "lib"); + + ArrayList classPaths = new ArrayList(); + File classes = new File(webINFFile, "classes"); + if (classes.exists() && classes.isDirectory()) { + classPaths.add(classes); + } + + File lib = new File(webINFFile, "lib"); if (lib.exists() && lib.isDirectory()) { - cp.addAll(Arrays.asList(lib.listFiles(new FileFilter() { - + classPaths.addAll(Arrays.asList(lib.listFiles(new FileFilter() { + @Override public boolean accept(File f) { if (f.isFile()) { @@ -53,34 +61,42 @@ public boolean accept(File f) { } }))); } - try (FileWriter w = new FileWriter(args[1]);) { - new EndPointScanner().scan(cp, w); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + + FileWriter fileWriter = null; + try { + fileWriter = new FileWriter(args[1]); + new EndPointScanner().scan(classPaths, fileWriter); + } catch (IOException ex) { + ex.printStackTrace(); } } - + static void usage() { System.out.printf("Usage: EndPointScanner %n"); } - - public void scan(final List cp, final Writer w) { + + /** + * Scans the class paths. + * + * @param classPaths + * @param writer + */ + public void scan(final List classPaths, final Writer writer) { new FastClasspathScanner("") { URLClassLoader classLoader; - + @Override public List getUniqueClasspathElements() { - return cp; + return classPaths; } - + @Override public ClassLoader getClassLoader() { if (classLoader == null) { - URL[] urls = new URL[cp.size()]; - for (int j = 0, n = cp.size(); j < n; j++) + URL[] urls = new URL[classPaths.size()]; + for (int j = 0, n = classPaths.size(); j < n; j++) try { - urls[j] = cp.get(j).toURI().toURL(); + urls[j] = classPaths.get(j).toURI().toURL(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -89,62 +105,59 @@ public ClassLoader getClassLoader() { } return classLoader; } - + @Override public void scan() { try { super.scan(); } finally { - try { - if (classLoader != null) + try { + if (classLoader != null) { classLoader.getClass().getMethod("close").invoke(classLoader); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + } + } catch (Exception ex) { + ex.printStackTrace(); } } } - - }.matchClassesImplementing(ServerApplicationConfig.class, - new InterfaceMatchProcessor() { - - @Override - public void processMatch(Class arg0) { - try { - w.write("ServerApplicationConfig "); - w.write(arg0.getName()); - w.write(CR); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - }).matchClassesWithAnnotation(ServerEndpoint.class, new ClassAnnotationMatchProcessor() { - public void processMatch(Class matchingClass) { + + }.matchClassesImplementing(ServerApplicationConfig.class, new InterfaceMatchProcessor() { + + @Override + public void processMatch(Class arg0) { try { - w.write("ServerEndpoint "); - w.write(matchingClass.getName()); - w.write(CR); + writer.write("ServerApplicationConfig "); + writer.write(arg0.getName()); + writer.write(CR); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } + + }).matchClassesWithAnnotation(ServerEndpoint.class, new ClassAnnotationMatchProcessor() { + public void processMatch(Class matchingClass) { + try { + writer.write("ServerEndpoint "); + writer.write(matchingClass.getName()); + writer.write(CR); + } catch (IOException ex) { + ex.printStackTrace(); + } + } }).matchSubclassesOf(Endpoint.class, new SubclassMatchProcessor() { - + @Override public void processMatch(Class arg0) { try { - w.write("Endpoint "); - w.write(arg0.getName()); - w.write(CR); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + writer.write("Endpoint "); + writer.write(arg0.getName()); + writer.write(CR); + } catch (IOException ex) { + ex.printStackTrace(); } } }).scan(); - + } } diff --git a/1.x/src/rogatkin/wskt/SSLSelectorAcceptor.java b/src/rogatkin/wskt/SSLSelectorAcceptor.java old mode 100644 new mode 100755 similarity index 70% rename from 1.x/src/rogatkin/wskt/SSLSelectorAcceptor.java rename to src/rogatkin/wskt/SSLSelectorAcceptor.java index 5e604b8..f871679 --- a/1.x/src/rogatkin/wskt/SSLSelectorAcceptor.java +++ b/src/rogatkin/wskt/SSLSelectorAcceptor.java @@ -68,54 +68,50 @@ public class SSLSelectorAcceptor extends SSLAcceptor { private ServerSocketChannel channel; - private Selector selector; - - private Iterator readyItor; - + private Iterator readyItr; private boolean clientAuth; - - //protected SSLEngine sslEngine; + + // protected SSLEngine sslEngine; private SSLContext context; - protected ExecutorService exec; - + public Socket accept() throws IOException { do { - if (readyItor == null) { - if (selector.select() > 0) - readyItor = selector.selectedKeys().iterator(); - else + if (readyItr == null) { + if (selector.select() > 0) { + readyItr = selector.selectedKeys().iterator(); + } else { throw new IOException(); + } } - - if (readyItor.hasNext()) { - + + if (readyItr.hasNext()) { // Get key from set - SelectionKey key = (SelectionKey) readyItor.next(); - + SelectionKey selectionKey = readyItr.next(); // Remove current entry - readyItor.remove(); + readyItr.remove(); // TODO add processing CancelledKeyException - if (key.isValid() && key.isAcceptable()) { + if (selectionKey.isValid() && selectionKey.isAcceptable()) { // Get channel - ServerSocketChannel keyChannel = (ServerSocketChannel) key.channel(); - + ServerSocketChannel keyChannel = (ServerSocketChannel) selectionKey.channel(); // Get server socket ServerSocket serverSocket = keyChannel.socket(); - + // Accept request SSLEngine sslEngine = context.createSSLEngine(); - if (clientAuth) + if (clientAuth) { sslEngine.setNeedClientAuth(clientAuth); + } sslEngine.setUseClientMode(false); return new SSLChannelSocket(serverSocket.accept(), sslEngine, exec); } - } else - readyItor = null; + } else { + readyItr = null; + } } while (true); } - + public void destroy() throws IOException { String exceptions = ""; try { @@ -128,142 +124,156 @@ public void destroy() throws IOException { } catch (IOException e) { exceptions += e.toString(); } - if (exceptions.length() > 0) + if (exceptions.length() > 0) { throw new IOException(exceptions); - if (exec != null) + } + if (exec != null) { exec.shutdownNow(); + } } - - public void init(Map inProperties, Map outProperties) throws IOException { + + /** + * @see Acme.Serve.SSLAcceptor#init(java.util.Map, java.util.Map) + */ + public void init(Map inProperties, Map outProperties) throws IOException { clientAuth = "true".equals(inProperties.get(ARG_CLIENTAUTH)); - context = initSSLContext(inProperties, outProperties); - selector = Selector.open(); - + channel = ServerSocketChannel.open(); channel.configureBlocking(false); - int port = Utils.parseInt(inProperties.get(ARG_PORT), Utils.parseInt(inProperties.get(Serve.ARG_PORT), PORT)); - so_hs_timeout = Utils.parseInt(inProperties.get(ARG_SO_HS_TIMEOUT), SO_HS_TIMEOIUT); + int port = Utils.parseInt(inProperties.get(ARG_PORT), Utils.parseInt(inProperties.get(Serve.ARG_PORT), PORT)); + socketHandshakeTimeout = Utils.parseInt(inProperties.get(ARG_SO_HS_TIMEOUT), SO_HS_TIMEOIUT); InetSocketAddress isa = null; - if (inProperties.get(Serve.ARG_BINDADDRESS) != null) + if (inProperties.get(Serve.ARG_BINDADDRESS) != null) { try { isa = new InetSocketAddress((String) inProperties.get(Serve.ARG_BINDADDRESS), port); - } catch (Exception e) { + } catch (Exception ex) { } - if (isa == null) + } + + if (isa == null) { isa = new InetSocketAddress(port); + } + // TODO add ARG_BACKLOG channel.socket().bind(isa); - + // Register interest in when connection channel.register(selector, SelectionKey.OP_ACCEPT); if (outProperties != null) { - if (channel.socket().isBound()) + if (channel.socket().isBound()) { outProperties.put(Serve.ARG_BINDADDRESS, channel.socket().getInetAddress().getHostName()); - else + } else { outProperties.put(Serve.ARG_BINDADDRESS, InetAddress.getLocalHost().getHostName()); + } } exec = Executors.newSingleThreadScheduledExecutor(); } - + + /** + * @see Acme.Serve.SSLAcceptor#toString() + */ public String toString() { - return "SSLSelectorAcceptor - " + (channel == null ? "unset" : "" + channel.socket()); + return "SSLSelectorAcceptor - " + (channel != null ? channel.socket() : "Unset!"); } - + protected static class SSLChannelSocket extends Socket { Socket socket; - SSLSocketChannel channel; - ByteBuffer readBuff, writeBuff; - InputStream inp; - OutputStream outp; - - protected SSLChannelSocket(Socket socket, SSLEngine sslEngine, ExecutorService exec) throws IOException { + SSLSocketChannel sslSocketChannel; + ByteBuffer readBuffer, writeBuffer; + InputStream inputStream; + OutputStream outputStream; + + protected SSLChannelSocket(final Socket socket, SSLEngine sslEngine, ExecutorService exec) throws IOException { this.socket = socket; - setSoTimeout(so_hs_timeout); - channel = new SSLSocketChannel(socket.getChannel(), sslEngine, exec, null); - readBuff = ByteBuffer.allocate(1024 * 16); - readBuff.flip(); - writeBuff = ByteBuffer.allocate(1024); + setSoTimeout(socketHandshakeTimeout); + sslSocketChannel = new SSLSocketChannel(socket.getChannel(), sslEngine, exec, null); + readBuffer = ByteBuffer.allocate(1024 * 16); + readBuffer.flip(); + writeBuffer = ByteBuffer.allocate(1024); } - + public ByteChannel getByteChannel() { - return channel; + return sslSocketChannel; } - + public SSLSession getSession() { - //channel.sslEngine.getSSLParameters(); - return channel.sslEngine.getSession(); + // channel.sslEngine.getSSLParameters(); + return sslSocketChannel.sslEngine.getSession(); } - + @Override public SocketChannel getChannel() { - return channel.unwrapChannel(); + return sslSocketChannel.unwrapChannel(); } - + @Override public InetAddress getInetAddress() { return socket.getInetAddress(); } - + @Override public int getLocalPort() { return socket.getLocalPort(); } - + @Override public SocketAddress getRemoteSocketAddress() { return socket.getRemoteSocketAddress(); } - + @Override public InputStream getInputStream() throws IOException { - if (inp == null) - inp = Channels.newInputStream(channel); - return inp; + if (inputStream == null) { + inputStream = Channels.newInputStream(sslSocketChannel); + } + + return inputStream; } - + int printFilter(int c) { - //System.err.printf("%c", c); + // System.err.printf("%c", c); return c; } - + @Override public void setSoTimeout(int timeout) throws SocketException { - socket.setSoTimeout(timeout); + socket.setSoTimeout(timeout); } - + @Override public int getSoTimeout() throws SocketException { return socket.getSoTimeout(); } - + @Override public OutputStream getOutputStream() throws IOException { - if (outp == null) - outp = Channels.newOutputStream(channel); - return outp; + if (outputStream == null) { + outputStream = Channels.newOutputStream(sslSocketChannel); + } + + return outputStream; } } - + protected static class SSLSocketChannel implements ByteChannel { /** * This object is used to feed the {@link SSLEngine}'s wrap and unwrap * methods during the handshake phase. **/ - protected static ByteBuffer emptybuffer = ByteBuffer.allocate(0); - - protected ExecutorService exec; - + protected static ByteBuffer emptyBuffer = ByteBuffer.allocate(0); + + protected ExecutorService executor; protected List> tasks; - + /** raw payload incoming */ protected ByteBuffer inData; /** encrypted data outgoing */ protected ByteBuffer outCrypt; /** encrypted data incoming */ protected ByteBuffer inCrypt; - + /** the underlying channel */ protected SocketChannel socketChannel; /** @@ -271,11 +281,11 @@ protected static class SSLSocketChannel implements ByteChannel { * channel */ protected SelectionKey selectionKey; - + protected SSLEngine sslEngine; protected SSLEngineResult readEngineResult; protected SSLEngineResult writeEngineResult; - + /** * Should be used to count the buffer allocations. But because of #190 * where HandshakeStatus.FINISHED is not properly returned by nio @@ -283,19 +293,18 @@ protected static class SSLSocketChannel implements ByteChannel { * {@link #createBuffers(SSLSession)} needs to be called. **/ protected int bufferallocations = 0; - - protected SSLSocketChannel(SocketChannel channel, SSLEngine sslEngine, ExecutorService exec, SelectionKey key) - throws IOException { - if (channel == null || sslEngine == null || exec == null) + + protected SSLSocketChannel(SocketChannel channel, SSLEngine sslEngine, ExecutorService executor, SelectionKey key) throws IOException { + if (channel == null || sslEngine == null || executor == null) { throw new IllegalArgumentException("parameter must not be null"); - + } + this.socketChannel = channel; this.sslEngine = sslEngine; - this.exec = exec; - - readEngineResult = writeEngineResult = new SSLEngineResult(Status.BUFFER_UNDERFLOW, - sslEngine.getHandshakeStatus(), 0, 0); // init to prevent NPEs - + this.executor = executor; + + // init to prevent NPEs + readEngineResult = writeEngineResult = new SSLEngineResult(Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0); tasks = new ArrayList>(3); if (key != null) { key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); @@ -303,11 +312,11 @@ protected SSLSocketChannel(SocketChannel channel, SSLEngine sslEngine, ExecutorS } createBuffers(sslEngine.getSession()); // kick off handshake - socketChannel.write(wrap(emptybuffer));// initializes res + socketChannel.write(wrap(emptyBuffer));// initializes res // TODO put it in thread - //processHandshake(); + // processHandshake(); } - + private void consumeFutureUninterruptible(Future f) { try { boolean interrupted = false; @@ -315,25 +324,34 @@ private void consumeFutureUninterruptible(Future f) { try { f.get(); break; - } catch (InterruptedException e) { + } catch (InterruptedException ex) { interrupted = true; } } - if (interrupted) + + if (interrupted) { Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - throw new RuntimeException(e); + } + } catch (ExecutionException ex) { + throw new RuntimeException(ex); } } - + /** * This method will do whatever necessary to process the sslengine * handshake. Thats why it's called both from the * {@link #read(ByteBuffer)} and {@link #write(ByteBuffer)} **/ private void processHandshake() throws IOException { - if (sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) - return; // since this may be called either from a reading or a writing thread and because this method is synchronized it is necessary to double check if we are still handshaking. + if (sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) { + /* + * since this may be called either from a reading or a writing + * thread and because this method is synchronized it is + * necessary to double check if we are still handshaking. + */ + return; + } + if (!tasks.isEmpty()) { Iterator> it = tasks.iterator(); while (it.hasNext()) { @@ -341,13 +359,14 @@ private void processHandshake() throws IOException { if (f.isDone()) { it.remove(); } else { - if (isBlocking()) + if (isBlocking()) { consumeFutureUninterruptible(f); + } return; } } } - + if (sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { if (!isBlocking() || readEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) { inCrypt.compact(); @@ -366,27 +385,39 @@ private void processHandshake() throws IOException { } consumeDelegatedTasks(); if (tasks.isEmpty() || sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) { - socketChannel.write(wrap(emptybuffer)); + socketChannel.write(wrap(emptyBuffer)); if (writeEngineResult.getHandshakeStatus() == HandshakeStatus.FINISHED) { createBuffers(sslEngine.getSession()); return; } } - assert (sslEngine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING);// this function could only leave NOT_HANDSHAKING after createBuffers was called unless #190 occurs which means that nio wrap/unwrap never return HandshakeStatus.FINISHED - - bufferallocations = 1; // look at variable declaration why this line exists and #190. Without this line buffers would not be be recreated when #190 AND a rehandshake occur. + + /* + * this function could only leave NOT_HANDSHAKING after + * createBuffers was called unless #190 occurs which means that nio + * wrap/unwrap never return HandshakeStatus.FINISHED + */ + assert (sslEngine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING); + + /* + * look at variable declaration why this line exists and #190. + * Without this line buffers would not be be recreated when #190 AND + * a rehandshake occur. + */ + bufferallocations = 1; } - + private synchronized ByteBuffer wrap(ByteBuffer b) throws SSLException { outCrypt.compact(); writeEngineResult = sslEngine.wrap(b, outCrypt); - //if (writeEngineResult.getStatus() != SSLEngineResult.Status.OK) - //throw new SSLException("Can't wrap " + b + " in " + outCrypt + ", because " - // + writeEngineResult.getStatus()); + // if (writeEngineResult.getStatus() != SSLEngineResult.Status.OK) + // throw new SSLException("Can't wrap " + b + " in " + outCrypt + ", + // because " + // + writeEngineResult.getStatus()); outCrypt.flip(); return outCrypt; } - + /** * performs the unwrap operation by unwrapping from {@link #inCrypt} to * {@link #inData} @@ -396,36 +427,42 @@ private synchronized ByteBuffer unwrap() throws SSLException { do { rem = inData.remaining(); readEngineResult = sslEngine.unwrap(inCrypt, inData); - } while (readEngineResult.getStatus() == SSLEngineResult.Status.OK - && (rem != inData.remaining() || sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)); + } while (readEngineResult.getStatus() == SSLEngineResult.Status.OK && (rem != inData.remaining() || sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)); + inData.flip(); return inData; } - + protected void consumeDelegatedTasks() { Runnable task; while ((task = sslEngine.getDelegatedTask()) != null) { - tasks.add(exec.submit(task)); + tasks.add(executor.submit(task)); // task.run(); } } - + protected void createBuffers(SSLSession session) { int netBufferMax = session.getPacketBufferSize(); int appBufferMax = Math.max(session.getApplicationBufferSize(), netBufferMax); - + if (inData == null) { inData = ByteBuffer.allocate(appBufferMax); outCrypt = ByteBuffer.allocate(netBufferMax); inCrypt = ByteBuffer.allocate(netBufferMax); } else { - if (inData.capacity() != appBufferMax) + if (inData.capacity() != appBufferMax) { inData = ByteBuffer.allocate(appBufferMax); - if (outCrypt.capacity() != netBufferMax) + } + + if (outCrypt.capacity() != netBufferMax) { outCrypt = ByteBuffer.allocate(netBufferMax); - if (inCrypt.capacity() != netBufferMax) + } + + if (inCrypt.capacity() != netBufferMax) { inCrypt = ByteBuffer.allocate(netBufferMax); + } } + inData.rewind(); inData.flip(); inCrypt.rewind(); @@ -434,7 +471,7 @@ protected void createBuffers(SSLSession session) { outCrypt.flip(); bufferallocations++; } - + public int write(ByteBuffer src) throws IOException { if (!isHandShakeComplete()) { processHandshake(); @@ -442,7 +479,7 @@ public int write(ByteBuffer src) throws IOException { } return socketChannel.write(wrap(src)); } - + /** * Blocks when in blocking mode until at least one byte has been * decoded.
@@ -466,41 +503,52 @@ public int read(ByteBuffer dst) throws IOException { } } // assert ( bufferallocations > 1 ); //see #190 - //if( bufferallocations <= 1 ) { - // createBuffers( sslEngine.getSession() ); - //} - /* 1. When "dst" is smaller than "inData" readRemaining will fill "dst" with data decoded in a previous read call. - * 2. When "inCrypt" contains more data than "inData" has remaining space, unwrap has to be called on more time(readRemaining) + // if( bufferallocations <= 1 ) { + // createBuffers( sslEngine.getSession() ); + // } + /* + * 1. When "dst" is smaller than "inData" readRemaining will fill + * "dst" with data decoded in a previous read call. + * 2. When "inCrypt" contains more data than "inData" has remaining + * space, unwrap has to be called on more time(readRemaining) */ int purged = readRemaining(dst); if (purged != 0) return purged; - - /* We only continue when we really need more data from the network. - * Thats the case if inData is empty or inCrypt holds to less data than necessary for decryption + + /* + * We only continue when we really need more data from the network. + * Thats the case if inData is empty or inCrypt holds to less data + * than necessary for decryption */ assert (inData.position() == 0); inData.clear(); - - if (!inCrypt.hasRemaining()) + + if (!inCrypt.hasRemaining()) { inCrypt.clear(); - else + } else { inCrypt.compact(); - - if (isBlocking() || readEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) + } + + if (isBlocking() || readEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) { if (socketChannel.read(inCrypt) == -1) { return -1; } + } + inCrypt.flip(); unwrap(); - + int transfered = transfereTo(inData, dst); if (transfered == 0 && isBlocking()) { - return read(dst); // "transfered" may be 0 when not enough bytes were received or during rehandshaking + // "transfered" may be 0 when not enough bytes were received or + // during rehandshaking + return read(dst); } + return transfered; } - + /** * {@link #read(ByteBuffer)} may not be to leave all buffers(inData, * inCrypt) @@ -509,84 +557,90 @@ private int readRemaining(ByteBuffer dst) throws SSLException { if (inData.hasRemaining()) { return transfereTo(inData, dst); } - if (!inData.hasRemaining()) + + if (!inData.hasRemaining()) { inData.clear(); + } // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW) if (inCrypt.hasRemaining()) { unwrap(); int amount = transfereTo(inData, dst); - if (amount > 0) + if (amount > 0) { return amount; + } } + return 0; } - + public boolean isConnected() { return socketChannel.isConnected(); } - + public void close() throws IOException { try { sslEngine.closeOutbound(); sslEngine.getSession().invalidate(); - if (socketChannel.isOpen()) - socketChannel.write(wrap(emptybuffer));// FIXME what if not all bytes can be written + if (socketChannel.isOpen()) { + // FIXME what if not all bytes can be written + socketChannel.write(wrap(emptyBuffer)); + } } finally { socketChannel.close(); } - //System.err.printf("Socke %s is %b%n", socketChannel, socketChannel.isOpen()); - //exec.shutdownNow(); + // System.err.printf("Socke %s is %b%n", socketChannel, + // socketChannel.isOpen()); + // exec.shutdownNow(); } - + private boolean isHandShakeComplete() { HandshakeStatus status = sslEngine.getHandshakeStatus(); - return status == SSLEngineResult.HandshakeStatus.FINISHED - || status == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; + return status == SSLEngineResult.HandshakeStatus.FINISHED || status == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; } - + public SelectableChannel configureBlocking(boolean b) throws IOException { return socketChannel.configureBlocking(b); } - + public boolean connect(SocketAddress remote) throws IOException { return socketChannel.connect(remote); } - + public boolean finishConnect() throws IOException { return socketChannel.finishConnect(); } - + public Socket socket() { return socketChannel.socket(); } - + public boolean isInboundDone() { return sslEngine.isInboundDone(); } - + @Override public boolean isOpen() { return socketChannel.isOpen(); } - + public boolean isNeedWrite() { - return outCrypt.hasRemaining() || !isHandShakeComplete(); // FIXME this condition can cause high cpu load during handshaking when network is slow + // FIXME this condition can cause high cpu load during handshaking + // when network is slow + return outCrypt.hasRemaining() || !isHandShakeComplete(); } - + public void writeMore() throws IOException { write(outCrypt); } - + public boolean isNeedRead() { - return inData.hasRemaining() - || (inCrypt.hasRemaining() && readEngineResult.getStatus() != Status.BUFFER_UNDERFLOW && readEngineResult - .getStatus() != Status.CLOSED); + return inData.hasRemaining() || (inCrypt.hasRemaining() && readEngineResult.getStatus() != Status.BUFFER_UNDERFLOW && readEngineResult.getStatus() != Status.CLOSED); } - + public int readMore(ByteBuffer dst) throws SSLException { return readRemaining(dst); } - + private int transfereTo(ByteBuffer from, ByteBuffer to) { int fremain = from.remaining(); int toremain = to.remaining(); @@ -601,13 +655,13 @@ private int transfereTo(ByteBuffer from, ByteBuffer to) { to.put(from); return fremain; } - + } - + public boolean isBlocking() { return socketChannel.isBlocking(); } - + public SocketChannel unwrapChannel() { return socketChannel; } diff --git a/1.x/src/rogatkin/wskt/SimpleConfigurator.java b/src/rogatkin/wskt/SimpleConfigurator.java similarity index 100% rename from 1.x/src/rogatkin/wskt/SimpleConfigurator.java rename to src/rogatkin/wskt/SimpleConfigurator.java diff --git a/1.x/src/rogatkin/wskt/SimpleHSRequest.java b/src/rogatkin/wskt/SimpleHSRequest.java similarity index 76% rename from 1.x/src/rogatkin/wskt/SimpleHSRequest.java rename to src/rogatkin/wskt/SimpleHSRequest.java index eaafad6..7f7f42b 100644 --- a/1.x/src/rogatkin/wskt/SimpleHSRequest.java +++ b/src/rogatkin/wskt/SimpleHSRequest.java @@ -27,52 +27,57 @@ import java.net.URI; import java.net.URISyntaxException; import java.security.Principal; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.websocket.server.HandshakeRequest; -public class SimpleHSRequest implements HandshakeRequest { +import Acme.Utils; - HttpServletRequest request; - SimpleHSRequest(HttpServletRequest req) { - request = req; +public class SimpleHSRequest implements HandshakeRequest { + + private HttpServletRequest request; + + SimpleHSRequest(HttpServletRequest request) { + this.request = request; } + /** + * + * @return + * @see javax.websocket.server.HandshakeRequest#getHeaders() + */ @Override public Map> getHeaders() { - HashMap> headersMap = new HashMap>(); - for(Enumeration hn = request.getHeaderNames(); hn.hasMoreElements();) { - String name = hn.nextElement(); - headersMap.put(name, Collections.list(request.getHeaders(name))); - } - return headersMap; + return Utils.getRequestHeaders(request); } - + + /** + * + * @return + * @see javax.websocket.server.HandshakeRequest#getHttpSession() + */ @Override public Object getHttpSession() { return request.getSession(false); } - + + /** + * + * @return + * @see javax.websocket.server.HandshakeRequest#getParameterMap() + */ @Override public Map> getParameterMap() { - HashMap> paramsMap = new HashMap>(); - for (Map.Entry e : request.getParameterMap().entrySet()) { - paramsMap.put(e.getKey(), Arrays.asList(e.getValue())); - } - return paramsMap; + return Utils.getRequestParameters(request); } - + @Override public String getQueryString() { return request.getQueryString(); } - + @Override public URI getRequestURI() { try { @@ -82,15 +87,15 @@ public URI getRequestURI() { } return null; } - + @Override public Principal getUserPrincipal() { return request.getUserPrincipal(); } - + @Override public boolean isUserInRole(String arg0) { return request.isUserInRole(arg0); } - + } diff --git a/1.x/src/rogatkin/wskt/SimpleHSResponse.java b/src/rogatkin/wskt/SimpleHSResponse.java similarity index 81% rename from 1.x/src/rogatkin/wskt/SimpleHSResponse.java rename to src/rogatkin/wskt/SimpleHSResponse.java index 2143db5..f9434f4 100644 --- a/1.x/src/rogatkin/wskt/SimpleHSResponse.java +++ b/src/rogatkin/wskt/SimpleHSResponse.java @@ -24,29 +24,30 @@ */ package rogatkin.wskt; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import javax.websocket.HandshakeResponse; -public class SimpleHSResponse implements HandshakeResponse { +import Acme.Utils; - HttpServletResponse response; +public class SimpleHSResponse implements HandshakeResponse { + + private HttpServletResponse response; - SimpleHSResponse(HttpServletResponse r) { - response = r; + SimpleHSResponse(HttpServletResponse response) { + this.response = response; } + /** + * + * @return + * @see javax.websocket.HandshakeResponse#getHeaders() + */ @Override public Map> getHeaders() { - HashMap> headersMap = new HashMap>(); - for(String name: response.getHeaderNames()) { - headersMap.put(name, new ArrayList(response.getHeaders(name))); - } - return headersMap; + return Utils.getResponseHeaders(response); } - + } diff --git a/src/rogatkin/wskt/SimpleProvider.java b/src/rogatkin/wskt/SimpleProvider.java new file mode 100755 index 0000000..a2ed6b2 --- /dev/null +++ b/src/rogatkin/wskt/SimpleProvider.java @@ -0,0 +1,637 @@ +/* tjws - JSR356 + * Copyright (C) 2004-2015 Dmitriy Rogatkin. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Created on Jan 11, 2015 +*/ +package rogatkin.wskt; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLDecoder; +import java.nio.channels.ByteChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; +import javax.websocket.CloseReason; +import javax.websocket.DeploymentException; +import javax.websocket.Endpoint; +import javax.websocket.Extension; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerApplicationConfig; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; +import Acme.Utils; +import Acme.Serve.Serve; +import Acme.Serve.Serve.ServeConnection; +import Acme.Serve.Serve.WebsocketProvider; +import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; +import io.github.lukehutch.fastclasspathscanner.matchprocessor.ClassAnnotationMatchProcessor; +import io.github.lukehutch.fastclasspathscanner.matchprocessor.InterfaceMatchProcessor; +import io.github.lukehutch.fastclasspathscanner.matchprocessor.SubclassMatchProcessor; + +/** + * @author Rohtash Singh Lakra + * @date 04/06/2018 12:46:53 PM + */ +public class SimpleProvider implements WebsocketProvider, Runnable { + + public static final String WSKT_KEY = "Sec-WebSocket-Key"; + public static final String WSKT_ORIGIN = "Origin"; + public static final String WSKT_PROTOCOL = "Sec-WebSocket-Protocol"; + public static final String WSKT_VERSION = "Sec-WebSocket-Version"; + public static final String WSKT_ACEPT = "Sec-WebSocket-Accept"; + // HandshakeRequest.SEC_WEBSOCKET_EXTENSIONS + public static final String WSKT_EXTS = "Sec-WebSocket-Extensions"; + + public static final String WSKT_RFC4122 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + public static final String PROP_WSKT_MAIN_CONTAINER = "tjws.websocket.container"; + static final boolean debugEnabled = false; + + /** JAVAX_WEBSOCKET_SERVER_CONTAINER */ + public static final String JAVAX_WEBSOCKET_SERVER_CONTAINER = "javax.websocket.server.ServerContainer"; + + // static final ForkJoinPool mainPool = new ForkJoinPool(); + + protected Selector selector; + protected Serve serve; + protected ExecutorService messageFlowExec; + protected ConcurrentLinkedQueue penndingSessions; + protected boolean useRootContainer; + + /** + * Returns the useRootContainer value. + * + * @return + */ + protected boolean isUseRootContainer() { + return useRootContainer; + } + + /** + * The useRootContainer to be set. + * + * @param useRootContainer + */ + protected void setUseRootContainer(final boolean useRootContainer) { + this.useRootContainer = useRootContainer; + } + + /** + * @see Acme.Serve.Serve.WebsocketProvider#init(Acme.Serve.Serve) + */ + @Override + public void init(final Serve serve) { + this.serve = serve; + try { + penndingSessions = new ConcurrentLinkedQueue(); + selector = Selector.open(); + final Thread threadSelector = new Thread(this, "Websocket Provider Selector"); + threadSelector.setDaemon(true); + threadSelector.start(); + } catch (IOException ex) { + throw new RuntimeException("Can't initialize selector, websocket functionality is disabled", ex); + } + + setUseRootContainer(Boolean.getBoolean(PROP_WSKT_MAIN_CONTAINER)); + messageFlowExec = Executors.newCachedThreadPool(); + } + + /** + * @see Acme.Serve.Serve.WebsocketProvider#handshake(java.net.Socket, + * java.lang.String, javax.servlet.Servlet, + * javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void handshake(final Socket socket, String path, Servlet servlet, HttpServletRequest request, HttpServletResponse response) throws IOException { + if (socket.getChannel() == null) { + response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Websockets implemented only with SelectorAcceptor"); + return; + } + + final String webSocketVersion = request.getHeader(WSKT_VERSION); + if (webSocketVersion == null || "13".equals(webSocketVersion.trim()) == false) { + response.addHeader(WSKT_VERSION, "13"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + String key = request.getHeader(WSKT_KEY); + if (key == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Sec Key is missed"); + return; + } + + String contextPath; + try { + contextPath = (String) servlet.getClass().getMethod("getContextPath").invoke(servlet); + } catch (Exception e) { + if (isUseRootContainer()) { + contextPath = ""; + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No endpoints associated with container allowed"); + return; + } + } + + SimpleServerContainer serverContainer; + if (servlet != null) { + serverContainer = (SimpleServerContainer) servlet.getServletConfig().getServletContext().getAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER); + } else { + serverContainer = (SimpleServerContainer) serve.getAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER); + } + + if (serverContainer == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No end points associated with path " + path); + return; + } + + String found = null; + int hops = -1; + Map foundVarMap = null; + for (String keyContextPath : serverContainer.endpoints.keySet()) { + Map varMap = matchTemplate(path, contextPath + keyContextPath); + if (varMap != null) { + if (found == null || hops > varMap.size()) { + found = keyContextPath; + hops = varMap.size(); + foundVarMap = varMap; + } + } + } + + if (found == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No matching endpoint found for path:" + path); + return; + } + + final ServerEndpointConfig endPointConfig = serverContainer.endpoints.get(found); + // Objects.requireNonNull(epc.getConfigurator()); + final String webSocketOrigin = request.getHeader(WSKT_ORIGIN); + if (endPointConfig.getConfigurator().checkOrigin(webSocketOrigin) == false) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin check failed:" + webSocketOrigin); + return; + } + endPointConfig.getConfigurator().modifyHandshake(endPointConfig, new SimpleHSRequest(request), new SimpleHSResponse(response)); + request.setAttribute("javax.websocket.server.ServerEndpointConfig", endPointConfig); + request.setAttribute("javax.websocket.server.PathParametersMap", foundVarMap); + + response.setHeader(WSKT_ACEPT, getSHA1Base64(key.trim() + WSKT_RFC4122)); + response.setHeader(Serve.ServeConnection.UPGRADE, Serve.ServeConnection.WEBSOCKET); + // resp.setHeader(Serve.ServeConnection.CONNECTION, + // Serve.ServeConnection.KEEPALIVE + ", " + // + Serve.ServeConnection.UPGRADE); + // resp.addHeader(Serve.ServeConnection.CONNECTION, + // Serve.ServeConnection.UPGRADE); + if (serverContainer.getDefaultMaxSessionIdleTimeout() > 0) { + response.setHeader(Serve.ServeConnection.KEEPALIVE, "timeout=" + serverContainer.getDefaultMaxSessionIdleTimeout() / 1000); + } + response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS); + } + + /** + * @see Acme.Serve.Serve.WebsocketProvider#upgrade(java.net.Socket, + * java.lang.String, javax.servlet.Servlet, + * javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void upgrade(final Socket socket, String path, Servlet servlet, HttpServletRequest request, HttpServletResponse response) throws IOException { + SocketChannel sc = socket.getChannel(); + sc.configureBlocking(false); + ByteChannel bc = sc; + try { + bc = (ByteChannel) socket.getClass().getMethod("getByteChannel").invoke(socket); + } catch (Exception e) { + if (debugEnabled) { + serve.log(e, "No byte channel"); + } + } + + SimpleServerContainer container = null; + if (servlet != null) { + container = (SimpleServerContainer) servlet.getServletConfig().getServletContext().getAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER); + } else if (isUseRootContainer()) { + container = (SimpleServerContainer) serve.getAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER); + } + + ServerEndpointConfig epc = (ServerEndpointConfig) request.getAttribute("javax.websocket.server.ServerEndpointConfig"); + final SimpleSession simpleSession = new SimpleSession(bc, container); + simpleSession.addMessageHandler(epc); + simpleSession.pathParamsMap = (Map) request.getAttribute("javax.websocket.server.PathParametersMap"); + if (request.getSession(false) != null) { + simpleSession.id = request.getSession(false).getId(); + /* + * TODO this approach isn't robust and flexible, so consider as + * temporarily + */ + request.getSession(false).setAttribute("javax.websocket.server.session", new HttpSessionBindingListener() { + + @Override + public void valueBound(HttpSessionBindingEvent event) { + + } + + @Override + public void valueUnbound(HttpSessionBindingEvent event) { + try { + simpleSession.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "Session invalidate")); + } catch (IOException ex) { + if (debugEnabled) { + serve.log(ex, "At closing on session invalidation"); + } + } + } + }); + } else { + simpleSession.id = "wskt-" + serve.generateSessionId(); + } + + simpleSession.principal = request.getUserPrincipal(); + simpleSession.setMaxIdleTimeout(container.getDefaultMaxSessionIdleTimeout()); + simpleSession.paramsMap = new HashMap>(); + for (Map.Entry e : request.getParameterMap().entrySet()) { + simpleSession.paramsMap.put(e.getKey(), Arrays.asList(e.getValue())); + } + simpleSession.query = request.getQueryString(); + try { + simpleSession.uri = new URI(request.getRequestURL().toString()); + } catch (URISyntaxException ex) { + + } + String protocol = request.getHeader(WSKT_PROTOCOL); + if (protocol != null) { + simpleSession.subprotocol = epc.getConfigurator().getNegotiatedSubprotocol(epc.getSubprotocols(), Arrays.asList(protocol.split(","))); + } + if (epc.getExtensions().size() > 0) { + // TODO maybe it should be going in handshake? + simpleSession.extensions = epc.getConfigurator().getNegotiatedExtensions(epc.getExtensions(), parseToExtensions(request.getHeader(HandshakeRequest.SEC_WEBSOCKET_EXTENSIONS))); + if (simpleSession.extensions.size() == 0) { + simpleSession.close(new CloseReason(CloseReason.CloseCodes.NO_EXTENSION, "")); + return; + } + } + + if (request instanceof ServeConnection) { + simpleSession.serveConnection = (ServeConnection) request; + ((ServeConnection) request).spawnAsync(simpleSession); + } else { + serve.log("Request isn't of ServeConnection type:" + request.getClass()); + } + + penndingSessions.add(simpleSession); + selector.wakeup(); + // sc.register(selector, SelectionKey.OP_READ, ss); + // ss.open(); + } + + @Override + public void destroy() { + if (isUseRootContainer()) { + try { + ((SimpleServerContainer) serve.getAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER)).contextDestroyed(null); + } catch (Exception ex) { + /* ignore me! */ + if (LogManager.isDebugEnabled()) { + LogManager.error("Error destroying context!", ex); + } + } + } + + messageFlowExec.shutdown(); + try { + selector.close(); + } catch (IOException ex) { + /* ignore me! */ + if (LogManager.isDebugEnabled()) { + LogManager.error("Error closing selector!", ex); + } + } + } + + /** + * @see Acme.Serve.Serve.WebsocketProvider#deploy(javax.servlet.ServletContext, + * java.util.List) + */ + @Override + public void deploy(final ServletContext servletContext, final List classPaths) { + final SimpleServerContainer serverContainer = new SimpleServerContainer(this); + final HashSet appConfigs = new HashSet(); + final HashSet> annSeps = new HashSet>(); + final HashSet> endPoints = new HashSet>(); + new FastClasspathScanner("") { + /** + * @see io.github.lukehutch.fastclasspathscanner.FastClasspathScanner#getUniqueClasspathElements() + */ + @Override + public List getUniqueClasspathElements() { + if (classPaths == null) { + if (servletContext != null) { + ClassLoader classLoader = servletContext.getClass().getClassLoader(); + if (classLoader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) classLoader).getURLs(); + if (urls != null && urls.length > 0) { + ArrayList result = new ArrayList(urls.length); + for (URL url : urls) { + try { + result.add(new File(URLDecoder.decode(url.getFile(), IOHelper.UTF_8))); + } catch (UnsupportedEncodingException e) { + serve.log("Can't add path component " + url + " :" + e); + } + } + return result; + } + } + } + + return super.getUniqueClasspathElements(); + } + + return classPaths; + } + + /** + * @see io.github.lukehutch.fastclasspathscanner.FastClasspathScanner#getClassLoader() + */ + @Override + public ClassLoader getClassLoader() { + if (servletContext != null) { + try { + return (ClassLoader) servletContext.getClass().getMethod("getClassLoader").invoke(servletContext); + } catch (Exception ex) { + return servletContext.getClass().getClassLoader(); + } + } + + return null; + } + }.matchClassesImplementing(ServerApplicationConfig.class, new InterfaceMatchProcessor() { + + @Override + public void processMatch(Class arg0) { + try { + appConfigs.add(arg0.newInstance()); + } catch (InstantiationException e) { + serve.log(e, "Error at deployment"); + } catch (IllegalAccessException e) { + serve.log(e, "Error at deployment"); + } + } + + }).matchClassesWithAnnotation(ServerEndpoint.class, new ClassAnnotationMatchProcessor() { + public void processMatch(Class matchingClass) { + annSeps.add(matchingClass); + } + }).matchSubclassesOf(Endpoint.class, new SubclassMatchProcessor() { + + /** + * @see io.github.lukehutch.fastclasspathscanner.matchprocessor.SubclassMatchProcessor#processMatch(java.lang.Class) + */ + @Override + public void processMatch(Class endPoint) { + endPoints.add(endPoint); + } + }).scan(); + + if (appConfigs.size() > 0) { + for (ServerApplicationConfig serverAppConfig : appConfigs) { + for (Class endPointClass : serverAppConfig.getAnnotatedEndpointClasses(annSeps)) { + try { + serverContainer.addEndpoint(endPointClass); + serve.log("Deployed ServerEndpoint:" + endPointClass); + } catch (DeploymentException ex) { + + } + } + + for (ServerEndpointConfig endPointConfig : serverAppConfig.getEndpointConfigs(endPoints)) { + try { + serverContainer.addEndpoint(endPointConfig); + serve.log("Deployed ServerEndpointConfig:" + endPointConfig); + } catch (DeploymentException ex) { + + } + } + } + } else { + for (Class sEndPointClass : annSeps) { + try { + serverContainer.addEndpoint(sEndPointClass); + serve.log("Deployed ServerEndpoint:" + sEndPointClass); + } catch (DeploymentException ex) { + + } + } + } + + servletContext.setAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER, serverContainer); + try { + servletContext.addListener(serverContainer); + } catch (Error ex) { + // serve is still on old servlet spec + } + } + + String getSHA1Base64(String key) { + try { + MessageDigest cript = MessageDigest.getInstance("SHA-1"); + cript.reset(); + cript.update(key.getBytes()); + return Utils.base64Encode(cript.digest()); + } catch (NoSuchAlgorithmException nsa) { + + } + return null; + } + + Map matchTemplate(String uri, String template) { + // System.err.printf("Matching %s to %s%n", uri, template); + Map parsed = parseTemplate(template); + Pattern p = Pattern.compile(parsed.get(0)); + Matcher m = p.matcher(uri); + if (m.matches()) { + HashMap result = new HashMap(); + for (int i = 0; i < m.groupCount(); i++) + result.put(parsed.get(i + 1), m.group(i + 1)); + // System.err.printf("Success %s%n", result); + return result; + } + // System.err.printf("unsucc %s%n", parsed); + return null; + } + + static final int s_invar = 1, s_inuri = 0; + + Map parseTemplate(String template) { + HashMap result = new HashMap(); + String regExp = ""; + int vi = 0; + int st = s_inuri; + String varName = null; + for (int i = 0, n = template.length(); i < n; i++) { + char c = template.charAt(i); + switch (st) { + case s_inuri: + if (c == '/') + regExp += c; + else if (c == '{') { + st = s_invar; + varName = ""; + } else { + // TODO check if reg exp escape needed + regExp += c; + } + break; + case s_invar: + if (c == '}') { + vi++; + regExp += "((?:[a-zA-Z0-9-\\._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)"; + st = s_inuri; + result.put(vi, varName); + } else { + // TODO check if valid character ALPHA, DIGIT, _, or %DD + varName += c; + } + break; + } + } + result.put(0, regExp); + return result; + } + + /** + * parses ext1;param=val param=val, ext2 + * + * @param parse + * @return + */ + List parseToExtensions(String parse) { + if (parse == null || parse.isEmpty()) + return Collections.emptyList(); + return Collections.emptyList(); + } + + @Override + public void run() { + while (selector.isOpen()) { + try { + for (SimpleSession ss = penndingSessions.poll(); ss != null; ss = penndingSessions.poll()) { + SocketChannel sc = null; + if (ss.channel instanceof SocketChannel) + sc = (SocketChannel) ss.channel; + else + try { + sc = (SocketChannel) ss.channel.getClass().getMethod("unwrapChannel").invoke(ss.channel); + } catch (Exception e) { + + } + if (sc != null) { + sc.register(selector, SelectionKey.OP_READ, ss); + ss.open(); + } else + serve.log("Session with not proper channel will be closed"); + } + + int readyChannels = selector.select(1000); + if (readyChannels == 0) + continue; + + Set selectedKeys = selector.selectedKeys(); + + Iterator keyIterator = selectedKeys.iterator(); + + while (keyIterator.hasNext()) { + + SelectionKey key = keyIterator.next(); + if (debugEnabled) { + serve.log("key:" + key + " " + key.isValid() + " chan " + key.channel()); + } + + if (!key.isValid()) { + continue; + } + + if (key.isAcceptable()) { + // a connection was accepted by a ServerSocketChannel. + } else if (key.isConnectable()) { + // a connection was established with a remote server. + } else if (key.isReadable()) { + // a channel is ready for reading + if (key.channel().isOpen() && !messageFlowExec.isShutdown()) { + messageFlowExec.submit(((SimpleSession) key.attachment())); + // ((SimpleSession) key.attachment()).run(); + } else { + if (debugEnabled) { + serve.log("Cancel key :" + key + ", channel closed"); + } + key.cancel(); + } + } else if (key.isWritable()) { + // a channel is ready for writing + // TODO perhaps trigger flag in session too execute + // writing bach + } + + keyIterator.remove(); + } + } catch (Exception ex) { + serve.log("Websocket runtime problem", ex); + if (!selector.isOpen()) { + break; + } + } + } + } +} diff --git a/1.x/src/rogatkin/wskt/SimpleServerContainer.java b/src/rogatkin/wskt/SimpleServerContainer.java old mode 100644 new mode 100755 similarity index 54% rename from 1.x/src/rogatkin/wskt/SimpleServerContainer.java rename to src/rogatkin/wskt/SimpleServerContainer.java index 6d728e8..bb1df47 --- a/1.x/src/rogatkin/wskt/SimpleServerContainer.java +++ b/src/rogatkin/wskt/SimpleServerContainer.java @@ -28,10 +28,8 @@ import java.net.URI; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -40,11 +38,11 @@ import javax.servlet.ServletContextListener; import javax.websocket.ClientEndpointConfig; import javax.websocket.CloseReason; +import javax.websocket.CloseReason.CloseCodes; import javax.websocket.DeploymentException; import javax.websocket.Endpoint; import javax.websocket.Extension; import javax.websocket.Session; -import javax.websocket.CloseReason.CloseCodes; import javax.websocket.server.ServerContainer; import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; @@ -55,177 +53,223 @@ * application * * @author Dmitriy - * + * @author Rohtash Singh Lakra */ public class SimpleServerContainer implements ServerContainer, ServletContextListener { - + HashMap endpoints; SimpleProvider provider; - + HashSet sessions; - ExecutorService asyncService; - - int defBufSize = 1024 * 8; - + int maxBufferSize = 1024 * 8; long idleTimeout; long asyncTimeout; - + + /** + * + * @param simpleProvider + */ public SimpleServerContainer(SimpleProvider simpleProvider) { provider = simpleProvider; endpoints = new HashMap(); sessions = new HashSet(); asyncService = Executors.newSingleThreadExecutor(); } - + + /** + * @see javax.websocket.server.ServerContainer#addEndpoint(java.lang.Class) + */ @Override - public void addEndpoint(Class arg0) throws DeploymentException { - if (arg0.isAssignableFrom(ServerEndpointConfig.class)) { + public void addEndpoint(Class endPointClass) throws DeploymentException { + if (endPointClass.isAssignableFrom(ServerEndpointConfig.class)) { try { - addEndpoint((ServerEndpointConfig) arg0.newInstance()); - } catch (InstantiationException e) { - throw new DeploymentException("Error in deployment end point", e); - } catch (IllegalAccessException e) { - throw new DeploymentException("Error in deployment end point", e); + addEndpoint((ServerEndpointConfig) endPointClass.newInstance()); + } catch (InstantiationException ex) { + throw new DeploymentException("Error in deployment end point", ex); + } catch (IllegalAccessException ex) { + throw new DeploymentException("Error in deployment end point", ex); } } else { - ServerEndpoint sep = arg0.getAnnotation(ServerEndpoint.class); + ServerEndpoint serverEndPoint = endPointClass.getAnnotation(ServerEndpoint.class); Configurator configurator = null; - if (ServerEndpointConfig.Configurator.class !=sep.configurator()) + if (ServerEndpointConfig.Configurator.class != serverEndPoint.configurator()) { try { - configurator = sep.configurator().newInstance(); - } catch(Exception e) { - throw new DeploymentException("Can't instantiate custom Configurator for "+sep.configurator(), e); + configurator = serverEndPoint.configurator().newInstance(); + } catch (Exception ex) { + throw new DeploymentException("Can't instantiate custom Configurator for:" + serverEndPoint.configurator(), ex); } - addEndpoint(ServerEndpointConfig.Builder.create(arg0, sep.value()) - .subprotocols(Arrays.asList(sep.subprotocols())).encoders(Arrays.asList(sep.encoders())) - .decoders(Arrays.asList(sep.decoders())).configurator(configurator).build()); + } + addEndpoint(ServerEndpointConfig.Builder.create(endPointClass, serverEndPoint.value()).subprotocols(Arrays.asList(serverEndPoint.subprotocols())).encoders(Arrays.asList(serverEndPoint.encoders())).decoders(Arrays.asList(serverEndPoint.decoders())).configurator(configurator).build()); } - } - + + /** + * @see javax.websocket.server.ServerContainer#addEndpoint(javax.websocket.server.ServerEndpointConfig) + */ @Override - public void addEndpoint(ServerEndpointConfig arg0) throws DeploymentException { - if (endpoints.containsKey(arg0.getPath())) - throw new DeploymentException("More than one end points use same path " + arg0.getPath()); - endpoints.put(arg0.getPath(), arg0); + public void addEndpoint(ServerEndpointConfig serverEndPointConfig) throws DeploymentException { + if (endpoints.containsKey(serverEndPointConfig.getPath())) { + throw new DeploymentException("More than one end points use same path:" + serverEndPointConfig.getPath()); + } + endpoints.put(serverEndPointConfig.getPath(), serverEndPointConfig); } - + @Override public Session connectToServer(Object arg0, URI arg1) throws DeploymentException, IOException { throw new UnsupportedOperationException("No client websocket support"); } - + @Override public Session connectToServer(Class arg0, URI arg1) throws DeploymentException, IOException { throw new UnsupportedOperationException("No client websocket support"); } - + @Override - public Session connectToServer(Endpoint arg0, ClientEndpointConfig arg1, URI arg2) throws DeploymentException, - IOException { + public Session connectToServer(Endpoint arg0, ClientEndpointConfig arg1, URI arg2) throws DeploymentException, IOException { throw new UnsupportedOperationException("No client websocket support"); } - + @Override - public Session connectToServer(Class arg0, ClientEndpointConfig arg1, URI arg2) - throws DeploymentException, IOException { + public Session connectToServer(Class arg0, ClientEndpointConfig arg1, URI arg2) throws DeploymentException, IOException { throw new UnsupportedOperationException("No client websocket support"); } - + @Override public long getDefaultAsyncSendTimeout() { return asyncTimeout; } - + @Override public int getDefaultMaxBinaryMessageBufferSize() { - return defBufSize; + return maxBufferSize; } - + @Override public long getDefaultMaxSessionIdleTimeout() { return idleTimeout; } - + @Override public int getDefaultMaxTextMessageBufferSize() { - return defBufSize; + return maxBufferSize; } - + @Override public Set getInstalledExtensions() { return null; } - + @Override public void setAsyncSendTimeout(long arg0) { if (arg0 >= 0) asyncTimeout = arg0; } - + + /** + * @see javax.websocket.WebSocketContainer#setDefaultMaxBinaryMessageBufferSize(int) + */ @Override - public void setDefaultMaxBinaryMessageBufferSize(int arg0) { - if (arg0 > 1024) - defBufSize = arg0; + public void setDefaultMaxBinaryMessageBufferSize(int maxBufferSize) { + if (maxBufferSize > 1024) { + this.maxBufferSize = maxBufferSize; + } } - + + /** + * @see javax.websocket.WebSocketContainer#setDefaultMaxSessionIdleTimeout(long) + */ @Override - public void setDefaultMaxSessionIdleTimeout(long arg0) { - if (arg0 < 0) + public void setDefaultMaxSessionIdleTimeout(long maxIdleTimeout) { + if (maxIdleTimeout < 0) { return; - idleTimeout = arg0; + } + idleTimeout = maxIdleTimeout; } - + + /** + * @see javax.websocket.WebSocketContainer#setDefaultMaxTextMessageBufferSize(int) + */ @Override - public void setDefaultMaxTextMessageBufferSize(int arg0) { - if (arg0 > 1024) - defBufSize = arg0; + public void setDefaultMaxTextMessageBufferSize(int maxBufferSize) { + if (maxBufferSize > 1024) { + this.maxBufferSize = maxBufferSize; + } } - - void log(String msg, Object... params) { - log(null, msg, params); + + /** + * + * @param message + * @param params + */ + void log(String message, Object... params) { + log(null, message, params); } - - void log(Throwable e, String msg, Object... params) { - msg = "websocket : " + msg; - if (e == null) - if (params == null || params.length == 0) - provider.serve.log(msg); - else - provider.serve.log(String.format(msg, params)); - else if (params == null || params.length == 0) - provider.serve.log(msg, e); - else - provider.serve.log(String.format(msg, params), e); + + /** + * + * @param throwable + * @param message + * @param params + */ + void log(Throwable throwable, String message, Object... params) { + message = "websocket : " + message; + if (throwable == null) { + if (params == null || params.length == 0) { + provider.serve.log(message); + } else { + provider.serve.log(String.format(message, params)); + } + } else if (params == null || params.length == 0) { + provider.serve.log(message, throwable); + } else { + provider.serve.log(String.format(message, params), throwable); + } } - + + /** + * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) + */ @Override - public void contextDestroyed(ServletContextEvent arg0) { - CloseReason cr = new CloseReason(CloseCodes.SERVICE_RESTART, ""); - //ArrayList copyss = new ArrayList(sessions); - for (SimpleSession ss : new ArrayList(sessions)) + public void contextDestroyed(ServletContextEvent event) { + CloseReason closeReason = new CloseReason(CloseCodes.SERVICE_RESTART, ""); + // ArrayList copyss = new + // ArrayList(sessions); + for (SimpleSession ss : new ArrayList(sessions)) { try { - //System.err.printf("Closing session %s%n", ss); - ss.close(cr); + // System.err.printf("Closing session %s%n", ss); + ss.close(closeReason); } catch (IOException e) { - + } + } + sessions.clear(); asyncService.shutdown(); } - + + /** + * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) + */ @Override - public void contextInitialized(ServletContextEvent arg0) { - + public void contextInitialized(ServletContextEvent event) { + } - - void addSession(SimpleSession ss) { - sessions.add(ss); + + /** + * + * @param simpleSession + */ + void addSession(SimpleSession simpleSession) { + sessions.add(simpleSession); } - - void removeSession(SimpleSession ss) { - sessions.remove(ss); + + /** + * + * @param simpleSession + */ + void removeSession(SimpleSession simpleSession) { + sessions.remove(simpleSession); } - + } diff --git a/1.x/src/rogatkin/wskt/SimpleSession.java b/src/rogatkin/wskt/SimpleSession.java old mode 100644 new mode 100755 similarity index 51% rename from 1.x/src/rogatkin/wskt/SimpleSession.java rename to src/rogatkin/wskt/SimpleSession.java index c962c41..17498ab --- a/1.x/src/rogatkin/wskt/SimpleSession.java +++ b/src/rogatkin/wskt/SimpleSession.java @@ -76,17 +76,24 @@ import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpointConfig; +import Acme.IOHelper; import Acme.Serve.Serve.AsyncCallback; import Acme.Serve.Serve.ServeConnection; public class SimpleSession implements Session, AsyncCallback, Runnable { - + enum FrameState { - prepare, header, length, length16, length64, mask, data + prepare, + header, + length, + length16, + length64, + mask, + data } - + // ///// TODO encapsulate in a parser class - ByteBuffer buf; + ByteBuffer byteBuffer; boolean frameFinal; FrameState state; boolean masked; @@ -97,298 +104,330 @@ enum FrameState { int dataLen; boolean frameText; byte[] completeData; + // ///////////////////////////////// ByteChannel channel; - ServeConnection conn; // temporary - + ServeConnection serveConnection; // temporary HashSet handlers; - + String id; - long idleTimeout; Map> paramsMap; Map pathParamsMap; String query; URI uri; Principal principal; - SimpleServerContainer container; + SimpleServerContainer serverContainer; private SimpleBasic basicRemote; - ServerEndpointConfig endpointConfig; + ServerEndpointConfig endPointConfig; String subprotocol; List extensions; Map userProperties; - + static final boolean __debugOn = false; static final boolean __parseDebugOn = __debugOn; - - SimpleSession(ByteChannel sc, SimpleServerContainer c) { - channel = sc; - container = c; - container.addSession(this); - buf = ByteBuffer.allocate(c.getDefaultMaxBinaryMessageBufferSize()); - buf.mark(); + + SimpleSession(final ByteChannel byteChannel, final SimpleServerContainer serverContainer) { + channel = byteChannel; + this.serverContainer = serverContainer; + serverContainer.addSession(this); + byteBuffer = ByteBuffer.allocate(serverContainer.getDefaultMaxBinaryMessageBufferSize()); + byteBuffer.mark(); state = FrameState.prepare; handlers = new HashSet(); userProperties = new HashMap(); } - + public synchronized void run() { - if (!isOpen()) + if (!isOpen()) { return; + } + try { - conn.extendAsyncTimeout(-1); - int l = channel.read(buf); - conn.extendAsyncTimeout(getMaxIdleTimeout()); - if (l < 0) + serveConnection.extendAsyncTimeout(-1); + int l = channel.read(byteBuffer); + serveConnection.extendAsyncTimeout(getMaxIdleTimeout()); + if (l < 0) { throw new IOException("Closed"); - else if (l > 0) { - if (__parseDebugOn) - container.log("Read len %d", l); + } else if (l > 0) { + if (__parseDebugOn) { + serverContainer.log("Read len %d", l); + } parseFrame(); } } catch (IOException e) { - container.log("Non blocking frame read exception : "+e); - if (__parseDebugOn) - container.log(e, ""); + serverContainer.log("Non blocking frame read exception : " + e); + if (__parseDebugOn) { + serverContainer.log(e, ""); + } + try { close(); } catch (IOException e1) { - + } } catch (Throwable t) { - if (t instanceof ThreadDeath) + if (t instanceof ThreadDeath) { throw (ThreadDeath) t; + } boolean handled = false; for (SimpleMessageHandler mh : handlers) { handled |= mh.processError(t); } - if (!handled) - container.log(t, "Unhandled error"); + if (!handled) { + serverContainer.log(t, "Unhandled error"); + } + try { close(); } catch (IOException e1) { - + } } } - + void parseFrame() { - int lim = buf.position(); - buf.reset(); - buf.limit(lim); + int lim = byteBuffer.position(); + byteBuffer.reset(); + byteBuffer.limit(lim); // buf.flip(); int avail; boolean forceOp = false; - readmore: while (buf.hasRemaining() || forceOp) { + readmore: + while (byteBuffer.hasRemaining() || forceOp) { switch (state) { - case header: - case prepare: - byte hb = buf.get(); - if (__parseDebugOn) - container.log("hdr 0%x", hb); - frameFinal = (hb & 0x80) != 0; - oper = hb & 0x0f; - state = FrameState.length; - dataLen = 0; - break; - case length: - byte lb = buf.get(); - masked = (lb & 0x80) != 0; - len = lb & 0x7f; - if (len == 126) - state = FrameState.length16; - else if (len == 127) - state = FrameState.length64; - else - state = masked ? FrameState.mask : FrameState.data; - forceOp = !masked; - if (__parseDebugOn) - container.log("len %d st %s avail %d", len, state, buf.limit() - buf.position()); - break; - case length16: - avail = buf.remaining(); - if (avail >= 2) { - // buf.order(ByteOrder.BIG_ENDIAN); - len = buf.get() & 255; - len = (len << 8) | (buf.get() & 255); - state = masked ? FrameState.mask : FrameState.data; - break; - } else { - break readmore; - } - case length64: - avail = buf.remaining(); - if (avail >= 8) { - len = buf.getLong(); - if (len > Integer.MAX_VALUE || len < 0) - throw new IllegalArgumentException("Frame length is too long"); - state = masked ? FrameState.mask : FrameState.data; + case header: + case prepare: + byte hb = byteBuffer.get(); + if (__parseDebugOn) { + serverContainer.log("hdr 0%x", hb); + } + frameFinal = (hb & 0x80) != 0; + oper = hb & 0x0f; + state = FrameState.length; + dataLen = 0; break; - } else - break readmore; - case mask: - avail = buf.remaining(); - if (avail >= 4) { - mask = buf.getInt(); - state = FrameState.data; - // break; - } else - break readmore; - case data: - if (__parseDebugOn) - container.log("data oper 0%x len %d", oper, len); - boolean contin = false; - // if (contin) - // oper = frameText ? 1 : 2; - - avail = buf.remaining(); - if (dataLen == 0) { - if (avail >= len) { - data = new byte[(int) len]; - buf.get(data); - dataLen = (int) len; + case length: + byte lb = byteBuffer.get(); + masked = (lb & 0x80) != 0; + len = lb & 0x7f; + if (len == 126) { + state = FrameState.length16; + } else if (len == 127) { + state = FrameState.length64; } else { - data = new byte[(int) avail]; - buf.get(data); - dataLen = avail; + state = masked ? FrameState.mask : FrameState.data; } - } else { - int sl = (int) Math.min(avail, len - dataLen); - data = Arrays.copyOf(data, dataLen + sl); - buf.get(data, dataLen, sl); - dataLen += sl; - } - if (dataLen == len) { // all data - state = FrameState.header; - if (masked) { - int mp = 0; - for (int p = 0; p < data.length; p++) - data[p] = (byte) (data[p] ^ (mask >> (8 * (3 - mp++ % 4)) & 255)); + forceOp = !masked; + if (__parseDebugOn) { + serverContainer.log("len %d st %s avail %d", len, state, byteBuffer.limit() - byteBuffer.position()); } - switch (oper) { - case 1: - frameText = true; - break; - case 2: - frameText = false; + break; + case length16: + avail = byteBuffer.remaining(); + if (avail >= 2) { + // buf.order(ByteOrder.BIG_ENDIAN); + len = byteBuffer.get() & 255; + len = (len << 8) | (byteBuffer.get() & 255); + state = masked ? FrameState.mask : FrameState.data; break; + } else { + break readmore; } - switch (oper) { - case 8: // close - CloseReason cr = null; - if (data != null && data.length >= 2) { - short reason = (short) ((data[1] & 255) + (data[0] << 8)); - String msg; - if (data.length > 2) { - msg = bytesToString(Arrays.copyOfRange(data, 2, data.length)); - } else - msg = ""; - cr = new CloseReason(CloseCodes.getCloseCode(reason), msg); - } - if (__parseDebugOn) - container.log("close(%s)", cr); - try { - close(cr, data); // echo is handled by close - } catch (IOException e1) { - + case length64: + avail = byteBuffer.remaining(); + if (avail >= 8) { + len = byteBuffer.getLong(); + if (len > Integer.MAX_VALUE || len < 0) { + throw new IllegalArgumentException("Frame length is too long"); } + state = masked ? FrameState.mask : FrameState.data; break; - case 0x9: // ping - try { - ((SimpleBasic) getBasicRemote()).sendEcho((byte) 10, data); - } catch (IOException e1) { - container.log(e1, "Problem in returning pong"); + } else { + break readmore; + } + case mask: + avail = byteBuffer.remaining(); + if (avail >= 4) { + mask = byteBuffer.getInt(); + state = FrameState.data; + // break; + } else { + break readmore; + } + case data: + if (__parseDebugOn) { + serverContainer.log("data oper 0%x len %d", oper, len); + } + boolean contin = false; + // if (contin) + // oper = frameText ? 1 : 2; + + avail = byteBuffer.remaining(); + if (dataLen == 0) { + if (avail >= len) { + data = new byte[(int) len]; + byteBuffer.get(data); + dataLen = (int) len; + } else { + data = new byte[(int) avail]; + byteBuffer.get(data); + dataLen = avail; } - break; - case 0xa: // pong - for (SimpleMessageHandler mh : handlers) { - // System.err.printf("process pong %s%n", mh); - mh.processPong(data); + } else { + int sl = (int) Math.min(avail, len - dataLen); + data = Arrays.copyOf(data, dataLen + sl); + byteBuffer.get(data, dataLen, sl); + dataLen += sl; + } + + if (dataLen == len) { // all data + state = FrameState.header; + if (masked) { + int mp = 0; + for (int p = 0; p < data.length; p++) + data[p] = (byte) (data[p] ^ (mask >> (8 * (3 - mp++ % 4)) & 255)); } - break; - case 0: - contin = true; - case 1: - case 2: - boolean partConsumed = false; - if (frameText) { - for (SimpleMessageHandler mh : handlers) { - partConsumed |= mh.processText(bytesToString(data), frameFinal); - if (__parseDebugOn) - container.log("process text part %s - %b", mh, partConsumed); - } - } else { - for (SimpleMessageHandler mh : handlers) { - partConsumed |= mh.processBinary(data, frameFinal); - if (__parseDebugOn) - container.log("process binary part %s - %b", mh, partConsumed); - } + + switch (oper) { + case 1: + frameText = true; + break; + case 2: + frameText = false; + break; } - if (partConsumed == false) { - if (!contin) - completeData = data; - else { - completeData = Arrays.copyOf(completeData, completeData.length + data.length); - System.arraycopy(data, 0, completeData, completeData.length - data.length, data.length); - } - if (frameFinal) { + + switch (oper) { + case 8: // close + CloseReason cr = null; + if (data != null && data.length >= 2) { + short reason = (short) ((data[1] & 255) + (data[0] << 8)); + String msg; + if (data.length > 2) { + msg = bytesToString(Arrays.copyOfRange(data, 2, data.length)); + } else { + msg = ""; + } + cr = new CloseReason(CloseCodes.getCloseCode(reason), msg); + } + if (__parseDebugOn) { + serverContainer.log("close(%s)", cr); + } + + try { + close(cr, data); // echo is handled by close + } catch (IOException e1) { + + } + break; + case 0x9: // ping + try { + ((SimpleBasic) getBasicRemote()).sendEcho((byte) 10, data); + } catch (IOException e1) { + serverContainer.log(e1, "Problem in returning pong"); + } + break; + case 0xa: // pong + for (SimpleMessageHandler mh : handlers) { + // System.err.printf("process pong %s%n", + // mh); + mh.processPong(data); + } + break; + case 0: + contin = true; + case 1: + case 2: + boolean partConsumed = false; if (frameText) { for (SimpleMessageHandler mh : handlers) { - mh.processText(bytesToString(completeData)); - if (__parseDebugOn) - container.log("process text %s", mh); + partConsumed |= mh.processText(bytesToString(data), frameFinal); + if (__parseDebugOn) { + serverContainer.log("process text part %s - %b", mh, partConsumed); + } } } else { for (SimpleMessageHandler mh : handlers) { - mh.processBinary(completeData); - if (__parseDebugOn) - container.log("process binary %s", mh); + partConsumed |= mh.processBinary(data, frameFinal); + if (__parseDebugOn) { + serverContainer.log("process binary part %s - %b", mh, partConsumed); + } } } - } - } - break; - default: - container.log("Invalid frame op 0%x, len %d", oper, len); - try { - close(new CloseReason(CloseReason.CloseCodes.PROTOCOL_ERROR, "Unsupported frame operation:" - + oper)); - } catch (IOException e) { - container.log(e, "Exception at closing"); + + if (partConsumed == false) { + if (!contin) { + completeData = data; + } else { + completeData = Arrays.copyOf(completeData, completeData.length + data.length); + System.arraycopy(data, 0, completeData, completeData.length - data.length, data.length); + } + + if (frameFinal) { + if (frameText) { + for (SimpleMessageHandler mh : handlers) { + mh.processText(bytesToString(completeData)); + if (__parseDebugOn) { + serverContainer.log("process text %s", mh); + } + } + } else { + for (SimpleMessageHandler mh : handlers) { + mh.processBinary(completeData); + if (__parseDebugOn) { + serverContainer.log("process binary %s", mh); + } + } + } + } + } + break; + default: + serverContainer.log("Invalid frame op 0%x, len %d", oper, len); + try { + close(new CloseReason(CloseReason.CloseCodes.PROTOCOL_ERROR, "Unsupported frame operation:" + oper)); + } catch (IOException e) { + serverContainer.log(e, "Exception at closing"); + } + break readmore; } - break readmore; } - } - forceOp = false; + forceOp = false; } } - if (__parseDebugOn) - container.log("Exited %b", buf.hasRemaining()); - if (buf.hasRemaining()) { - buf.mark(); - buf.position(lim); - buf.limit(buf.capacity()); + + if (__parseDebugOn) { + serverContainer.log("Exited %b", byteBuffer.hasRemaining()); + } + + if (byteBuffer.hasRemaining()) { + byteBuffer.mark(); + byteBuffer.position(lim); + byteBuffer.limit(byteBuffer.capacity()); } else { - buf.clear(); - buf.mark(); + byteBuffer.clear(); + byteBuffer.mark(); } } - + String bytesToString(byte[] b) { try { - return new String(b, "UTF-8"); + return new String(b, IOHelper.UTF_8); } catch (UnsupportedEncodingException e) { return new String(data); } } - - void addMessageHandler(ServerEndpointConfig arg0) throws IllegalStateException { - if (endpointConfig != null) + + void addMessageHandler(ServerEndpointConfig endPointConfig) throws IllegalStateException { + if (endPointConfig != null) { throw new IllegalStateException("Only one endpoint can be associated with session/connection"); - endpointConfig = arg0; + } + + this.endPointConfig = endPointConfig; handlers.add(new SimpleMessageHandler()); } - + @Override public void addMessageHandler(MessageHandler arg0) throws IllegalStateException { SimpleMessageHandler smh = new SimpleMessageHandler(arg0); @@ -397,7 +436,7 @@ public void addMessageHandler(MessageHandler arg0) throws IllegalStateException throw new IllegalStateException("Only one handler of each type allowed"); } handlers.add(new SimpleMessageHandler(arg0)); - + } @Override @@ -405,50 +444,48 @@ public void addMessageHandler(Class handClass, Whole whole) { // TODO Auto-generated method stub } - + @Override public void addMessageHandler(Class handClass, Partial partial) { // TODO Auto-generated method stub - } - + @Override public void close() throws IOException { close(null); - } - + @Override public void close(CloseReason reason) throws IOException { close(reason, null); } - - public void close(CloseReason reason, byte[] b) throws IOException { - //new Exception("attempt close already closed").printStackTrace(); + + public void close(CloseReason reason, byte[] dataBytes) throws IOException { + // new Exception("attempt close already closed").printStackTrace(); if (isOpen() == false) { return; } + try { for (SimpleMessageHandler mh : handlers) { mh.processClose(reason); - // mh.destroy(); } - if (b == null) + if (dataBytes == null) if (reason == null) - b = new byte[0]; + dataBytes = new byte[0]; else { ByteBuffer bb = ByteBuffer.allocate(2 + reason.getReasonPhrase().length()); bb.putShort((short) reason.getCloseCode().getCode()); if (reason.getReasonPhrase().length() > 0) bb.put(reason.getReasonPhrase().getBytes()); bb.flip(); - b = new byte[bb.remaining()]; - bb.put(b); + dataBytes = new byte[bb.remaining()]; + bb.put(dataBytes); } if (basicRemote != null) { try { - basicRemote.sendEcho((byte) 8, b); + basicRemote.sendEcho((byte) 8, dataBytes); } catch (Exception e) { // eat it, can be closed } @@ -456,10 +493,11 @@ public void close(CloseReason reason, byte[] b) throws IOException { basicRemote = null; } } finally { - if (__debugOn) - container.log("Channel closed"); + if (__debugOn) { + serverContainer.log("Channel closed"); + } userProperties = null; - container.removeSession(this); + serverContainer.removeSession(this); try { channel.close(); } catch (Exception e) { @@ -468,121 +506,127 @@ public void close(CloseReason reason, byte[] b) throws IOException { channel = null; } } - + @Override public Async getAsyncRemote() { // TODO maybe cache return new SimpleAsync(); } - + @Override public Basic getBasicRemote() { // TODO investigate if possible to use from different threads - if (basicRemote == null) + if (basicRemote == null) { basicRemote = new SimpleBasic(); + } + return basicRemote; } - + @Override public WebSocketContainer getContainer() { - return container; + return serverContainer; } - + @Override public String getId() { return id; } - + @Override public int getMaxBinaryMessageBufferSize() { - return buf.capacity(); + return byteBuffer.capacity(); } - + @Override public long getMaxIdleTimeout() { return idleTimeout; } - + @Override public int getMaxTextMessageBufferSize() { - return buf.capacity(); + return byteBuffer.capacity(); } - + @Override public Set getMessageHandlers() { HashSet result = new HashSet(); for (SimpleMessageHandler smh : handlers) { - if (smh.endpoint instanceof MessageHandler) + if (smh.endpoint instanceof MessageHandler) { result.add((MessageHandler) smh.endpoint); + } } + return result; } - + @Override public List getNegotiatedExtensions() { return extensions; } - + @Override public String getNegotiatedSubprotocol() { return subprotocol; } - + @Override public Set getOpenSessions() { HashSet result = new HashSet(); - for (SimpleSession ss : container.sessions) { - if (endpointConfig == ss.endpointConfig) + for (SimpleSession ss : serverContainer.sessions) { + if (endPointConfig == ss.endPointConfig) { result.add(ss); + } } + return result; } - + @Override public Map getPathParameters() { return pathParamsMap; } - + @Override public String getProtocolVersion() { return "13"; } - + @Override public String getQueryString() { return query; } - + @Override public Map> getRequestParameterMap() { return paramsMap; } - + @Override public URI getRequestURI() { return uri; } - + @Override public Principal getUserPrincipal() { return principal; } - + @Override public Map getUserProperties() { return userProperties; } - + @Override public boolean isOpen() { return channel != null && channel.isOpen(); } - + @Override public boolean isSecure() { - return conn.isSecure(); + return serveConnection.isSecure(); } - + @Override public void removeMessageHandler(MessageHandler arg0) { for (SimpleMessageHandler smh : handlers) { @@ -592,38 +636,43 @@ public void removeMessageHandler(MessageHandler arg0) { } } } - + + /** + * @see javax.websocket.Session#setMaxBinaryMessageBufferSize(int) + */ @Override - public void setMaxBinaryMessageBufferSize(int arg0) { - if (buf.capacity() < arg0 && buf.remaining() == 0) - buf = ByteBuffer.allocate(arg0); + public void setMaxBinaryMessageBufferSize(int capacity) { + if (byteBuffer.capacity() < capacity && byteBuffer.remaining() == 0) + byteBuffer = ByteBuffer.allocate(capacity); } - + + /** + * @see javax.websocket.Session#setMaxIdleTimeout(long) + */ @Override - public void setMaxIdleTimeout(long arg0) { - idleTimeout = arg0; + public void setMaxIdleTimeout(long maxIdleTimeout) { + idleTimeout = maxIdleTimeout; } - + @Override public void setMaxTextMessageBufferSize(int arg0) { - if (buf.capacity() < arg0 && buf.remaining() == 0) - buf = ByteBuffer.allocate(arg0); + if (byteBuffer.capacity() < arg0 && byteBuffer.remaining() == 0) + byteBuffer = ByteBuffer.allocate(arg0); } - + static class ParameterEntry { ParameterEntry(int type) { sourceType = type; } - + ParameterEntry() { - } - + int sourceType; String sourceName; Set decoder; } - + class SimpleMessageHandler implements MessageHandler { private static final int TEXT = 1; private static final int BIN = 2; @@ -638,335 +687,380 @@ class SimpleMessageHandler implements MessageHandler { private static final int READER = 11; private static final int BYTEBUF = 12; private static final int INPUT = 13; - + Method onText, onBin, onPong; Method onOpen; Method onClose; Method onError; boolean partText, partBin; - - ParameterEntry[] paramMapText, paramMapOpen, paramMapClose, paramMapError, paramMapPong, paramMapBin; - + + ParameterEntry[] paramMapText, paramMapOpen, paramMapClose, + paramMapError, paramMapPong, paramMapBin; Object endpoint; Object result; - + // ServerEndpointConfig endpointConfig; - + SimpleMessageHandler() { - Class epc = endpointConfig.getEndpointClass(); + Class epc = endPointConfig.getEndpointClass(); try { endpoint = epc.newInstance(); - endpointConfig.getConfigurator().getEndpointInstance(epc); + endPointConfig.getConfigurator().getEndpointInstance(epc); } catch (InstantiationException e) { - container.log(e, "Can't instantiate end point for %s", epc); + serverContainer.log(e, "Can't instantiate end point for %s", epc); } catch (IllegalAccessException e) { - container.log(e, "Can't instantiate end point for %s", epc); + serverContainer.log(e, "Can't instantiate end point for %s", epc); } - Method[] ms = epc.getDeclaredMethods(); - for (Method m : ms) { - if (m.getAnnotation(OnMessage.class) != null) { - int pi = 0; - Annotation[][] annots = m.getParameterAnnotations(); - Class[] params = m.getParameterTypes(); - ParameterEntry[] pmap = new ParameterEntry[params.length]; - boolean partReq = false, primeText = false, primeBin = false; - for (Class t : params) { - pmap[pi] = new ParameterEntry(); - if (t == String.class) { - PathParam pp = (PathParam) getFromList(annots[pi], PathParam.class); - if (pp == null) { - pmap[pi].sourceType = TEXT; - if (onText != null) + + Method[] methods = epc.getDeclaredMethods(); + for (Method method : methods) { + if (method.getAnnotation(OnMessage.class) != null) { + int paramIndex = 0; + Annotation[][] paramAnnotations = method.getParameterAnnotations(); + Class[] paramTypes = method.getParameterTypes(); + final ParameterEntry[] paramEntries = new ParameterEntry[paramTypes.length]; + boolean partReq = false, primeText = false, + primeBin = false; + for (Class paramClass : paramTypes) { + paramEntries[paramIndex] = new ParameterEntry(); + if (paramClass == String.class) { + final PathParam pathParam = (PathParam) getFromList(paramAnnotations[paramIndex], PathParam.class); + if (pathParam == null) { + paramEntries[paramIndex].sourceType = TEXT; + if (onText != null) { throw new IllegalStateException("A text message handler has already been configured"); - onText = m; - paramMapText = pmap; + } + onText = method; + paramMapText = paramEntries; primeText = true; } else { // if (pathParamsMap.containsKey(pp.value()) == // false) // throw new - // IllegalArgumentException("Not supported variable " + // IllegalArgumentException("Not supported + // variable " // + pp.value()); - pmap[pi].sourceName = pp.value(); - pmap[pi].sourceType = PATH_PARAM; + paramEntries[paramIndex].sourceName = pathParam.value(); + paramEntries[paramIndex].sourceType = PATH_PARAM; } - } else if (t.isAssignableFrom(Session.class)) { - pmap[pi].sourceType = SESSION_PARAM; - } else if (t == boolean.class) { - pmap[pi].sourceType = BOOLEAN; + } else if (paramClass.isAssignableFrom(Session.class)) { + paramEntries[paramIndex].sourceType = SESSION_PARAM; + } else if (paramClass == boolean.class) { + paramEntries[paramIndex].sourceType = BOOLEAN; partReq = true; - } else if (t == byte[].class) { - if (onBin != null) + } else if (paramClass == byte[].class) { + if (onBin != null) { throw new IllegalStateException("A binary message handler has already been configured"); - pmap[pi].sourceType = BIN; - onBin = m; - paramMapBin = pmap; + } + paramEntries[paramIndex].sourceType = BIN; + onBin = method; + paramMapBin = paramEntries; primeBin = true; - } else if (t.isAssignableFrom(Reader.class)) { - if (onText != null) + } else if (paramClass.isAssignableFrom(Reader.class)) { + if (onText != null) { throw new IllegalStateException("A text message handler has already been configured"); - onText = m; - pmap[pi].sourceType = READER; - paramMapText = pmap; - } else if (t == ByteBuffer.class) { - if (onBin != null) + } + onText = method; + paramEntries[paramIndex].sourceType = READER; + paramMapText = paramEntries; + } else if (paramClass == ByteBuffer.class) { + if (onBin != null) { throw new IllegalStateException("A binary message handler has already been configured"); - onBin = m; - pmap[pi].sourceType = BYTEBUF; - paramMapBin = pmap; - } else if (t == InputStream.class) { + } + onBin = method; + paramEntries[paramIndex].sourceType = BYTEBUF; + paramMapBin = paramEntries; + } else if (paramClass == InputStream.class) { if (onBin != null) throw new IllegalStateException("A binary message handler has already been configured"); - onBin = m; - pmap[pi].sourceType = INPUT; - paramMapBin = pmap; - } else if (t == PongMessage.class) { - if (onPong != null) + onBin = method; + paramEntries[paramIndex].sourceType = INPUT; + paramMapBin = paramEntries; + } else if (paramClass == PongMessage.class) { + if (onPong != null) { throw new IllegalStateException("A pong message handler has already been configured"); - pmap[pi].sourceType = PONG; - onPong = m; - paramMapPong = pmap; + } + paramEntries[paramIndex].sourceType = PONG; + onPong = method; + paramMapPong = paramEntries; } else { - if (endpointConfig.getDecoders() != null) { - Set decoders = matchDecoders(t, Decoder.Text.class, String.class); + if (endPointConfig.getDecoders() != null) { + Set decoders = matchDecoders(paramClass, Decoder.Text.class, String.class); if (decoders.size() > 0) { - if (onText != null) + if (onText != null) { throw new IllegalStateException("A text message handler has already been configured"); - onText = m; - pmap[pi].decoder = decoders; - pmap[pi].sourceType = DECODER; - paramMapText = pmap; + } + onText = method; + paramEntries[paramIndex].decoder = decoders; + paramEntries[paramIndex].sourceType = DECODER; + paramMapText = paramEntries; } else { - decoders = matchDecoders(t, Decoder.TextStream.class, Reader.class); + decoders = matchDecoders(paramClass, Decoder.TextStream.class, Reader.class); if (decoders.size() > 0) { - if (onText != null) + if (onText != null) { throw new IllegalStateException("A text message handler has already been configured"); - onText = m; - pmap[pi].decoder = decoders; - pmap[pi].sourceType = DECODER; - paramMapText = pmap; + } + onText = method; + paramEntries[paramIndex].decoder = decoders; + paramEntries[paramIndex].sourceType = DECODER; + paramMapText = paramEntries; } else { - decoders = matchDecoders(t, Decoder.Binary.class, ByteBuffer.class); + decoders = matchDecoders(paramClass, Decoder.Binary.class, ByteBuffer.class); if (decoders.size() > 0) { - if (onBin != null) + if (onBin != null) { throw new IllegalStateException("A binary message handler has already been configured"); - onBin = m; - pmap[pi].decoder = decoders; - pmap[pi].sourceType = DECODER; - paramMapBin = pmap; + } + onBin = method; + paramEntries[paramIndex].decoder = decoders; + paramEntries[paramIndex].sourceType = DECODER; + paramMapBin = paramEntries; } else { - decoders = matchDecoders(t, Decoder.BinaryStream.class, InputStream.class); + decoders = matchDecoders(paramClass, Decoder.BinaryStream.class, InputStream.class); if (decoders.size() > 0) { - if (onBin != null) + if (onBin != null) { throw new IllegalStateException("A binary message handler has already been configured"); - onBin = m; - pmap[pi].decoder = decoders; - pmap[pi].sourceType = DECODER; - paramMapBin = pmap; + } + onBin = method; + paramEntries[paramIndex].decoder = decoders; + paramEntries[paramIndex].sourceType = DECODER; + paramMapBin = paramEntries; } } } } - } } - pi++; + paramIndex++; } partText = primeText && partReq; partBin = primeBin && partReq; - } else if (m.getAnnotation(OnOpen.class) != null) { - onOpen = m; + } else if (method.getAnnotation(OnOpen.class) != null) { + onOpen = method; paramMapOpen = creatParamMap(onOpen); - } else if (m.getAnnotation(OnError.class) != null) { - onError = m; + } else if (method.getAnnotation(OnError.class) != null) { + onError = method; paramMapError = creatParamMap(onError); - } else if (m.getAnnotation(OnClose.class) != null) { - onClose = m; + } else if (method.getAnnotation(OnClose.class) != null) { + onClose = method; paramMapClose = creatParamMap(onClose); } } - } - + boolean sameType(SimpleMessageHandler smh) { - if (smh.onText != null) - if (onText != null) + if (smh.onText != null) { + if (onText != null) { return partText == smh.partText; - if (smh.onPong != null) + } + } + + if (smh.onPong != null) { return onPong != null; - if (smh.onBin != null) - if (onBin != null) + } + + if (smh.onBin != null) { + if (onBin != null) { return partBin == smh.partBin; + } + } return false; } - + void destroy() { destroyDecoders(paramMapText); destroyDecoders(paramMapBin); } - - void destroyDecoders(ParameterEntry[] pmap) { - if (pmap != null) - for (ParameterEntry pe : pmap) { - if (pe.decoder != null) - for (Decoder decoder : pe.decoder) + + /** + * + * @param paramEntries + */ + void destroyDecoders(ParameterEntry[] paramEntries) { + if (paramEntries != null) + for (ParameterEntry paramEntry : paramEntries) { + if (paramEntry.decoder != null) { + for (Decoder decoder : paramEntry.decoder) { decoder.destroy(); + } + } } } - - SimpleMessageHandler(MessageHandler mh) { - initHandler(mh); + + /** + * + * @param msgHandler + */ + SimpleMessageHandler(MessageHandler msgHandler) { + initHandler(msgHandler); } - - void initHandler(MessageHandler mh) { - boolean partial = mh instanceof MessageHandler.Partial; - Class mhc = mh.getClass(); + + /** + * + * @param msgHandler + */ + void initHandler(MessageHandler msgHandler) { + boolean partial = msgHandler instanceof MessageHandler.Partial; + Class mhc = msgHandler.getClass(); for (Method m : mhc.getDeclaredMethods()) { - if (!"onMessage".equals(m.getName())) + if (!"onMessage".equals(m.getName())) { continue; + } + Class[] pts = m.getParameterTypes(); switch (pts.length) { - case 2: - if (!partial) - continue; - if (pts[1] != boolean.class) - continue; - case 1: - if (pts[0] == String.class) { - onText = m; - endpoint = mh; - paramMapText = new ParameterEntry[pts.length]; - paramMapText[0] = new ParameterEntry(TEXT); - if (partial) { - paramMapText[1] = new ParameterEntry(BOOLEAN); - partText = true; - } - } else if (pts[0].isAssignableFrom(Reader.class)) { - onText = m; - endpoint = mh; - paramMapText = new ParameterEntry[pts.length]; - paramMapText[0] = new ParameterEntry(READER); - if (partial) { - paramMapText[1] = new ParameterEntry(BOOLEAN); - partText = true; - } - } else if (pts[0] == PongMessage.class) { - if (partial) - throw new IllegalArgumentException("Pong message handler has to be Whole"); - onPong = m; - endpoint = mh; - paramMapPong = new ParameterEntry[1]; - paramMapPong[0] = new ParameterEntry(PONG); - } else if (pts[0] == byte[].class) { - onBin = m; - endpoint = mh; - paramMapBin = new ParameterEntry[pts.length]; - paramMapBin[0] = new ParameterEntry(BIN); - if (partial) { - paramMapBin[1] = new ParameterEntry(BOOLEAN); - partBin = true; + case 2: + if (!partial) { + continue; } - } else if (pts[0] == ByteBuffer.class) { - onBin = m; - endpoint = mh; - paramMapBin = new ParameterEntry[pts.length]; - paramMapBin[0] = new ParameterEntry(BYTEBUF); - if (partial) { - paramMapBin[1] = new ParameterEntry(BOOLEAN); - partBin = true; + + if (pts[1] != boolean.class) { + continue; } - } else { - if (endpointConfig.getDecoders() == null) - break; - Set decs = matchDecoders(pts[0], Decoder.Text.class, String.class); - if (decs.size() > 0) { + case 1: + if (pts[0] == String.class) { onText = m; - endpoint = mh; + endpoint = msgHandler; paramMapText = new ParameterEntry[pts.length]; - paramMapText[0] = new ParameterEntry(DECODER); - paramMapText[0].decoder = decs; + paramMapText[0] = new ParameterEntry(TEXT); if (partial) { paramMapText[1] = new ParameterEntry(BOOLEAN); partText = true; } - break; - } - decs = matchDecoders(pts[0], Decoder.TextStream.class, Reader.class); - if (decs.size() > 0) { + } else if (pts[0].isAssignableFrom(Reader.class)) { onText = m; - endpoint = mh; + endpoint = msgHandler; paramMapText = new ParameterEntry[pts.length]; - paramMapText[0] = new ParameterEntry(DECODER); - paramMapText[0].decoder = decs; + paramMapText[0] = new ParameterEntry(READER); if (partial) { paramMapText[1] = new ParameterEntry(BOOLEAN); partText = true; } - break; - } - decs = matchDecoders(pts[0], Decoder.Binary.class, ByteBuffer.class); - if (decs.size() > 0) { + } else if (pts[0] == PongMessage.class) { + if (partial) { + throw new IllegalArgumentException("Pong message handler has to be Whole"); + } + onPong = m; + endpoint = msgHandler; + paramMapPong = new ParameterEntry[1]; + paramMapPong[0] = new ParameterEntry(PONG); + } else if (pts[0] == byte[].class) { onBin = m; - endpoint = mh; + endpoint = msgHandler; paramMapBin = new ParameterEntry[pts.length]; - paramMapBin[0] = new ParameterEntry(DECODER); - paramMapBin[0].decoder = decs; + paramMapBin[0] = new ParameterEntry(BIN); if (partial) { paramMapBin[1] = new ParameterEntry(BOOLEAN); partBin = true; } - break; - } - decs = matchDecoders(pts[0], Decoder.BinaryStream.class, InputStream.class); - if (decs.size() > 0) { + } else if (pts[0] == ByteBuffer.class) { onBin = m; - endpoint = mh; + endpoint = msgHandler; paramMapBin = new ParameterEntry[pts.length]; - paramMapBin[0] = new ParameterEntry(DECODER); - paramMapBin[0].decoder = decs; + paramMapBin[0] = new ParameterEntry(BYTEBUF); if (partial) { paramMapBin[1] = new ParameterEntry(BOOLEAN); partBin = true; } - break; + } else { + if (endPointConfig.getDecoders() == null) { + break; + } + + Set decs = matchDecoders(pts[0], Decoder.Text.class, String.class); + if (decs.size() > 0) { + onText = m; + endpoint = msgHandler; + paramMapText = new ParameterEntry[pts.length]; + paramMapText[0] = new ParameterEntry(DECODER); + paramMapText[0].decoder = decs; + if (partial) { + paramMapText[1] = new ParameterEntry(BOOLEAN); + partText = true; + } + break; + } + decs = matchDecoders(pts[0], Decoder.TextStream.class, Reader.class); + if (decs.size() > 0) { + onText = m; + endpoint = msgHandler; + paramMapText = new ParameterEntry[pts.length]; + paramMapText[0] = new ParameterEntry(DECODER); + paramMapText[0].decoder = decs; + if (partial) { + paramMapText[1] = new ParameterEntry(BOOLEAN); + partText = true; + } + break; + } + decs = matchDecoders(pts[0], Decoder.Binary.class, ByteBuffer.class); + if (decs.size() > 0) { + onBin = m; + endpoint = msgHandler; + paramMapBin = new ParameterEntry[pts.length]; + paramMapBin[0] = new ParameterEntry(DECODER); + paramMapBin[0].decoder = decs; + if (partial) { + paramMapBin[1] = new ParameterEntry(BOOLEAN); + partBin = true; + } + break; + } + decs = matchDecoders(pts[0], Decoder.BinaryStream.class, InputStream.class); + if (decs.size() > 0) { + onBin = m; + endpoint = msgHandler; + paramMapBin = new ParameterEntry[pts.length]; + paramMapBin[0] = new ParameterEntry(DECODER); + paramMapBin[0].decoder = decs; + if (partial) { + paramMapBin[1] = new ParameterEntry(BOOLEAN); + partBin = true; + } + break; + } } - } - break; + break; } } } - + Set matchDecoders(Class type, Class dt, Class param) { HashSet result = new HashSet(); - for (Class dc : endpointConfig.getDecoders()) { + for (Class dc : endPointConfig.getDecoders()) { if (dt.isAssignableFrom(dc)) { Method dm; try { dm = dc.getDeclaredMethod("decode", param); if (dm.getReturnType() == type) { Decoder decoder = dc.newInstance(); - decoder.init(endpointConfig); + decoder.init(endPointConfig); result.add(decoder); } } catch (Exception e) { - if (__debugOn) - container.log(e, "Problem of adding decoder %s", dc); - else - container.log("Problem %s at adding decoder %s", e, dc); + if (__debugOn) { + serverContainer.log(e, "Problem of adding decoder %s", dc); + } else { + serverContainer.log("Problem %s at adding decoder %s", e, dc); + } } } } + return result; } - - Annotation getFromList(Annotation[] annots, Class targAnnot) { - if (annots != null) - for (Annotation a : annots) - if (a.annotationType() == targAnnot) - return a; + + Annotation getFromList(Annotation[] annotations, Class targAnnot) { + if (annotations != null) { + for (Annotation annotation : annotations) { + if (annotation.annotationType() == targAnnot) { + return annotation; + } + } + } + return null; } - + ParameterEntry[] creatParamMap(Method m) { Annotation[][] annots = m.getParameterAnnotations(); Class[] params = m.getParameterTypes(); @@ -982,8 +1076,9 @@ ParameterEntry[] creatParamMap(Method m) { pmap[pi].sourceType = CLOSEREASON_PARAM; } else if (t == String.class) { PathParam pp = (PathParam) getFromList(annots[pi], PathParam.class); - if (pp == null) + if (pp == null) { throw new IllegalArgumentException("String parameter isn't supported"); + } // if (pathParamsMap.containsKey(pp.value()) == false) // throw new // IllegalArgumentException("Not supported variable " + @@ -992,288 +1087,322 @@ ParameterEntry[] creatParamMap(Method m) { pmap[pi].sourceType = PATH_PARAM; } else if (t == Throwable.class) { pmap[pi].sourceType = THROWABLE_PARAM; - } else + } else { throw new IllegalArgumentException("Argument of " + t + " isn't allowed for a parameter"); + } + pi++; } return pmap; } - + void processPong(final byte[] b) { if (onPong != null) { Class[] paramts = onText.getParameterTypes(); Object[] params = new Object[paramts.length]; for (int pi = 0; pi < params.length; pi++) switch (paramMapPong[pi].sourceType) { - case PONG: - params[pi] = new PongMessage() { - - @Override - public ByteBuffer getApplicationData() { - // TODO Auto-generated method stub - return ByteBuffer.wrap(b); - } - - }; - break; - case PATH_PARAM: - params[pi] = pathParamsMap.get(paramMapPong[pi].sourceName); - break; + case PONG: + params[pi] = new PongMessage() { + + @Override + public ByteBuffer getApplicationData() { + // TODO Auto-generated method stub + return ByteBuffer.wrap(b); + } + + }; + break; + case PATH_PARAM: + params[pi] = pathParamsMap.get(paramMapPong[pi].sourceName); + break; } try { result = onPong.invoke(endpoint, params); } catch (Exception e) { - container.log(e, "Error in sending pong"); - if (!processError(e)) - container.log(e, "Unhandled error"); + serverContainer.log(e, "Error in sending pong"); + if (!processError(e)) { + serverContainer.log(e, "Unhandled error"); + } } } } - - boolean processBinary(byte[] b, boolean f) { + + boolean processBinary(byte[] dataBytes, boolean part) { if (onBin != null && partBin) { - processBinary(b, f); + processBinary(dataBytes, part); return true; } + return false; } - - void processBinary(byte[] b) { - processBinary(b, null); + + void processBinary(byte[] dataBytes) { + processBinary(dataBytes, null); } - - void processBinary(byte[] b, Boolean part) { + + void processBinary(byte[] dataBytes, Boolean part) { if (onBin != null) { Class[] paramts = onBin.getParameterTypes(); Object[] params = new Object[paramts.length]; - for (int pi = 0; pi < params.length; pi++) + for (int pi = 0; pi < params.length; pi++) { switch (paramMapBin[pi].sourceType) { - case BIN: - params[pi] = b; - break; - case SESSION_PARAM: - params[pi] = SimpleSession.this; - break; - case PATH_PARAM: - params[pi] = pathParamsMap.get(paramMapBin[pi].sourceName); - break; - case BOOLEAN: - params[pi] = part; - break; - case DECODER: - ByteBuffer bb = ByteBuffer.wrap(b); - for (Decoder decoder : paramMapBin[pi].decoder) - if (((Decoder.Binary) decoder).willDecode(bb)) - try { - params[pi] = ((Decoder.Binary) decoder).decode(bb); - break; - } catch (DecodeException e) { - if (__debugOn) - container.log(e, "in decoding..."); - if (!processError(e)) - container.log(e, "Unhandled error"); + case BIN: + params[pi] = dataBytes; + break; + case SESSION_PARAM: + params[pi] = SimpleSession.this; + break; + case PATH_PARAM: + params[pi] = pathParamsMap.get(paramMapBin[pi].sourceName); + break; + case BOOLEAN: + params[pi] = part; + break; + case DECODER: + ByteBuffer byteBuffer = ByteBuffer.wrap(dataBytes); + for (Decoder decoder : paramMapBin[pi].decoder) { + if (((Decoder.Binary) decoder).willDecode(byteBuffer)) { + try { + params[pi] = ((Decoder.Binary) decoder).decode(byteBuffer); + break; + } catch (DecodeException e) { + if (__debugOn) { + serverContainer.log(e, "in decoding..."); + } + + if (!processError(e)) { + serverContainer.log(e, "Unhandled error"); + } + } } - break; - case BYTEBUF: - params[pi] = ByteBuffer.wrap(b); - break; - case INPUT: - params[pi] = new ByteArrayInputStream(b); - break; - default: - container.log("Unmapped binary parameter %d at calling %s", pi, onBin); - params[pi] = null; + } + break; + case BYTEBUF: + params[pi] = ByteBuffer.wrap(dataBytes); + break; + case INPUT: + params[pi] = new ByteArrayInputStream(dataBytes); + break; + default: + serverContainer.log("Unmapped binary parameter %d at calling %s", pi, onBin); + params[pi] = null; } + } try { - if (__debugOn) - container.log("Called %s", b); + if (__debugOn) { + serverContainer.log("Called %s", dataBytes); + } result = onBin.invoke(endpoint, params); if (result != null) { - if (result instanceof String) + if (result instanceof String) { getBasicRemote().sendText(result.toString()); + } } } catch (Exception e) { - container.log(e, "Error in sending binary data"); - if (!processError(e)) - container.log(e, "Unhandled error"); + serverContainer.log(e, "Error in sending binary data"); + if (!processError(e)) { + serverContainer.log(e, "Unhandled error"); + } } - } else - container.log("No handler for binary message %s", b); + } else { + serverContainer.log("No handler for binary message %s", dataBytes); + } } - + boolean processText(String t, boolean f) { if (onText != null && partText) { processText(t, f); return true; } + return false; } - + void processText(String t) { processText(t, null); } - + void processText(String t, Boolean part) { if (onText != null) { Class[] paramts = onText.getParameterTypes(); Object[] params = new Object[paramts.length]; for (int pi = 0; pi < params.length; pi++) switch (paramMapText[pi].sourceType) { - case TEXT: - params[pi] = t; - break; - case SESSION_PARAM: - params[pi] = SimpleSession.this; - break; - case PATH_PARAM: - params[pi] = pathParamsMap.get(paramMapText[pi].sourceName); - break; - case BOOLEAN: - params[pi] = part; - break; - case DECODER: - for (Decoder decoder : paramMapText[pi].decoder) - if (((Decoder.Text) decoder).willDecode(t)) - try { - params[pi] = ((Decoder.Text) decoder).decode(t); - break; - } catch (DecodeException e) { - if (__debugOn) - container.log(e, "in decoding..."); - if (!processError(e)) - container.log(e, "Unhandled error"); + case TEXT: + params[pi] = t; + break; + case SESSION_PARAM: + params[pi] = SimpleSession.this; + break; + case PATH_PARAM: + params[pi] = pathParamsMap.get(paramMapText[pi].sourceName); + break; + case BOOLEAN: + params[pi] = part; + break; + case DECODER: + for (Decoder decoder : paramMapText[pi].decoder) + if (((Decoder.Text) decoder).willDecode(t)) { + try { + params[pi] = ((Decoder.Text) decoder).decode(t); + break; + } catch (DecodeException e) { + if (__debugOn) { + serverContainer.log(e, "in decoding..."); + } + if (!processError(e)) { + serverContainer.log(e, "Unhandled error"); + } + } } - break; - case READER: - params[pi] = new StringReader(t); - break; - default: - container.log("Unmapped text parameter %d at call %s", pi, onText); - params[pi] = null; + break; + case READER: + params[pi] = new StringReader(t); + break; + default: + serverContainer.log("Unmapped text parameter %d at call %s", pi, onText); + params[pi] = null; } + try { - if (__debugOn) - container.log("Called %s", t); + if (__debugOn) { + serverContainer.log("Called %s", t); + } result = onText.invoke(endpoint, params); if (result != null) { - if (result instanceof String) + if (result instanceof String) { getBasicRemote().sendText(result.toString()); + } } } catch (Exception e) { - container.log(e, "Exception in text message processing"); + serverContainer.log(e, "Exception in text message processing"); } - } else - container.log("No handler for text message %s", t); + } else { + serverContainer.log("No handler for text message %s", t); + } } - + void processOpen() { if (onOpen != null) { Class[] paramts = onOpen.getParameterTypes(); Object[] params = new Object[paramts.length]; - if (paramMapOpen != null) - for (int pi = 0; pi < params.length; pi++) + if (paramMapOpen != null) { + for (int pi = 0; pi < params.length; pi++) { switch (paramMapOpen[pi].sourceType) { - case SESSION_PARAM: - params[pi] = SimpleSession.this; - break; - case ENDPOINTCONFIG_PARAM: - params[pi] = endpointConfig; - break; - case PATH_PARAM: - params[pi] = pathParamsMap.get(paramMapOpen[pi].sourceName); - break; - default: - container.log("Unmapped open parameter %d at call %s", pi, onOpen); - params[pi] = null; + case SESSION_PARAM: + params[pi] = SimpleSession.this; + break; + case ENDPOINTCONFIG_PARAM: + params[pi] = endPointConfig; + break; + case PATH_PARAM: + params[pi] = pathParamsMap.get(paramMapOpen[pi].sourceName); + break; + default: + serverContainer.log("Unmapped open parameter %d at call %s", pi, onOpen); + params[pi] = null; } - + } + } + try { - if (__debugOn) - container.log("Called %s", "on open"); + if (__debugOn) { + serverContainer.log("Called %s", "on open"); + } result = onOpen.invoke(endpoint, params); } catch (Exception e) { - container.log(e, "Exception in onOpen"); + serverContainer.log(e, "Exception in onOpen"); } } } - + void processClose(CloseReason reason) { if (onClose != null) { Class[] paramts = onClose.getParameterTypes(); Object[] params = new Object[paramts.length]; - if (paramMapClose != null) - for (int pi = 0; pi < params.length; pi++) + if (paramMapClose != null) { + for (int pi = 0; pi < params.length; pi++) { switch (paramMapClose[pi].sourceType) { - case SESSION_PARAM: - params[pi] = SimpleSession.this; - break; - case ENDPOINTCONFIG_PARAM: - params[pi] = endpointConfig; - break; - case PATH_PARAM: - params[pi] = pathParamsMap.get(paramMapClose[pi].sourceName); - break; - case CLOSEREASON_PARAM: - params[pi] = reason; - break; - default: - container.log("Unmapped close parameter %d at call %s", pi, onClose); - params[pi] = null; + case SESSION_PARAM: + params[pi] = SimpleSession.this; + break; + case ENDPOINTCONFIG_PARAM: + params[pi] = endPointConfig; + break; + case PATH_PARAM: + params[pi] = pathParamsMap.get(paramMapClose[pi].sourceName); + break; + case CLOSEREASON_PARAM: + params[pi] = reason; + break; + default: + serverContainer.log("Unmapped close parameter %d at call %s", pi, onClose); + params[pi] = null; } + } + } + try { - if (__debugOn) - container.log("Called %s", "on close"); + if (__debugOn) { + serverContainer.log("Called %s", "on close"); + } result = onClose.invoke(endpoint, params); } catch (Exception e) { - container.log(e, "Exception in onClose"); + serverContainer.log(e, "Exception in onClose"); } } } - + boolean processError(Throwable error) { if (onError != null) { Class[] paramts = onError.getParameterTypes(); Object[] params = new Object[paramts.length]; - if (paramMapError != null) - for (int pi = 0; pi < params.length; pi++) + if (paramMapError != null) { + for (int pi = 0; pi < params.length; pi++) { switch (paramMapError[pi].sourceType) { - case SESSION_PARAM: - params[pi] = SimpleSession.this; - break; - case THROWABLE_PARAM: - params[pi] = error; - break; - case PATH_PARAM: - params[pi] = pathParamsMap.get(paramMapError[pi].sourceName); - break; - default: - container.log("Unmapped error parameter %d at call %s", pi, onError); - params[pi] = null; + case SESSION_PARAM: + params[pi] = SimpleSession.this; + break; + case THROWABLE_PARAM: + params[pi] = error; + break; + case PATH_PARAM: + params[pi] = pathParamsMap.get(paramMapError[pi].sourceName); + break; + default: + serverContainer.log("Unmapped error parameter %d at call %s", pi, onError); + params[pi] = null; } + } + } + try { - if (__debugOn) - container.log("Called %s", "on error"); + if (__debugOn) { + serverContainer.log("Called %s", "on error"); + } result = onError.invoke(endpoint, params); return true; - } catch (Exception e) { - container.log(e, "Exception in onError"); + } catch (Exception ex) { + serverContainer.log(ex, "Exception in onError"); } } + return false; } - + Object getResult() { return result; } } - + class SimpleBasic implements Basic { Random rn = new Random(); boolean masked; boolean cont; HashMap, Encoder> encoders; ByteBuffer[] batchBuffer; - + @Override public void flushBatch() throws IOException { if (batchBuffer != null) { @@ -1283,40 +1412,43 @@ public void flushBatch() throws IOException { batchBuffer = new ByteBuffer[0]; } } - + @Override public boolean getBatchingAllowed() { return batchBuffer != null; } - + @Override public void sendPing(ByteBuffer arg0) throws IOException, IllegalArgumentException { - if (arg0 == null || arg0.remaining() > 125) + if (arg0 == null || arg0.remaining() > 125) { throw new IllegalArgumentException("Control frame data length can't exceed 125"); + } sendBuffer(createFrame(true, arg0), true); } - + @Override public void sendPong(ByteBuffer arg0) throws IOException, IllegalArgumentException { - if (arg0 == null || arg0.remaining() > 125) + if (arg0 == null || arg0.remaining() > 125) { throw new IllegalArgumentException("Control frame data length can't exceed 125"); + } sendBuffer(createFrame(false, arg0), true); } - + @Override public void setBatchingAllowed(boolean arg0) throws IOException { batchBuffer = new ByteBuffer[0]; } - + @Override public OutputStream getSendStream() throws IOException { return new ByteArrayOutputStream() { boolean closed; - + @Override public void close() throws IOException { - if (closed) + if (closed) { throw new IOException("Stream is already closed"); + } flush(); sendBinary(ByteBuffer.wrap(toByteArray())); super.close(); @@ -1324,58 +1456,60 @@ public void close() throws IOException { } }; } - + @Override public Writer getSendWriter() throws IOException { return new StringWriter() { boolean closed; - + @Override public void close() throws IOException { - if (closed) + if (closed) { throw new IOException("Writer is already closed"); + } flush(); sendText(toString()); super.close(); closed = true; } - + }; } - + @Override public void sendBinary(ByteBuffer arg0) throws IOException { sendBuffer(createFrame(arg0, true, true)); } - + void sendBuffer(ByteBuffer bb) throws IOException { sendBuffer(bb, false); } - + void sendBuffer(ByteBuffer bb, boolean nobatch) throws IOException { if (batchBuffer != null && !nobatch) { batchBuffer = Arrays.copyOf(batchBuffer, batchBuffer.length + 1); batchBuffer[batchBuffer.length - 1] = bb; } else { - conn.extendAsyncTimeout(-1); + serveConnection.extendAsyncTimeout(-1); try { for (int len = bb.remaining(); len > 0; len = bb.remaining()) { int lc = channel.write(bb); - if (lc < 0) + if (lc < 0) { throw new IOException("Can't sent complete buffer, remmaining " + len); + } } } finally { - conn.extendAsyncTimeout(getMaxIdleTimeout()); + serveConnection.extendAsyncTimeout(getMaxIdleTimeout()); } } } - + @Override public void sendBinary(ByteBuffer arg0, boolean arg1) throws IOException { sendBuffer(createFrame(arg0, arg1, !cont)); cont = !arg1; } - + /** * Sends a custom developer object, blocking until it has been * transmitted. Containers will by default be able to encode java @@ -1397,93 +1531,99 @@ public void sendBinary(ByteBuffer arg0, boolean arg1) throws IOException { */ @Override public void sendObject(Object arg0) throws IOException, EncodeException { - if (encoders == null) + if (encoders == null) { initEncoders(); + } Encoder ec = encoders.get(arg0.getClass()); if (ec == null) throw new EncodeException(arg0, "There is no encoder"); if (ec instanceof Encoder.Text) { sendText(((Encoder.Text) ec).encode(arg0)); } else if (ec instanceof Encoder.TextStream) { - ((Encoder.TextStream) ec).encode(arg0, getSendWriter()); // TODO - // perhaps - // close - // writer + // TODO perhaps close writer + ((Encoder.TextStream) ec).encode(arg0, getSendWriter()); } else if (ec instanceof Encoder.Binary) { sendBinary(((Encoder.Binary) ec).encode(arg0)); } else if (ec instanceof Encoder.BinaryStream) { ((Encoder.BinaryStream) ec).encode(arg0, getSendStream()); - } else + } else { throw new EncodeException(ec, "The encoder doesn't provide proper encding method"); - + } } - + private void initEncoders() { encoders = new HashMap, Encoder>(); - for (Class ec : endpointConfig.getEncoders()) { - for (Method em : ec.getDeclaredMethods()) { - if (__debugOn) - container.log("method %s returns %s", em.getName(), em.getReturnType()); - if (!"encode".equals(em.getName())) + for (Class encoderClasses : endPointConfig.getEncoders()) { + for (Method em : encoderClasses.getDeclaredMethods()) { + if (__debugOn) { + serverContainer.log("method %s returns %s", em.getName(), em.getReturnType()); + } + + if (!"encode".equals(em.getName())) { continue; + } Class rt = em.getReturnType(); // Type[] pts = em.getGenericParameterTypes(); Class[] pts = em.getParameterTypes(); if (rt == String.class) { if (pts.length == 1) { try { - Encoder e = ec.newInstance(); - e.init(endpointConfig); - encoders.put(pts[0], e); - } catch (Exception e) { - if (__debugOn) - container.log(e, "at encoder creation"); + Encoder encoder = encoderClasses.newInstance(); + encoder.init(endPointConfig); + encoders.put(pts[0], encoder); + } catch (Exception ex) { + if (__debugOn) { + serverContainer.log(ex, "at encoder creation"); + } } } } // else // throw new IllegalArgumentException - // ("Only text encoders are implemented - "+rt+" for method "+em.getName()); + // ("Only text encoders are implemented - "+rt+" for + // method "+em.getName()); } } - + } - + @Override public void sendText(String arg0) throws IOException { sendBuffer(createFrame(arg0, true, true)); } - + @Override public void sendText(String arg0, boolean arg1) throws IOException { sendBuffer(createFrame(arg0, arg1, !cont)); cont = !arg1; } - + void sendEcho(byte op, byte[] data) throws IOException { - if (data.length > 125) + if (data.length > 125) { throw new IllegalArgumentException("Control frame data length can't exceed 125"); - ByteBuffer bb = prepreFrameHeader(op, data.length, true, true); - bb.put(data).flip(); - sendBuffer(bb, true); + } + + ByteBuffer byteBuffer = prepreFrameHeader(op, data.length, true, true); + byteBuffer.put(data).flip(); + sendBuffer(byteBuffer, true); } - + ByteBuffer createFrame(ByteBuffer bbp, boolean fin, boolean first) { - //System.err.printf("Sending %d bytes as final %b as first %b%n", - // bbp.remaining(), fin, first); + // System.err.printf("Sending %d bytes as final %b as first %b%n", + // bbp.remaining(), fin, first); ByteBuffer bb = prepreFrameHeader((byte) 2, bbp.remaining(), fin, first); bb.put(bbp).flip(); - //System.err.printf("Send frame %s of %d %s 0%x %x %x %x %n", bbp, - // bb.remaining(), bb, bb.get(0), bb.get(1), bb.get(2), - //bb.get(3)); + // System.err.printf("Send frame %s of %d %s 0%x %x %x %x %n", bbp, + // bb.remaining(), bb, bb.get(0), bb.get(1), bb.get(2), + // bb.get(3)); return bb; } - + ByteBuffer createFrame(boolean ping, ByteBuffer bbp) { - ByteBuffer bb = prepreFrameHeader((byte) (ping ? 0x9 : 0xa), bbp.remaining(), true, true); - bb.put(bbp).flip(); - return bb; + ByteBuffer byteBuffer = prepreFrameHeader((byte) (ping ? 0x9 : 0xa), bbp.remaining(), true, true); + byteBuffer.put(bbp).flip(); + return byteBuffer; } - + ByteBuffer prepreFrameHeader(byte cmd, long len, boolean fin, boolean first) { if (cmd != 1 && cmd != 2) { fin = first = true; @@ -1502,116 +1642,128 @@ ByteBuffer prepreFrameHeader(byte cmd, long len, boolean fin, boolean first) { bl += 6; lm |= 127; } - } else + } else { lm |= len; - ByteBuffer bb = ByteBuffer.allocate(bl + (int) len); + } + + ByteBuffer byteBuffer = ByteBuffer.allocate(bl + (int) len); byte hb = (byte) (fin ? 0x80 : 0); - if (first) + if (first) { hb |= cmd; - bb.put(hb).put(lm); - if (len > 125) - if (len <= Short.MAX_VALUE) - bb.putShort((short) len); - else - bb.putLong(len); - return bb; + } + + byteBuffer.put(hb).put(lm); + if (len > 125) { + if (len <= Short.MAX_VALUE) { + byteBuffer.putShort((short) len); + } else { + byteBuffer.putLong(len); + } + } + return byteBuffer; } - + ByteBuffer createFrame(String text, boolean fin, boolean first) { cont = !fin && !first; byte[] mb = null; try { - mb = text == null || text.length() == 0 ? new byte[0] : text.getBytes("UTF-8"); + mb = text == null || text.length() == 0 ? new byte[0] : text.getBytes(IOHelper.UTF_8); } catch (UnsupportedEncodingException e) { mb = text.getBytes(); } - + ByteBuffer bb = prepreFrameHeader((byte) 1, (long) mb.length, fin, first); if (masked) { bb.putInt(mask); int mp = 0; - for (int p = 0; p < mb.length; p++) + for (int p = 0; p < mb.length; p++) { mb[p] = (byte) (mb[p] ^ (mask >> (8 * (3 - mp++ % 4)) & 255)); + } } + bb.put(mb); bb.flip(); - if (__debugOn) - container.log("Create frame %s of %d %s hdr: 0%x%x", text, bb.remaining(), bb, bb.get(0), bb.get(1)); + if (__debugOn) { + serverContainer.log("Create frame %s of %d %s hdr: 0%x%x", text, bb.remaining(), bb, bb.get(0), bb.get(1)); + } + return bb; } - + void destroy() { - if (encoders != null) - for (Encoder ec : encoders.values()) + if (encoders != null) { + for (Encoder ec : encoders.values()) { ec.destroy(); + } + } } - + } - + void open() { for (SimpleMessageHandler mh : handlers) { mh.processOpen(); } } - + class SimpleAsync implements Async { long sendTimeout; - + SimpleAsync() { getBasicRemote(); } - + @Override public void flushBatch() throws IOException { basicRemote.flushBatch(); } - + @Override public boolean getBatchingAllowed() { return basicRemote.getBatchingAllowed(); } - + @Override public void sendPing(ByteBuffer arg0) throws IOException, IllegalArgumentException { basicRemote.sendPing(arg0); - + } - + @Override public void sendPong(ByteBuffer arg0) throws IOException, IllegalArgumentException { basicRemote.sendPong(arg0); } - + @Override public void setBatchingAllowed(boolean arg0) throws IOException { basicRemote.setBatchingAllowed(arg0); } - + @Override public long getSendTimeout() { return sendTimeout; } - + @Override public Future sendBinary(final ByteBuffer arg0) { - return container.asyncService.submit(new Callable() { - + return serverContainer.asyncService.submit(new Callable() { + @Override public Void call() throws Exception { - synchronized (basicRemote) { // TODO it can be not required - // since socket will - // synchronize + synchronized (basicRemote) { + // TODO it can be not required since socket will + // synchronize basicRemote.sendBinary(arg0); } return null; } }); } - + @Override public void sendBinary(final ByteBuffer arg0, final SendHandler arg1) { - container.asyncService.execute(new Runnable() { - + serverContainer.asyncService.execute(new Runnable() { + @Override public void run() { try { @@ -1620,15 +1772,15 @@ public void run() { } catch (IOException e) { arg1.onResult(new SendResult(e)); } - + } }); } - + @Override public Future sendObject(final Object arg0) { - return container.asyncService.submit(new Callable() { - + return serverContainer.asyncService.submit(new Callable() { + @Override public Void call() throws Exception { basicRemote.sendObject(arg0); @@ -1636,11 +1788,11 @@ public Void call() throws Exception { } }); } - + @Override public void sendObject(final Object arg0, final SendHandler arg1) { - container.asyncService.execute(new Runnable() { - + serverContainer.asyncService.execute(new Runnable() { + @Override public void run() { try { @@ -1649,15 +1801,15 @@ public void run() { } catch (Exception e) { arg1.onResult(new SendResult(e)); } - + } }); } - + @Override public Future sendText(final String arg0) { - return container.asyncService.submit(new Callable() { - + return serverContainer.asyncService.submit(new Callable() { + @Override public Void call() throws Exception { basicRemote.sendText(arg0); @@ -1665,11 +1817,11 @@ public Void call() throws Exception { } }); } - + @Override public void sendText(final String arg0, final SendHandler arg1) { - container.asyncService.execute(new Runnable() { - + serverContainer.asyncService.execute(new Runnable() { + @Override public void run() { try { @@ -1678,38 +1830,41 @@ public void run() { } catch (IOException e) { arg1.onResult(new SendResult(e)); } - + } }); } - + @Override public void setSendTimeout(long arg0) { - if (arg0 < 0) + if (arg0 < 0) { return; + } sendTimeout = arg0; } - + } - + @Override public void notifyTimeout() { - if (isOpen()) + if (isOpen()) { try { close(); } catch (IOException e) { - if (__debugOn) - container.log(e, "close() at timeout"); + if (__debugOn) { + serverContainer.log(e, "close() at timeout"); + } } + } } - + @Override public long getTimeout() { return idleTimeout; } - + public String getRemoteAddr() { - return conn.getRemoteAddr(); + return serveConnection.getRemoteAddr(); } - + } diff --git a/1.x/src/webapp.mf b/src/webapp.mf similarity index 100% rename from 1.x/src/webapp.mf rename to src/webapp.mf diff --git a/1.x/test/bee-web.xml b/test/bee-web.xml similarity index 100% rename from 1.x/test/bee-web.xml rename to test/bee-web.xml diff --git a/1.x/test/env.xml b/test/env.xml similarity index 100% rename from 1.x/test/env.xml rename to test/env.xml diff --git a/1.x/test/html-js/fileupload.js b/test/html-js/fileupload.js similarity index 100% rename from 1.x/test/html-js/fileupload.js rename to test/html-js/fileupload.js diff --git a/1.x/test/html-js/wsk-chat.html b/test/html-js/wsk-chat.html similarity index 100% rename from 1.x/test/html-js/wsk-chat.html rename to test/html-js/wsk-chat.html diff --git a/1.x/test/html-js/wsk-monitor.html b/test/html-js/wsk-monitor.html similarity index 100% rename from 1.x/test/html-js/wsk-monitor.html rename to test/html-js/wsk-monitor.html diff --git a/1.x/test/html-js/wsk-paste.html b/test/html-js/wsk-paste.html similarity index 100% rename from 1.x/test/html-js/wsk-paste.html rename to test/html-js/wsk-paste.html diff --git a/1.x/test/html-js/wsk-slides.html b/test/html-js/wsk-slides.html similarity index 100% rename from 1.x/test/html-js/wsk-slides.html rename to test/html-js/wsk-slides.html diff --git a/1.x/test/html-js/wsk-upload.html b/test/html-js/wsk-upload.html similarity index 100% rename from 1.x/test/html-js/wsk-upload.html rename to test/html-js/wsk-upload.html diff --git a/test/java/tjws/embedded/AllCertsTrustManager.java b/test/java/tjws/embedded/AllCertsTrustManager.java new file mode 100644 index 0000000..e5d963e --- /dev/null +++ b/test/java/tjws/embedded/AllCertsTrustManager.java @@ -0,0 +1,78 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.X509TrustManager; + +/** + * Create a trust manager that does not validate certificate chains. + * + * @author Rohtash Singh Lakra + * @date 03/22/2018 03:58:24 PM + */ +public class AllCertsTrustManager implements X509TrustManager { + + /** + * (non-Javadoc) + * + * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], + * java.lang.String) + */ + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + // TODO Auto-generated method stub + } + + /** + * (non-Javadoc) + * + * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], + * java.lang.String) + */ + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + // TODO Auto-generated method stub + } + + /** + * (non-Javadoc) + * + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } +} diff --git a/test/java/tjws/embedded/AllHostNameVerifier.java b/test/java/tjws/embedded/AllHostNameVerifier.java new file mode 100644 index 0000000..e0b3b67 --- /dev/null +++ b/test/java/tjws/embedded/AllHostNameVerifier.java @@ -0,0 +1,52 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +/** + * @author Rohtash Singh Lakra + * (Rohtash.Lakra@nasdaq.com) + * @date 03/22/2018 03:56:15 PM + */ +public class AllHostNameVerifier implements HostnameVerifier { + /** + * @see javax.net.ssl.HostnameVerifier#verify(java.lang.String, + * javax.net.ssl.SSLSession) + */ + @Override + public boolean verify(String hostName, SSLSession sslSession) { + return true; + } + +} diff --git a/test/java/tjws/embedded/EmbeddedServlet.java b/test/java/tjws/embedded/EmbeddedServlet.java new file mode 100755 index 0000000..b1b10c8 --- /dev/null +++ b/test/java/tjws/embedded/EmbeddedServlet.java @@ -0,0 +1,125 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; + +/** + * The EmbeddedServlet handles all local requests. + * + * @author Rohtash Singh Lakra + * @date 03/15/2018 03:39:08 PM + */ +public class EmbeddedServlet extends HttpServlet { + + /** serialVersionUID */ + private static final long serialVersionUID = 1L; + + public EmbeddedServlet() { + } + + /** + * @param servletConfig + * @throws ServletException + * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) + */ + public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + } + + /** + * @param request + * @param response + * @throws ServletException + * @throws IOException + * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, + * * + * javax.servlet.http.HttpServletResponse) + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + process(request, response); + } + + /** + * @param request + * @param response + * @throws ServletException + * @throws IOException + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, + * * + * javax.servlet.http.HttpServletResponse) + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + process(request, response); + } + + /** + * Processes all requests. + * + * @param servletRequest + * @param servletResponse + * @throws ServletException + * @throws IOException + */ + private void process(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { + try { + String pathSegment = servletRequest.getRequestURI(); + if (pathSegment.endsWith("/") || pathSegment.endsWith("html")) { + byte[] dataBytes = IOHelper.readBytes(EmbeddedServlet.class.getResourceAsStream("web/index.html"), true); + LogManager.info("dataBytes:\n" + IOHelper.toUTF8String(dataBytes) + "\n"); + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_HTML, dataBytes, servletResponse); + } else if (pathSegment.endsWith("favicon.ico")) { + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_ICON, IOHelper.readIconBytes(), servletResponse); + } else if (pathSegment.endsWith(".js")) { + if (pathSegment.startsWith("/")) { + pathSegment = pathSegment.substring(1); + } + byte[] dataBytes = IOHelper.readBytes(EmbeddedServlet.class.getResourceAsStream(pathSegment), true); + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_JSON, dataBytes, servletResponse); + } else { + IOHelper.sendResponse(IOHelper.CONTENT_TYPE_HTML, "Invalid Request".getBytes(), servletResponse); + } + } catch (Exception ex) { + LogManager.error(ex); + } + } +} diff --git a/test/java/tjws/embedded/TJWSServer.java b/test/java/tjws/embedded/TJWSServer.java new file mode 100644 index 0000000..e40d8ec --- /dev/null +++ b/test/java/tjws/embedded/TJWSServer.java @@ -0,0 +1,186 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import java.io.PrintStream; +import java.util.Properties; + +import com.rslakra.logger.LogManager; + +import rogatkin.web.WarRoller; +import rogatkin.web.WebAppServlet; + +/** + * @author Rohtash Singh Lakra (Rohtash.Lakra@nasdaq.com) + * @date 03/15/2018 04:00:49 PM + */ + +/** + * @author Rohtash Singh (rsingh@boardvantage.com) + * @version 1.0.0 + * @since Apr 28, 2015 5:26:56 PM + */ +public final class TJWSServer extends Acme.Serve.Serve { + + /** serialVersionUID */ + private static final long serialVersionUID = 2121247574146350235L; + + /** warDeployer */ + private WarRoller warDeployer; + + /** deployed */ + private boolean deployed; + + /** + * The default constructor which is the only one that works in android. + * + * @param arguments + * @param logStream + * @param runtime + * @param preferenceManager + */ + public TJWSServer(final Properties arguments, PrintStream logStream, Object runtime) { + super(arguments, logStream); + /* provide SERVLET context Android environment access */ + try { + WebAppServlet.setRuntimeEnv(runtime); + } catch (Exception ex) { + LogManager.error(ex); + } + + LogManager.debug("TJWSServer(" + arguments + ", " + logStream + ", " + runtime + ")"); + } + + /** + * @return + */ + public boolean isDeployed() { + return deployed; + } + + /** + * The deployed to be set. + * + * @param deployed + */ + public void setDeployed(boolean deployed) { + LogManager.debug("setDeployed(" + deployed + ")"); + this.deployed = deployed; + } + + /** + * Overriding method for public access + * + * @param mappingTable + * @see Acme.Serve.Serve#setMappingTable(Acme.Serve.Serve.PathTreeDictionary) + */ + @Override + public void setMappingTable(PathTreeDictionary mappingTable) { + LogManager.debug("setMappingTable(" + mappingTable + ")"); + super.setMappingTable(mappingTable); + } + + /** + * (non-Javadoc) + * + * @see Acme.Serve.Serve#setRealms(Acme.Serve.Serve.PathTreeDictionary) + */ + @Override + protected void setRealms(PathTreeDictionary realms) { + LogManager.debug("setRealms(" + realms + ")"); + super.setRealms(realms); + } + + /** + * @param key + * @param value + */ + @SuppressWarnings("unchecked") + public synchronized void setProperty(Object key, Object value) { + LogManager.debug("setProperty(" + key + ", " + value + ")"); + if (super.arguments == null) { + super.arguments = new Properties(); + } + + super.arguments.put(key, value); + } + + /** + * Removes the specified property. + * + * @param key + */ + public synchronized void removeProperty(Object key) { + LogManager.debug("removeProperty(" + key + ")"); + if (super.arguments != null) { + super.arguments.remove(key); + } + } + + /** + * Deploy the local web server into the warDeployer. + */ + public synchronized void deployWebServer() { + LogManager.debug("+deployWebServer(), deployed:" + isDeployed()); + try { + if (!isDeployed()) { + if (warDeployer == null) { + warDeployer = new WarRoller(); + } + + warDeployer.deploy(this); + setDeployed(true); + } + } catch (Throwable ex) { + LogManager.error("Unexpected problem in deployment, ex:", ex); + if (ex instanceof ThreadDeath) { + throw (ThreadDeath) ex; + } + } + + LogManager.debug("-deployWebServer(), deployed:" + isDeployed()); + } + + /** + * @param logEnabled + */ + protected void setLogEnabled(boolean logEnabled) { + if (logEnabled) { + setProperty(ARG_LOG_OPTIONS, "L"); + } else { + removeProperty(ARG_LOG_OPTIONS); + } + + setAccessLogged(); + } + +} \ No newline at end of file diff --git a/test/java/tjws/embedded/TestCertificate.java b/test/java/tjws/embedded/TestCertificate.java new file mode 100755 index 0000000..88f39c8 --- /dev/null +++ b/test/java/tjws/embedded/TestCertificate.java @@ -0,0 +1,95 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.Provider; +import java.security.Security; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; + +/** + * @author Rohtash Singh Lakra (Rohtash.Lakra@nasdaq.com) + * @date 03/22/2018 01:26:54 PM + */ +public class TestCertificate { + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + try { + // add security provider + IOHelper.addBouncyCastleProvider(); + + String parentFolderPath = IOHelper.pathString(TestCertificate.class); + LogManager.debug("parentFolderPath:" + parentFolderPath); + final String keStoreFile = "newConf/tjws.bks"; + final String keyStoreFilePath = IOHelper.pathString(parentFolderPath, keStoreFile); + LogManager.debug("keyStoreFilePath:" + keyStoreFilePath); + final String KEY_TRUST_STORE = "javax.net.ssl.trustStore"; + System.setProperty(KEY_TRUST_STORE, keyStoreFilePath); + LogManager.debug("truststore" + System.getProperty(KEY_TRUST_STORE)); + final Provider provide = Security.getProvider("BC"); + LogManager.debug(provide.getInfo() + " version:" + provide.getVersion()); + final String trustStoreType = KeyStore.getDefaultType(); + LogManager.debug("trustStoreType:" + trustStoreType); + final KeyStore keyStore = KeyStore.getInstance("BKS"); + LogManager.debug("keyStore:" + keyStore); + final InputStream keyStoreStream = new FileInputStream(keyStoreFilePath); + keyStore.load(keyStoreStream, "password".toCharArray()); + LogManager.debug("Loaded!"); + + // final String algorithm = + // TrustManagerFactory.getDefaultAlgorithm(); + // TrustManagerFactory trustManagerFactory = + // TrustManagerFactory.getInstance(algorithm, provide); + // trustManagerFactory.init((KeyStore) null); + // X509TrustManager xTrustManager = (X509TrustManager) + // trustManagerFactory.getTrustManagers()[0]; + // for (X509Certificate xCertificate : + // xTrustManager.getAcceptedIssuers()) { + // String certStr = "S:" + xCertificate.getSubjectDN().getName() + + // "\nI:" + xCertificate.getIssuerDN().getName(); + // System.out.println(certStr); + // } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/test/java/tjws/embedded/TestConnection.java b/test/java/tjws/embedded/TestConnection.java new file mode 100755 index 0000000..ac74034 --- /dev/null +++ b/test/java/tjws/embedded/TestConnection.java @@ -0,0 +1,245 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; + +/** + * How to Turn Off Certificate Validation in Java HTTPS Connections? + * + * Avoiding these exceptions is possible by switching off the certificate + * validation and host verification for SSL for the current Java virtual + * machine. This can be done by replacing the default SSL trust manager and the + * default SSL hostname verifier using this class. + * + * Voilla! Now the code runs as expected: it downloads the resource from an + * https address with invalid certificate. + * + * Note: - + * Be careful when using this hack! Skipping certificate validation is dangerous + * and should be done in testing environments only. + * + * @author Rohtash Singh Lakra + * @date 03/19/2018 10:19:17 AM + */ +public final class TestConnection { + + private final String keyStoreFile = "conf/tjws.jks"; + private final String PASSWORD = "password"; + + private final boolean sslEnabled; + + /** + * + * @param sslEnabled + */ + public TestConnection(final boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + /** + * @param keyStoreStream + * @param passChars + * @return + */ + public static KeyStore initKeyStore(final InputStream keyStoreStream, final char[] passChars) { + final String trustStoreType = KeyStore.getDefaultType(); + KeyStore keyStore = null; + if (keyStoreStream == null) { + throw new IllegalArgumentException("Invalid keyStoreStream:" + keyStoreStream); + } + + if (passChars == null) { + throw new IllegalArgumentException("Invalid passChars:" + String.valueOf(passChars)); + } + + try { + keyStore = KeyStore.getInstance(trustStoreType); + keyStore.load(keyStoreStream, passChars); + } catch (java.security.cert.CertificateException ex) { + ex.printStackTrace(); + } catch (NoSuchAlgorithmException ex) { + ex.printStackTrace(); + } catch (KeyStoreException ex) { + ex.printStackTrace(); + } catch (IOException ex) { + ex.printStackTrace(); + } + + return keyStore; + } + + /** + * Create and initialize the SSLContext + * + * @param mContext + * @param keyStoreFile + * @param password + * @return + */ + public SSLContext createSSLContext(final String keyStoreFile, final String password) { + SSLContext sslContext = null; + try { + final String keyStoreFilePath = IOHelper.pathString(IOHelper.pathString(TestConnection.class), keyStoreFile); + final InputStream keyStoreStream = new FileInputStream(keyStoreFilePath); + final KeyStore keyStore = initKeyStore(keyStoreStream, password.toCharArray()); + + // Create key manager + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, password.toCharArray()); + final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); + + // Create trust manager + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + // Initialize SSLContext + sslContext = SSLContext.getInstance("TLSv1"); + sslContext.init(keyManagers, trustManagers, new SecureRandom()); + } catch (Exception ex) { + ex.printStackTrace(); + } + + return sslContext; + } + + /** + * Create a socket factory with certificate. + * + * @return + */ + public final SSLSocketFactory newSSLSocketFactory() { + SSLSocketFactory sslSocketFactory = null; + try { + sslSocketFactory = createSSLContext(keyStoreFile, PASSWORD).getSocketFactory(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + return sslSocketFactory; + } + + /** + * Create a socket factory that trusts all certificates. + * + * @return + */ + public final SSLSocketFactory newSSLSocketFactoryWithTrustAllCerts() { + SSLSocketFactory sslSocketFactory = null; + try { + final String keyStoreFilePath = IOHelper.pathString(IOHelper.pathString(TestConnection.class), keyStoreFile); + final InputStream keyStoreStream = new FileInputStream(keyStoreFilePath); + final KeyStore keyStore = initKeyStore(keyStoreStream, PASSWORD.toCharArray()); + // Create key manager + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, PASSWORD.toCharArray()); + final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); + + final SSLContext sslContext = SSLContext.getInstance("TLSv1"); + sslContext.init(keyManagers, new TrustManager[] { new AllCertsTrustManager() }, new SecureRandom()); + sslSocketFactory = sslContext.getSocketFactory(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + return sslSocketFactory; + } + + /** + * Test the server connection. + */ + public void testSSLConnection() { + SSLSocketFactory sslSocketFactory = null; + BufferedReader bReader = null; + try { + HttpURLConnection urlConnection = null; + if (sslEnabled) { + urlConnection = (HttpsURLConnection) new URL("https://localhost:9161/").openConnection(); + } else { + urlConnection = (HttpURLConnection) new URL("http://localhost:5161/").openConnection(); + } + + if (sslEnabled && (urlConnection instanceof HttpsURLConnection)) { + // Create socket factory + if (sslSocketFactory == null) { + sslSocketFactory = newSSLSocketFactory(); + } + + // Install the SSL socket factory on the connection. + ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory); + } + + bReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + String line; + while ((line = bReader.readLine()) != null) { + LogManager.debug(line); + } + } catch (Exception ex) { + LogManager.error(ex); + } finally { + IOHelper.closeSilently(bReader); + } + } + + /** + * + * @param args + */ + public static void main(String[] args) { + TestConnection testConnection = new TestConnection(true); + testConnection.testSSLConnection(); + } + +} diff --git a/test/java/tjws/embedded/TestEmbeddedServer.java b/test/java/tjws/embedded/TestEmbeddedServer.java new file mode 100755 index 0000000..0a7b256 --- /dev/null +++ b/test/java/tjws/embedded/TestEmbeddedServer.java @@ -0,0 +1,318 @@ +// Copyright (C)2018 by Rohtash Singh Lakra . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions 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. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ +// + +// All enhancements Copyright (C)2018 by Rohtash Singh Lakra +// This version is compatible with JSDK 2.5 +// http://tjws.sourceforge.net +package tjws.embedded; + +import java.io.File; +import java.io.PrintStream; +import java.util.Properties; + +import com.rslakra.logger.LogManager; + +import Acme.IOHelper; +import Acme.Serve.SSLAcceptor; +import Acme.Serve.Serve; +import Acme.Serve.Serve.Status; +import rogatkin.web.WebApp; +import rogatkin.web.WebAppServlet; + +/** + * @author Rohtash Singh Lakra + * @date 03/15/2018 03:35:59 PM + */ +public final class TestEmbeddedServer { + + /** sslEnabled */ + private boolean sslEnabled; + + /** port */ + private int port; + + /** webServer */ + private TJWSServer webServer; + /** logStream */ + private PrintStream logStream; + + /** + * + * @return + */ + public boolean isSSLEnabled() { + return sslEnabled; + } + + /** + * + * @param sslEnabled + */ + public void setSSLEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + /** + * + * @return + */ + public int getPort() { + return port; + } + + /** + * Sets the default port. + */ + public void setDefaultPort() { + if (isSSLEnabled()) { + setPort(9161); + } else { + setPort(5161); + } + } + + /** + * + * @param port + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Initializes the logging stream. + */ + private void initLogging() { + File logDir = new File(IOHelper.getLogsDir()); + if (!logDir.exists()) { + LogManager.debug("Creating [" + logDir.getAbsolutePath() + "] folder ..."); + logDir.mkdirs(); + } + + if (logStream == null) { + try { + logStream = new PrintStream(new File(logDir, "tjws.logs"), "UTF-8"); + } catch (Exception ex) { + LogManager.error(ex); + } + + if (logStream == null) { + logStream = System.out; + } else { + System.setErr(logStream); + } + } + } + + /** + * Initializes the embedded web server. + * + * @param enableSSLWebServer + */ + public void initServer(final boolean sslEnabled) { + setSSLEnabled(sslEnabled); + if (webServer == null) { + initLogging(); + setDefaultPort(); + + // setting properties for the server, and exchangeable Acceptors + Properties properties = new Properties(); + properties.setProperty(Serve.ARG_NOHUP, Serve.ARG_NOHUP); + /* keepAlive time. */ +// properties.setProperty(Serve.ARG_MAX_CONN_USE, String.valueOf(100)); + + // log properties + properties.setProperty(Serve.ARG_ACCESS_LOG_FMT, "{0} {2} [{3,date,yyyy/MM/dd HH:mm:ss Z}] \"{4} {5} {6}\" {7,number,#}"); + properties.setProperty(Serve.ARG_LOG_DIR, IOHelper.getLogsDir()); + + if (isSSLEnabled()) { + // SSL configurations. + properties.setProperty(Serve.ARG_PORT, String.valueOf(getPort())); + // properties.setProperty(SSLAcceptor.ARG_PORT, + // String.valueOf(getPort())); + properties.setProperty(Serve.ARG_ACCEPTOR_CLASS, "Acme.Serve.SSLAcceptor"); + // properties.setProperty(Serve.ARG_ACCEPTOR_CLASS, + // "rogatkin.wskt.SSLSelectorAcceptor"); + String parentFolderPath = IOHelper.pathString(TestEmbeddedServer.class); + LogManager.debug("parentFolderPath:" + parentFolderPath); + final String keyStoreFilePath = IOHelper.pathString(parentFolderPath, "conf/tjws.jks"); + LogManager.debug("keyStoreFilePath:" + keyStoreFilePath); + properties.setProperty(SSLAcceptor.ARG_KEYSTOREFILE, keyStoreFilePath); + // properties.setProperty(SSLAcceptor.ARG_USE_KEYSTORE_BYTES, + // String.valueOf(true)); + // try { + // final byte[] keyStoreBytes = + // IOHelper.readBytes(keyStoreFilePath, true); + // properties.setProperty(SSLAcceptor.ARG_KEYSTOREFILE, + // keyStoreBytes); + // } catch (IOException ex) { + // LogManager.debug(ex); + // } + // properties.setProperty(SSLAcceptor.ARG_PROTOCOL, "TLSv1.2"); + properties.setProperty(SSLAcceptor.ARG_KEYSTORETYPE, "JKS"); + properties.setProperty(SSLAcceptor.ARG_CLIENTAUTH, "false"); + properties.setProperty(SSLAcceptor.ARG_KEYSTOREPASS, "password"); + // properties.setProperty(SSLAcceptor.ARG_KEYSTORETYPE, "BKS"); + } else { + properties.remove(Serve.ARG_ACCEPTOR_CLASS); + // this acceptor is required for web-socket support + // properties.setProperty("acceptorImpl", + // "Acme.Serve.SelectorAcceptor"); + } + + webServer = new TJWSServer(properties, logStream, this); + webServer.addServlet("/", new EmbeddedServlet()); + webServer.setProperty(Serve.ARG_PORT, getPort()); + + // add shutdown hook. + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + webServer.notifyStop(); + webServer.destroyAllServlets(); + } + })); + + /** Set System properties. */ + System.setProperty(WebAppServlet.WAR_NAME_AS_CONTEXTPATH, "yes"); + // set dex class loader 'AndroidClassLoader' + // System.setProperty(WebApp.DEF_WEBAPP_CLASSLOADER, + // AndroidClassLoader.class.getName()); + System.setProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR, IOHelper.getLogsDir()); + LogManager.debug("webappdir:" + System.getProperty(WebApp.DEF_WEBAPP_AUTODEPLOY_DIR) + ", for app:" + IOHelper.getLogsDir()); + webServer.deployWebServer(); + + } else { + LogManager.debug("webServer is already initialized!"); + } + } + + /** + * Returns true if the web server is running. + * + * @return + */ + public boolean isRunning() { + return (webServer != null && webServer.isRunning()); + } + + /** + * Stops the webServer. + */ + public void stopServer() { + if (isRunning()) { + webServer.notifyStop(); + } + + webServer.destroyAllServlets(); + webServer.setDeployed(false); + webServer = null; + + if (logStream != System.out && logStream != null) { + logStream.close(); + logStream = null; + } + + LogManager.debug("Web Server is stopped successfully!"); + } + + /** + * + */ + private void startServer() { + if (!isRunning()) { + new Thread() { + /** + * Check the staus of the server. + * + * @see Thread#run() + */ + @Override + public void run() { + try { + // give a chance to server to run + Thread.sleep(1000); + } catch (InterruptedException ex) { + // ignore me! + } finally { + LogManager.debug("Serve Running:" + webServer.isRunning()); + } + } + }.start(); + new Thread() { + /** + * Starts the web server here. + * + * @see Thread#run() + */ + @Override + public void run() { + try { + Status result = webServer.serve(); + webServer.log("Error running server! Error code:" + result); + } finally { + LogManager.debug("Serve Running:" + webServer.isRunning()); + } + } + }.start(); + } + } + + /** + * The starting point of the server. + * Once, the server has started, try to access the following url on the + * browser: + * + *

+	 * http://localhost:5161/
+	 * OR
+	 * http://localhost:5161/html
+	 * 
+ * + * If you have enabled, the SSL, you have to use the following URL: + * + *
+	 * https://localhost:9161/
+	 * OR
+	 * https://localhost:9161/html
+	 * 
+ * + * Even you can use the following command, to get the server information and + * it's certificate: + * openssl s_client -connect localhost:9161 | openssl x509 -noout -subject + * -issuer + * + * @param args + */ + public static void main(String... args) { + // LogManager.setLogLevel(Level.DEBUG); + // LogManager.debug("TempDir:" + IOHelper.getTempDir()); + TestEmbeddedServer server = new TestEmbeddedServer(); + server.initServer(true); + server.startServer(); + } +} diff --git a/test/java/tjws/embedded/conf/tjws.bks b/test/java/tjws/embedded/conf/tjws.bks new file mode 100644 index 0000000..4396087 Binary files /dev/null and b/test/java/tjws/embedded/conf/tjws.bks differ diff --git a/test/java/tjws/embedded/conf/tjws.crt b/test/java/tjws/embedded/conf/tjws.crt new file mode 100644 index 0000000..4821914 --- /dev/null +++ b/test/java/tjws/embedded/conf/tjws.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIJAL7OuDjhmcFlMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwIBcNMTgwMzE5MTY1OTU2WhgPMjE5NzA4MjQxNjU5NTZa +MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ +bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDG81u6dp7dMBWKUTvpOcBrh19u3msjUwjMw+gEd6oG0R8RUxPKs+tQ +M5ovbbUQfzn3SBro5QrvE82wZzOefAt2ariCJ8ehl1BNXBIcoKvWwHPiZNyboGOP +Ie3vqsMBa7mFhHdgGVLZh/X0IBSg6S2vMbDw03Hmte33fQn0yKCXwyG8SLUTd6hs +OUvxPHc3sVxtb2kudfGqZa+KNVf+X3VKIqF4+A0dTACh2xK0fu2NKO+qP1jj9WeM +rN/zp7xqFp7EJ1T0OXDpeqh6qNvnD5nhP7Q/SF+rff6G5UW/2mBm6n8+z3gA/fMw +NrtKdpgdJKjiqBnSW167ixY3ls9grYi5AgMBAAGjgacwgaQwHQYDVR0OBBYEFBWA +HEE3vY1NG15RtqWQa61v7H9jMHUGA1UdIwRuMGyAFBWAHEE3vY1NG15RtqWQa61v +7H9joUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8G +A1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkAvs64OOGZwWUwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAbEgqG+zxwFm/TUFo/slvJZzIdhTK +AeQ9hmdjn8vCcSvRQ2zTzq6YLVk3NEyd7EWb2RZop5+7aGoXT3zqnNjzI6QFLcfK ++C2BLj5oA25ZnZSD8z76FyQKPR8z8iLDaqfFZ5AGsT0xSb61yVdrvf3oV+m5j0uR +ElNDNs/YDy/vRoK/NXdqdozPbZv4Ed63jNnbtswanuZ4x/tG868fsaaxjF+i7I8Z +L2Mgx8ymKXPPlKTHiPXQGkNvxlrTn7p5DrYyNNTp27X/0VymnKcKQ0G29CbqOuQl +/LBlkGw+ZiPhojh80/RmWx3aQeSjfyiVRr0e9FCW93rY9kEaV+qCUYvn3g== +-----END CERTIFICATE----- diff --git a/test/java/tjws/embedded/conf/tjws.csr b/test/java/tjws/embedded/conf/tjws.csr new file mode 100644 index 0000000..78bf86b --- /dev/null +++ b/test/java/tjws/embedded/conf/tjws.csr @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC1zCCAb8CAQAweTELMAkGA1UEBhMCQ0ExEzARBgNVBAgTCkNhbGlmb3JuaWEx +EzARBgNVBAcTCk1lbmxvIFBhcmsxFTATBgNVBAoTDFJTTGFrcmEgSW5jLjEVMBMG +A1UECxMMUlNMYWtyYSBJbmMuMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzIO6T9/Zr6ekzgggelCNBHMPQ+rEvEqb3 +Z49pTjmhfMJRd46PmYW5eufLw++AYPQPQowdTGiFqb75yKw+etVBYmz+fQ/7orI5 +9esl18undpR67CgrlgRHhR6Qpc8147C86ou2bKpCU4iCtkwZO1Sh0Z5+FkSOm93s +P8kGoW63OIUaZYo2e9REkbUqZWvT3gcgxTKcfTU28HBPtICE5Ic1q7CLEnrnsAYC +30VWgxIryxdt1vCP2mdj9SmDJGlJkP7y+S20HQ8d6v7kQ2Q3f+3uCoAzzv6uGNCK +lokHPdn94+rMLACAfTbdRHfvL8GPLXRPnQXCWfx1auqadhKCp1LDAgMBAAGgGTAX +BgkqhkiG9w0BCQcxChMIcGFzc3dvcmQwDQYJKoZIhvcNAQEFBQADggEBAJiLGXtf +tANO+nj83/K1iPXb8Bpa1bbcwLcJGJbrcJsQvh9bzXHsKSTeovbAwvRnRyXGpAt8 +4gXdvDqwDmnw4ZI9ui5FHcDgYfnwS7HLxhN5YDHaKOHr4wpZY6enLrYER8H4y7Ky +aHLJvYN8MeARfWPShPUdpjT6qnuEwf6SUbeoCTH9SUEJysG54uAp9L/Ky4DY85W6 +SRhCnlcw515D4EM0FmGBEIynqqi12yzZibbB9PpiObg0+YGlBjjiFob4gz49RThU +B2ffVTiATF2uP7aRkPxvLqJbiyY2tvbDgMblLskKgye6FakKVtfVFxZNy9zruLni ++Dbg8vWYULcKXgw= +-----END CERTIFICATE REQUEST----- diff --git a/test/java/tjws/embedded/conf/tjws.jks b/test/java/tjws/embedded/conf/tjws.jks new file mode 100644 index 0000000..69bf5e8 Binary files /dev/null and b/test/java/tjws/embedded/conf/tjws.jks differ diff --git a/test/java/tjws/embedded/conf/tjws.key b/test/java/tjws/embedded/conf/tjws.key new file mode 100644 index 0000000..e2f3fd8 --- /dev/null +++ b/test/java/tjws/embedded/conf/tjws.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxvNbunae3TAVilE76TnAa4dfbt5rI1MIzMPoBHeqBtEfEVMT +yrPrUDOaL221EH8590ga6OUK7xPNsGcznnwLdmq4gifHoZdQTVwSHKCr1sBz4mTc +m6BjjyHt76rDAWu5hYR3YBlS2Yf19CAUoOktrzGw8NNx5rXt930J9Migl8MhvEi1 +E3eobDlL8Tx3N7FcbW9pLnXxqmWvijVX/l91SiKhePgNHUwAodsStH7tjSjvqj9Y +4/VnjKzf86e8ahaexCdU9Dlw6Xqoeqjb5w+Z4T+0P0hfq33+huVFv9pgZup/Ps94 +AP3zMDa7SnaYHSSo4qgZ0lteu4sWN5bPYK2IuQIDAQABAoIBAFUoTZcetxlOP6oY +42ANDEP6ierW4V0ZaabcJC/lWK3aTUYJHWuiX5LQw6qRdvM8wf8KqhoOEAQNoflj +80BfMDjbrWZoyJZuQj0ar9X5IBSoA/Jf4d3rZTIa/9GaciXlil+QN9i2fjQGckyw +fqPxq1BWILq0hwiNzvIkX2KbjcHnTdhYvEc1csz6x5WCV3fRuBRF1rX+HN8HAx8V +AaeGluHcCTRJW8FYIfkYrMdieGoKN4APuVjnVXcV4+UhrAGtxPi2inwSdTgNPZp0 +/YwqcdUjY/49xjq+6AoY9g0Gan/J86eg3ErZ6TEDVrHkD0MjbZH/RPZmcgOXXcD5 +BVN4ZAECgYEA/JP26fcQ/qhKDGd7G5MmfSl0eMzzwNW7L2pQC+lmpkoTQF1d+Prz +CQ+hG3SdLbvXcVGVWbdlNBsZL2GFK75n7yLiKSCEWsK3+zWCADzZ0vUTh8DNRv++ +F5U8zwTvzLN9mlzfAMvbJlcSaw7kpQRXS5fGMUieE785DOKIGHM2M+ECgYEAyaVk +17SITRjT3YXw/H6atzPwCJ7vyPesj8P6dmvZLKoamDBZW3lfi0Dx9qo5SW6D9smd +Bm68+CPBzZmj9cqoYhwusTlTLAfbHoHVax0WSuxquw/33Itu/BIHFHG45lyK57cn +ALgp9Fre9YvjtQxLHOxwnE2fkz6GhDNNhC7db9kCgYAEJpZXL/U6ih91ZrnyMQ/f +3K+KUKvszlZeKBwapgJG107Lrv0dW1plGrmmDtuKZdzbguC2cbobChr22V5r4pwo +pOUckek66JpHaZCyWk2mFtr0TynQceF4174BFO6v6X816zLK+46laabm1X7Sa2jX +2C2sn6nhXzIb0Rk1dac9YQKBgAx218Ppmd9CIJ550AqbfM7EPBscT/AZNyZv08SM +KBF1tk0f9/YKi5hc/Ffl78KVPTz8+2LRZ4bjFvCxhYwE6eGeolg8FeML3USGe/2x +/5XEBVjoxMZyK/sS1jMyUF6U69Uk4hlOSPGcyFlfO0UOrHnuN4vB1JJSdBgp36nD +B9cJAoGBAL+BclnADVfBMDJX6oHf4KdYbgvhNo2UCnwe0q3LDaFAGKiXtgd+yRXT +0RR0H3ErNSoMioCCxA3EUjZ6URdqiwh0m+ieYZ8yMy1bIgG10s9WTPv1g7P6lFBj +YXPcJxHQyUWFiVg8wJADSwn3rf7pp25kNplhQ9U9MWoXIXLhonXU +-----END RSA PRIVATE KEY----- diff --git a/test/java/tjws/embedded/newConf/tjws.bks b/test/java/tjws/embedded/newConf/tjws.bks new file mode 100644 index 0000000..67933ca Binary files /dev/null and b/test/java/tjws/embedded/newConf/tjws.bks differ diff --git a/test/java/tjws/embedded/web/index.html b/test/java/tjws/embedded/web/index.html new file mode 100644 index 0000000..c7efbfe --- /dev/null +++ b/test/java/tjws/embedded/web/index.html @@ -0,0 +1,27 @@ + + + + +TJWS Index + + + + +

Embedded TJWS Welcome you!

+ +
+
+
+
+ + + + + +
+
+ + + diff --git a/test/java/tjws/embedded/web/rsl.js b/test/java/tjws/embedded/web/rsl.js new file mode 100644 index 0000000..7961e71 --- /dev/null +++ b/test/java/tjws/embedded/web/rsl.js @@ -0,0 +1,25 @@ +/** + * Adds the default string to the given div. + * + * @param idDiv + * @returns + */ +function addDefaults(idDiv) { + var div = document.getElementById(idDiv); + if (div) { + div.innerHTML += 'Rohtash Singh Lakra\n'; + } +} + +/** + * Clears the given div. + * + * @param idDiv + * @returns + */ +function clearDefaults(idDiv) { + var div = document.getElementById(idDiv); + if (div) { + div.innerHTML = ''; + } +} \ No newline at end of file diff --git a/test/java/tjws/test/EchoServer.java b/test/java/tjws/test/EchoServer.java new file mode 100755 index 0000000..10897dd --- /dev/null +++ b/test/java/tjws/test/EchoServer.java @@ -0,0 +1,80 @@ +package tjws.test; + +import java.io.IOException; + +import java.util.Date; + +import javax.servlet.http.HttpSession; +import javax.websocket.EndpointConfig; +import javax.websocket.OnClose; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +/** + * @ServerEndpoint gives the relative name for the end point + * This will be accessed via + * ws://localhost:8080/EchoChamber/echo + * Where "localhost" is the address of the host, + * "EchoChamber" is the name of the package + * and "echo" is the address to access this class from the + * server + */ +@ServerEndpoint(value = "/echo/{room}", configurator = GetHttpSessionConfigurator.class) +public class EchoServer { + /** + * @OnOpen allows us to intercept the creation of a new session. + * The session class allows us to send data to the user. + * In the method onOpen, we'll let the user know that the handshake + * was + * successful. + */ + @OnOpen + public void onOpen(Session session, EndpointConfig config) { + System.out.println(session.getId() + " has opened a connection"); + boolean htp_sess = config.getUserProperties().containsKey(HttpSession.class.getName()); + try { + session.getBasicRemote().sendText((session.isSecure() ? "Secure c" : "C") + "onnection Established at " + new Date() + " htp session " + htp_sess); + session.setMaxIdleTimeout(60 * 1000); + } catch(IOException ex) { + ex.printStackTrace(); + } + } + + /** + * When a user sends a message to the server, this method will intercept the + * message + * and allow us to react to it. For now the message is read as a String. + */ + @OnMessage + public String onMessage(Session session, String message, @javax.websocket.server.PathParam("room") String room) { + System.out.printf("Message from %s/%dms : %s (%s)%n", session.getId(), session.getMaxIdleTimeout(), message, room); + /* + * try { + * session.getBasicRemote().sendText(message); + * } catch (IOException ex) { + * ex.printStackTrace(); + * } + */ + String fromShare = ""; + for(Session s : session.getOpenSessions()) { + if(s != session && s.isOpen() && s.getUserProperties().get("SHARE") != null) + fromShare += " " + (String) s.getUserProperties().get("SHARE"); + } + session.getUserProperties().put("SHARE", message); + if(fromShare.length() > 0) + message += " from others " + fromShare; + return message; + } + + /** + * The user closes the connection. + * + * Note: you can't send messages to the client from this method + */ + @OnClose + public void onClose(Session session) { + System.out.println("Session " + session.getId() + " has ended at " + new Date()); + } +} \ No newline at end of file diff --git a/1.x/test/java/tjws/test/FileupdateServer.java b/test/java/tjws/test/FileupdateServer.java old mode 100644 new mode 100755 similarity index 78% rename from 1.x/test/java/tjws/test/FileupdateServer.java rename to test/java/tjws/test/FileupdateServer.java index 6a8a91d..63c4201 --- a/1.x/test/java/tjws/test/FileupdateServer.java +++ b/test/java/tjws/test/FileupdateServer.java @@ -18,7 +18,7 @@ public class FileupdateServer implements Runnable { WatchService watchService; Session session; Thread pollThr; - + @OnOpen public void setMonitor(@PathParam("directory") String directory, Session s) { System.out.printf("Watch for %s%n", directory); @@ -26,75 +26,74 @@ public void setMonitor(@PathParam("directory") String directory, Session s) { watchService = FileSystems.getDefault().newWatchService(); session = s; Path p = new File(directory).toPath(); - p.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, - StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); - session.getBasicRemote().sendText("Registered "+p); + p.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); + session.getBasicRemote().sendText("Registered " + p); pollThr = new Thread(this); pollThr.start(); - } catch (IOException e) { + } catch(IOException e) { try { session.getBasicRemote().sendText("Can't setup watcher :" + e); - } catch (IOException e2) { - + } catch(IOException e2) { + } } } - + @Override public void run() { - for (;;) { + for(;;) { try { WatchKey watchKey = watchService.take(); // poll(10, ); - if (!processWatchKey(watchKey)) + if(!processWatchKey(watchKey)) break; - } catch (InterruptedException ie) { + } catch(InterruptedException ie) { break; } } } - + @OnClose public void stopWatch() { - if (pollThr != null) + if(pollThr != null) pollThr.interrupt(); } - + private boolean processWatchKey(WatchKey watchKey) { - for (WatchEvent event : watchKey.pollEvents()) { - if (StandardWatchEventKinds.OVERFLOW == event.kind()) + for(WatchEvent event : watchKey.pollEvents()) { + if(StandardWatchEventKinds.OVERFLOW == event.kind()) continue; try { session.getBasicRemote().sendObject(((Path) event.context()).toFile()); - } catch (Exception e) { + } catch(Exception e) { e.printStackTrace(); } } - + return watchKey.reset(); - + } - + public static class Filecoders implements Encoder.Text, Decoder.Text { - + public File decode(String s) throws DecodeException { return new File(s); } - + public boolean willDecode(String s) { return true; } - + public String encode(File file) throws EncodeException { return file.getPath(); } - + public void init(EndpointConfig config) { - + } - + public void destroy() { - + } - + } } \ No newline at end of file diff --git a/test/java/tjws/test/GetHttpSessionConfigurator.java b/test/java/tjws/test/GetHttpSessionConfigurator.java new file mode 100755 index 0000000..3fb4b7a --- /dev/null +++ b/test/java/tjws/test/GetHttpSessionConfigurator.java @@ -0,0 +1,21 @@ +package tjws.test; + +import javax.servlet.http.HttpSession; +import javax.websocket.HandshakeResponse; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerEndpointConfig; + +public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator { + + /** + * + * @param config + * @param request + * @param response + */ + @Override + public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { + HttpSession httpSession = (HttpSession) request.getHttpSession(); + config.getUserProperties().put(HttpSession.class.getName(), httpSession); + } +} diff --git a/1.x/test/java/tjws/test/ImgPasteServer.java b/test/java/tjws/test/ImgPasteServer.java old mode 100644 new mode 100755 similarity index 80% rename from 1.x/test/java/tjws/test/ImgPasteServer.java rename to test/java/tjws/test/ImgPasteServer.java index 829b121..c193b24 --- a/1.x/test/java/tjws/test/ImgPasteServer.java +++ b/test/java/tjws/test/ImgPasteServer.java @@ -7,6 +7,7 @@ import javax.websocket.OnMessage; import javax.websocket.server.ServerEndpoint; + @ServerEndpoint(value = "/paste/image") public class ImgPasteServer { String imageName; @@ -18,12 +19,12 @@ public void processCommand(String cmd) { @OnMessage public void processData(byte[] data) { - try (OutputStream os = Files.newOutputStream(Paths.get(imageName))){ + try(OutputStream os = Files.newOutputStream(Paths.get(imageName))) { os.write(data); - } catch (IOException e) { + } catch(IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } - + } diff --git a/1.x/test/java/tjws/test/SlideServer.java b/test/java/tjws/test/SlideServer.java old mode 100644 new mode 100755 similarity index 70% rename from 1.x/test/java/tjws/test/SlideServer.java rename to test/java/tjws/test/SlideServer.java index 897009d..9ec348a --- a/1.x/test/java/tjws/test/SlideServer.java +++ b/test/java/tjws/test/SlideServer.java @@ -27,97 +27,91 @@ */ @ServerEndpoint(value = "/slides/{mode}", decoders = { SlideServer.String2Int.class }) public class SlideServer { - + @OnOpen - public void registerInRoom(Session ses, - @PathParam("mode") String mode) { + public void registerInRoom(Session ses, @PathParam("mode") String mode) { ses.getUserProperties().put("mode", mode); } @OnMessage - public void showSlideNo(Integer slideNo, Session ses, - @PathParam("mode") String mode) { + public void showSlideNo(Integer slideNo, Session ses, @PathParam("mode") String mode) { List params = ses.getRequestParameterMap().get("dir"); - if (params == null || params.size() == 0) + if(params == null || params.size() == 0) return; File slideDir = new File(params.get(0).trim()); File[] slides = slideDir.listFiles(new FileFilter() { public boolean accept(File pathname) { String n = pathname.getName().toLowerCase(); - return pathname.isFile() && (n.endsWith(".jpg") - || n.endsWith(".gif") || n.endsWith(".png") - || n.endsWith(".jpeg")); + return pathname.isFile() && (n.endsWith(".jpg") || n.endsWith(".gif") || n.endsWith(".png") || n.endsWith(".jpeg")); } }); - if (slides == null || slides.length == 0) { + if(slides == null || slides.length == 0) { try { - ses.getBasicRemote().sendText( - "Empty or non existent " + slideDir); - } catch (IOException e1) { + ses.getBasicRemote().sendText("Empty or non existent " + slideDir); + } catch(IOException e1) { e1.printStackTrace(); } return; } - if (slides.length > 0) { - if (slideNo < 0) + if(slides.length > 0) { + if(slideNo < 0) slideNo = 0; - else if (slideNo > slides.length - 1) + else if(slideNo > slides.length - 1) slideNo = slides.length - 1; } - for(Session s:ses.getOpenSessions()) { - if (mode.equals(s.getUserProperties().get("mode"))) + for(Session s : ses.getOpenSessions()) { + if(mode.equals(s.getUserProperties().get("mode"))) showSlide(slides[slideNo], s); } } private void showSlide(File slide, Session ses) { - try (FileInputStream slideIm = new FileInputStream(slide); - OutputStream webIm = ses.getBasicRemote().getSendStream()) { + try(FileInputStream slideIm = new FileInputStream(slide); OutputStream webIm = ses.getBasicRemote().getSendStream()) { Utils.copyStream(slideIm, webIm, 0); - } catch (Exception e) { + } catch(Exception e) { e.printStackTrace(); try { ses.getBasicRemote().sendText("Can't open " + e); - } catch (IOException e1) { + } catch(IOException e1) { e1.printStackTrace(); } } } - + public static class String2Int implements Decoder.Text { - + @Override public void destroy() { // TODO Auto-generated method stub - + } - + @Override public void init(EndpointConfig arg0) { // TODO Auto-generated method stub - + } - + @Override public Integer decode(String arg0) throws DecodeException { try { return Integer.parseInt(arg0); - } catch (NumberFormatException e) { + } catch(NumberFormatException e) { throw new DecodeException(arg0, "Can't decode", e); } } - + @Override public boolean willDecode(String arg0) { try { decode(arg0); return true; - } catch (DecodeException e) { - + } catch(DecodeException e) { + } return false; } - + } } \ No newline at end of file diff --git a/1.x/test/java/tjws/test/UploadServer.java b/test/java/tjws/test/UploadServer.java old mode 100644 new mode 100755 similarity index 68% rename from 1.x/test/java/tjws/test/UploadServer.java rename to test/java/tjws/test/UploadServer.java index 10bfd24..59c3483 --- a/1.x/test/java/tjws/test/UploadServer.java +++ b/test/java/tjws/test/UploadServer.java @@ -19,60 +19,60 @@ import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; -@ServerEndpoint(value = "/upload/{file}", decoders = UploadServer.CmdDecoder.class, encoders=UploadServer.CmdEncoder.class) +@ServerEndpoint(value = "/upload/{file}", decoders = UploadServer.CmdDecoder.class, encoders = UploadServer.CmdEncoder.class) public class UploadServer { - + RandomAccessFile uploadFile; String fileName; @OnMessage public void savePart(byte[] part, Session ses) { - if (uploadFile == null) { - if (fileName != null) + if(uploadFile == null) { + if(fileName != null) try { uploadFile = new RandomAccessFile(fileName, "rw"); - } catch (FileNotFoundException e) { + } catch(FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } } - if (uploadFile != null) - try { - uploadFile.write(part); - System.err.printf("Stored part of %db%n", part.length); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + if(uploadFile != null) + try { + uploadFile.write(part); + System.err.printf("Stored part of %db%n", part.length); + } catch(IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } - + @OnMessage public void processCmd(CMD cmd, Session ses, @PathParam("file") String uploadDir) { - switch (cmd.cmd) { - case 1: // start - fileName = cmd.data; - if (uploadDir != null && uploadDir.isEmpty() == false) { - // assure dir - new File(uploadDir).mkdirs(); - fileName = uploadDir + File.separatorChar + fileName; - } - System.err.printf("Start upload of %s%n", cmd.data); - break; - case 2: // finish - close(ses); - cmd.cmd = 3; - ses.getAsyncRemote().sendObject(cmd); - break; + switch(cmd.cmd) { + case 1: // start + fileName = cmd.data; + if(uploadDir != null && uploadDir.isEmpty() == false) { + // assure dir + new File(uploadDir).mkdirs(); + fileName = uploadDir + File.separatorChar + fileName; + } + System.err.printf("Start upload of %s%n", cmd.data); + break; + case 2: // finish + close(ses); + cmd.cmd = 3; + ses.getAsyncRemote().sendObject(cmd); + break; } } - + @OnClose public void close(Session ses) { - if (uploadFile != null) { + if(uploadFile != null) { try { uploadFile.close(); - } catch (IOException e) { + } catch(IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } @@ -80,21 +80,21 @@ public void close(Session ses) { fileName = null; } } - + static class CMD { public int cmd; public String data; } - + public static class CmdDecoder implements Decoder.Text { @Override public void init(final EndpointConfig config) { } - + @Override public void destroy() { } - + @Override public CMD decode(final String textMessage) throws DecodeException { CMD cmd = new CMD(); @@ -103,22 +103,22 @@ public CMD decode(final String textMessage) throws DecodeException { cmd.cmd = obj.getInt("cmd"); return cmd; } - + @Override public boolean willDecode(final String s) { return true; } } - + public static class CmdEncoder implements Encoder.Text { @Override public void init(final EndpointConfig config) { } - + @Override public void destroy() { } - + @Override public String encode(final CMD cmd) throws EncodeException { return Json.createObjectBuilder().add("cmd", cmd.cmd).add("data", cmd.data).build().toString(); diff --git a/tjws-v1.0.0.jar b/tjws-v1.0.0.jar new file mode 100644 index 0000000..d746484 Binary files /dev/null and b/tjws-v1.0.0.jar differ diff --git a/1.x/win-service/StdAfx.cpp b/win-service/StdAfx.cpp similarity index 100% rename from 1.x/win-service/StdAfx.cpp rename to win-service/StdAfx.cpp diff --git a/1.x/win-service/StdAfx.h b/win-service/StdAfx.h similarity index 100% rename from 1.x/win-service/StdAfx.h rename to win-service/StdAfx.h diff --git a/1.x/win-service/resource.h b/win-service/resource.h similarity index 100% rename from 1.x/win-service/resource.h rename to win-service/resource.h diff --git a/1.x/win-service/servservice.cpp b/win-service/servservice.cpp similarity index 100% rename from 1.x/win-service/servservice.cpp rename to win-service/servservice.cpp diff --git a/1.x/win-service/servservice.sln b/win-service/servservice.sln similarity index 100% rename from 1.x/win-service/servservice.sln rename to win-service/servservice.sln diff --git a/1.x/win-service/servservice.vcproj b/win-service/servservice.vcproj similarity index 100% rename from 1.x/win-service/servservice.vcproj rename to win-service/servservice.vcproj diff --git a/1.x/win-service/servservice.vcxproj b/win-service/servservice.vcxproj similarity index 100% rename from 1.x/win-service/servservice.vcxproj rename to win-service/servservice.vcxproj diff --git a/1.x/win-service/servservice.vcxproj.filters b/win-service/servservice.vcxproj.filters similarity index 100% rename from 1.x/win-service/servservice.vcxproj.filters rename to win-service/servservice.vcxproj.filters diff --git a/1.x/win-service/servservice.vcxproj.user b/win-service/servservice.vcxproj.user similarity index 100% rename from 1.x/win-service/servservice.vcxproj.user rename to win-service/servservice.vcxproj.user diff --git a/1.x/win-service/version.rc b/win-service/version.rc similarity index 100% rename from 1.x/win-service/version.rc rename to win-service/version.rc