diff --git a/README.txt b/README.txt deleted file mode 100644 index f9245f46..00000000 --- a/README.txt +++ /dev/null @@ -1,97 +0,0 @@ -This is the README file for version 1.2 of Helma Object Publisher. - -=========== -ABOUT HELMA -=========== - -Helma is a scriptable platform for creating dynamic, database backed -web sites. - -Helma provides an easy way to map relational database tables to objects. -These objects are wrapped with a layer of scripts and skins that allow -them to be presented and manipulated over the web. The clue here is that -both functions and skins work in an object oriented manner and force -a clear separation between content, functionality and presentation. -Actions are special functions that are callable over the web. Macros are -special functions that expose functionality to the presentation layer. -Skins are pieces of layout that do not contain any application logic, -only macro tags as placeholders for parts that are dynamically provided -by the application. - -In short, Helma provides a one stop framework to create web applications -with less code and in shorter time than most of the other software out -there. - -=================== -SYSTEM REQUIREMENTS -=================== - -You need a Java virtual machine 1.3 or higher to run Helma. - -For Windows, Linux and Solaris you can get a Java runtime or development -kit from http://java.sun.com/j2se/downloads.html. - -If you are on Mac OS X, you already have a Java runtime that will work -well with Helma. - -Unfortunately, there is no Java 2 interpreter for Mac OS Classic, so -you can't use Helma on Mac OS 9. - -============================ -INSTALLING AND RUNNING HELMA -============================ - -Simply unzip or untar the contents of the archive file into any place -on your hard disk. Start Helma by invoking hop.bat or hop.sh from the -command line, depending on whether you are on Windows or -Linux/Unix/MacOSX. If the java command is not found, try setting the -JAVA_HOME variable in the start script to the location of your Java -installation. - -You may also want to have a look at the start script for other settings. -You can adjust server wide settings in the server.properties file. For -example, you should set the smtp property to the name of the SMTP server -that Helma should use to send Email. Applications can be started or -stopped by editing the apps.properties file through the web interface -using the Management application that is part of Helma. - -If you manage to get it running you should be able to connect your -browser to http://localhost:8080/ or http://127.0.0.1:8080/ -(port 8080 on the local machine, that is). - -Helma comes with a version of Jetty, a lightweight yet industrial strenth -web server developed by Mortbay Consulting. See http://jetty.mortbay.com/ -for more information. While Jetty works well for deploying real web sites, -you may want to run Helma behind an existing web server. This is most -easily done by running Helma with the AJPv13 listener which allows you to -plug Helma into any web server using the Apache mod_jk module. See -http://jakarta.apache.org/tomcat/tomcat-4.1-doc/jk2/index.html for more -information on mod_jk and AJPv13. - -Finally, Helma can be plugged into Servlet containers using Servlet -classes that communicate with Helma either directly or via Java RMI. -(Be warned that these options may be harder to set up and maintain though, -since most of the recent development efforts have been geared towards the -mod_jk/AJPv13 setup.) - - -===================================== -DOCUMENTATION AND FURTHER INFORMATION -===================================== - -Currently, documentation-in-progress is available online at -http://helma.org/. We know that it sucks and hope to do some substantial -improvments within the coming weeks and months. - -Your input is highly welcome. There is a mailing-list to discuss Helma at -http://helma.org/lists/listinfo/hop. Don't hesitate to voice any questions, -proposals, complaints, praise you may have on the list. We know we have -a lot to do and to learn, and we're open to suggestions. - -For questions, comments or suggestions also feel free to contact -hannes@helma.at. - - --- - -Last modified on December 5, 2002 by Hannes Wallnoefer diff --git a/apps.properties b/apps.properties deleted file mode 100644 index 962ebe05..00000000 --- a/apps.properties +++ /dev/null @@ -1,4 +0,0 @@ -# List of apps to start. - -test - diff --git a/build/README b/build/README deleted file mode 100644 index 8f0dc893..00000000 --- a/build/README +++ /dev/null @@ -1,93 +0,0 @@ -This is the README file for the Helma build files as part of the Helma Object Publisher. It is included in the current distribution (version 1.2pre as of 8 November 2001) downloadable at . - - - -The build directory consists of the following files: - - ant.jar - build.bat - build.sh - build.xml - crimson.jar - jaxp.jar - README - - -PREREQUISITES -============= - -The Helma build script is using a software called Ant. Ant is a build system that was developed for the Jakarta Tomcat project. For more information about Ant, see . - -To run Ant, you also need JDK 1.3 or higher . - -For checking out the source files from Helma's CVS you also need a local installation of a CVS command-line client. More information about CVS at . - - -STARTING BUILD -============== - -The build system is started by invoking the shell script appropriate to your platform, ie. build.sh for *nix (Linux, NetBSD etc.) and build.bat for Windows systems. You need to modify the script and set the JAVA_HOME to fit your system. - -The generic syntax is - - ./build target - -The parameter "target" specifies one of the following build targets. - - -BUILD A SNAPSHOT -================ - -To build a helma.jar with the most up-to-date version of helma yourself you need to run - -./build checkout - -and - -./build snapshot - - -BUILD TARGETS -============= - -checkout - Fetches (or updates, resp.) the Helma source code in the src/-directory from the CVS. If you've still got the sourcecode that came with the distribution in there, you need to move that away first. - -snapshot - Runs snapshotcompile and stuffs the class files as .jar archive in the lib directory. The file is named helma-yyyymmdd.jar. - -snapshotcompile - Compiles the source files contained in the src/hop directory into the classes directory (which will be created if necessary). You can use the source files from your distribution or you can get the most recent version by checking out the "hop"-module from the cvs. - -fullcheckout - Fetches (or updates, resp.) everything that's needed to create a full Helma distribution (source files, build files, libs, demo-apps) from the CVS and copies them into the work/checkout/ directory (which will be created if necessary). - -compile - Compiles the source files contained in the work/checkout/hop/ directory into the work/classes/ directory (which will be created if necessary). - -jar - Stuffs the files in work/classes/ together and saves them as .jar archive in the work directory. The file is named helma-yyyymmdd.jar. - -javadocs - Creates the Java API documentation for the Helma classes. The resulting files are saved into the work/docs/api/ directory (which will be created if necessary). - -helmadocs - Gets the documentation from helma.org via http in a printable version. (still some way to go..) - -package - Builds all previous targets (checkout, compile, jar, javadoc) and saves the created files in the directory work/helma-1.x/ (with 1.x being the version number). All directories will be created if necessary. - -package-zip - Same as "package". Additionally, the files in the output directory will be compressed as .zip file. - -package-tgz - Same as "package". Additionall, the file in the output directory will be compressed as .tar.gz file. - -package-all - Builds all previous targets. The result is a complete and up-to-date (as in the CVS) installation of Helma, the API documentation, source and build files as well as compressed packages for *nix and Windows systems including all the files. - - --- - -This README was last updated on 26 April 2002. Questions? tobi@helma.org - diff --git a/build/ant.jar b/build/ant.jar deleted file mode 100644 index ba757dfc..00000000 Binary files a/build/ant.jar and /dev/null differ diff --git a/build/build.bat b/build/build.bat deleted file mode 100644 index 19583079..00000000 --- a/build/build.bat +++ /dev/null @@ -1,48 +0,0 @@ -@echo off - -set TARGET=%1% -REM set JAVA_HOME=c:\programme\jdk13 - -REM -------------------------------------------- -REM No need to edit anything past here -REM -------------------------------------------- - -set BUILDFILE=build.xml -if "%TARGET%" == "" goto setdist -goto cont1 - -:cont1 -if not "%2%" == "" goto setapp -goto final - -:setdist -set TARGET=usage -goto cont1 - -:setapp -set APPNAME=-Dapplication=%2% -goto final - -:final - -if "%JAVA_HOME%" == "" goto javahomeerror - -set CP=%CLASSPATH%;ant.jar;jaxp.jar;crimson.jar -if exist %JAVA_HOME%\lib\tools.jar set CP=%CP%;%JAVA_HOME%\lib\tools.jar - -echo Classpath: %CP% -echo JAVA_HOME: %JAVA_HOME% - -%JAVA_HOME%\bin\java.exe -classpath "%CP%" %APPNAME% org.apache.tools.ant.Main -buildfile %BUILDFILE% %TARGET% - -goto end - - -REM -----------ERROR------------- -:javahomeerror -echo "ERROR: JAVA_HOME not found in your environment." -echo "Please, set the JAVA_HOME variable in your environment to match the" -echo "location of the Java Virtual Machine you want to use." - -:end - diff --git a/build/build.sh b/build/build.sh deleted file mode 100755 index c7116e30..00000000 --- a/build/build.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh - -# export JAVA_HOME=/usr/lib/j2sdk1.4.0 - -#-------------------------------------------- -# No need to edit anything past here -#-------------------------------------------- -if test -z "${JAVA_HOME}" ; then - echo "ERROR: JAVA_HOME not found in your environment." - echo "Please, set the JAVA_HOME variable in your environment to match the" - echo "location of the Java Virtual Machine you want to use." - exit -fi - -if test -f ${JAVA_HOME}/lib/tools.jar ; then - CLASSPATH=${CLASSPATH}:${JAVA_HOME}/lib/tools.jar -fi - -if test -n "${2}" ; then - APPNAME=-Dapplication=${2} -fi - -CP=${CLASSPATH}:ant.jar:jaxp.jar:../lib/crimson.jar - -echo "Classpath: ${CP}" -echo "JAVA_HOME: ${JAVA_HOME}" - -BUILDFILE=build.xml - -${JAVA_HOME}/bin/java -classpath ${CP} ${APPNAME} org.apache.tools.ant.Main -buildfile ${BUILDFILE} ${1} - diff --git a/build/build.xml b/build/build.xml deleted file mode 100644 index 177c24bb..00000000 --- a/build/build.xml +++ /dev/null @@ -1,402 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/crimson.jar b/build/crimson.jar deleted file mode 100644 index 2ad58524..00000000 Binary files a/build/crimson.jar and /dev/null differ diff --git a/build/jaxp.jar b/build/jaxp.jar deleted file mode 100644 index b881783e..00000000 Binary files a/build/jaxp.jar and /dev/null differ diff --git a/build/main/apps.properties b/build/main/apps.properties deleted file mode 100644 index 85768f87..00000000 --- a/build/main/apps.properties +++ /dev/null @@ -1,13 +0,0 @@ -# List of applications to start. - -base -base.mountpoint = / -base.static = static -base.staticMountpoint = /static - -manage - -gong -himp -bloggerapi -lillebror diff --git a/build/main/db.properties b/build/main/db.properties deleted file mode 100644 index 9dc57b94..00000000 --- a/build/main/db.properties +++ /dev/null @@ -1,16 +0,0 @@ -# This is where you specify relational data sources to -# map Helma types to relational databases. -# -# If you want to define a data source just for one -# application, simply copy the db.properties file to -# the application directory. -# -# The actual mapping of types is done in the -# type.properties file in the prototype directories. -# - -# Properties of JDBC data sources -myDataSource.url = jdbc:mysql://db.domain.com/space -myDataSource.driver = org.gjt.mm.mysql.Driver -myDataSource.user = username -myDataSource.password = xyz diff --git a/build/main/hop.bat b/build/main/hop.bat deleted file mode 100755 index 06771c62..00000000 --- a/build/main/hop.bat +++ /dev/null @@ -1,79 +0,0 @@ -@echo off -rem Batch file for Starting Helma with a JDK-like virtual machine. - -rem To add jar files to the classpath, simply place them into the -rem lib/ext directory of this Helma installation. - -:: Initialize variables -:: (don't touch this section) -set JAVA_HOME= -set HOP_HOME= -set HTTP_PORT= -set XMLRPC_PORT= -set AJP13_PORT= -set RMI_PORT= -set OPTIONS= - -:: Set TCP ports for Helma servers -:: (comment/uncomment to de/activate) -set HTTP_PORT=8080 -rem set XMLRPC_PORT=8081 -rem set AJP13_PORT=8009 -rem set RMI_PORT=5050 - -:: Uncomment to set HOP_HOME -rem set HOP_HOME=c:\program files\helma - -:: Uncomment to set JAVA_HOME variable -rem set JAVA_HOME=c:\program files\java - -:: Uncomment to pass options to the Java virtual machine -rem set JAVA_OPTIONS=-server -Xmx128m - -::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:::::: No user configuration needed below this line ::::::: -::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -:: Setting the script path -set INSTALL_DIR=%~d0%~p0 - -:: Using JAVA_HOME variable if defined. Otherwise, -:: Java executable must be contained in PATH variable -if "%JAVA_HOME%"=="" goto default - set JAVACMD=%JAVA_HOME%\bin\java - goto end -:default - set JAVACMD=java -:end - -:: Setting HOP_HOME to script path if undefined -if "%HOP_HOME%"=="" ( - set HOP_HOME=%INSTALL_DIR% -) -cd %HOP_HOME% - - -:: Setting Helma server options -if not "%HTTP_PORT%"=="" ( - echo Starting HTTP server on port %HTTP_PORT% - set OPTIONS=%OPTIONS% -w %HTTP_PORT% -) -if not "%XMLRPC_PORT%"=="" ( - echo Starting XML-RPC server on port %XMLRPC_PORT% - set OPTIONS=%OPTIONS% -x %XMLRPC_PORT% -) -if not "%AJP13_PORT%"=="" ( - echo Starting AJP13 listener on port %AJP13_PORT% - set OPTIONS=%OPTIONS% -jk %AJP13_PORT% -) -if not "%RMI_PORT%"=="" ( - echo Starting RMI server on port %RMI_PORT% - set OPTIONS=%OPTIONS% -p %RMI_PORT% -) -if not "%HOP_HOME%"=="" ( - echo Serving applications from %HOP_HOME% - set OPTIONS=%OPTIONS% -h "%HOP_HOME% -) - -:: Invoking the Java virtual machine -%JAVACMD% %JAVA_OPTIONS% -jar "%INSTALL_DIR%\launcher.jar" %OPTIONS% diff --git a/build/main/hop.sh b/build/main/hop.sh deleted file mode 100644 index 1ee2af9a..00000000 --- a/build/main/hop.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/sh -# Shell script for starting Helma with a JDK-like virtual machine. - -# To add JAR files to the classpath, simply place them into the -# lib/ext directory. - -# uncomment to set JAVA_HOME variable -# JAVA_HOME=/usr/lib/java - -# uncomment to set HOP_HOME, otherwise we get it from the script path -# HOP_HOME=/usr/local/helma - -# options to pass to the Java virtual machine -# JAVA_OPTIONS="-server -Xmx128m" - -# Set TCP ports for Helma servers -# (comment/uncomment to de/activate) -HTTP_PORT=8080 -# XMLRPC_PORT=8081 -# AJP13_PORT=8009 -# RMI_PORT=5050 - -########################################################### -###### No user configuration needed below this line ####### -########################################################### - -# if JAVA_HOME variable is set, use it. Otherwise, Java executable -# must be contained in PATH variable. -if [ "$JAVA_HOME" ]; then - JAVACMD="$JAVA_HOME/bin/java" -else - JAVACMD=java -fi - -# Check if java command is executable -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." - echo " We cannot execute $JAVACMD" - exit -fi - -# Get the Helma installation directory -INSTALL_DIR="${0%/*}" -cd $INSTALL_DIR -INSTALL_DIR=$PWD - -# get HOP_HOME variable if it isn't set -if [ -z "$HOP_HOME" ]; then - # try to get HOP_HOME from script file and pwd - # strip everyting behind last slash - HOP_HOME="${0%/*}" - cd $HOP_HOME - HOP_HOME=$PWD -else - cd $HOP_HOME -fi -echo "Starting Helma in directory $HOP_HOME" - -if [ "$HTTP_PORT" ]; then - SWITCHES="$SWITCHES -w $HTTP_PORT" - echo Starting HTTP server on port $HTTP_PORT -fi -if [ "$XMLRPC_PORT" ]; then - SWITCHES="$SWITCHES -x $XMLRPC_PORT" - echo Starting XML-RPC server on port $XMLRPC_PORT -fi -if [ "$AJP13_PORT" ]; then - SWITCHES="$SWITCHES -jk $AJP13_PORT" - echo Starting AJP13 listener on port $AJP13_PORT -fi -if [ "$RMI_PORT" ]; then - SWITCHES="$SWITCHES -p $RMI_PORT" - echo Starting RMI server on port $RMI_PORT -fi -if [ "$HOP_HOME" ]; then - SWITCHES="$SWITCHES -h $HOP_HOME" -fi - -# Invoke the Java VM -$JAVACMD $JAVA_OPTIONS -jar "$INSTALL_DIR/launcher.jar" $SWITCHES diff --git a/build/main/license.txt b/build/main/license.txt deleted file mode 100644 index 5b5e251b..00000000 --- a/build/main/license.txt +++ /dev/null @@ -1,49 +0,0 @@ - Copyright (c) 1999-2002 Helma Project. 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. - - 3. Products derived from this software may not be called "Helma" - or "Hop", nor may "Helma" or "Hop" appear in their name, without - prior written permission of the Helma Project Group. For written - permission, please contact helma@helma.org. - - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 HELMA PROJECT OR ITS - 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. - -This product contains the FESI EcmaScript interpreter written by -Jean-Marc Lugrin (http://home.worldcom.ch/jmlugrin/fesi/). FESI is -released under the GNU Lesser General Public License (see licenses/lesser.txt). - -This product contains software from the Acme package written by Jef -Poskanzer. Please see the licensing terms in the Acme source code and check out -Jef's site at http://www.acme.com/. - -This product includes software developed by the Apache Software Foundation -released under the Apache Software License (licenses/apache.txt). - -This product includes software developed by the JDOM Project -(http://www.jdom.org/). Please see the licensing terms in licenses/jdom.txt - -This product includes software developed by the Word Wide Web Consortium -(http://www.w3c.org/). Please see the licensing terms in licenses/w3c.html. diff --git a/build/main/server.properties b/build/main/server.properties deleted file mode 100644 index ce1ef12f..00000000 --- a/build/main/server.properties +++ /dev/null @@ -1,27 +0,0 @@ -# The SMTP server to use for sending mails. Set and -# uncomment this line before trying to send mails from -# Helma applications. -# -# smtp=mail.yourdomain.com - - -# Some examples for server-wide locale settings -# (please refer to http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html -# for country codes, resp. http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt -# for language codes). -# -# country = AT -# language = de -# -# country = UK -# language = en -# -# country = FR -# language = fr -# -# country = CZ -# language = cs - -# list ip addresses for admin-application here: -allowAdmin=127.0.0.1, 192.168.0.1 - diff --git a/build/main/static/helma.gif b/build/main/static/helma.gif deleted file mode 100644 index 475b94fc..00000000 Binary files a/build/main/static/helma.gif and /dev/null differ diff --git a/build/main/static/helma2.gif b/build/main/static/helma2.gif deleted file mode 100644 index 8bbb844b..00000000 Binary files a/build/main/static/helma2.gif and /dev/null differ diff --git a/build/main/static/himp/original.jpg b/build/main/static/himp/original.jpg deleted file mode 100644 index d8e24618..00000000 Binary files a/build/main/static/himp/original.jpg and /dev/null differ diff --git a/build/main/static/test.txt b/build/main/static/test.txt deleted file mode 100644 index f4311c2f..00000000 --- a/build/main/static/test.txt +++ /dev/null @@ -1,4 +0,0 @@ - - This file should appear at http://:/static/test.txt - if you use the embedded Web server (-w option on commandline). - diff --git a/compile.sh b/compile.sh deleted file mode 100755 index 95839541..00000000 --- a/compile.sh +++ /dev/null @@ -1,6 +0,0 @@ -cd build -./build.sh jar -cd .. -mv lib/helma-* lib/helma.jar -./hop.sh - diff --git a/db.properties b/db.properties deleted file mode 100644 index 9dc57b94..00000000 --- a/db.properties +++ /dev/null @@ -1,16 +0,0 @@ -# This is where you specify relational data sources to -# map Helma types to relational databases. -# -# If you want to define a data source just for one -# application, simply copy the db.properties file to -# the application directory. -# -# The actual mapping of types is done in the -# type.properties file in the prototype directories. -# - -# Properties of JDBC data sources -myDataSource.url = jdbc:mysql://db.domain.com/space -myDataSource.driver = org.gjt.mm.mysql.Driver -myDataSource.user = username -myDataSource.password = xyz diff --git a/docs/reference.html b/docs/reference.html deleted file mode 100644 index d03585fe..00000000 --- a/docs/reference.html +++ /dev/null @@ -1,2472 +0,0 @@ - - - Printer-friendly Output - - - - - -

Reference

- -

- -

This is a growing collection of Helma documentation categorized by functionality. -

Application Object

- -

- -

app represents the Application object in Hop. By adding variables to this object it is possible to store temporary global variables, which are independent from request evaluator threads, i.e. they are shared by all threads. But be aware that they are not persistent and lost as soon as you restart the application. -

errorCount

- -

- -

Syntax -
app.errorCount

Description -
Returns the number of Errors which occured due to User Requests since the application has been started. -
-
Note: "File Not Found" Errors are not counted.

Example -
res.write(app.errorCount); -
8
-

getActiveThreads()

- -

- -

Syntax -
app.getActiveThreads()

Description -
This function returns the number of currently working Request Evaluator Threads. -
-
If this number reaches the maximum allowed Treads Hop returns a "maximum thread count reached" error page.

Example -
res.write(app.getMaxThreads()); -
12
-

getFreeThreads()

- -

- -

Syntax -
app.getFreeThreads()

Description -
This function returns the number of additional of Request Evaluator Threads, which could be created at the current moment. -
-
This is equivalent to the number of current Threads deducted from the number of maximum THreads.

Example -
res.write(app.getActiveThreads()); -
2 -
-
res.write(app.getMaxThreads()); -
12 -
-
res.write(app.getFreeThreads()); -
10
-

getMaxActiveThreads()

- -

- -

Syntax -
app.getMaxActiveThreads()

Description -
This function returns the historic maximum number of Request Evaluator Threads, which occured at some point since the application has been started.

Example -
res.write(app.getMaxActiveThreads()); -
6
-

getMaxThreads()

- -

- -

Syntax -
app.getMaxActiveThreads()

Description -
This function returns the historic maximum number of Request Evaluator Threads, which occured at some point since the application has been started.

Example -
res.write(app.getMaxActiveThreads()); -
6
-

requestCount

- -

- -

Syntax -
app.requestCount

Description -
Returns the number of HTTP-Requests since the application has been started.

Example -
res.write(app.requestCount); -
231
-

setMaxThreads()

- -

- -

Syntax -
app.setMaxThreads(Number)

Description -
This function enables the programmer to adjust the number of maximum allowed Request Evaluator Threads without having to restart the application.

Example -
app.setMaxThreads(10); -
res.write(app.getMaxThreads()); -
10
-

skinfiles

- -

Array containing the skins of an application. - -

Syntax -
app.skinfiles

Description -
To access the actual content of a skin file in the inner loop you'd say app.skinfiles[a][b]. To access a skin file by name, you'd say something like app.skinfiles.root.test.

Example -
for (var a in app.skinfiles) { -
  res.write(a + "<br>"); -
  for (var b in app.skinfiles[a]) { -
    res.write("&nbsp;&nbsp;&nbsp;&nbsp;" + b + "<br>"); -
  } -
}
-

upSince

- -

- -

Syntax -
app.upSince

Description -
Returns the createtime of the Application object, i.e. the time when the application was started.

Example -
res.write(app.upSince.format("dd.MMM yyyy HH:mm")); -
06.Sep 2001 13:09
-

xmlrpcCount

- -

- -

Syntax -
app.xmlrpcCount

Description -
Returns the number of XML-RPC-Requests since the application has been started.

Example -
res.write(app.xmlrpcCount); -
12
-

Date Object

- -

- -

-

format()

- -

Formatting a date string for custom output. - -

Syntax -
Date.format(String)

Description -
Formats the date string of a date object for custom output. The function's string parameter is used as a pattern to describe the desired format. Most common are the following pattern letters:

-Symbol Meaning              Presentation   Example
------- -------              ------------   -------
-y      year                 (Number)       1996
-M      month in year        (Text, Number) July, 07
-d      day in month         (Number)       10
-h      hour in am/pm (1~12) (Number)       12
-H      hour in day (0~23)   (Number)       0
-m      minute in hour       (Number)       30
-s      second in minute     (Number)       55
-E      day in week          (Text)         Tuesday
-a      am/pm marker         (Text)         PM
-Please note that the output is depending on the locale settings of the Helma server. For further reference refer to the examples below or directly to the documentation of the Java SimpleDateFormat class.

Example -
var d = new Date(); -
res.write(d.format("EEE d.M.y, HH:mm'h'")); -
Thu 9.8.01, 15:15h -
-
res.write(d.format("dd. MMM. yyyy, hh:mm:ss aa")); -
09. Aug. 2001, 03:15:44 PM -
-
res.write(d.format("hh:mm:ss,SS")); -
03:15:44,609 -
-
res.write(d.format("EEEEE d MMMMM yyyy")); -
Thursday 9 August 2001 -
-
res.write(d.format("EEE, d MMM yyyy HH:mm:ss z")); -
Thu, 9 Aug 2001 15:15:44 CET
-

Direct Database Interface

- -

- -

The Direct Db interface allows the developer to directly access relational databases defined in the db.properties file without going through the Helma objectmodel layer. -
-
var con = getDBConnection("db_source_name"); -
-
This returns a Connection object from the Helma connection pool that can be used as specified by the Fesi DbAccess protocol, except that it is not necessary to call the connect() and disconnect() functions. -
-
var rows = con.executeRetrieval("select title from dummy"); -
while (rows.next()) -
  res.write(rows.getColumnItem("title")+"<br>"); -
-
-

FESI Extensions

- -

- -

FESI (pronounced like fuzzy) is a full implementation of the ECMAScript language as defined in the ECMA technical standard specification ECMA-262 (June 97 edition). -
-
ECMAScript is largely equivalent to the JavaScript language version 1.1 or to the core part of JScript, but without the extensions specific to Netscape Navigator. Instead, FESI comes with its own extensions as listed below. -
-
These parts of the documentation are adapted from the FESI Homepage courtesy by Jean-Marc Lugrin. -

throwError()

- -

- -

Syntax -
throwError(stringOrException)

Description -
This function throws an exception, ie. the script interpreter aborts, the stringOrException parameter is converted to a string and immediately written to the response object for output.

Example -
throwError("Aborting without any reason"); -
Runtime error Aborting without any reason -
detected at line 1 of function 'main_action' in string starting with: 'function main_action (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {'...
-

tryEval()

- -

- -

Syntax -
tryEval(functionString, defaultValue)

Description -
tryEval() evaluates the functionString parameter just like the standard ECMAScript function eval() does, but returns an object with two properties, value and error. -
-
If the evaluation is successful, the value property contains the result of the evaluation and the error property equals to null (which tests as false). -
-
If the evaluation results in an error, the value property has either the value of the optional defaultValue parameter (if specified) or undefined, and the error property contains an object describing the error, which is guaranteed to test as true. -
-
The error object string representation is some description of the error. In the future more detailed error information may be available.

Example -
var trial = tryEval("undefinedFunction()", -1) -
if (trial.error) -
   res.writeln(trial.error); -
res.writeln(trial.value); -
-
FESI.Exceptions.EcmaScriptException: Runtime error no global function named 'undefinedFunction' detected at line 1 in string: 'undefinedFunction()' -
-1
-

FTP Client

- -

- -

This object represents an Ftp client object for sending and receiving files from an Ftp server. The constructor is called FtpServer and invoked as follows: -
-
var ftp = new FtpClient("ftp.mydomain.com"); -
-
The Ftp client needs Daniel Savarese's NetComponents library in the classpath in order to work. -
-
Functions and Properties -

ascii()

- -

- -

Syntax -
FtpObject.ascii();

Description -
Set transfermodus to Ascii for transmitting text.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
ftp.ascii();
-

binary()

- -

- -

Syntax -
FtpObject.binary();

Description -
Set transfer mode to binary for transmitting images and other non-text files.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
ftp.binary();
-

cd()

- -

- -

Syntax -
FtpObject.cd(Path);

Description -
Change the current path on the FTP server.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
-
// use absolute pathname -
ftp.cd("/home/users/fred/www"); -
-
// change to parent directory -
ftp.cd(".."); -
-
// use relative pathname -
ftp.cd("images");
-

getFile()

- -

- -

Syntax -
FtpObject.getFile(RemoteFile, LocalFile);

Description -
Transfer a file from the server to the local file system.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
ftp.getFile(".htaccess", "htaccess.txt");
-

getString()

- -

- -

Syntax -
FtpObject.getString(RemoteFile);

Description -
Retrieves a file from the remote server and returns it as string.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
var str = ftp.getString("messages.txt");
-

lcd()

- -

- -

Syntax -
FtpObject.lcd(LocalPath);

Description -
Change the local path of the FTP client.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
-
// use absolute pathname -
ftp.lcd("/home/users/fred/www"); -
-
// change to parent directory -
ftp.lcd(".."); -
-
// use relative pathname -
ftp.lcd("images");
-

login()

- -

- -

Syntax -
FtpObject.login(UserName, Password);

Description -
Log in to the FTP server. The function returns true if successful, false otherwise.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
if (ftp.login("user", "pass")) -
   res.write("User logged in."); -
else -
   res.write("Unable to log in."); -
-
User logged in.
-

logout()

- -

- -

Syntax -
FtpObject.logout();

Description -
Terminate the current FTP session.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
ftp.putFile("htaccess.txt", ".htaccess"); -
ftp.logout();
-

mkdir()

- -

- -

Syntax -
FtpObject.mkdir(String);

Description -
Creates a new directory on the server. The name of the directory is determined as the function's string parameter. Returns false when an error occured (e.g. due to access restrictions, directory already exists etc.), otherwise true.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
if (ftp.mkdir("testdir")) -
   ftp.cd("testdir") -
else -
   ftp.logout();
-

putFile()

- -

- -

Syntax -
FtpObject.putFile(LocalFile, RemoteFile);

Description -
Transfers a file from the local file system to the remote server. Returns true if the transmission was successful, otherwise false.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
if (ftp.putFile("testfile")) -
   res.write("File transfered successfully."); -
else -
   res.write("Transfer error."); -
-
File transfered successfully.
-

putString()

- -

- -

Syntax -
FtpObject.putString(String, RemoteFile);

Description -
Transfer text from a string to a file on the remote server.

Example -
var ftp = new FtpClient("ftp.host.dom"); -
ftp.login("user", "pass"); -
ftp.putString("Hello, World!", "message.txt");
-

Global Functions

- -

- -

These are the global functions that are added to the Hop interpreter in addition to the standard global functions found in a JavaScript interpreter. -

authenticate()

- -

- -

Syntax -
authenticate(UserNameString, PasswordString)

Description -
This function authenticates against a standard Unix password file, which is both secure (encrypted using CRYPT) and can be managed using the htpasswd utility which is included in the Apache web server distribution. -
-
The function just returns true or false, so you have to make sure yourself you remember the result in the user object by setting some cache flag. -
-
The function compares the two arguments with the data in the file called "passwd", stored in the Helma installation directory. This can be overridden by a file with the same name in the application directory. -
-
Please note that this function is currently not working under Windows because the Windows version of Apache's htpasswd can use a special type of MD5 encryption only.

Example -
var login = authenticate("user", "pass"); -
if (login) -
   res.write("Welcome back!"); -
else -
   res.write("Oops, please try again..."); -
-
Welcome back!
-

countActiveUsers()

- -

- -

Syntax -
countActiveUsers()

Description -
Returns the number of currently active users.

Example -
var nr = countActiveUsers(); -
res.write(nr); -
18
-

createSkin()

- -

- -

Syntax -
createSkin(String)

Description -
Turns a string into a Skin object ready for rendering with renderSkin() and renderSkinAsString().

Example -
var str = "Hello, <% response.body %>!"; -
var skin = createSkin(str); -
res.body = "World"; -
renderSkin(skin); -
-
Hello, World!
-

encode()

- -

Preparing a string for smooth html output. - -

Syntax -
encode(string)

Description -
Encodes a string by replacing linebreaks with <br> tags and diacritical characters as well as html tags with their equivalent html entities.

Example -
var str = encode("<b>Bananer växer\n minsann inte på träd.<b>"); -
res.write(str); -
&lt;b&gt;Bananer v&auml;xer -
<br> minsann inte p&aring; tr&auml;d.&lt;/b&gt;
-

encodeForm()

- -

- -

Syntax -
encodeForm(String)

Description -
Similar to encode() this functions substitutes html entities but leaves newlines untouched. This is what you usually want to do for encoding form content (esp. with textarea values).

Example -
var str = encodeForm("<b>Bananer växer\n minsann inte på träd.<b>"); -
res.write(str); -
&lt;b&gt;Bananer v&auml;xer -
minsann inte p&aring; tr&auml;d.&lt;/b&gt;
-

encodeXml()

- -

Preparing a string for smooth xml output. - -

Syntax -
encodeXml(string)

Description -
Encodes a string by replacing < and > with &lt; and &gt; as well as & with its html entity &amp;.

Example -
var str = encodeXml("<title>Smørebrød</title>"); -
res.write(str); -
&lt;title&gt;Sm&amp;oslash;rebr&amp;oslash;d&lt;/title&gt;
-

format()

- -

Preparing a string for smooth html output. - -

Syntax -
format(string)

Description -
Encodes a string similar to encode() but keeping the markup tags and trying to avoid <br> tags where possible (e.g. in table structures).

Example -
var str = encode("<b>Bananer växer\n minsann inte på träd.<b>"); -
res.write(str); -
<b>Bananer v&auml;xer -
<br> minsann inte p&aring; tr&auml;d.</b>
-

getActiveUsers()

- -

Retrieving active Users. - -

Syntax -
getActiveUsers()

Description -
Returns an array that contains all User Objects of users who are currently browsing the Hop application. This includes users who are logged in as well as anonymous users.

Example -
var myUsers = getActiveUsers(); -
res.write(myUsers); -
UserNode 6df1869674117400@e4042e487b, UserNode Snoopy, UserNode Woodstock
-

getAllUsers()

- -

Retrieving the names of all registered users. - -

Syntax -
getAllUsers()

Description -
Returns an array that contains the names of all registered users. Use the getUser() function to retrieve the actual user object. This is to be used with caution with large amounts of users.

Example -
var myUsers = getAllUsers(); -
res.write(myUsers); -
Snoopy, Lucy, Linux, Woodstock -
-
res.write(getUser(myUsers[1])); -
UserObject Lucy
-
-

getProperty()

- -

Retrieving a global Property. - -

Syntax -
getProperty(string)

Description -
Returns a Property named string stored in one of the files app.properties or server.properties. If the Property exists in both of the files, app.properties overwrites server.properties. This way server.properties defines Properties for all applications which app.properties can refine for a particular application. app.properties is located in the top directory of a Hop application. server.properties is located in the Hop installation directory. -
-
There is a complete list of Hop's System Properties

Example -
var smtp = getProperty("smtp"); -
res.write(smtp); -
mail.helma.org
-

getURL()

- -

Retrieving the content behind a URL. - -

Syntax -
getURL(url)

Description -
Allocates and retrieves a remote file from a url.

Example -
var url = getURL("http://helma.org/"); -
res.write(url);
-
...see helma.org :-> -
-
var url = getURL("ftp://user:pass@ftp.server.dom/welcome.txt"); -
res.write(url); -
Welcome on the FTP server of server.dom!
-
-
var url = getURL("file:///home/snoopy/www/title.txt"); -
res.write(url); -
The Nudist on the Late Shift
-

getUser()

- -

Retrieving a User Object. - -

Syntax -
getUser(string)

Description -
Returns a Hop Object describing the user referred to with string.

Example -
var myUser = getUser("Snoopy"); -
res.write(myUser.email); -
atomicdog@helma.org
-

getUserBySession()

- -

Retrieving a User Object. - -

Syntax -
getUserBySession(sessionId)

Description -
Returns a user object with a certain session id (= Helma session cookie).

Example -
-
var id = user.sessionID; -
var user = getUserBySession(id); -
res.write(user.name); -
Snoopy
-
(quite recursive, isn't it?) -

isActive()

- -

Determining whether a user is logged in. - -

Syntax -
isActive(userObject)

Description -
Returns true if the user referred to by the user object is logged in.

Example -
var user = getUser("Snoopy"); -
res.write(isActive(user)); -
false
-

renderSkin()

- -

- -

Syntax -
renderSkin(String, ParameterObject)

Description -
Renders a global skin (ie. a skin file inside the global directory). The name of the skin is defined by the string parameter. -
-
A skin is a file that only contains markup (e.g. Html or Xml) and macros. Macros are references to Helma functions wrapped in special tags (<% and %>). For more information about skin and macro techniques please refer to the section about Helma Skins. -
-
Optionally, a JavaScript object can be assigned to the function call as second argument. This object's properties later can be accessed from the skin via pseudo-macro calls of the kind <% param.PropertyName %> -
-
If a param property is not set but referred to in the skin file, it will be replaced with an empty string. Please note that this behaviour is different from generic macro calls.

Example -
Contents of the file global/example.skin: -
<html> -
<head> -
   <title>Hello, <% param.title %>!</title> -
</head> -
<body bgcolor="<% param.bgcolor %>"> -
I greet you <% param.amount %> times. -
</body> -
</html>
-
-
Rendering the skin: -
var param = new Object(); -
param.bgcolor = "#ffcc00"; -
param.title = "World"; -
param.amount = "12345"; -
renderSkin("example", param); -
-
<html> -
<head> -
   <title>Hello, World!</title> -
</head> -
<body bgcolor="#ffcc00"> -
I greet you 12345 times. -
</body>
-

renderSkinAsString()

- -

- -

Syntax -
renderSkinAsString(String, ParameterObject)

Description -
Renders a global skin just the same way as renderSkin() does. The only difference is though, that this function returns the result as string instead of immediately writing it to the response object.

Example -
var str = renderSkinAsString("example", param); -
res.write(str);
-
-
which is equivalent to -
-
renderSkin("example", param); -

stripTags()

- -

Removing markup tags from a string. - -

Syntax -
stripTags(string)

Description -
Removes any < and > as well as everyhing between both of these two characters. In other words: extracts the essence of the text from a string without anything that looks like markup.

Example -
var str = "<html><b>The Nudist on the Late Shift</b></html>"; -
res.write(str); -
The Nudist on the Late Shift
-

write()

- -

- -

Syntax -
write(String)

Description -
This function echoes the string parameter on the console display. Very useful for debugging purposes.

Example -
write("Hello, Console!"); -
Hello, Console!
-

writeln()

- -

- -

Syntax -
writeln(String)

Description -
This function echoes the string parameter on the console display and additionally a newline character. Very useful for debugging purposes.

Example -
writeln("Hello,"); -
writeln("Console!"); -
Hello, -
Console!
-

Hop Object

- -

- -

The HopObject is the basic building block of a Hop applications. The website root object, the user object, as well as any custom type defined by the application are HopObjects and inherit all functionality described below. -
-
In addition to defining and scripting special types of HopObjects it is possible to extend all HopObjects at once by defining a prototype called hopobject. -
-
Functions and Properties -

add()

- -

Adding a Subnode to a Hop Object. - -

Syntax -
hopObject.add(hopObject)

Description -
Adds a Hop Object as new Subnode to another Hop Object. The new Subnode is added after the last Subnode already contained in the Hop Object.

Example -
res.write(root.size()); -
0 -
var myStory= new story(); -
root.add(myStory); -
res.write(root.size()); -
1
-
-
It is also possible to add a bunch of Subnodes with only one function call: -
var myAuthor= new author(); -
var myTitle= "The Nudist On The Late Shift"; -
var myStory= new story(); -
root.add(myAuthor, myTitle, myStory); -
res.write(root.size()); -
3
-

addAt()

- -

Adding a Subnode to a Hop Object. - -

Syntax -
hopObject.addAt(number, hopObject)

Description -
Adds a Subnode to a Hop Object. Unlike add() the position of the Subnode is determined by a number as first parameter in the function call. -
-
Using addAt() instead of add() usually only has an effect with the embedded database, since the order of objects stored in a relational database depends on the value of some column. Thus when adding objects stored in a relational database, one may as well use add().

Example -
res.write(root.get(23)); -
null -
var myStory= new story(); -
root.addAt(23, myStory); -
res.write(root.get(23)); -
hopObject story
-

cache

- -

- -

Syntax -
HopObject.cache

Description -
Each HopObject contains a cache object to store temporary properties (e.g. strings, numbers or other objects) in. These properties can be accessed in any thread until the application is restarted or the HopObject is invalidated, either manually using the invalidate() function or whenever Helma is fetching the HopObject's data from a remote database. -
-
There is no way to make the cache object persistent.

Example -
user.cache.message = "This is a temporary message." -

contains()

- -

Determining if a Hop Object contains a certain Subnode. - -

Syntax -
hopObject.contains(hopObject)

Description -
Returns the index position of a Subnode contained by a Hop Object (as usual for JavaScript starting with 0 referring to the first position). The index position is a relative value inside a Hop Object (not to be confused with a Hop ID which is unique for each Hop Object). If there is no appropriate Subnode inside the Hop Object the returned value equals -1

Example -
var obj = root.get("myObject"); -
res.write(root.contains(obj)); -
23 -
-
obj = root.get("blobject"); -
res.write(root.contains(obj)); -
-1
-

count()

- -

Counting Subnodes. - -

Syntax -
hopObject.count()

Description -
Returns the amount of Subnodes contained in a Hop Object.

Example -
res.write(root.count()); -
5
-

editor()

- -

- -

Syntax -
hopObject.editor(string, width, height)

Description -
Returns an input element for the object's property defined by the string parameter. The result can be used inside an Html form. The property's value is set to the form elements value. If the optional height parameter is set, a text area is used instead of a one-line text field.

Example -
var editor = this.editor("title", 20); -
res.write("<form>" + editor + "</form>"); -
-
<form><input type="text" name="title" size="20" value="Hello, World"></form> -
-
var editor = this.editor("bodytext", 20, 5); -
res.write("<form>" + editor + "</form>"); -
-
<form><textarea name="bodytext" cols="20" rows="5" wrap="virtual">When the going gets tough, the tough goes shopping.</textarea></form>
-

get()

- -

Retrieving Properties and Subnodes. - -

Syntax -
hopObject.get(stringOrNumber)

Description -
Retrieves a Property or a Subnode of a known Hop Object. The type of the result depends on the type of the submitted parameter: a number will retrieve the Subnode of the Hop Object at the corresponding index position, a string the corresponding Property of the Hop Object. Finally, a number as string retrieves the subnode with the corresponding Hop ID.

Example -
root.get(0); -
HopObject author -
root.get(1); -
HopObject story -
-
root.get("date"); -
Wed Oct 18 02:01:41 GMT+01:00 1971 -
root.get("title"); -
The Nudist On The Late Shift -
-
root.get("1"); -
HopObject author
-

href()

- -

Getting a Hop Object's url-compatible reference. - -

Syntax -
hopObject.href() -
hopObject.href(string)

Description -
Returns the absoulte url path of a Hop Object relative to the application's root. Any string parameter is simply appended to the return value. Useful to refer to a Hop Object in a markup tag (e.g. with a href parameter in an html <a> tag).

Example -
var obj = root.get(0); -
-
res.write("<a href=\"" + obj.href() + "\">"); -
<a href="/main/"> -
-
res.write("<a href=\"" + obj.href("edit") + "\">"); -
<a href="/main/edit"> -
-
-

invalidate()

- -

Delete a Hop Object from the cache. - -

Syntax -
hopObject.invalidate()

Description -
Marks a HopObject as invalid so that it is fetched again from the database the next time it's accessed. In other words, use this function to kick an object out of Helma's database cache.

Example -
var obj = this.get(0); -
obj.invalidate();
-

list()

- -

Listing Hop Objects. - -

Syntax -
hopObject.list()

Description -
Returns an array including all Subnodes of a Hop Object. Useful if array data is required, however general use should be avoided in favor of the method described below.

Example -
var objectList = root.list(); -
for (var i=0; i<objectList.length; i++){ -
 var myObject = objectList[i]; -
 res.write(myObject.created + "<br>"); -
} -
Wed Oct 18 02:01:41 GMT+01:00 1971 -
Fri Nov 03 13:25:15 GMT+01:00 2000 -
Mon May 29 07:43:09 GMT+01:00 1999
-
-
With increasing amounts of Subnodes tied to a Hop Object the use of list() becomes seriously inefficient – as long as not all Subnodes really need to be read out. This is due to the creation of a JavaScript Array containing the whole bunch of Subnodes each time the list() function is called. Instead, it is recommended to determine the amount of Subnodes using the count() function and looping through them using get(): -
-
var amount = root.size(); -
for (var i=0; i<amount; i++){ -
 var myObject = root.get(i); -
 res.write(myObject.created + "<br>"); -
} -
Wed Oct 18 02:01:41 GMT+01:00 1971 -
Fri Nov 03 13:25:15 GMT+01:00 2000 -
Mon May 29 07:43:09 GMT+01:00 1999
-

remove()

- -

Removing a Subnode. - -

Syntax -
hopObject.remove()

Description -
Removes a known Subnode from a Hop Object. The subnode can be determined e.g. via the get() function.

Example -
res.write(root.size()); -
24 -
var myObject = root.get(5); -
root.remove(myObject); -
res.write(root.size()); -
23
-

renderSkin()

- -

- -

Syntax -
HopObject.renderSkin(String, ParameterObject)

Description -
Renders a skin of this object. The name of the skin is defined by the string parameter. -
-
A skin is a file that only contains markup (e.g. Html or Xml) and macros. Macros are references to Helma functions wrapped in special tags (<% and %>). For more information about skin and macro techniques please refer to the section about Helma Skins. -
-
Optionally, a JavaScript object can be assigned to the function call as second argument. This object's properties later can be accessed from the skin via pseudo-macro calls of the kind <% param.PropertyName %> -
-
If a param property is not set but referred to in the skin file, it will be replaced with an empty string. Please note that this behaviour is different from generic macro calls.

Example -
Contents of the file root/example.skin: -
<html> -
<head> -
   <title>Hello, <% param.title %>!</title> -
</head> -
<body bgcolor="<% param.bgcolor %>"> -
I greet you <% param.amount %> times. -
</body> -
</html>
-
-
Rendering the skin: -
var param = new Object(); -
param.bgcolor = "#ffcc00"; -
param.title = "World"; -
param.amount = "12345"; -
root.renderSkin("example", param); -
-
<html> -
<head> -
   <title>Hello, World!</title> -
</head> -
<body bgcolor="#ffcc00"> -
I greet you 12345 times. -
</body>
-

renderSkinAsString()

- -

- -

Syntax -
HopObject.renderSkinAsString(String, ParameterObject)

Description -
Renders a skin of this object just the same way as renderSkin() does. The only difference is though, that this function returns the result as string instead of immediately writing it to the response object.

Example -
var str = root.renderSkinAsString("example", param); -
res.write(str);
-
-
which is equivalent to -
-
root.renderSkin("example", param); -

set()

- -

Changing Properties and Subnodes. - -

Syntax -
hopObject.set(stringOrNumber, value)

Description -
Replaces the value of a Property or Subnode with a new value.

Example -
res.write(root.get(23)); -
null -
var myAuthor = new author(); -
root.set(23, myAuthor); -
res.write(root.get(23)); -
hopObject author -
-
res.write(root.title); -
null -
var myTitle = "The Nudist On The Late Shift"; -
root.set("title", myTitle); -
res.write(root.title); -
The Nudist On The Late Shift
-

setParent()

- -

Defining a Hop Object as parent for a Subnode. - -

Syntax -
hopObject.setParent(hopObject)

Description -
Sometimes it is necessary to set a Subnode's parent to a certain Hop Object. This is caused by the way Hop caches Subnodes. Especially if you are retrieving a Subnode from a relational database through different ways (e.g. by using subnoderelation) and you want to remove this Subnode or apply the href() function on it.

Example -
var trash = user.stories.get(23); -
trash.setParent(root); -
root.remove(trash);
-

size()

- -

Counting Subnodes. - -

Please refer to count(). -

_id

- -

- -

Syntax -
hopObject._id

Description -
Returns the internal id of the object. This property is assigned by Helma and cannot be set.

Example -
var obj = root.get(0); -
res.write(obj._id); -
43
-

_parent

- -

- -

Syntax -
hopObject._parent

Description -
Returns the parent object of this object.

Example -
var obj = root.get(0); -
res.write(obj._parent); -
HopObject root
-

Image Processing

- -

- -

The image object allows you to read, manipulate, and save images. An image object is created using the Image() constructor. -
-
var img = new Image(imageUrl); -
var img = new Image(imageUrl, imageFilter);
-
-
For this to work, you must have Sun's Jimi library in your classpath. -
-
Example: -
var img = new Image("http://helma.org/image.gif"); -
var img = new Image("file:///home/images/image.jpg"); -
-
var filter = new Packages.com.sun.jimi.core.filters.Rotate(90); -
var img = new Image("http://helma.org/image.gif", filter);
. -
-
Please refer to the getSource() function for details and examples of the imageFilter parameter. -
-

crop()

- -

Cutting out a rectangular area of an image. - -

Syntax -
imageObject.crop(x, y, width, height)

Description -
Cuts out (crops) a rectanglular area of an image. The dimensions of the area are calculated from the x- and y-offset from the top left corner of the image as upper left reference point to x + width and y + height as lower right reference point.

Example -
var img = new Image("http://helma.org/images/original.gif"); -
res.write("<img src=\"/images/original.gif\">"); -
-
-
-
img.crop(58,9,48,21); -
img.saveAs("/www/images/processed.gif"); -
res.write("<img src=\"/images/processed.gif\">"); -
-
-

drawLine()

- -

Adding a drawn line to an image. - -

Syntax -
imageObject.drawLine(x1, x2, y1, y2)

Description -
Draws a line onto an image. The line starts at the reference point defined by the offsets x1 and y1 from the top left corner of the image and ends at the reference point defined by the offsets x2 and y2.

Example -
var img = new Image("http://helma.org/images/originalgif"); -
res.write("<img src=\"/images/original.gif\">"); -
-
-
-
img.setColor(204,0,0); -
img.drawLine(58,26,100,26); -
img.saveAs("/www/images/processed.gif"); -
res.write("<img src=\"/images/processed.gif\">"); -
-
-

drawRect()

- -

Adding a drawn rectangle to an image. - -

Syntax -
imageObject.drawRect(x, y, width, height)

Description -
Draws a rectangle onto an image. The rectangle's dimensions are calculated from the x- and y-offset from the top left corner of the image as upper left reference point to x + width and y + height as lower right reference point.

Example -
var img = new Image("http://helma.org/images/originalgif"); -
res.write("<img src=\"/images/original.gif\">"); -
-
-
-
img.setColor(204,0,0); -
img.drawRect(57,8,46,20); -
img.saveAs("/www/images/processed.gif"); -
res.write("<img src=\"/images/processed.gif\">"); -
-
-

drawString()

- -

Adding text to an image. - -

Syntax -
imageObject.drawString(string, x, y)

Description -
Draws a string onto an image. The string will be drawn starting at the x- and y-offset from the top left corner of the imaget.

Example -
var img = new Image("http://helma.org/images/original.gif"); -
res.write("<img src=\"/images/original.gif\">"); -
-
-
-
img.setColor(204,0,0); -
img.drawString("rocks!",82,35); -
img.saveAs("/www/images/processed.gif"); -
res.write("<img src=\"/images/processed.gif\">"); -
-
-

fillRect()

- -

Adding a filled rectangle to an image. - -

Syntax -
imageObject.fillRect(x, y, width, height)

Description -
Draws a filled rectangle onto an image. The rectangle's dimensions are calculated from the x- and y-offset from the top left corner of the image as upper left reference point to (x + width) and (y + height) as lower right reference point.

Example -
var img = new Image("http://helma.org/images/original.gif"); -
res.write("<img src=\"/images/original.gif\">"); -
-
-
-
img.setColor(204,0,0); -
img.fillRect(58,27,43,29); -
img.saveAs("/www/images/processed.gif"); -
res.write("<img src=\"/images/processed.gif\">"); -
-
-

getHeight()

- -

Determining the height of an image. - -

Syntax -
imageObject.getHeight()

Description -
Returns the height of an image measured in pixels.

Example -
var img = new Image("http://helma.org/images/hop.gif"); -
res.write("<img src=\"/images/hop.gif\">"); -
-
-
-
var height = img.getHeight(); -
res.write(height); -
35
-

getSource()

- -

- -

Syntax -
Image.getSource()

Description -
To use the image filters provided by the Jimi java image processing package Packages.com.sun.jimi.core.filters, a specific class of image objects is needed. Helma wraps the sun.awt.image objects into a custom class. To use Helma image objects with Jimi's filters these have to be "unwrapped" using the getSource() function. -
-
The following filter functions have been successfully applied the way as described in the examples above:

  • Rotate(degreeNumber)
  • -
  • Gray()
  • -
  • Flip(typeNumber)
  • -
  • Oil(intensityNumber)
  • -
  • Invert()
  • -
  • Smooth(intensityNumber)
  • -
  • Shear(degreeNumber)
  • -
  • Edges()
  • -
  • Shrink(multiplyNumber)
  • -
  • Enlarge(divisionNumber)
-Please take into account that the quality might suffer depending on the type and amount of filters applied to the image.

Example -
var img = new Image("http://helma.org/static/original.jpg"); -
var rotator = new Packages.com.sun.jimi.core.filters.Rotate(45); -
var processed = new Image(img, rotator); -
processed.saveAs("/path/to/static/processed.jpg"); -
res.write("&lt;img src=\"/static/processed.jpg\&gt;"); -
-
-
-
var img = new Image("http://helma.org/static/original.jpg"); -
var filter = Packages.com.sun.jimi.core.filters; -
var oil = new filter.Oil(img.getSource(), 3); -
var processed = new Image(img, oil); -
processed.saveAs("/path/to/static/processed.jpg"); -
res.write("&lt;img src=\"/static/processed.jpg\&gt;"); -
-
-

getWidth()

- -

Determining the width of an image. - -

Syntax -
imageObject.getWidth()

Description -
Returns the width of an image measured in pixels.

Example -
var img = new Image("http://helma.org/images/hop.gif"); -
res.write("<img src=\"/images/hop.gif\">"); -
-
-
-
var width = img.getWidth(); -
res.write(width); -
174
-

reduceColors()

- -

Setting the color depth of an image. - -

Syntax -
imageObject.reduceColors(number)

Description -
Reduces the number of colors used in an image to the amount specified with number. Use with caution, generally. Gif images need a color depth of max. 256 colors maximum.

Example -
var img = new Image("http://helma.org/images/original.jpg"); -
res.write("<img src=\"/images/original.jpg\">"); -
-
-
-
img.reduceColors(8); -
img.saveAs("/www/images/processed.jpg"); -
res.write("<img src=\"/images/processed.jpg\">"); -
-
-

resize()

- -

Setting the dimensions of an image. - -

Syntax -
imageObject.resize(width, heigth)

Description -
Sets the height and width of an image to new values. The new width and height have to be integers, so be careful to round the new values eventually. In case of a gif image be sure to reduce the image to 256 colors after resizing by using the reduceColors() function.

Example -
var img = new Image("http://helma.org/images/original.jpg"); -
res.write("<img src=\"/images/original.jpg\">"); -
-
-
-
var factor = 0.66; -
var wd = Math.round(img.getWidth() * factor); -
var ht = Math.round(img.getHeight() * factor); -
img.resize(wd, ht); -
img.saveAs("/www/images/processed.jpg"); -
-
res.write("<img src=\"/images/processed.jpg\">"); -
-
-

saveAs()

- -

Storing an image on the hard disk. - -

Syntax -
imageObject.saveAs(path)

Description -
Stores the binary data of an image on the hard disk. Before the image is converted into the appropriate image format determined by the file extension (please refer to the JIMI documentation for a detailed overview of the available formats).

Example -
var img = new Image("http://helma.org/images/original.jpg"); -
res.write("<img src=\"/images/original.jpg\">"); -
-
-
-
img.saveAs("/www/images/processed.png"); -
res.write("<img src=\"/images/processed.png\">"); -
-
-

setColor()

- -

Selecting a drawing color. - -

Syntax -
imageObject.setColor(colorOrRgbValues)

Description -
Determines the color of the following drawing actions either by a 24-bit integer (0–16777215) or by an rgb-tuple (each element ranging from 0 to 255).

Example -
var img = new Image("http://helma.org/images/original.jpg"); -
res.write("<img src=\"/images/original.jpg\">"); -
-
-
-
img.setColor(16777215); -
img.fillRect(80, 50, 30, 30); -
img.setColor(255, 255, 0); -
img.fillRect(65, 15, 30, 30); -
img.saveAs("/www/images/processed.png"); -
res.write("<img src=\"/images/processed.png\">"); -
-
-

setFont()

- -

Selecting a typeface for font setting. - -

Syntax -
imageObject.setFont(name, style, size)

Description -
Determines the font face, style and size of a font to be used in following drawString() actions. name specifies the font face as string (e.g. "sansserif", "dialog"). -
-
The integer style sets the font to normal (0), bold (1), italic (2) or bold and italic (3). size, also an integer, refers to the font size in pixels. -
-
Please take a look at this description about adding fonts to the Java Runtime for a detailed look onto Java's font mechanics.

Example -
var img = new Image("http://helma.org/images/original.jpg"); -
res.write("<img src=\"/images/original.jpg\">"); -
-
-
-
img.setColor(255, 255, 255); -
img.setFont("serif", 0, 12); -
img.drawString("I shot the serif.", 50, 15); -
img.setFont("sansserif", 1, 14); -
img.drawString("But I didn't shoot", 10, 100); -
img.setFont("monospaced", 2, 16); -
img.drawString("the monotype.", 15, 115); -
img.saveAs("/www/images/processed.png"); -
res.write("<img src=\"/images/processed.png\">"); -
-
-

Java Object Access

- -

- -

See the Fesi documentation for Java object access. -
-
For starters, objects from the core Java Api (in the java.* packages) can be instantiated directly, while other Java classes need the Packages prefix. -
-
var buffer = new java.lang.StringBuffer(); -
var foo = new Packages.com.bar.util.Foo();
-
-
Use Sun's Api Specification to find out more about Java objects. -
-
Example -
/** -
* This function returns a date string -
* from a Date object formatted -
* according to a custom locale. -
*/ -
function getLocaleDate(date) { -
   // Here the locale is set (english / Ireland): -
   var locale = new java.util.Locale("en", "IE"); -
   // Creating the date formatter: -
   var dateFormat = new java.text.SimpleDateFormat("EEEE d MMMM yyyy, HH:mm", locale); -
   // Formatting the Date object as date string: -
   var dateString = dateFormat.format(date); -
   return(dateString); -
}
-

Mail Client

- -

- -

Mail objects are used to send email via Smtp and are created by using the Mail() constructor: -
-
var mail = new Mail(); -
-
The mail object can than be manipulated and sent using the functions listed below. -
-
You'll need the JavaMail library installed for this to work. Also, don't forget to set your mail server via the smtp property. -
-
Note: Make sure that the Smtp server itself is well-configured, so that it accepts Mails coming from your server and does not deny relaying. -
Best and fastest configuration is of course if you run your own Smtp server (e.g. sendmail), but which might be a bit tricky to set up. -

addBCC()

- -

- -

Syntax -
mailObject.addBCC(EmailString, NameString)

Description -
Adds a recipient to the list of addresses to get a "blind carbon copy" of the message. The first argument specifies the receipient's e-mail address. The second argument is optional and specifies the name of the recipient.

Example -
var mail = new Mail(); -
mail.addBCC("hop@helma.at"); -
mail.addBCC("tobi@helma.at", "Tobi Schaefer");
-

addCC()

- -

- -

Syntax -
mailObject.addCC(EmailString, NameString)

Description -
Adds an address to the list of carbon copy recipients. The first argument specifies the receipient's e-mail address. The second argument is optional and specifies the name of the recipient.

Example -
var mail = new Mail(); -
mail.addCC("hop@helma.at"); -
mail.addCC("tobi@helma.at", "Tobi Schaefer");
-

addPart()

- -

- -

Syntax -
mailObject.addPart(Object)

Description -
Adds a mime-part to the message. The mime-part (e.g. a gif image or an rtf document) has to be wrapped into a java.io.File object.

Example -
var file = new java.io.File("/home/snoopy/woodstock.jpg"); -
var mail = new Mail(); -
mail.setFrom("snoopy@doghouse.com"); -
mail.setTo("woodstock@birdcage.com"); -
mail.setSubject("Look at this!"); -
mail.addPart("I took a photograph from you. Neat, isn't it? -Snoop"); -
mail.addPart(file); -
mail.send();
-

addText()

- -

- -

Syntax -
mailObject.addText(String)

Description -
Appends a string to the body text of the message. Note that this method will overwrite any multi-mime-parts already added to the message.

Example -
var mail = new Mail(); -
mail.addText("Hello, World!");
-

addTo()

- -

- -

Syntax -
mailObject.addTo(EmailString, NameString)

Description -
Adds a receipient to the address list of the message. The first argument specifies the receipient's e-mail address. The second argument is optional and specifies the name of the recipient.

Example -
var mail = new Mail(); -
mail.addTo("hop@helma.at"); -
mail.addTo("tobi@helma.at", "Tobi Schaefer");
-

send()

- -

- -

Syntax -
mailObject.send()

Description -
This function actually sends the message created with the mail object using the smtp server as specified in an appropriate property file.

Example -
var mail = new Mail(); -
mail.addTo("watching@michi.tv", "michi"); -
mail.addCC("franzi@home.at", "franzi"); -
mail.addBCC("monie@home.at"); -
mail.setFrom("chef@frischfleisch.at", "Hannes"); -
mail.setSubject("Registration Conformation"); -
mail.addText("Thanks for your Registration..."); -
mail.send();
-
-

setFrom()

- -

- -

Syntax -
mailObject.setFrom(EmailString, NameString)

Description -
Sets the sender of the message. The first argument specifies the sender's e-mail address. The second argument is optional and specifies the name of the sender.

Example -
var mail = new Mail(); -
mail.setFrom("tobi@helma.at", "Tobi Schaefer");
-

setSubject()

- -

- -

Syntax -
mailObject.setSubject(String)

Description -
Sets the subject of the message.

Example -
var mail = new Mail(); -
mail.setSubject("Hello, World!");
-

status

- -

- -

Syntax -
mailObject.status

Description -
Returns the current status of the message. If an error has occured the status is greater than zero. Here are the error codes:

-nr   error description
---   -----------------
- 0   no error
-10   error with setSubject()
-11   error with addText()
-12   error with addPart()
-20   error with addTo()
-21   error with addCC()
-22   error with addBCC()
-30   error while trying to send the Message

Example -
var mail = new Mail(); -
mail.addTo("idont@know@myemail.com"); -
res.write(mail.status); -
20
-

Number Object

- -

- -

-

format()

- -

- -

Syntax -
Number.format(PatternString)

Description -
Formats a number as string for custom output. The function's string parameter is used as a pattern to describe the desired format. In the pattern string you can use the following pattern letters:

-Symbol   Meaning
-------   -------
-  0      a digit
-  #      a digit, zero shows as absent
-  .      placeholder for decimal separator
-  ,      placeholder for grouping separator.
-  E      separates mantissa and exponent for
-         exponential formats.
-  ;      separates formats.
-  -      default negative prefix.
-  %      multiply by 100 and show as percentage
-  ?      multiply by 1000 and show as per mille
-  ¤      currency sign; replaced by currency symbol;
-         if doubled, replaced by international currency
-         symbol. If present in a pattern, the monetary
-         decimal separator is used instead of the decimal
-         separator.
-  X      any other characters can be used in the prefix
-         or suffix.
-  '      used to quote special characters in a prefix
-         or suffix.
-Please note that the output is depending on the locale settings of the Helma server. For further reference refer to the examples below or directly to the documentation of the Java DecimalFormat class

Example -
var nr = 12345.67890; -
res.write(nr.format("#.00 ¤")); -
12345,68 öS -
-
res.write(nr.format("###,####.00 ¤¤")); -
1.2345,68 ATS -
-
var nr = 0.0987654321; -
res.write(nr.format("0.###%")); -
9,877% -
-
var nr = 7.9E-5 -
res.write(nr.format("0.######")); -
0,000079
-

Object-Relational Mapping

- -

- -

The Hop comes with the ability to store Hop objects natively in its embedded object database. However, for many purposes it is advisable to use an external relational database product for object storage for reasons including features, accessability and reliability. -
-
A prototype can specify how its data properties are stored in relational database tables by providing a types.properties file. This file is located in the prototype's directory along with the prototype code. It is basically a Java properties file that maps JavaScript properties to database columns. Unfortunately, the mapping rules have gone from clean and simple to rather obscure as features were added to the Hop. -
-
A basic type.properties file might look like this: -

_datasource = my_data_source
-_tablename = my_table
-
-_subnodes = <child.db_parent_id
-_id = id
-
-title = db_title
-createdate = db_createdate
-owner = db_owner_id>user.id
-The first thing we notice is that some properties begin with an underscore ("_") while others don't. This is a simple convention to separate those properties which are needed by Hop internally from those that specify script-accessible properties of this prototype. -
-
In the following, we describe the different kinds of entries that can be used in type.properties files. -
-

Path Object

- -

- -

Description -
The objects in the uri path of a request are not only accessible as array members of the global path object, but also as named properties of path via the name of their prototype. For instance, if an object in the uri path has a prototype called "story", it will be accessible as path.story. -
-
Example -
Assumed the request path of an application is -
/h_files/myDocument/storyTitle/23 -
-
for (var i=0; i<path.length; i++) -
   res.writeln(path[i]); -
-
HopObject file -
HopObject document -
HopObject story -
HopObject note
-
-
var obj = path.story; -
res.write(obj); -
-
HopObject story
-
-

Property Files

- -

- -

Helma's property files are simple text files containing information e.g. about which applications to start, about the database connection, server configuration etc. -
-
There is no general syntax of the various properties, however most of the time each line represents a property's assignment the way -
-
propertyName = propertyValue(s) -
-
A line starting with a hash character # will be handled as comment: -
-
# This is a comment. -
This is no comment. # This is no comment, either.
-

app.properties

- -

- -

Description -
This file is located in an application's directory (e.g. apps/myApp/). A wide variety of properties can be defined here. Generally, any imaginable name can be used as a property and assigned a string value the way -
-
propertyName = propertyValue -
-
Properties defined in such a way can be evaluated from inside Helma's scripting environment by using the getProperty() function. -
-
However, there is a bunch of pre-defined properties that are used internally by Helma. Be careful not to accidentally bend these special properties for your custom purposes or your application eventually could behave unexpectedly. -
-
Many of those pre-defined properties also can be defined server-wide in server.properties. However, any property that is set there will be overwritten by an appropriate setting in app.properties. -
-
Example -
# Setting some properties: -
backgroundColor = #3333ff -
title = "Hello, World!"
-
-
Accessing the properties e.g. from root/main.hac: -
var bgColor = getProperty("backgroundColor"); -
res.write(bgColor); -
#3333ff -
-
var title = getProperty("title"); -
res.write(title); -
Hello, World!
-

apps.properties

- -

- -

Description -
This file is located in Helma's installation directory. It contains a list of applications that helma will handle (ie. start up, execute, update). The name of an application refers to a directory with the same name in helma's apps directory. -
-
Example -
hopblog -
antville -
gong -
kolin -
-
Special case: appname = self -
-
Using this syntax enables the application appname to script Helma herself. Currently, there can be only one application set-up this way: -
-
Example -
hopblog -
antville -
base = self -
gong
-

db.properties

- -

- -

Description -
This file is located in Helma's installation directory. It contains a list of data sources and data source properties setting up the basic connection between Helma and relational databases. -
-
To define data sources, the property sources is assigned a comma-separated list of names (certainly, the list can contain only one element): -
-
sources = dataSourceName -
-
In consequence the following properties of the data source(s) must be set: -
-
dataSourceName.url -
dataSourceName.driver -
dataSourceName.user -
dataSourceName.password
-
-
Example -
sources = mySqlDB, oracleDB, hsqlDB -
-
mySqlDB.url = jdbc:mysql://db.domain.com/mysql -
mySqlDB.driver = org.gjt.mm.mysql.Driver -
mySqlDB.user = username -
mySqlDB.password = secretPassword -
-
oracleDB.url = jdbc:oracle://db.domain.com/oracle -
oracleDB.driver = oracle.jdbc.driver.OracleDriver -
oracleDB.user = username2 -
oracleDB.password = secretPassword2 -
-
hsqlDB.url = jdbc:hsqldb:dbData -
hsqlDB.driver=org.hsqldb.jdbcDriver -
hsqlDB.user=sa -
hsqlDB.password=
-

server.properties

- -

- -

Description -
This file is located in Helma's installation directory. It contains pre-defined properties that are used internally by Helma for configuring the server. -
-
Many of these properties also can be defined in an app.properties file. Any property that is set there will overwrite the appropriate setting in server.properties. -
-
Example -
# Setting a custom locale: -
country = AT -
language = de -
-
# Defining a mail server: -
smtp = mail.domain.dom
-

type.properties

- -

- -

This file is located in a prototype's directory (e.g. apps/myApp/myProto). It contains definitions that specify the way Helma maps the relational database tables to hierarchical objects. -

Basic Mappings

- -

- -

The _db entry describes the database to use for storing objects of this type. dbname is the name of a database as defined in the db.properties file. -
-
_db = dbname -
-
The _table entry tells Helma which table to use for objects of this type within the database. -
-
_table = TABLENAME -
-
The _id entry defines the column to use as primary key. Helma requires a single primary key with no other functionality. -
-
_id = ID_COLUMN -
-
The optional _name entry tells Helma which database column to use as object name. This is important for the user prototype, since it defines which column constitutes the user name. -
-
_name = NAME_COLUMN -
-
The _parent entry contains a list of properties of objects of this type to be used as parent. Objects must know their parent in order to generate correct URLs in their href() function. -
-
_parent = property1, property2 -

Simple Property Mappings

- -

- -

The mappings for simple (non-object) properties simple map a property name of the specified object type to a column of the relational database table. The type of the property or column need not be specified. Helma does all necessary conversion when reading or writing a property value. -
-
prop1 = DB_COLUMN_1 -
prop2 = DB_COLUMN_2
-
-
To prevent a property from being overwritten by the application it can be made readonly. -
-
prop1.readonly = true -

Mountpoint Mappings

- -

- -

Mountpoints provide a simple way to directly attach a prototype to the URL path. If the path contains the name of a mountpoint the prototype's objects are accessible simply by adding their id (or a property defined by ._accessname) to the URL string. -
-
myMountpoint = mountpoint(myProto) -
-
In the example above, the path /myMountpoint/23/test refers to the action test.hac of the object with id 23, which is derived from the myProto prototype. -

Object Property Mappings

- -

- -

Properties that contain other objects are defined by the object keyword and the prototype name of the referenced object in brackets. The object reference is resolved via two entries: -
-
prop3 = object (protoype) -
prop3.local = LOCAL_DB_COLUMN -
prop3.foreign = FOREIGN_DB_COLUMN
-
-
prop3.local specifies the part of the reference in the local database-table, prop3.foreign the column in the table where objects of the referenced prototype are stored. By executing the assignment obj.prop3 = someObject, the database-column specified by prop3.local will be set to the value of FOREIGN_DB_COLUMN, or null if someObject == null. -

Collection Mappings

- -

- -

The following section describes the entries used to define collections of objects. There are two kinds of collections: First, every object can itself act as a collection, and second, it can define additional properties to be used as collections. Direct descendents are defined with entries starting with _children, while additional collections are defined using their property name. Otherwise the syntax for the two is the same. -
-
The following are examples for simple collection mappings for both the direct descendants and those contained in a collection-property called prop4. The .foreign entry is used in both cases to specify a column in the foreign table used to collect the objects. Exactly those objects will be collected whose FOREIGN_DB_COLUMN value equals the LOCAL_DB_COLUMN value of the object holding the collection. Leaving away .local and .foreign creates a collection of all available objects of the specified prototype. -
-
_children = collection (protoype) -
_children.local = LOCAL_DB_COLUMN -
_children.foreign = FOREIGN_DB_COLUMN -
-
prop4 = collection (protoype) -
prop4.local = LOCAL_DB_COLUMN -
prop4.foreign = FOREIGN_DB_COLUMN
-
-
By executing obj.add(otherObj) resp. obj.prop4.add(otherObj), the FOREIGN_DB_COLUMN will be set to the value of LOCAL_DB_COLUMN. -
-
By default, child objects can be accessed from the containing parent object through their index-position or ID value. Additionally the entry .accessname can be used to specify a database column in the child table. The value of this column will be used as name of the objects contained in this collection. -
-
prop4.accessname = DB_COLUMN -
-
With the above mapping, an object contained in the prop4 collection with a DB_COLUMN value of "xyz" would be reachable as this.prop4.xyz from the containing object. -
-
filter can be used to add an additional condition for the selection of objects which is not dependent on the object holding the collection. order contains the sorting to be applied to the child objects. group tells Helma to group the objects in the collection according to the value in DB_GROUPCOLUMN. -
-
prop4.filter = DB_FILTERCOLUMN is not null -
prop4.order = DB_ORDERCOLUMN desc -
prop4.group = DB_GROUPCOLUMN -
prop4.group.order = DB_GROUPORDERCOLUMN
-
-
Notice the two appearences of order above. The first one, prop4.order sorts the objects, the second, prop4.group.order sorts the grouped objects, that Helma will create as a result of the group entry. With this it's also possible to sort the grouped objects ascending, but the contents of the grouped objects descending. -

Additional Join Conditions

- -

- -

For both object and collection mappings, it is possible to provide any number of additional restraints used to join the local with the other table to further limit the selected objects. -
-
prop4.local.1 = FIRST_LOCAL_COLUMN -
prop4.foreign.1 = FIRST_FOREIGN_COLUMN -
prop4.local.2 = SECOND_LOCAL_COLUMN -
prop4.foreign.2 = SECOND_FOREIGN_COLUMN
-
-
Whenever one specifies more than one restraint, the use of .[Number] is mandatory. -

List of All Properties

- -

- -

This is a list of all pre-defined properties that can be set in one of the files server.properties, db.properties and app.properties (type.properties coming soon). Which property is available in which file is displayed in the "Range" column. -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertyRangeDescription
actionExtensionserver, appSets the extension for Helma action files. Default setting is actionExtension = .hac. Changing this setting is not recommended. Use with caution and at your own risk.
allowWebserverSpecifies ip adresses (or networks) that are allowed to connect to the Helma rmi servlet server (port 5055). For more than one ip adress put a comma between the entries, subnets should be written as i.e. 192.168.0.*.
allowXmlRpcserver, appSame as allowWeb, but for the xml-rpc server (port 5056).
appHomeserverDefines the path to the location of Helma applications. If not specified, [hopHome]/apps will be used.
appsPropFileserverSets the location of the apps.properties file (i.e. for security reasons). The default is the root directory of your Helma installation.
baseURIserver, appSpecifies the prefix to add to urls generated by a Helma application. For example, if your application is "mounted" at /myapp in the server's document tree, you'd set baseURI = /myapp.
cachesizeserverDefines the size of the node cache in bytes.
charsetserverDefines the character encoding. The default is ISO-8859-1 (Western) encoding. You can use any of the encodings supported by Java.
countryserverLike language, this is used to set the country for proper localisation. For details you can refer to this list of country codes.
dbHomeserverDefines the path to the location of the embedded database files. If not specified, [hopHome]/db will be used
debugserver, appSwitches between "normal" logging output (debug = false) and the extensive "debug" output (debug = true) which may be useful when developing. Default setting is false.
exposeTemplatesserver, appTo directly call a .hsp (instead of a .hac) file via the http interface it is necessary to set exposeTemplates = true. Default setting is false.
hopHomeserverThis property defines the Helma working directory, e.g. hopHome = /hop/apps. If not specified, the current directory is used.
hrefSkinappThe name of the skin that is assigned to this property is used to extend the href() function. E.g. setting hrefSkin = customLink will cause Helma to set param.path to the result of href() and to render the skinfile customLink.skin as if the function renderSkin("customLink", param) was invoked. Take a look at the hrefSkin example for the whole picture.
idBaseValueserver, appUsed to set the current value of the internal ID generator. This is useful when starting a new internal db (where the id value would normally start at 1), but relational dbs are used that already contain data. Only applied if the current counter value is smaller than idBaseValue.
languageserverUsed to set the language on systems where the Java runtime doesn't recognize it by itself (e.g. Linux), which may be important for date formatting and the like. Refer to this list of language codes for details.
linkMethodserver, applinkMethod = query | path
Deprecated.
logDirserver, app
logSQLserver, appWith this option set to "true", Helma writes out all sql select statements to the logging device (and just those, so you won't find any insert, update or delete statements in there).
maxThreadsserverSets the maximum number of Helma's Java threads, e.g. maxThreads = 12. This is one of the parameters you should adjust for each server depending on the applications you run. If you see an error like "maximum thread count reached" you should increase the value of this property.
paranoidserverIf set to true, switches Helma to "paranoid" mode, which means that it won't accept connections from servers with unknown ip adresses >you can specify allowed ip adresses with the allowWeb and allowXmlRpc properties. Default setting is paranoid = false.
requestTimeoutserverDefines the time in seconds after which a request receives a timeout. Normally there is no need to change this value, but if you have tasks in your Helma application that take a longer time, you should increase this value.
scriptExtensionserver, appUsed to change the extension of script files. Default setting is scriptingExtension = .js. Changing this setting is not recommended. Use with caution and at your own risk.
sessionTimeoutserver, appThis determines the time (in minutes) after which an inactive session becomes invalid.
skinPathapp
smtpserver, appSpecifies an smtp server, e.g. smtp = mail.server.dom. If you want Helma to send e-mail you should define this property.
sourcesdbDefines the name of one or more data sources to be used in an application, e.g. sources = mySqlDB, oracleDB. Each data source has then to be specified in detail by assigning values to its properties url, driver, user and password. Refer to the description of db.properties for further information.
templateExtensionserver, appUsed to change the extension of Helma template files. Changing this setting is not recommended. Use with caution and at your own risk.
timezoneserverIt might be necessary to explicitly set the timezone for Helma. If new Date() puts out the wrong date, check if this option was set correctly. For details, refer to this list of timezones
xmlparserserver, appCan be used to specify a different Xml parser, e.g. xmlparser = minml. The default value is openxml.
XmlRpcAccessserver, appFunctions which should be callable via Xml-Rpc need to be listed in this property on a per-application basis. The list contains entries of the kind prototype.function for each exposed function separated by commata, e.g. XmlRpcAccess = weblog.getStory, weblog.showStatus.
xmlRpcHandlerNameappSetting this property makes it possible to change the name under which an application is registered with the XML-RPC server. This means that the functions exposed via XML-RPC will have a "blogger" prefix. For instance a function called "newPost" will be XML-RPC callable as blogger.newPost instead of antville.newPost.
- -

Example Files

- -

- -

server.properties -
# Setting the extension for Helma action files: -
actionExtension = .hac -
-
# Allowing some ip addreses for web access: -
allowWeb = 192.168.0.*, 194.152.169.160 -
-
# Allowing some ip addreses for xml-rpc access: -
allowXmlRpc = 192.168.0.* -
-
# Setting the directory where Helma applications reside: -
appHome = /helma-1.2/apps -
-
# Setting the location of apps.properties: -
appsPropFile = /helma-1.2/propFiles -
-
# Setting the application's base uri: -
baseURI = /apps/testApp -
-
# Setting the size of Helma's cache memory: -
cachesize = 1000 -
-
# Setting the character encoding: -
charset = UTF8 -
-
# Setting the country code: -
country = AT -
-
# Setting the location of database files: -
dbHome = /etc/db/helma -
-
# Enabling debugging: -
debug = true -
-
# Enabling web access to .hsp templates: -
exposeTemplates = true -
-
# Setting the Helma working directory -
hopHome = /helma-1.2 -
-
# Setting the base value to create id numbers from: -
idBaseValue = 5000 -
-
# Setting the language code: -
language = de -
-
# Enabling database logging -
logSQL = true -
-
# Setting the maximum number of server threads: -
maxThreads = 12 -
-
# Enabling restricted web access to the Helma server: -
paranoid = true -
-
# Setting the duration after a request times out: -
requestTimeout = 60 -
-
# Setting the extension of JavaScript files: -
scriptExtension = .js -
-
# Setting the duration after an inactive session times out: -
sessionTimeout = 10 -
-
# Setting a smtp server: -
smtp = mail.server.dom -
-
# Setting a relational data source: -
sources = mySqlDB -
-
# Setting the extension of Helma templates: -
templateExtension = .hsp -
-
# Setting the server's timezone: -
timezone = GMT -
-
# Enabling the MinML xml parser: -
xmlparser = minml -
-
# Defining which application functions should be accessible via xml-rpc: -
XmlRpcAccess = weblog.getStory, weblog.showStatus -
-

Request Object

- -

- -

The request object represents the request coming from the client. It is accessible as a global variable called req. -

data

- -

- -

Syntax -
req.data.String;

Description -
Retrieves the corresponding value from the http request. The value can either come from a cookie, or from a "post" or "get" http request. Hop does not make any difference here. -
-
The following variables are automatically set by Helma if they are available:

  • HopSession -
    The id of the current hop session cookie
  • -
  • http_browser -
    Name and version of the client Browser
  • -
  • http_host -
    Name of the local server
  • -
  • http_remotehost -
    Internet address of the user
  • -
  • http_referer -
    URL of the page which linked the user to the current page
-req.get() provides exactly the same functionality in a what we think not as comfortable way (gotta type brackets and quotes). But it's just a matter of taste which one to use.

Example -
Here we see all three methods of setting a name, value pair: -
res.write("<form action=" + root.href("showValues") + " method="post"><input name="city"><input type="submit"></form>"); -
-
res.write("<form action=" + root.href("showValues") + " method="get"><input name="district"><input type="submit"></form>"); -
-
res.setCookie("street", "Lindengasse");
-
-
root/showValues.hac: -
res.write(req.data.city); -
res.write(req.data.district); -
res.write(req.data.street);
-
-
Note: If you have got a cookie and a form element with the same name sent by "get" or "post", the cookie value will be overridden by the form value. -
-
If you are very curious and want to see all the values sent by the http request, you can use the getReqData() function. -

get()

- -

- -

Syntax -
req.get(String)

Description -
Retrieves the corresponding value from the http request. The value can either come from a cookie, or from a "post" or "get" http request. Hop does not make any difference here. -
-
This is an alternative way of accessing request data to the req.data object. Please see the req.data documentation for more information.

Example -
res.write(req.get("http_remotehost")); -
127.0.0.1
-

path

- -

- -

Syntax -
req.path

Description -
returns the path of the current request

Example -
res.write(req.path); -
docs/reference/req/path
-

session

- -

- -

Syntax -
req.session

Description -
returns the Session ID of the current user

Example -
res.write(req.session); -
717163f187abf800@e4b40a0e88
-

Response Object

- -

- -

The response object represents the response to be sent back to the client. It is accessible as a global variable called res. -

body

- -

Deprectated property. - -

This property is deprecated and will not be supported in future releases of Helma. -
-
Use res.data instead, by attaching the appropriate property to it. -

cache

- -

- -

Syntax -
res.cache = Boolean

Description -
Specifies on a per-response base whether to allow client-side caching of the response or not. The default value is set to true, but can be changed globally by passing caching=false to the initial Helma java call. Please refer to the section about servlet properties for more details.

Example -
res.cache = true; -

charset

- -

Setting character encoding. - -

Syntax -
res.charset = CharsetString

Description -
Sets Helma's character encoding according to the list of supported encodings. By default, Helma uses ISO-8859-1 (western) encoding. It is also possible to set the encoding server or application wide using the charset property in the appropriate file.

Example -
res.charset = "UTF8"; -
res.write("ÄÖÜäöüß"); -
// this is displayed if the brower's encoding is set to "Western" -
ÄÖÜäöüß
-

contentType

- -

- -

Syntax -
res.contentType = ContentTypeString

Description -
The contentType of the http response can be set manually by changing the value of this Property. The default value is "text/html".

Example -
res.contentType="text/plain"; -
res.contentType="text/xml"; -

data

- -

- -

res.data can be used to attach any property propertyName onto it to make it available in a skin via <% response.propertyName %>. -
-
Example -
-
== root/main.hac -
res.data.title = "Test"; -
res.data.body = "Hello, World!"; -
root.renderSkin("main");
-
-
== root/main.skin -
<html> -
<head> -
  <title><% response.title %></title> -
</head> -
<body> -
-
<% response.body %> -
-
</body> -
</html>
-

encode()

- -

- -

Syntax -
res.encode(String)

Description -
Works similar to the global function encode() but writes the result directly to the response string buffer. Encodes a string by replacing linebreaks with <br> tags and diacritical characters as well as html tags with their equivalent html entities.

Example -
res.encode("<b>Bananer växer\n minsann inte på träd.<b>"); -
&lt;b&gt;Bananer v&auml;xer -
<br> minsann inte p&aring; tr&auml;d.&lt;/b&gt;
-

encodeXml()

- -

- -

Syntax -
res.encodeXml(String)

Description -
Works the same way as the global Function encodeXml(), but writes the result directly to the response string buffer.

Example -
res.encodeXml("<title>Smørebrød</title>"); -
&lt;title&gt;Sm&amp;oslash;rebr&amp;oslash;d&lt;/title&gt;
-

error

- -

Contains an internal Helma error message. - -

Syntax -
res.error

Description -
Contains a string describing an error if one should occur. If no error was detected, res.error contains an empty string. A good place for this function is a custom error page to display errors in a pretty layout.

Example -
res.write(res.error); -
Runtime error Syntax error detected near line 1, column 24, after in string starting with: 'function main_action (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {'...
-

format()

- -

- -

Syntax -
res.format(String);

Description -
Encodes a string similar to encode() but keeping the markup tags and trying to avoid <br> tags where possible (e.g. in table structures).

Example -
res.encode("<b>Bananer växer\n minsann inte på träd.<b>"); -
<b>Bananer v&auml;xer -
<br> minsann inte p&aring; tr&auml;d.</b>
-

head

- -

Deprectated property. - -

This property is deprecated and will not be supported in future releases of Helma. -
-
Use res.data instead, by attaching the appropriate property to it. -

message

- -

Buffer a string for output. - -

When this property is set, its value can be retrieved either by res.message from within an action or a JavaScript file or by <% response.message %> from within a skin file. -
-
Additionally, it will survive an HTTP redirect which can be necessary to display warnings or error messages to the user. The property's value will be cleared at latest after a redirected response was output. -

redirect()

- -

- -

Syntax -
res.redirect(UrlString);

Description -
Redirects the user to the specified url immediately. The JavaScript code following this command will not be processed anymore.

Example -
Here is a simple check using a hypothetic isAdmin() function to grant access to authorized people only: -
-
if (!user.isAdmin()) -
   res.redirect("/main");
-

reset()

- -

- -

Syntax -
res.reset();

Description -
Resets the current Response StringBuffer.

Example -
res.write("Writing something to the response"); -
// changing my mind (e.g. an error occured somewhere) -
res.reset(); -
res.write("Actually this is what I wanted to tell you: ..."); -
-
Actually this is what I wanted to tell you: ...
-

setCookie()

- -

- -

Syntax -
res.setCookie(KeyString, ValueString, NumberOfDays);

Description -
Sets a Cookie on the client machine. The third number argument is optional and specifies the number of days until the cookie expires.

Example -
The following can be used to "remember" users, and automatically log them in, when they return to your site. -
-
res.setCookie("username", "michi", 10); -
res.setCookie("password", "strenggeheim", 10);
-

title

- -

Deprectated property. - -

This property is deprecated and will not be supported in future releases of Helma. -
-
Use res.data instead, by attaching the appropriate property to it. -

write()

- -

Writes to the Response StringBuffer - -

Syntax -
res.write(String);

Description -
Transforms the passed argument to a string (only if necessary) and appends the result to the response string buffer. Throws an error if no argument or an undefined argument is passed.

Example -
var now = new Date(); -
res.write("current time: " + now); -
-
current time: Thu Feb 15 23:34:29 GMT+01:00 2001
-

writeBinary()

- -

- -

Syntax -
res.writeBinary(javaByteArray);

Description -
This function takes one argument, which must be a Java byte array. Useful when handling binary data retrieved via http file upload.

Example -
var upload = req.data.fileUpload; -
res.writeBinary(upload);
-

writeln()

- -

- -

Syntax -
res.writeln(string)

Description -
Transforms the passed argument to a string (only if necessary), appends an Html break <br> and appends the result to the response string buffer. Throws an error if no argument or an undefined argument is passed. Useful for debugging tasks.

Example -
res.writeln("Hello,"); -
res.write("World!"); -
Hello,<br> -
World!
-

Skin Object

- -

- -

-

allowMacro()

- -

- -

Syntax -
allowMacro(String)

Description -
This function is necessary to limit the range of allowed macros to be rendered to an explicit set. This is useful when text entered by non-trusted users is interpreted as skins to provide macro functions on a user-level.

Example -
Two macro functions defined in a JavaScript file: -
function isAllowed_macro() { -
  return("Hello"); -
} -
-
function isForbidden_macro() { -
  return("World"); -
}
-
-
The action that enables one of the macros: -
var str = "<% root.isAllowed %>, <% root.isForbidden %>!"; -
var skin = createSkin(str); -
// as soon as we call allowMacro() on a skin, only those -
// macros explicitely set are allowed to be evaluated. -
// all others will result in an error msg. -
skin.allowMacro("root.isAllowed"); -
renderSkin(skin); -
-
Hello, [Macro root.isForbidden not allowed in sandbox]!
-

containsMacro()

- -

- -

Syntax -
containsMacro(String)

Description -
This function checks whether a skin does contain the macro specified by the string parameter. This is thus useful to make sure a user-edited skin does not contain any macro with which the application would break.

Example -
var skin1 = createSkin("myMacro"); -
var skin2 = createSkin("<% myMacro %>"); -
res.writeln(skin1.containsMacro("myMacro")); -
false -
-
res.writeln(skin2.containsMacro("myMacro")); -
true
-

User Object

- -

- -

-

lastActive()

- -

Determine the last time of a certain user being logged in. - -

Syntax -
user.lastActive()

Description -
Returns a Date Object of the timestamp the current user was logged in the last time. Please note that you can use this function with the user prototype only, not with any user HopObject.

Example -
res.write(user.lastActive()) -
Thu Nov 02 16:12:13 GMT+01:00 2000
-

login()

- -

- -

Syntax -
UserObject.login(UserNameString, PasswordString)

Description -
Returns true if the user name / password pair match the stored values in the database. Otherwise it returns false.

Example -
var login = user.login("user", "pass"); -
if (login) -
   res.write("Welcome back!"); -
else -
   res.write("Oops, please try again..."); -
-
Welcome back!
-

onSince()

- -

- -

Syntax -
userObject.onSince()

Description -
Returns the date string of the time the user's session was started.

Example -
var usr = getUser("Tobi"); -
res.write(usr.onSince()); -
Fri Aug 10 16:36:36 GMT+02:00 2001
-

register()

- -

- -

Syntax -
userObject.register(usernameString, passwordString)

Description -
Stores this user in the database using two arguments as user name and password phrase. Returns a valid user HopObject if the transaction was successful, false otherwise (e.g. if a user HopObject with the same name already exists). Additional properties can be attached to the user HopObject the usual way, then.

Example -
var newUser = user.register("snoopy", "woodstock"); -
res.write(newUser); -
HopObject snoopy -
-
newUser.email = "snoopy@peanuts.com"; -
newUser.fullname = "Snoop Doggy Dogg";
-

touch()

- -

- -

Syntax -
UserObject.touch()

Description -
Refreshes the user's session, moving its expiration date to now plus session timeout unless it is "touched" again either by the user requesting a page or calling touch().

Example -
var usr = getUser("tobi"); -
usr.touch();
-

uid

- -

- -

Syntax -
UserObject.uid

Description -
Returns the database-internal id of the current user. If the user is logged into the application uid is set, otherwise it is null.

Example -
res.writeln(user); -
res.writeln(user.uid); -
TransientNode [session cache] -
null
-
-
res.writeln(user); -
res.writeln(user.uid); -
HopObject tobi -
tobi
-

XML and HTML Parsing

- -

- -

Syntax -
getXmlDocument(XmlString) -
getXmlDocument(UrlString) -
getXmlDocument(java.io.InputStream) -
getXmlDocument(java.io.Reader) -
-
getHtmlDocument(HtmlString) -
getHtmlDocument(UrlString) -
getHtmlDocument(java.io.InputStream) -
getHtmlDocument(java.io.Reader) -
-
jdomize(DomDocument)

Description -
The Xml and Html parsing functions take one parameter and try to parse it into a Dom document object. If the document could not be retrieved or contains invalid markup, the functions return null. -
-
The Dom object can be processed according to the Java language binding for Dom Level 1. -
-
Be sure to update your Helma 1.x installation with the patched openxml.jar file for this to work. -
-
As an alternative to the W3C Dom Api, Dom documents may be transformed into JDOM documents using the global jdomize() function. JDom documents are far easier to handle than Dom documents. Be sure to have the jdom.jar file in your classpath for this to work.

Example -
This .hac file fetches an Xml document containing news headlines and generates some simple Html output. -
-
var xmltext = getXmlDocument("http://www.salon.at/news/lxml"); -
if (xmltext == null) -
 res.write("Error retrieving Xml document!"); -
else { -
 var newslist = xmltext.firstChild.childNodes; -
 for (var i=0; i<newslist.length; i++) { -
  var newsitem = newslist.item(i); -
  // make sure we only look at <headline> elements, -
  // ignoring whitespace CDATA -
  if (newsitem.nodeName == "headline") { -
   // get the <title> element -
   var titleElem = newsitem.getElementsByTagName("title").item(0); -
   // get the character data contained in it -
   var title = titleElem.firstChild.nodeValue; -
   // get the <url> element -
   var urlElem = newsitem.getElementsByTagName("url").item(0); -
   // get the actual url character data -
   var url = urlElem.firstChild.nodeValue -
   res.write ("<a href='"+url+"'>"+encode(title)+"</a><br>"); -
  } -
 } -
}
-

XML-RPC

- -

- -

Remote procedure calls via Xml-Rpc are very straightforward with the Hop for both client and server side. -

XML-RPC Client

- -

- -

Description -
Xml-Rpc calls are performed using a Remote object. Remote objects are created with the Url of the Xml-Rpc service. Functions of the remote Xml-Rpc service can then be called just like local functions. -
-
To compensate for the missing exception handling, Remote objects return result wrappers which contain either the result of the remote function, or a description of the error if one occurred. -
-
Example -
var xr = new Remote("http://helma.domain.tld:5056/"); -
var msg1 = xr.helmaorg.getXmlRpcMessage(); -
if (msg1.error) -
   res.write(msg1.error); -
else -
   res.write(msg1.result); -
-
Hello, Xml-Rpc World! -
-
var msg2 = xr.hotelGuide.hotels.grandimperial.getXmlRpcMessage(); -
if (!msg2.error) -
   res.write(msg2.result); -
-
Welcome to the Grand Imperial Hotel, Vienna! -
-
var msg3 = xr.kolin.document.comments["23"].getXmlRpcMessage(); -
if (!msg3.error) -
   res.write(msg3.result); -
-
Here you can write your comments. -
-
var xr = new Remote("http://betty.userland.com/RPC2"); -
var state = xr.examples.getStateName(23); -
if (!state.error) -
   res.write(state.result); -
-
Minnesota
-
-

XML-RPC Server

- -

- -

Description -
The Helma Xml-Rpc server is running on port 5056 by default, or port+1 if the -p command line parameter is specified. -
-
You can make any Helma function callable via Xml-Rpc. To do so, the function needs to be added to the XmlRpcAccess property in the app.properties file. -
-
For example, if you have two functions, listThings() and addThing(), in the root prototype you want to call via Xml-Rpc, add the following line to the app.properties file of your application: -
-
XmlRpcAccess = root.listThings, myprototype.addThing -
-
Xml-Rpc function names have the application name as first element followed by an optional object path within the application and the actual function name. Thus, a function called sayHello() in the root directory of an application called myapp would result in an Xml-Rpc function name of myapp.sayHello. -
-
There are a few things to consider when working with server side Xml-Rpc:

  • There is no Helma user object associated with an Xml-Rpc request.

  • -
  • There is no request object associated with an Xml-Rpc request.

  • -
  • You can pass any primitive Javascript types as parameters as well as objects and arrays, but should not pass a persistent HopObject directly as parameter or return value. Xml-Rpc can't handle objects with circular references, i.e. if obj1 has a reference to obj2, obj2 must not have a reference to obj1.
- - - - - - diff --git a/hop.bat b/hop.bat deleted file mode 100755 index 06771c62..00000000 --- a/hop.bat +++ /dev/null @@ -1,79 +0,0 @@ -@echo off -rem Batch file for Starting Helma with a JDK-like virtual machine. - -rem To add jar files to the classpath, simply place them into the -rem lib/ext directory of this Helma installation. - -:: Initialize variables -:: (don't touch this section) -set JAVA_HOME= -set HOP_HOME= -set HTTP_PORT= -set XMLRPC_PORT= -set AJP13_PORT= -set RMI_PORT= -set OPTIONS= - -:: Set TCP ports for Helma servers -:: (comment/uncomment to de/activate) -set HTTP_PORT=8080 -rem set XMLRPC_PORT=8081 -rem set AJP13_PORT=8009 -rem set RMI_PORT=5050 - -:: Uncomment to set HOP_HOME -rem set HOP_HOME=c:\program files\helma - -:: Uncomment to set JAVA_HOME variable -rem set JAVA_HOME=c:\program files\java - -:: Uncomment to pass options to the Java virtual machine -rem set JAVA_OPTIONS=-server -Xmx128m - -::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:::::: No user configuration needed below this line ::::::: -::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -:: Setting the script path -set INSTALL_DIR=%~d0%~p0 - -:: Using JAVA_HOME variable if defined. Otherwise, -:: Java executable must be contained in PATH variable -if "%JAVA_HOME%"=="" goto default - set JAVACMD=%JAVA_HOME%\bin\java - goto end -:default - set JAVACMD=java -:end - -:: Setting HOP_HOME to script path if undefined -if "%HOP_HOME%"=="" ( - set HOP_HOME=%INSTALL_DIR% -) -cd %HOP_HOME% - - -:: Setting Helma server options -if not "%HTTP_PORT%"=="" ( - echo Starting HTTP server on port %HTTP_PORT% - set OPTIONS=%OPTIONS% -w %HTTP_PORT% -) -if not "%XMLRPC_PORT%"=="" ( - echo Starting XML-RPC server on port %XMLRPC_PORT% - set OPTIONS=%OPTIONS% -x %XMLRPC_PORT% -) -if not "%AJP13_PORT%"=="" ( - echo Starting AJP13 listener on port %AJP13_PORT% - set OPTIONS=%OPTIONS% -jk %AJP13_PORT% -) -if not "%RMI_PORT%"=="" ( - echo Starting RMI server on port %RMI_PORT% - set OPTIONS=%OPTIONS% -p %RMI_PORT% -) -if not "%HOP_HOME%"=="" ( - echo Serving applications from %HOP_HOME% - set OPTIONS=%OPTIONS% -h "%HOP_HOME% -) - -:: Invoking the Java virtual machine -%JAVACMD% %JAVA_OPTIONS% -jar "%INSTALL_DIR%\launcher.jar" %OPTIONS% diff --git a/hop.sh b/hop.sh deleted file mode 100755 index 1ee2af9a..00000000 --- a/hop.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/sh -# Shell script for starting Helma with a JDK-like virtual machine. - -# To add JAR files to the classpath, simply place them into the -# lib/ext directory. - -# uncomment to set JAVA_HOME variable -# JAVA_HOME=/usr/lib/java - -# uncomment to set HOP_HOME, otherwise we get it from the script path -# HOP_HOME=/usr/local/helma - -# options to pass to the Java virtual machine -# JAVA_OPTIONS="-server -Xmx128m" - -# Set TCP ports for Helma servers -# (comment/uncomment to de/activate) -HTTP_PORT=8080 -# XMLRPC_PORT=8081 -# AJP13_PORT=8009 -# RMI_PORT=5050 - -########################################################### -###### No user configuration needed below this line ####### -########################################################### - -# if JAVA_HOME variable is set, use it. Otherwise, Java executable -# must be contained in PATH variable. -if [ "$JAVA_HOME" ]; then - JAVACMD="$JAVA_HOME/bin/java" -else - JAVACMD=java -fi - -# Check if java command is executable -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." - echo " We cannot execute $JAVACMD" - exit -fi - -# Get the Helma installation directory -INSTALL_DIR="${0%/*}" -cd $INSTALL_DIR -INSTALL_DIR=$PWD - -# get HOP_HOME variable if it isn't set -if [ -z "$HOP_HOME" ]; then - # try to get HOP_HOME from script file and pwd - # strip everyting behind last slash - HOP_HOME="${0%/*}" - cd $HOP_HOME - HOP_HOME=$PWD -else - cd $HOP_HOME -fi -echo "Starting Helma in directory $HOP_HOME" - -if [ "$HTTP_PORT" ]; then - SWITCHES="$SWITCHES -w $HTTP_PORT" - echo Starting HTTP server on port $HTTP_PORT -fi -if [ "$XMLRPC_PORT" ]; then - SWITCHES="$SWITCHES -x $XMLRPC_PORT" - echo Starting XML-RPC server on port $XMLRPC_PORT -fi -if [ "$AJP13_PORT" ]; then - SWITCHES="$SWITCHES -jk $AJP13_PORT" - echo Starting AJP13 listener on port $AJP13_PORT -fi -if [ "$RMI_PORT" ]; then - SWITCHES="$SWITCHES -p $RMI_PORT" - echo Starting RMI server on port $RMI_PORT -fi -if [ "$HOP_HOME" ]; then - SWITCHES="$SWITCHES -h $HOP_HOME" -fi - -# Invoke the Java VM -$JAVACMD $JAVA_OPTIONS -jar "$INSTALL_DIR/launcher.jar" $SWITCHES diff --git a/lib/activation.jar b/lib/activation.jar deleted file mode 100644 index db4b1fb5..00000000 Binary files a/lib/activation.jar and /dev/null differ diff --git a/lib/apache-dom.jar b/lib/apache-dom.jar deleted file mode 100644 index e1e980a0..00000000 Binary files a/lib/apache-dom.jar and /dev/null differ diff --git a/lib/crimson.jar b/lib/crimson.jar deleted file mode 100644 index 42658472..00000000 Binary files a/lib/crimson.jar and /dev/null differ diff --git a/lib/ext/rhino.jar b/lib/ext/rhino.jar deleted file mode 100644 index d8dd327d..00000000 Binary files a/lib/ext/rhino.jar and /dev/null differ diff --git a/lib/jdom.jar b/lib/jdom.jar deleted file mode 100644 index 7ccb9fda..00000000 Binary files a/lib/jdom.jar and /dev/null differ diff --git a/lib/jetty.jar b/lib/jetty.jar deleted file mode 100644 index 2304e01a..00000000 Binary files a/lib/jetty.jar and /dev/null differ diff --git a/lib/jimi.jar b/lib/jimi.jar deleted file mode 100644 index 8bed0837..00000000 Binary files a/lib/jimi.jar and /dev/null differ diff --git a/lib/mail.jar b/lib/mail.jar deleted file mode 100644 index eb2269d7..00000000 Binary files a/lib/mail.jar and /dev/null differ diff --git a/lib/netcomponents.jar b/lib/netcomponents.jar deleted file mode 100644 index 21ce702d..00000000 Binary files a/lib/netcomponents.jar and /dev/null differ diff --git a/lib/servlet.jar b/lib/servlet.jar deleted file mode 100644 index d2f0db9d..00000000 Binary files a/lib/servlet.jar and /dev/null differ diff --git a/lib/xmlrpc.jar b/lib/xmlrpc.jar deleted file mode 100644 index b360b037..00000000 Binary files a/lib/xmlrpc.jar and /dev/null differ diff --git a/license.txt b/license.txt deleted file mode 100644 index 5b5e251b..00000000 --- a/license.txt +++ /dev/null @@ -1,49 +0,0 @@ - Copyright (c) 1999-2002 Helma Project. 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. - - 3. Products derived from this software may not be called "Helma" - or "Hop", nor may "Helma" or "Hop" appear in their name, without - prior written permission of the Helma Project Group. For written - permission, please contact helma@helma.org. - - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 HELMA PROJECT OR ITS - 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. - -This product contains the FESI EcmaScript interpreter written by -Jean-Marc Lugrin (http://home.worldcom.ch/jmlugrin/fesi/). FESI is -released under the GNU Lesser General Public License (see licenses/lesser.txt). - -This product contains software from the Acme package written by Jef -Poskanzer. Please see the licensing terms in the Acme source code and check out -Jef's site at http://www.acme.com/. - -This product includes software developed by the Apache Software Foundation -released under the Apache Software License (licenses/apache.txt). - -This product includes software developed by the JDOM Project -(http://www.jdom.org/). Please see the licensing terms in licenses/jdom.txt - -This product includes software developed by the Word Wide Web Consortium -(http://www.w3c.org/). Please see the licensing terms in licenses/w3c.html. diff --git a/licenses/apache.txt b/licenses/apache.txt deleted file mode 100644 index b37087c5..00000000 --- a/licenses/apache.txt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * The Apache Software License, Version 1.1 - * - * - * Copyright (c) 1999 The Apache Software Foundation. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Xerces" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.ibm.com. For more - * information on the Apache Software Foundation, please see - * . - */ diff --git a/licenses/jdom.txt b/licenses/jdom.txt deleted file mode 100644 index 2aad34f0..00000000 --- a/licenses/jdom.txt +++ /dev/null @@ -1,56 +0,0 @@ -/*-- - - $Id$ - - Copyright (C) 2000-2002 Brett McLaughlin & Jason Hunter. - 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 disclaimer that follows - these conditions in the documentation and/or other materials - provided with the distribution. - - 3. The name "JDOM" must not be used to endorse or promote products - derived from this software without prior written permission. For - written permission, please contact license@jdom.org. - - 4. Products derived from this software may not be called "JDOM", nor - may "JDOM" appear in their name, without prior written permission - from the JDOM Project Management (pm@jdom.org). - - In addition, we request (but do not require) that you include in the - end-user documentation provided with the redistribution and/or in the - software itself an acknowledgement equivalent to the following: - "This product includes software developed by the - JDOM Project (http://www.jdom.org/)." - Alternatively, the acknowledgment may be graphical using the logos - available at http://www.jdom.org/images/logos. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JDOM AUTHORS OR THE PROJECT - 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. - - This software consists of voluntary contributions made by many - individuals on behalf of the JDOM Project and was originally - created by Brett McLaughlin and - Jason Hunter . For more information on the - JDOM Project, please see . - - */ - diff --git a/licenses/lesser.txt b/licenses/lesser.txt deleted file mode 100644 index b1e3f5a2..00000000 --- a/licenses/lesser.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/licenses/sun-javamail.txt b/licenses/sun-javamail.txt deleted file mode 100644 index 6984ddb7..00000000 --- a/licenses/sun-javamail.txt +++ /dev/null @@ -1,170 +0,0 @@ - Sun Microsystems, Inc. - Binary Code License Agreement - -READ THE TERMS OF THIS AGREEMENT AND ANY PROVIDED SUPPLEMENTAL LICENSE TERMS -(COLLECTIVELY "AGREEMENT") CAREFULLY BEFORE OPENING THE SOFTWARE MEDIA -PACKAGE. BY OPENING THE SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF -THIS AGREEMENT. IF YOU ARE ACCESSING THE SOFTWARE ELECTRONICALLY, INDICATE -YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" BUTTON AT THE END -OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL THESE TERMS, PROMPTLY RETURN -THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF THE -SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DECLINE" BUTTON AT THE END -OF THIS AGREEMENT. - -1. LICENSE TO USE. Sun grants you a non-exclusive and non-transferable -license for the internal use only of the accompanying software and -documentation and any error corrections provided by Sun (collectively -"Software"), by the number of users and the class of computer hardware for -which the corresponding fee has been paid. - -2. RESTRICTIONS. Software is confidential and copyrighted. Title to -Software and all associated intellectual property rights is retained by Sun -and/or its licensors. Except as specifically authorized in any Supplemental -License Terms, you may not make copies of Software, other than a single copy -of Software for archival purposes. Unless enforcement is prohibited by -applicable law, you may not modify, decompile, or reverse engineer -Software. You acknowledge that Software is not designed, licensed or -intended for use in the design, construction, operation or maintenance of -any nuclear facility. Sun disclaims any express or implied warranty of -fitness for such uses. No right, title or interest in or to any trademark, -service mark, logo or trade name of Sun or its licensors is granted under -this Agreement. - -3. LIMITED WARRANTY. Sun warrants to you that for a period of ninety (90) -days from the date of purchase, as evidenced by a copy of the receipt, the -media on which Software is furnished (if any) will be free of defects in -materials and workmanship under normal use. Except for the foregoing, -Software is provided "AS IS". Your exclusive remedy and Sun's entire -liability under this limited warranty will be at Sun's option to replace -Software media or refund the fee paid for Software. - -4. DISCLAIMER OF WARRANTY. UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS -OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED -WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR -NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS -ARE HELD TO BE LEGALLY INVALID. - -5. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO -EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR -DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE -DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT -OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's -liability to you, whether in contract, tort (including negligence), or -otherwise, exceed the amount paid by you for Software under this Agreement. -The foregoing limitations will apply even if the above stated warranty fails -of its essential purpose. - -6. Termination. This Agreement is effective until terminated. You may -terminate this Agreement at any time by destroying all copies of Software. -This Agreement will terminate immediately without notice from Sun if you -fail to comply with any provision of this Agreement. Upon Termination, you -must destroy all copies of Software. - -7. Export Regulations. All Software and technical data delivered under this -Agreement are subject to US export control laws and may be subject to export -or import regulations in other countries. You agree to comply strictly with -all such laws and regulations and acknowledge that you have the -responsibility to obtain such licenses to export, re-export, or import as -may be required after delivery to you. - -8. U.S. Government Restricted Rights. If Software is being acquired by or -on behalf of the U.S. Government or by a U.S. Government prime contractor or -subcontractor (at any tier), then the Government's rights in Software and -accompanying documentation will be only as set forth in this Agreement; this -is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of -Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD -acquisitions). - -9. Governing Law. Any action related to this Agreement will be governed by -California law and controlling U.S. federal law. No choice of law rules of -any jurisdiction will apply. - -10. Severability. If any provision of this Agreement is held to be -unenforceable, this Agreement will remain in effect with the provision -omitted, unless omission would frustrate the intent of the parties, in which -case this Agreement will immediately terminate. - -11. Integration. This Agreement is the entire agreement between you and -Sun relating to its subject matter. It supersedes all prior or -contemporaneous oral or written communications, proposals, representations -and warranties and prevails over any conflicting or additional terms of any -quote, order, acknowledgment, or other communication between the parties -relating to its subject matter during the term of this Agreement. No -modification of this Agreement will be binding, unless in writing and signed -by an authorized representative of each party. - - - - JAVAMAIL, VERSION 1.2 - SUPPLEMENTAL LICENSE TERMS - -These supplemental license terms ("Supplemental Terms") add to or modify the -terms of the Binary Code License Agreement (collectively, the "Agreement"). -Capitalized terms not defined in these Supplemental Terms shall have the -same meanings ascribed to them in the Agreement. These Supplemental Terms -shall supersede any inconsistent or conflicting terms in the Agreement, or -in any license contained within the Software. - -1. Software Internal Use and Development License Grant. Subject to the -terms and conditions of this Agreement, including, but not limited to -Section 3 (Java(TM) Technology Restrictions) of these Supplemental Terms, -Sun grants you a non-exclusive, non-transferable, limited license to -reproduce internally and use internally the binary form of the Software, -complete and unmodified, for the sole purpose of designing, developing and -testing your Java applets and applications ("Programs"). - -2. License to Distribute Software. Subject to the terms and conditions of -this Agreement, including, but not limited to Section 3 (Java (TM) -Technology Restrictions) of these Supplemental Terms, Sun grants you a -non-exclusive, non-transferable, limited license to reproduce and distribute -the Software in binary code form only, provided that (i) you distribute the -Software complete and unmodified and only bundled as part of, and for the -sole purpose of running, your Java applets or applications ("Programs"), -(ii) the Programs add significant and primary functionality to the Software, -(iii) you do not distribute additional software intended to replace any -component(s) of the Software, (iv) you do not remove or alter any -proprietary legends or notices contained in the Software, (v) you only -distribute the Software subject to a license agreement that protects Sun's -interests consistent with the terms contained in this Agreement, and (vi) -you agree to defend and indemnify Sun and its licensors from and against any -damages, costs, liabilities, settlement amounts and/or expenses (including -attorneys' fees) incurred in connection with any claim, lawsuit or action by -any third party that arises or results from the use or distribution of any -and all Programs and/or Software. - -3. Java Technology Restrictions. You may not modify the Java Platform -Interface ("JPI", identified as classes contained within the "java" package -or any subpackages of the "java" package), by creating additional classes -within the JPI or otherwise causing the addition to or modification of the -classes in the JPI. In the event that you create an additional class and -associated API(s) which (i) extends the functionality of the Java platform, -and (ii) is exposed to third party software developers for the purpose of -developing additional software which invokes such additional API, you must -promptly publish broadly an accurate specification for such API for free use -by all developers. You may not create, or authorize your licensees to -create additional classes, interfaces, or subpackages that are in any way -identified as "java", "javax", "sun" or similar convention as specified by -Sun in any naming convention designation. - -4. Trademarks and Logos. You acknowledge and agree as between you and Sun -that Sun owns the SUN, SOLARIS, JAVA, JINI, FORTE, STAROFFICE, STARPORTAL -and iPLANET trademarks and all SUN, SOLARIS, JAVA, JINI, FORTE, STAROFFICE, -STARPORTAL and iPLANET-related trademarks, service marks, logos and other -brand designations ("Sun Marks"), and you agree to comply with the Sun -Trademark and Logo Usage Requirements currently located at -http://www.sun.com/policies/trademarks. Any use you make of the Sun Marks -inures to Sun's benefit. - -5. Source Code. Software may contain source code that is provided solely for -reference purposes pursuant to the terms of this Agreement. Source code may -not be redistributed unless expressly provided for in this Agreement. - -6. Termination for Infringement. Either party may terminate this Agreement -immediately should any Software become, or in either party's opinion be -likely to become, the subject of a claim of infringement of any intellectual -property right. - -For inquiries please contact: Sun Microsystems, Inc. 901 San Antonio Road, -Palo Alto, California 94303 - diff --git a/licenses/w3c.html b/licenses/w3c.html deleted file mode 100644 index 26049b75..00000000 --- a/licenses/w3c.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - W3C IPR SOFTWARE NOTICE - - -

- W3C IPR SOFTWARE NOTICE -

-

- Copyright © 2000 World Wide Web - Consortium, (Massachusetts - Institute of Technology, Institut - National de Recherche en Informatique et en Automatique, Keio University). All Rights - Reserved. -

-

- The DOM bindings are published under the W3C Software Copyright Notice - and License. The software license requires "Notice of any changes or - modifications to the W3C files, including the date changes were made." - Consequently, modified versions of the DOM bindings must document that - they do not conform to the W3C standard; in the case of the IDL binding, - the pragma prefix can no longer be 'w3c.org'; in the case of the Java - binding, the package names can no longer be in the 'org.w3c' package. -

-

- Note: The original version of the W3C Software Copyright Notice - and License could be found at http://www.w3.org/Consortium/Legal/copyright-software-19980720 -

-

- Copyright © 1994-2000 World Wide Web - Consortium, (Massachusetts - Institute of Technology, Institut - National de Recherche en Informatique et en Automatique, Keio University). All Rights - Reserved. http://www.w3.org/Consortium/Legal/ -

-

- This W3C work (including software, documents, or other related items) is - being provided by the copyright holders under the following license. By - obtaining, using and/or copying this work, you (the licensee) agree that - you have read, understood, and will comply with the following terms and - conditions: -

-

- Permission to use, copy, and modify this software and its documentation, - with or without modification,  for any purpose and without fee or - royalty is hereby granted, provided that you include the following on ALL - copies of the software and documentation or portions thereof, including - modifications, that you make: -

-
    -
  1. - The full text of this NOTICE in a location viewable to users of the - redistributed or derivative work. -
  2. -
  3. - Any pre-existing intellectual property disclaimers, notices, or terms - and conditions. If none exist, a short notice of the following form - (hypertext is preferred, text is permitted) should be used within the - body of any redistributed or derivative code: "Copyright © - [$date-of-software] World Wide Web - Consortium, (Massachusetts - Institute of Technology, Institut - National de Recherche en Informatique et en Automatique, Keio University). All Rights - Reserved. http://www.w3.org/Consortium/Legal/" -
  4. -
  5. - Notice of any changes or modifications to the W3C files, including the - date changes were made. (We recommend you provide URIs to the location - from which the code is derived.) -
  6. -
-

- THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT - HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS - FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR - DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, - TRADEMARKS OR OTHER RIGHTS. -

-

- COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR - CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR - DOCUMENTATION. -

-

- The name and trademarks of copyright holders may NOT be used in - advertising or publicity pertaining to the software without specific, - written prior permission. Title to copyright in this software and any - associated documentation will at all times remain with copyright - holders. -

- - diff --git a/server.properties b/server.properties deleted file mode 100644 index ce1ef12f..00000000 --- a/server.properties +++ /dev/null @@ -1,27 +0,0 @@ -# The SMTP server to use for sending mails. Set and -# uncomment this line before trying to send mails from -# Helma applications. -# -# smtp=mail.yourdomain.com - - -# Some examples for server-wide locale settings -# (please refer to http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html -# for country codes, resp. http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt -# for language codes). -# -# country = AT -# language = de -# -# country = UK -# language = en -# -# country = FR -# language = fr -# -# country = CZ -# language = cs - -# list ip addresses for admin-application here: -allowAdmin=127.0.0.1, 192.168.0.1 - diff --git a/src/Acme/IntHashtable.java b/src/Acme/IntHashtable.java deleted file mode 100644 index a4dcae34..00000000 --- a/src/Acme/IntHashtable.java +++ /dev/null @@ -1,396 +0,0 @@ -// IntHashtable - a Hashtable that uses ints as the keys -// -// This is 90% based on JavaSoft's java.util.Hashtable. -// -// Visit the ACME Labs Java page for up-to-date versions of this and other -// fine Java utilities: http://www.acme.com/java/ - -package Acme; - -import java.util.*; - -/// A Hashtable that uses ints as the keys. -//

-// Use just like java.util.Hashtable, except that the keys must be ints. -// This is much faster than creating a new Integer for each access. -//

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

-// @see java.util.Hashtable - -public class IntHashtable extends Dictionary implements Cloneable - { - /// The hash table data. - private IntHashtableEntry table[]; - - /// The total number of entries in the hash table. - private int count; - - /// Rehashes the table when count exceeds this threshold. - private int threshold; - - /// The load factor for the hashtable. - private float loadFactor; - - /// Constructs a new, empty hashtable with the specified initial - // capacity and the specified load factor. - // @param initialCapacity the initial number of buckets - // @param loadFactor a number between 0.0 and 1.0, it defines - // the threshold for rehashing the hashtable into - // a bigger one. - // @exception IllegalArgumentException If the initial capacity - // is less than or equal to zero. - // @exception IllegalArgumentException If the load factor is - // less than or equal to zero. - public IntHashtable( int initialCapacity, float loadFactor ) - { - if ( initialCapacity <= 0 || loadFactor <= 0.0 ) - throw new IllegalArgumentException(); - this.loadFactor = loadFactor; - table = new IntHashtableEntry[initialCapacity]; - threshold = (int) ( initialCapacity * loadFactor ); - } - - /// Constructs a new, empty hashtable with the specified initial - // capacity. - // @param initialCapacity the initial number of buckets - public IntHashtable( int initialCapacity ) - { - this( initialCapacity, 0.75f ); - } - - /// Constructs a new, empty hashtable. A default capacity and load factor - // is used. Note that the hashtable will automatically grow when it gets - // full. - public IntHashtable() - { - this( 101, 0.75f ); - } - - /// Returns the number of elements contained in the hashtable. - public int size() - { - return count; - } - - /// Returns true if the hashtable contains no elements. - public boolean isEmpty() - { - return count == 0; - } - - /// Returns an enumeration of the hashtable's keys. - // @see IntHashtable#elements - public synchronized Enumeration keys() - { - return new IntHashtableEnumerator( table, true ); - } - - /// Returns an enumeration of the elements. Use the Enumeration methods - // on the returned object to fetch the elements sequentially. - // @see IntHashtable#keys - public synchronized Enumeration elements() - { - return new IntHashtableEnumerator( table, false ); - } - - /// Returns true if the specified object is an element of the hashtable. - // This operation is more expensive than the containsKey() method. - // @param value the value that we are looking for - // @exception NullPointerException If the value being searched - // for is equal to null. - // @see IntHashtable#containsKey - public synchronized boolean contains( Object value ) - { - if ( value == null ) - throw new NullPointerException(); - IntHashtableEntry tab[] = table; - for ( int i = tab.length ; i-- > 0 ; ) - { - for ( IntHashtableEntry e = tab[i] ; e != null ; e = e.next ) - { - if ( e.value.equals( value ) ) - return true; - } - } - return false; - } - - /// Returns true if the collection contains an element for the key. - // @param key the key that we are looking for - // @see IntHashtable#contains - public synchronized boolean containsKey( int key ) - { - IntHashtableEntry tab[] = table; - int hash = key; - int index = ( hash & 0x7FFFFFFF ) % tab.length; - for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) - { - if ( e.hash == hash && e.key == key ) - return true; - } - return false; - } - - /// Gets the object associated with the specified key in the - // hashtable. - // @param key the specified key - // @returns the element for the key or null if the key - // is not defined in the hash table. - // @see IntHashtable#put - public synchronized Object get( int key ) - { - IntHashtableEntry tab[] = table; - int hash = key; - int index = ( hash & 0x7FFFFFFF ) % tab.length; - for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) - { - if ( e.hash == hash && e.key == key ) - return e.value; - } - return null; - } - - /// A get method that takes an Object, for compatibility with - // java.util.Dictionary. The Object must be an Integer. - public Object get( Object okey ) - { - if ( ! ( okey instanceof Integer ) ) - throw new InternalError( "key is not an Integer" ); - Integer ikey = (Integer) okey; - int key = ikey.intValue(); - return get( key ); - } - - /// Rehashes the content of the table into a bigger table. - // This method is called automatically when the hashtable's - // size exceeds the threshold. - protected void rehash() - { - int oldCapacity = table.length; - IntHashtableEntry oldTable[] = table; - - int newCapacity = oldCapacity * 2 + 1; - IntHashtableEntry newTable[] = new IntHashtableEntry[newCapacity]; - - threshold = (int) ( newCapacity * loadFactor ); - table = newTable; - - for ( int i = oldCapacity ; i-- > 0 ; ) - { - for ( IntHashtableEntry old = oldTable[i] ; old != null ; ) - { - IntHashtableEntry e = old; - old = old.next; - - int index = ( e.hash & 0x7FFFFFFF ) % newCapacity; - e.next = newTable[index]; - newTable[index] = e; - } - } - } - - /// Puts the specified element into the hashtable, 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. - // @param key the specified key in the hashtable - // @param value the specified element - // @exception NullPointerException If the value of the element - // is equal to null. - // @see IntHashtable#get - // @return the old value of the key, or null if it did not have one. - public synchronized Object put( int key, Object value ) - { - // Make sure the value is not null. - if ( value == null ) - throw new NullPointerException(); - - // Makes sure the key is not already in the hashtable. - IntHashtableEntry tab[] = table; - int hash = key; - int index = ( hash & 0x7FFFFFFF ) % tab.length; - for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) - { - if ( e.hash == hash && e.key == key ) - { - Object old = e.value; - e.value = value; - return old; - } - } - - if ( count >= threshold ) - { - // Rehash the table if the threshold is exceeded. - rehash(); - return put( key, value ); - } - - // Creates the new entry. - IntHashtableEntry e = new IntHashtableEntry(); - e.hash = hash; - e.key = key; - e.value = value; - e.next = tab[index]; - tab[index] = e; - ++count; - return null; - } - - /// A put method that takes an Object, for compatibility with - // java.util.Dictionary. The Object must be an Integer. - public Object put( Object okey, Object value ) - { - if ( ! ( okey instanceof Integer ) ) - throw new InternalError( "key is not an Integer" ); - Integer ikey = (Integer) okey; - int key = ikey.intValue(); - return put( key, value ); - } - - /// 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( int key ) - { - IntHashtableEntry tab[] = table; - int hash = key; - int index = ( hash & 0x7FFFFFFF ) % tab.length; - for ( IntHashtableEntry e = tab[index], prev = null ; e != null ; prev = e, e = e.next ) - { - if ( e.hash == hash && e.key == key ) - { - if ( prev != null ) - prev.next = e.next; - else - tab[index] = e.next; - --count; - return e.value; - } - } - return null; - } - - /// A remove method that takes an Object, for compatibility with - // java.util.Dictionary. The Object must be an Integer. - public Object remove( Object okey ) - { - if ( ! ( okey instanceof Integer ) ) - throw new InternalError( "key is not an Integer" ); - Integer ikey = (Integer) okey; - int key = ikey.intValue(); - return remove( key ); - } - - /// Clears the hash table so that it has no more elements in it. - public synchronized void clear() - { - IntHashtableEntry tab[] = table; - for ( int index = tab.length; --index >= 0; ) - tab[index] = null; - count = 0; - } - - /// Creates a clone of the hashtable. A shallow copy is made, - // the keys and elements themselves are NOT cloned. This is a - // relatively expensive operation. - public synchronized Object clone() - { - try - { - IntHashtable t = (IntHashtable) super.clone(); - t.table = new IntHashtableEntry[table.length]; - for ( int i = table.length ; i-- > 0 ; ) - t.table[i] = ( table[i] != null ) ? - (IntHashtableEntry) table[i].clone() : null; - return t; - } - catch ( CloneNotSupportedException e) - { - // This shouldn't happen, since we are Cloneable. - throw new InternalError(); - } - } - - /// Converts to a rather lengthy String. - public synchronized String toString() - { - int max = size() - 1; - StringBuffer buf = new StringBuffer(); - Enumeration k = keys(); - Enumeration e = elements(); - buf.append( "{" ); - - for ( int i = 0; i <= max; ++i ) - { - String s1 = k.nextElement().toString(); - String s2 = e.nextElement().toString(); - buf.append( s1 + "=" + s2 ); - if ( i < max ) - buf.append( ", " ); - } - buf.append( "}" ); - return buf.toString(); - } - } - - -class IntHashtableEntry - { - int hash; - int key; - Object value; - IntHashtableEntry next; - - protected Object clone() - { - IntHashtableEntry entry = new IntHashtableEntry(); - entry.hash = hash; - entry.key = key; - entry.value = value; - entry.next = ( next != null ) ? (IntHashtableEntry) next.clone() : null; - return entry; - } - } - - -class IntHashtableEnumerator implements Enumeration - { - boolean keys; - int index; - IntHashtableEntry table[]; - IntHashtableEntry entry; - - IntHashtableEnumerator( IntHashtableEntry table[], boolean keys ) - { - this.table = table; - this.keys = keys; - this.index = table.length; - } - - public boolean hasMoreElements() - { - if ( entry != null ) - return true; - while ( index-- > 0 ) - if ( ( entry = table[index] ) != null ) - return true; - return false; - } - - public Object nextElement() - { - if ( entry == null ) - while ( ( index-- > 0 ) && ( ( entry = table[index] ) == null ) ) - ; - if ( entry != null ) - { - IntHashtableEntry e = entry; - entry = e.next; - return keys ? new Integer( e.key ) : e.value; - } - throw new NoSuchElementException( "IntHashtableEnumerator" ); - } - } diff --git a/src/Acme/JPM/Encoders/GifEncoder.java b/src/Acme/JPM/Encoders/GifEncoder.java deleted file mode 100644 index af24b1a8..00000000 --- a/src/Acme/JPM/Encoders/GifEncoder.java +++ /dev/null @@ -1,690 +0,0 @@ -// GifEncoder - write out an image as a GIF -// -// Transparency handling and variable bit size courtesy of Jack Palevich. -// -// 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/ - -package Acme.JPM.Encoders; - -import java.util.*; -import java.io.*; -import java.awt.Image; -import java.awt.image.*; - -/// Write out an image as a GIF. -//

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

-// @see ToGif - -public class GifEncoder extends ImageEncoder - { - - private boolean interlace = false; - - /// Constructor from Image. - // @param img The image to encode. - // @param out The stream to write the GIF to. - public GifEncoder( Image img, OutputStream out ) throws IOException - { - super( img, out ); - } - - /// Constructor from Image with interlace setting. - // @param img The image to encode. - // @param out The stream to write the GIF to. - // @param interlace Whether to interlace. - public GifEncoder( Image img, OutputStream out, boolean interlace ) throws IOException - { - super( img, out ); - this.interlace = interlace; - } - - /// Constructor from ImageProducer. - // @param prod The ImageProducer to encode. - // @param out The stream to write the GIF to. - public GifEncoder( ImageProducer prod, OutputStream out ) throws IOException - { - super( prod, out ); - } - - /// Constructor from ImageProducer with interlace setting. - // @param prod The ImageProducer to encode. - // @param out The stream to write the GIF to. - public GifEncoder( ImageProducer prod, OutputStream out, boolean interlace ) throws IOException - { - super( prod, out ); - this.interlace = interlace; - } - - - int width, height; - int[][] rgbPixels; - - void encodeStart( int width, int height ) throws IOException - { - this.width = width; - this.height = height; - rgbPixels = new int[height][width]; - } - - void encodePixels( - int x, int y, int w, int h, int[] rgbPixels, int off, int scansize ) - throws IOException - { - // Save the pixels. - for ( int row = 0; row < h; ++row ) - System.arraycopy( - rgbPixels, row * scansize + off, - this.rgbPixels[y + row], x, w ); - - } - - Acme.IntHashtable colorHash; - - void encodeDone() throws IOException - { - int transparentIndex = -1; - int transparentRgb = -1; - // Put all the pixels into a hash table. - colorHash = new Acme.IntHashtable(); - int index = 0; - for ( int row = 0; row < height; ++row ) - { - for ( int col = 0; col < width; ++col ) - { - int rgb = rgbPixels[row][col]; - boolean isTransparent = ( ( rgb >>> 24 ) < 0x80 ); - if ( isTransparent ) - { - if ( transparentIndex < 0 ) - { - // First transparent color; remember it. - transparentIndex = index; - transparentRgb = rgb; - } - else if ( rgb != transparentRgb ) - { - // A second transparent color; replace it with - // the first one. - rgbPixels[row][col] = rgb = transparentRgb; - } - } - GifEncoderHashitem item = - (GifEncoderHashitem) colorHash.get( rgb ); - if ( item == null ) - { - if ( index >= 256 ) - throw new IOException( "too many colors for a GIF" ); - item = new GifEncoderHashitem( - rgb, 1, index, isTransparent ); - ++index; - colorHash.put( rgb, item ); - } - else - ++item.count; - } - } - - // Figure out how many bits to use. - int logColors; - if ( index <= 2 ) - logColors = 1; - else if ( index <= 4 ) - logColors = 2; - else if ( index <= 16 ) - logColors = 4; - else - logColors = 8; - - // Turn colors into colormap entries. - int mapSize = 1 << logColors; - byte[] reds = new byte[mapSize]; - byte[] grns = new byte[mapSize]; - byte[] blus = new byte[mapSize]; - for ( Enumeration e = colorHash.elements(); e.hasMoreElements(); ) - { - GifEncoderHashitem item = (GifEncoderHashitem) e.nextElement(); - reds[item.index] = (byte) ( ( item.rgb >> 16 ) & 0xff ); - grns[item.index] = (byte) ( ( item.rgb >> 8 ) & 0xff ); - blus[item.index] = (byte) ( item.rgb & 0xff ); - } - - GIFEncode( - out, width, height, interlace, (byte) 0, transparentIndex, - logColors, reds, grns, blus ); - } - - byte GetPixel( int x, int y ) throws IOException - { - GifEncoderHashitem item = - (GifEncoderHashitem) colorHash.get( rgbPixels[y][x] ); - if ( item == null ) - throw new IOException( "color not found" ); - return (byte) item.index; - } - - static void writeString( OutputStream out, String str ) throws IOException - { - byte[] buf = str.getBytes(); - out.write( buf ); - } - - // Adapted from ppmtogif, which is based on GIFENCOD by David - // Rowley . Lempel-Zim compression - // based on "compress". - - int Width, Height; - boolean Interlace; - int curx, cury; - int CountDown; - int Pass = 0; - - void GIFEncode( - OutputStream outs, int Width, int Height, boolean Interlace, byte Background, int Transparent, int BitsPerPixel, byte[] Red, byte[] Green, byte[] Blue ) - throws IOException - { - byte B; - int LeftOfs, TopOfs; - int ColorMapSize; - int InitCodeSize; - int i; - - this.Width = Width; - this.Height = Height; - this.Interlace = Interlace; - ColorMapSize = 1 << BitsPerPixel; - LeftOfs = TopOfs = 0; - - // Calculate number of bits we are expecting - CountDown = Width * Height; - - // Indicate which pass we are on (if interlace) - Pass = 0; - - // The initial code size - if ( BitsPerPixel <= 1 ) - InitCodeSize = 2; - else - InitCodeSize = BitsPerPixel; - - // Set up the current x and y position - curx = 0; - cury = 0; - - // Write the Magic header - writeString( outs, "GIF89a" ); - - // Write out the screen width and height - Putword( Width, outs ); - Putword( Height, outs ); - - // Indicate that there is a global colour map - B = (byte) 0x80; // Yes, there is a color map - // OR in the resolution - B |= (byte) ( ( 8 - 1 ) << 4 ); - // Not sorted - // OR in the Bits per Pixel - B |= (byte) ( ( BitsPerPixel - 1 ) ); - - // Write it out - Putbyte( B, outs ); - - // Write out the Background colour - Putbyte( Background, outs ); - - // Pixel aspect ratio - 1:1. - //Putbyte( (byte) 49, outs ); - // Java's GIF reader currently has a bug, if the aspect ratio byte is - // not zero it throws an ImageFormatException. It doesn't know that - // 49 means a 1:1 aspect ratio. Well, whatever, zero works with all - // the other decoders I've tried so it probably doesn't hurt. - Putbyte( (byte) 0, outs ); - - // Write out the Global Colour Map - for ( i = 0; i < ColorMapSize; ++i ) - { - Putbyte( Red[i], outs ); - Putbyte( Green[i], outs ); - Putbyte( Blue[i], outs ); - } - - // Write out extension for transparent colour index, if necessary. - if ( Transparent != -1 ) - { - Putbyte( (byte) '!', outs ); - Putbyte( (byte) 0xf9, outs ); - Putbyte( (byte) 4, outs ); - Putbyte( (byte) 1, outs ); - Putbyte( (byte) 0, outs ); - Putbyte( (byte) 0, outs ); - Putbyte( (byte) Transparent, outs ); - Putbyte( (byte) 0, outs ); - } - - // Write an Image separator - Putbyte( (byte) ',', outs ); - - // Write the Image header - Putword( LeftOfs, outs ); - Putword( TopOfs, outs ); - Putword( Width, outs ); - Putword( Height, outs ); - - // Write out whether or not the image is interlaced - if ( Interlace ) - Putbyte( (byte) 0x40, outs ); - else - Putbyte( (byte) 0x00, outs ); - - // Write out the initial code size - Putbyte( (byte) InitCodeSize, outs ); - - // Go and actually compress the data - compress( InitCodeSize+1, outs ); - - // Write out a Zero-length packet (to end the series) - Putbyte( (byte) 0, outs ); - - // Write the GIF file terminator - Putbyte( (byte) ';', outs ); - } - - // Bump the 'curx' and 'cury' to point to the next pixel - void BumpPixel() - { - // Bump the current X position - ++curx; - - // If we are at the end of a scan line, set curx back to the beginning - // If we are interlaced, bump the cury to the appropriate spot, - // otherwise, just increment it. - if ( curx == Width ) - { - curx = 0; - - if ( ! Interlace ) - ++cury; - else - { - switch( Pass ) - { - case 0: - cury += 8; - if ( cury >= Height ) - { - ++Pass; - cury = 4; - } - break; - - case 1: - cury += 8; - if ( cury >= Height ) - { - ++Pass; - cury = 2; - } - break; - - case 2: - cury += 4; - if ( cury >= Height ) - { - ++Pass; - cury = 1; - } - break; - - case 3: - cury += 2; - break; - } - } - } - } - - static final int EOF = -1; - - // Return the next pixel from the image - int GIFNextPixel() throws IOException - { - byte r; - - if ( CountDown == 0 ) - return EOF; - - --CountDown; - - r = GetPixel( curx, cury ); - - BumpPixel(); - - return r & 0xff; - } - - // Write out a word to the GIF file - void Putword( int w, OutputStream outs ) throws IOException - { - Putbyte( (byte) ( w & 0xff ), outs ); - Putbyte( (byte) ( ( w >> 8 ) & 0xff ), outs ); - } - - // Write out a byte to the GIF file - void Putbyte( byte b, OutputStream outs ) throws IOException - { - outs.write( b ); - } - - - // GIFCOMPR.C - GIF Image compression routines - // - // Lempel-Ziv compression based on 'compress'. GIF modifications by - // David Rowley (mgardi@watdcsu.waterloo.edu) - - // General DEFINEs - - static final int BITS = 12; - - static final int HSIZE = 5003; // 80% occupancy - - // GIF Image compression - modified 'compress' - // - // Based on: compress.c - File compression ala IEEE Computer, June 1984. - // - // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) - // Jim McKie (decvax!mcvax!jim) - // Steve Davies (decvax!vax135!petsd!peora!srd) - // Ken Turkowski (decvax!decwrl!turtlevax!ken) - // James A. Woods (decvax!ihnp4!ames!jaw) - // Joe Orost (decvax!vax135!petsd!joe) - - int n_bits; // number of bits/code - int maxbits = BITS; // user settable max # bits/code - int maxcode; // maximum code, given n_bits - int maxmaxcode = 1 << BITS; // should NEVER generate this code - - final int MAXCODE( int n_bits ) - { - return ( 1 << n_bits ) - 1; - } - - int[] htab = new int[HSIZE]; - int[] codetab = new int[HSIZE]; - - int hsize = HSIZE; // for dynamic table sizing - - int free_ent = 0; // first unused entry - - // block compression parameters -- after all codes are used up, - // and compression rate changes, start over. - boolean clear_flg = false; - - // Algorithm: use open addressing double hashing (no chaining) on the - // prefix code / next character combination. We do a variant of Knuth's - // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime - // secondary probe. Here, the modular division first probe is gives way - // to a faster exclusive-or manipulation. Also do block compression with - // an adaptive reset, whereby the code table is cleared when the compression - // ratio decreases, but after the table fills. The variable-length output - // codes are re-sized at this point, and a special CLEAR code is generated - // for the decompressor. Late addition: construct the table according to - // file size for noticeable speed improvement on small files. Please direct - // questions about this implementation to ames!jaw. - - int g_init_bits; - - int ClearCode; - int EOFCode; - - void compress( int init_bits, OutputStream outs ) throws IOException - { - int fcode; - int i /* = 0 */; - int c; - int ent; - int disp; - int hsize_reg; - int hshift; - - // Set up the globals: g_init_bits - initial number of bits - g_init_bits = init_bits; - - // Set up the necessary values - clear_flg = false; - n_bits = g_init_bits; - maxcode = MAXCODE( n_bits ); - - ClearCode = 1 << ( init_bits - 1 ); - EOFCode = ClearCode + 1; - free_ent = ClearCode + 2; - - char_init(); - - ent = GIFNextPixel(); - - hshift = 0; - for ( fcode = hsize; fcode < 65536; fcode *= 2 ) - ++hshift; - hshift = 8 - hshift; // set hash code range bound - - hsize_reg = hsize; - cl_hash( hsize_reg ); // clear hash table - - output( ClearCode, outs ); - - outer_loop: - while ( (c = GIFNextPixel()) != EOF ) - { - fcode = ( c << maxbits ) + ent; - i = ( c << hshift ) ^ ent; // xor hashing - - if ( htab[i] == fcode ) - { - ent = codetab[i]; - continue; - } - else if ( htab[i] >= 0 ) // non-empty slot - { - disp = hsize_reg - i; // secondary hash (after G. Knott) - if ( i == 0 ) - disp = 1; - do - { - if ( (i -= disp) < 0 ) - i += hsize_reg; - - if ( htab[i] == fcode ) - { - ent = codetab[i]; - continue outer_loop; - } - } - while ( htab[i] >= 0 ); - } - output( ent, outs ); - ent = c; - if ( free_ent < maxmaxcode ) - { - codetab[i] = free_ent++; // code -> hashtable - htab[i] = fcode; - } - else - cl_block( outs ); - } - // Put out the final code. - output( ent, outs ); - output( EOFCode, outs ); - } - - // output - // - // Output the given code. - // Inputs: - // code: A n_bits-bit integer. If == -1, then EOF. This assumes - // that n_bits =< wordsize - 1. - // Outputs: - // Outputs code to the file. - // Assumptions: - // Chars are 8 bits long. - // Algorithm: - // Maintain a BITS character long buffer (so that 8 codes will - // fit in it exactly). Use the VAX insv instruction to insert each - // code in turn. When the buffer fills up empty it and start over. - - int cur_accum = 0; - int cur_bits = 0; - - int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, - 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - - void output( int code, OutputStream outs ) throws IOException - { - cur_accum &= masks[cur_bits]; - - if ( cur_bits > 0 ) - cur_accum |= ( code << cur_bits ); - else - cur_accum = code; - - cur_bits += n_bits; - - while ( cur_bits >= 8 ) - { - char_out( (byte) ( cur_accum & 0xff ), outs ); - cur_accum >>= 8; - cur_bits -= 8; - } - - // If the next entry is going to be too big for the code size, - // then increase it, if possible. - if ( free_ent > maxcode || clear_flg ) - { - if ( clear_flg ) - { - maxcode = MAXCODE(n_bits = g_init_bits); - clear_flg = false; - } - else - { - ++n_bits; - if ( n_bits == maxbits ) - maxcode = maxmaxcode; - else - maxcode = MAXCODE(n_bits); - } - } - - if ( code == EOFCode ) - { - // At EOF, write the rest of the buffer. - while ( cur_bits > 0 ) - { - char_out( (byte) ( cur_accum & 0xff ), outs ); - cur_accum >>= 8; - cur_bits -= 8; - } - - flush_char( outs ); - } - } - - // Clear out the hash table - - // table clear for block compress - void cl_block( OutputStream outs ) throws IOException - { - cl_hash( hsize ); - free_ent = ClearCode + 2; - clear_flg = true; - - output( ClearCode, outs ); - } - - // reset code table - void cl_hash( int hsize ) - { - for ( int i = 0; i < hsize; ++i ) - htab[i] = -1; - } - - // GIF Specific routines - - // Number of characters so far in this 'packet' - int a_count; - - // Set up the 'byte output' routine - void char_init() - { - a_count = 0; - } - - // Define the storage for the packet accumulator - byte[] accum = new byte[256]; - - // Add a character to the end of the current packet, and if it is 254 - // characters, flush the packet to disk. - void char_out( byte c, OutputStream outs ) throws IOException - { - accum[a_count++] = c; - if ( a_count >= 254 ) - flush_char( outs ); - } - - // Flush the packet to disk, and reset the accumulator - void flush_char( OutputStream outs ) throws IOException - { - if ( a_count > 0 ) - { - outs.write( a_count ); - outs.write( accum, 0, a_count ); - a_count = 0; - } - } - - } - -class GifEncoderHashitem - { - - public int rgb; - public int count; - public int index; - public boolean isTransparent; - - public GifEncoderHashitem( int rgb, int count, int index, boolean isTransparent ) - { - this.rgb = rgb; - this.count = count; - this.index = index; - this.isTransparent = isTransparent; - } - - } diff --git a/src/Acme/JPM/Encoders/ImageEncoder.java b/src/Acme/JPM/Encoders/ImageEncoder.java deleted file mode 100644 index 9b5e8e56..00000000 --- a/src/Acme/JPM/Encoders/ImageEncoder.java +++ /dev/null @@ -1,271 +0,0 @@ -// ImageEncoder - abstract class for writing out an image -// -// 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. -// 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/ - -package Acme.JPM.Encoders; - -import java.util.*; -import java.io.*; -import java.awt.Image; -import java.awt.image.*; - -/// Abstract class for writing out an image. -//

-// A framework for classes that encode and write out an image in -// a particular file format. -//

-// This provides a simplified rendition of the ImageConsumer interface. -// It always delivers the pixels as ints in the RGBdefault color model. -// It always provides them in top-down left-right order. -// If you want more flexibility you can always implement ImageConsumer -// directly. -//

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

-// @see GifEncoder -// @see PpmEncoder -// @see Acme.JPM.Decoders.ImageDecoder - -public abstract class ImageEncoder implements ImageConsumer - { - - protected OutputStream out; - - private ImageProducer producer; - private int width = -1; - private int height = -1; - private int hintflags = 0; - private boolean started = false; - private boolean encoding; - private IOException iox; - private static final ColorModel rgbModel = ColorModel.getRGBdefault(); - private Hashtable props = null; - - /// Constructor. - // @param img The image to encode. - // @param out The stream to write the bytes to. - public ImageEncoder( Image img, OutputStream out ) throws IOException - { - this( img.getSource(), out ); - } - - /// Constructor. - // @param producer The ImageProducer to encode. - // @param out The stream to write the bytes to. - public ImageEncoder( ImageProducer producer, OutputStream out ) throws IOException - { - this.producer = producer; - this.out = out; - } - - - // Methods that subclasses implement. - - /// Subclasses implement this to initialize an encoding. - abstract void encodeStart( int w, int h ) throws IOException; - - /// Subclasses implement this to actually write out some bits. They - // are guaranteed to be delivered in top-down-left-right order. - // One int per pixel, index is row * scansize + off + col, - // RGBdefault (AARRGGBB) color model. - abstract void encodePixels( - int x, int y, int w, int h, int[] rgbPixels, int off, int scansize ) - throws IOException; - - /// Subclasses implement this to finish an encoding. - abstract void encodeDone() throws IOException; - - - // Our own methods. - - /// Call this after initialization to get things going. - public synchronized void encode() throws IOException - { - encoding = true; - iox = null; - producer.startProduction( this ); - while ( encoding ) - try - { - wait(); - } - catch ( InterruptedException e ) {} - if ( iox != null ) - throw iox; - } - - private boolean accumulate = false; - private int[] accumulator; - - private void encodePixelsWrapper( - int x, int y, int w, int h, int[] rgbPixels, int off, int scansize ) - throws IOException - { - if ( ! started ) - { - started = true; - encodeStart( width, height ); - if ( ( hintflags & TOPDOWNLEFTRIGHT ) == 0 ) - { - accumulate = true; - accumulator = new int[width * height]; - } - } - if ( accumulate ) - for ( int row = 0; row < h; ++row ) - System.arraycopy( - rgbPixels, row * scansize + off, - accumulator, ( y + row ) * width + x, - w ); - else - encodePixels( x, y, w, h, rgbPixels, off, scansize ); - } - - private void encodeFinish() throws IOException - { - if ( accumulate ) - { - encodePixels( 0, 0, width, height, accumulator, 0, width ); - accumulator = null; - accumulate = false; - } - } - - private synchronized void stop() - { - encoding = false; - notifyAll(); - } - - - // Methods from ImageConsumer. - - public void setDimensions( int width, int height ) - { - this.width = width; - this.height = height; - } - - public void setProperties( Hashtable props ) - { - this.props = props; - } - - public void setColorModel( ColorModel model ) - { - // Ignore. - } - - public void setHints( int hintflags ) - { - this.hintflags = hintflags; - } - - public void setPixels( - int x, int y, int w, int h, ColorModel model, byte[] pixels, - int off, int scansize ) - { - int[] rgbPixels = new int[w]; - for ( int row = 0; row < h; ++row ) - { - int rowOff = off + row * scansize; - for ( int col = 0; col < w; ++col ) - rgbPixels[col] = model.getRGB( pixels[rowOff + col] & 0xff ); - try - { - encodePixelsWrapper( x, y + row, w, 1, rgbPixels, 0, w ); - } - catch ( IOException e ) - { - iox = e; - stop(); - return; - } - } - } - - public void setPixels( - int x, int y, int w, int h, ColorModel model, int[] pixels, - int off, int scansize ) - { - if ( model == rgbModel ) - { - try - { - encodePixelsWrapper( x, y, w, h, pixels, off, scansize ); - } - catch ( IOException e ) - { - iox = e; - stop(); - return; - } - } - else - { - int[] rgbPixels = new int[w]; - for ( int row = 0; row < h; ++row ) - { - int rowOff = off + row * scansize; - for ( int col = 0; col < w; ++col ) - rgbPixels[col] = model.getRGB( pixels[rowOff + col] ); - try - { - encodePixelsWrapper( x, y + row, w, 1, rgbPixels, 0, w ); - } - catch ( IOException e ) - { - iox = e; - stop(); - return; - } - } - } - } - - public void imageComplete( int status ) - { - producer.removeConsumer( this ); - if ( status == ImageConsumer.IMAGEABORTED ) - iox = new IOException( "image aborted" ); - else - { - try - { - encodeFinish(); - encodeDone(); - } - catch ( IOException e ) - { - iox = e; - } - } - stop(); - } - - } diff --git a/src/helma/doc/DocApplication.java b/src/helma/doc/DocApplication.java deleted file mode 100644 index b263c4a0..00000000 --- a/src/helma/doc/DocApplication.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import helma.framework.IPathElement; -import helma.main.Server; -import helma.util.SystemProperties; -import java.io.*; -import java.util.*; -import java.awt.*; -/** - * - */ -public class DocApplication extends DocDirElement { - HashSet excluded; - - /** - * Creates a new DocApplication object. - * - * @param name ... - * @param location ... - * - * @throws DocException ... - */ - public DocApplication(String name, File location) throws DocException { - super(name, location, APPLICATION); - readProps(); - } - - /** - * Creates a new DocApplication object. - * - * @param name ... - * @param appDir ... - * - * @throws DocException ... - */ - public DocApplication(String name, String appDir) throws DocException { - super(name, new File(appDir), APPLICATION); - readProps(); - } - - /** - * - * - * @param args ... - */ - public static void main(String[] args) { - System.out.println("this is helma.doc"); - DocApplication app; - app = new DocApplication (args[0], args[1]); - app.readApplication (); - - // DocPrototype el = DocPrototype.newInstance (new File(args[0])); - // el.readFiles (); - // DocFunction func = DocFunction.newTemplate (new File(args[0])); - -// DocFunction func = DocFunction.newAction (new File(args[0])); - -// DocFunction[] func = DocFunction.newFunctions(new File(args[0])); -// for (int i=0; i e2.getType())) { - return 1; - } else if ((mode == BY_TYPE) && (e1.getType() < e2.getType())) { - return -1; - } else { - return e1.name.compareTo(e2.name); - } - } - - /** - * - * - * @param obj ... - * - * @return ... - */ - public boolean equals(Object obj) { - DocElement el = (DocElement) obj; - - if (el.name.equals(docEl.name) && (el.getType() == docEl.getType())) { - return true; - } else { - return false; - } - } -} diff --git a/src/helma/doc/DocDirElement.java b/src/helma/doc/DocDirElement.java deleted file mode 100644 index 29587adb..00000000 --- a/src/helma/doc/DocDirElement.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import java.io.*; -import java.util.*; - -/** - * - */ -public abstract class DocDirElement extends DocElement { - // a default file that is read as comment for applications - // and prototypes if found in their directories - public static final String[] DOCFILES = { - "doc.html", "doc.htm", "app.html", - "app.htm", "prototype.html", - "prototype.htm", "index.html", "index.htm" - }; - - protected DocDirElement(String name, File location, int type) { - super(name, location, type); - checkCommentFiles(); - } - - private void checkCommentFiles() throws DocException { - for (int i = 0; i < DOCFILES.length; i++) { - File f = new File(location, DOCFILES[i]); - - if (f.exists()) { - String rawComment = Util.readFile(f); - - parseComment(rawComment); - - return; - } - } - } -} diff --git a/src/helma/doc/DocElement.java b/src/helma/doc/DocElement.java deleted file mode 100644 index 2d08da58..00000000 --- a/src/helma/doc/DocElement.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import helma.framework.IPathElement; -import java.io.*; -import java.util.*; - -/** - * - */ -public abstract class DocElement implements IPathElement { - public static final int APPLICATION = 0; - public static final int PROTOTYPE = 1; - public static final int ACTION = 2; - public static final int TEMPLATE = 3; - public static final int FUNCTION = 4; - public static final int MACRO = 5; - public static final int SKIN = 6; - public static final int PROPERTIES = 7; - - // above constants are used as array indices - public static final String[] typeNames = { - "Application", "Prototype", "Action", - "Template", "Function", "Macro", "Skin", - "Properties" - }; - - // identifiers of this element - String name; - int type; - File location; - DocElement parent = null; - Map children = new HashMap(); - - // content - String content = ""; - String comment = ""; - List tags = new Vector(); - List parameters = new Vector(); - - protected DocElement(String name, String location, int type) - throws DocException { - this(name, new File(location), type); - } - - protected DocElement(String name, File location, int type) - throws DocException { - if (location.exists() == false) { - throw new DocException(name + " not found in " + location.toString()); - } - - this.name = name; - this.location = location; - this.type = type; - } - - /** - * the simple name of the element - */ - public String getName() { - return name; - } - - /** - * @return absolute path to location of element - * (directory for apps and prototypes, file for - * methods and properties files) - */ - public File getLocation() { - return location; - } - - /** - * - * - * @return ... - */ - public int getType() { - return type; - } - - /** - * - * - * @return ... - */ - public String getTypeName() { - return typeNames[type]; - } - - /** - * returns the comment string, empty string if no comment is set. - */ - public String getComment() { - return comment; - } - - /** - * the actual content of the doc element (the function body, the properties - * list, the file list etc. - */ - public String getContent() { - return content; - } - - /** - * - * - * @param rawContent ... - */ - public void addTag(String rawContent) { - if (tags == null) { - tags = new Vector(); - } - - try { - DocTag tag = DocTag.parse(rawContent); - - tags.add(tag); - } catch (DocException doc) { - debug(doc.toString()); - } - } - - /** - * list all tags - */ - public DocTag[] listTags() { - return (DocTag[]) tags.toArray(new DocTag[0]); - } - - /** - * filter the tags according to their type - */ - public DocTag[] listTags(String type) { - Vector retval = new Vector(); - - for (int i = 0; i < tags.size(); i++) { - if (((DocTag) tags.get(i)).getType().equals(type)) { - retval.add(tags.get(i)); - } - } - - return (DocTag[]) retval.toArray(); - } - - /** - * - * - * @param param ... - * - * @return ... - */ - public boolean hasParameter(String param) { - return parameters.contains(param); - } - - /** - * the list of parameters - */ - public String[] listParameters() { - return (String[]) parameters.toArray(new String[0]); - } - - /** - * add a string to the parameters-list - */ - protected void addParameter(String param) { - parameters.add(param); - } - - - /** - * parse rawComment, render DocTags - */ - void parseComment(String rawComment) { - try { - rawComment = rawComment.trim(); - StringTokenizer tok = new StringTokenizer(rawComment, "\n", true); - int BLANK = 0; - int TEXT = 1; - int TAGS = 2; - boolean lastEmpty = false; - int mode = BLANK; - StringBuffer buf = new StringBuffer(); - - while (tok.hasMoreTokens()) { - String line = Util.chopDelimiters(tok.nextToken().trim()); - - if ("".equals(line)) { - // if we've already had text, store that this line was empty - lastEmpty = (mode != BLANK) ? true : false; - - continue; - } - - // if we come here the first time, start with TEXT mode - mode = (mode == BLANK) ? TEXT : mode; - - // check if we have a new tag - if (DocTag.isTagStart(line)) { - // if we appended to comment text until now, store that ... - if (mode == TEXT) { - comment = buf.toString(); - } - - // if we appended to a tag, store that ... - if (mode == TAGS) { - addTag(buf.toString()); - } - - // reset buffer - buf = new StringBuffer(); - mode = TAGS; - } - - // append to current buffer - if (lastEmpty == true) { - buf.append("\n"); - } - - buf.append(line); - buf.append(" "); - lastEmpty = false; - } - - // store the last element, if there was at least one element ... - if (mode == TEXT) { - comment = buf.toString().trim(); - } else if (mode == TAGS) { - addTag(buf.toString()); - } - } catch (RuntimeException rt) { - debug("parse error in " + location + ": " + rt.getMessage()); - } - } - - - /** - * - * - * @param parent ... - */ - public void setParent(DocElement parent) { - this.parent = parent; - } - - /** - * - * - * @param child ... - */ - public void addChild(DocElement child) { - if (child == null) { - return; - } - - children.put(child.getElementName(), child); - } - - /** - * - * - * @return ... - */ - public int countChildren() { - return children.size(); - } - - /** - * - * - * @return ... - */ - public Map getChildren() { - return children; - } - - /** - * returns an array of doc elements, sorted by their name - */ - public DocElement[] listChildren() { - String[] keys = (String[]) children.keySet().toArray(new String[0]); - - Arrays.sort(keys); - - DocElement[] arr = new DocElement[keys.length]; - - for (int i = 0; i < keys.length; i++) { - arr[i] = (DocElement) children.get(keys[i]); - } - - return arr; - } - - /** - * walks up the tree and tries to find a DocApplication object - */ - public DocApplication getDocApplication() { - DocElement el = this; - - while (el != null) { - if (el instanceof DocApplication) { - return (DocApplication) el; - } - - el = (DocElement) el.getParentElement(); - } - - return null; - } - - /** - * from helma.framework.IPathElement. Elements are named - * like this: typename_name - */ - public String getElementName() { - return typeNames[type].toLowerCase() + "_" + name; - } - - /** - * from helma.framework.IPathElement. Retrieves a child from the - * children map. - */ - public IPathElement getChildElement(String name) { - try { - return (IPathElement) children.get(name); - } catch (ClassCastException cce) { - debug(cce.toString()); - cce.printStackTrace(); - - return null; - } - } - - /** - * from helma.framework.IPathElement. Returns the parent object - * of this instance if assigned. - */ - public IPathElement getParentElement() { - return parent; - } - - /** - * from helma.framework.IPathElement. Prototypes are assigned like - * this: "doc" + typename (e.g. docapplication, docprototype etc) - */ - public java.lang.String getPrototype() { - return "doc" + typeNames[type].toLowerCase(); - } - - /** - * - * - * @return ... - */ - public String toString() { - return "[" + typeNames[type] + " " + name + "]"; - } - - /** - * - * - * @param msg ... - */ - public static void debug(String msg) { - System.out.println(msg); - } -} diff --git a/src/helma/doc/DocException.java b/src/helma/doc/DocException.java deleted file mode 100644 index 3fa9abef..00000000 --- a/src/helma/doc/DocException.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -/** - * - */ -public class DocException extends RuntimeException { - String str; - - /** - * Creates a new DocException object. - * - * @param str ... - */ - public DocException(String str) { - super(str); - this.str = str; - } - - /** - * - * - * @return ... - */ - public String getMessage() { - return str; - } -} diff --git a/src/helma/doc/DocFileElement.java b/src/helma/doc/DocFileElement.java deleted file mode 100644 index 6cd4dd04..00000000 --- a/src/helma/doc/DocFileElement.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import java.io.File; - -/** - * abstract class for extracting doc information from files. - * not used at the moment but left in for further extensions- - */ -public abstract class DocFileElement extends DocElement { - protected DocFileElement(String name, File location, int type) { - super(name, location, type); - } - - - - - -} diff --git a/src/helma/doc/DocFunction.java b/src/helma/doc/DocFunction.java deleted file mode 100644 index 50a1ad0a..00000000 --- a/src/helma/doc/DocFunction.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import helma.framework.IPathElement; -import java.awt.Point; -import java.lang.reflect.Constructor; -import java.io.*; -import java.util.Vector; -import org.mozilla.javascript.TokenStream; - -/** - * - */ -public class DocFunction extends DocFileElement { - - protected DocFunction(String name, File location, DocElement parent, int type) { - super(name, location, type); - this.parent = parent; - } - - /** - * creates a new independent DocFunction object of type ACTION - */ - public static DocFunction newAction(File location) { - return newAction(location, null); - } - - /** - * creates a new DocFunction object of type ACTION connected to another DocElement - */ - public static DocFunction newAction(File location, DocElement parent) { - String name = Util.nameFromFile(location, ".hac"); - DocFunction func = new DocFunction(name, location, parent, ACTION); - String rawComment = ""; - try { - TokenStream ts = getTokenStream (location); - Point p = getPoint (ts); - ts.getToken(); - rawComment = Util.getStringFromFile(location, p, getPoint(ts)); - rawComment = Util.chopComment (rawComment); - } catch (IOException io) { - io.printStackTrace(); - throw new DocException (io.toString()); - } - func.parseComment(rawComment); - func.content = Util.readFile(location); - return func; - } - - /** - * reads a function file and creates independent DocFunction objects of type FUNCTION - */ - public static DocFunction[] newFunctions(File location) { - return newFunctions(location, null); - } - - - /** - * reads a function file and creates DocFunction objects of type FUNCTION - * connected to another DocElement. - */ - public static DocFunction[] newFunctions(File location, DocElement parent) { - Vector vec = new Vector(); - try { - // the function file: - TokenStream ts = getTokenStream (location); - DocFunction curFunction = null; - Point curFunctionStart = null; - while (!ts.eof()) { - - // store the position of the last token - Point endOfLastToken = getPoint (ts); - // new token - int tok = ts.getToken(); - - // if we're currently parsing a functionbody and come to the start - // of the next function or eof -> read function body - if (curFunction != null && (tok== TokenStream.FUNCTION || ts.eof())) { - curFunction.content = "function " + Util.getStringFromFile(location, curFunctionStart, endOfLastToken); - } - - if (tok == TokenStream.FUNCTION) { - // store the function start for parsing the function body later - curFunctionStart = getPoint (ts); - // get and chop the comment - String rawComment = Util.getStringFromFile(location, endOfLastToken, getPoint (ts)).trim (); - rawComment = Util.chopComment (rawComment); - // position stream at function name token - tok = ts.getToken(); - // get the name and create the function object - String name = ts.getString(); - curFunction = newFunction (name, location, parent); - curFunction.parseComment (rawComment); - vec.add (curFunction); - - // subloop on the tokenstream: find the parameters of a function - // only if it's a function (and not a macro or an action) - if (curFunction.type == FUNCTION) { - while (!ts.eof() && tok != TokenStream.RP) { - // store the position of the last token - endOfLastToken = getPoint (ts); - // new token - tok = ts.getToken(); - if (tok==TokenStream.NAME) { - curFunction.addParameter (ts.getString()); - } - } - } - } // end if - - } - - } catch (IOException io) { - io.printStackTrace(); - throw new DocException (io.toString()); - } - return (DocFunction[]) vec.toArray(new DocFunction[0]); - } - - - private static DocFunction newFunction (String funcName, File location, DocElement parent) { - if (funcName.endsWith("_action")) { - return new DocFunction(funcName, location, parent, ACTION); - } else if (funcName.endsWith("_macro")) { - return new DocFunction(funcName, location, parent, MACRO); - } else { - return new DocFunction(funcName, location, parent, FUNCTION); - } - } - - - /** - * creates a rhino token stream for a given file - */ - protected static TokenStream getTokenStream (File f) { - FileReader reader = null; - try { - reader = new FileReader(f); - } catch (FileNotFoundException fnfe) { - fnfe.printStackTrace(); - throw new DocException (fnfe.toString()); - } - String name = f.getName(); - int line = 0; - return new TokenStream (reader, null, null, name, line); - } - - - /** - * returns a pointer to the current position in the TokenStream - */ - protected static Point getPoint (TokenStream ts) { - return new Point (ts.getOffset(), ts.getLineno()); - } - - - - /** - * from helma.framework.IPathElement. All macros, templates, actions etc - * have the same prototype. - */ - public java.lang.String getPrototype() { - return "docfunction"; - } -} diff --git a/src/helma/doc/DocProperties.java b/src/helma/doc/DocProperties.java deleted file mode 100644 index ba96f2de..00000000 --- a/src/helma/doc/DocProperties.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import helma.framework.IPathElement; -import helma.util.SystemProperties; -import java.io.*; -import java.util.*; - -/** - * - */ -public class DocProperties extends DocFileElement { - Properties props = null; - - protected DocProperties(File location, DocElement parent) - throws DocException { - super(location.getName(), location, PROPERTIES); - this.parent = parent; - content = Util.readFile(location); - props = new SystemProperties(); - - try { - props.load(new FileInputStream(location)); - } catch (IOException e) { - debug("couldn't read file: " + e.toString()); - } catch (Exception e) { - throw new DocException(e.toString()); - } - } - - /** - * creates a new independent DocProperties object - */ - public static DocProperties newInstance(File location) { - return newInstance(location, null); - } - - /** - * creates a new DocProperties object connected to another DocElement - */ - public static DocProperties newInstance(File location, DocElement parent) { - try { - return new DocProperties(location, parent); - } catch (DocException doc) { - return null; - } - } - - /** - * - * - * @return ... - */ - public Properties getProperties() { - return props; - } - - /** - * - * - * @return ... - */ - public Properties getMappings() { - Properties childProps = new Properties(); - - for (Enumeration e = props.keys(); e.hasMoreElements();) { - String key = (String) e.nextElement(); - String value = props.getProperty(key); - - if (value.startsWith("collection") || value.startsWith("object") || - value.startsWith("mountpoint")) { - String prototype = value.substring(value.indexOf("(") + 1, - value.indexOf(")")).trim(); - - childProps.setProperty(key, prototype); - } - } - - return childProps; - } -} diff --git a/src/helma/doc/DocPrototype.java b/src/helma/doc/DocPrototype.java deleted file mode 100644 index 8db7c4f4..00000000 --- a/src/helma/doc/DocPrototype.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import helma.framework.IPathElement; -import java.io.*; -import java.util.*; - -/** - * - */ -public class DocPrototype extends DocDirElement { - private DocProperties typeProperties = null; - private DocPrototype parentPrototype = null; - - private DocPrototype(String name, File location, DocElement parent) { - super(name, location, PROTOTYPE); - this.parent = parent; - typeProperties = DocProperties.newInstance(new File(location, "type.properties")); - } - - /** - * creates a prototype that is independent of an - * application object - * @param homedirectory - */ - public static DocPrototype newInstance(File location) { - return newInstance(location, null); - } - - /** - * creates a prototype that is connected to an - * application object and resides in app's home dir. - * @param application - * @param name - */ - public static DocPrototype newInstance(File location, DocElement parent) { - DocPrototype pt = new DocPrototype(location.getName(), location, parent); - - return pt; - } - - /** - * checks the type.properites for _extend values and connected a possible - * parent prototype with this prototype. this can't be successfull at construction - * time but only -after- all prototypes are parsed and attached to a parent - * DocApplication object. - */ - public void checkInheritance() { - // hopobject is the top prototype: - if (name.equals("hopobject")) { - return; - } - - if (typeProperties != null) { - // check for "_extends" in the the type.properties - String ext = typeProperties.getProperties().getProperty("_extends"); - - if ((ext != null) && (parent != null)) { - // try to get the prototype if available - parentPrototype = (DocPrototype) parent.getChildElement("prototype_" + - ext); - } - } - - if ((parentPrototype == null) && (parent != null) && !name.equals("global")) { - // if no _extend was set, get the hopobject prototype - parentPrototype = (DocPrototype) parent.getChildElement("prototype_hopobject"); - } - } - - /** - * - * - * @return ... - */ - public DocPrototype getParentPrototype() { - return parentPrototype; - } - - /** - * - * - * @return ... - */ - public DocProperties getTypeProperties() { - return typeProperties; - } - - /** - * runs through the prototype directory and parses all helma files - */ - public void readFiles() { - children.clear(); - - String[] arr = location.list(); - - for (int i = 0; i < arr.length; i++) { - if (getDocApplication().isExcluded(arr[i])) { - continue; - } - - File f = new File(location.getAbsolutePath(), arr[i]); - - if (f.isDirectory()) { - continue; - } - - try { - if (arr[i].endsWith(".skin")) { - addChild(DocSkin.newInstance(f, this)); - } else if (arr[i].endsWith(".properties")) { - continue; - } else if (arr[i].endsWith(".hac")) { - addChild(DocFunction.newAction(f, this)); - } else if (arr[i].endsWith(".js")) { - DocElement[] elements = DocFunction.newFunctions(f, this); - - for (int j = 0; j < elements.length; j++) { - addChild(elements[j]); - } - } - } catch (Exception ex) { - System.out.println("couldn't parse file " + f.getAbsolutePath() + ": " + - ex.toString()); - ex.printStackTrace(); - } catch (Throwable err) { - System.out.println("couldn't parse file " + f.getAbsolutePath() + ": " + - err.toString()); - } - } - } -} diff --git a/src/helma/doc/DocSkin.java b/src/helma/doc/DocSkin.java deleted file mode 100644 index 87fd186c..00000000 --- a/src/helma/doc/DocSkin.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import helma.framework.IPathElement; -import java.io.*; -import java.util.*; - -/** - * - */ -public class DocSkin extends DocFileElement { - protected DocSkin(String name, File location, DocElement parent) { - super(name, location, SKIN); - this.parent = parent; - content = Util.readFile(location); - parseHandlers(); - } - - /** - * creates a new independent DocSkin object - */ - public static DocSkin newInstance(File location) { - return newInstance(location, null); - } - - /** - * creates a new DocSkin object connected to another DocElement - */ - public static DocSkin newInstance(File location, DocElement parent) { - String skinname = Util.nameFromFile(location, ".skin"); - DocSkin skin = new DocSkin(skinname, location, parent); - - return skin; - } - - /** - * parses the source code of the skin and - * extracts all included macros. code taken - * from helma.framework.core.Skin - * @see helma.framework.core.Skin - */ - private void parseHandlers() { - ArrayList partBuffer = new ArrayList(); - char[] source = content.toCharArray(); - int sourceLength = source.length; - - for (int i = 0; i < (sourceLength - 1); i++) { - if ((source[i] == '<') && (source[i + 1] == '%')) { - // found macro start tag - int j = i + 2; - - // search macro end tag - while ((j < (sourceLength - 1)) && - ((source[j] != '%') || (source[j + 1] != '>'))) { - j++; - } - - if (j > (i + 2)) { - String str = (new String(source, i + 2, j - i)).trim(); - - if (str.endsWith("%>")) { - str = str.substring(0, str.length() - 2); - } - - if (str.startsWith("//")) { - parseComment(str); - } else { - if (str.indexOf(" ") > -1) { - str = str.substring(0, str.indexOf(" ")); - } - - if ((str.indexOf(".") > -1) && - (str.startsWith("param.") || str.startsWith("response.") || - str.startsWith("request.") || str.startsWith("session.")) && - !partBuffer.contains(str)) { - partBuffer.add(str); - } - } - } - - i = j + 1; - } - } - - String[] strArr = (String[]) partBuffer.toArray(new String[0]); - - Arrays.sort(strArr); - - for (int i = 0; i < strArr.length; i++) { - addParameter(strArr[i]); - } - } - - /** - * from helma.framework.IPathElement. Use the same prototype as functions etc. - */ - public java.lang.String getPrototype() { - return "docfunction"; - } -} diff --git a/src/helma/doc/DocTag.java b/src/helma/doc/DocTag.java deleted file mode 100644 index 14e9c49b..00000000 --- a/src/helma/doc/DocTag.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import java.util.*; - -/** - * - */ -public final class DocTag { - - // the tag name - private String type; - - // the name of the parameter - private String name; - - // the actual comment - private String text; - - private DocTag(String type, String name, String text) { - this.type = type; - this.name = (name != null) ? name.trim() : ""; - this.text = (text != null) ? text.trim() : ""; - } - - - /** - * - * - * @param rawTag ... - * - * @return ... - * - * @throws DocException ... - */ - public static DocTag parse(String rawTag) throws DocException { - StringTokenizer tok = new StringTokenizer(rawTag.trim()); - String name = ""; - String type = ""; - StringBuffer comment = new StringBuffer (); - try { - type = matchTagName(tok.nextToken().substring (1)); - } catch (NoSuchElementException nsee) { - throw new DocException ("invalid tag: " + rawTag); - } - try { - if (isTagWithName(type)) { - name = tok.nextToken(); - } - while (tok.hasMoreTokens()) { - comment.append (" " + tok.nextToken()); - } - } catch (NoSuchElementException nsee) { // ignore - } - return new DocTag (type, name, comment.toString()); - } - - - /** - * @param checks if a line is a tag - * @return true/false - */ - public static boolean isTagStart(String rawTag) { - if (rawTag.trim().startsWith("@")) - return true; - else - return false; - } - - - /** - * match tags where we want different names to be valid - * as one and the same tag - * @param tagname original name - * @return modified name if tag was matched - */ - public static String matchTagName(String tagName) { - if ("returns".equals(tagName)) { - return "return"; - } else if ("arg".equals(tagName)) { - return "param"; - } else { - return tagName; - } - } - - - public static boolean isTagWithName(String tagName) { - if ("param".equals (tagName)) - return true; - else - return false; - } - - - /** - * - * - * @return ... - */ - public String getType() { - return type; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @return ... - */ - public String getText() { - return text; - } - - /** - * - * - * @return ... - */ - public String toString() { - StringBuffer buf = new StringBuffer ("[@" + type); - if (name!=null && !"".equals(name)) - buf.append (" " + name); - if (text!=null && !"".equals(text)) - buf.append (" " + text); - return buf.toString() + "]"; - } -} diff --git a/src/helma/doc/Util.java b/src/helma/doc/Util.java deleted file mode 100644 index 6bdc5f25..00000000 --- a/src/helma/doc/Util.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.doc; - -import java.awt.Point; -import java.io.*; - - -/** - * - */ -public final class Util { - /** - * chops a string from comment-delimiters - * - * @param line a line of raw text - * - * @return chopped string - */ - public static String chopDelimiters(String line) { - line = line.trim(); - if (line == null) { - return null; - } - if (line.endsWith("*/")) { - line = line.substring(0, line.length() - 2); - } - if (line.startsWith("/**")) { - line = line.substring(3).trim(); - } else if (line.startsWith("/*")) { - line = line.substring(2).trim(); - } else if (line.startsWith("*")) { - line = line.substring(1).trim(); - } else if (line.startsWith("//")) { - line = line.substring(2).trim(); - } - return line; - } - - /** - * chops anything that comes after a closing comment tag - * - * @param raw comment - * - * @return chopped comment - */ - public static String chopComment (String comment) { - int idx = comment.indexOf ("*/"); - if (idx>0) { - return comment.substring (0, idx+2); - } else { - return comment; - } - } - - - /** - * reads a complete file - * - * @param file - * - * @return string with content of file - */ - public static String readFile(File file) { - try { - StringBuffer buf = new StringBuffer(); - BufferedReader in = new BufferedReader(new FileReader(file)); - String line = in.readLine(); - - while (line != null) { - buf.append(line + "\n"); - line = in.readLine(); - } - - in.close(); - - return buf.toString(); - } catch (IOException e) { - return (""); - } - } - - - /** - * reads a part of a file defined by two points - - * @param start of string to extract defined by column x and row y - - * @param end of string to extract - - * @return string - */ - public static String getStringFromFile (File sourceFile, Point start, Point end) { - StringBuffer buf = new StringBuffer(); - int ct = 0; - try { - BufferedReader in = new BufferedReader(new FileReader(sourceFile)); - String line = ""; - while (line != null) { - line = in.readLine(); - if (line == null) { - break; - } - if ((ct > start.y) && (ct < end.y)) { - buf.append(line + "\n"); - } else if (ct == start.y) { - if (start.y==end.y) { - buf.append (line.substring (start.x, end.x)); - break; - } else { - buf.append(line.substring(start.x, line.length()) + "\n"); - } - } else if (ct == end.y) { - buf.append(line.substring(0, end.x)); - break; - } - ct++; - } - } catch (Exception e) { - e.printStackTrace(); - System.out.println(e.getMessage()); - } - return buf.toString().trim(); - } - - - /** - * method to debug file/stream-handling with Point objects. extracts the line p - * points to and prints it with a pointer to the given column - * - * @param sourceFile - * @param p x-value is used for column, y for row - * @param debugStr string prefixed to output - */ - public static void debugLineFromFile (File sourceFile, Point p, String debugStr) { - try { - BufferedReader in = new BufferedReader(new FileReader(sourceFile)); - String line = ""; - int ct = 0; - while (line != null) { - line = in.readLine (); - if (line==null) { - System.out.println ("eof reached"); - break; - } - if (ct==p.y) { - System.out.println (debugStr + ": " + line); - for (int i=0; i<(debugStr.length()+1+p.x); i++) { - System.out.print (" "); - } - System.out.println ("^"); - break; - } - ct++; - } - } catch (Exception e) { - e.printStackTrace(); - System.out.println(e.getMessage()); - } - } - - - - /** - * extracts the function name from a file. basically chops the given suffix - * and throws an error if the file name doesn't fit. - */ - public static String nameFromFile(File f, String suffix) - throws DocException { - String filename = f.getName(); - - if (!filename.endsWith(suffix)) { - throw new DocException("file doesn't have suffix " + suffix + ": " + - f.toString()); - } - - return filename.substring(0, filename.lastIndexOf(suffix)); - } - - -} diff --git a/src/helma/extensions/ConfigurationException.java b/src/helma/extensions/ConfigurationException.java deleted file mode 100644 index d134964d..00000000 --- a/src/helma/extensions/ConfigurationException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.extensions; - -/** - * - */ -public class ConfigurationException extends RuntimeException { - /** - * Creates a new ConfigurationException object. - * - * @param msg ... - */ - public ConfigurationException(String msg) { - super(msg); - } -} diff --git a/src/helma/extensions/HelmaExtension.java b/src/helma/extensions/HelmaExtension.java deleted file mode 100644 index 7bb0fa26..00000000 --- a/src/helma/extensions/HelmaExtension.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.extensions; - -import helma.framework.core.Application; -import helma.main.Server; -import helma.scripting.ScriptingEngine; -import java.util.HashMap; - -/** - * Helma extensions have to subclass this. The extensions to be loaded are - * defined in server.properties by setting extensions = - * packagename.classname, packagename.classname. - */ -public abstract class HelmaExtension { - /** - * called by the Server at startup time. should check wheter the needed classes - * are present and throw a ConfigurationException if not. - */ - public abstract void init(Server server) throws ConfigurationException; - - /** - * called when an Application is started. This should be synchronized when - * any self-initialization is performed. - */ - public abstract void applicationStarted(Application app) - throws ConfigurationException; - - /** - * called when an Application is stopped. - * This should be synchronized when any self-destruction is performed. - */ - public abstract void applicationStopped(Application app); - - /** - * called when an Application's properties are have been updated. - * note that this will be called at startup once *before* applicationStarted(). - */ - public abstract void applicationUpdated(Application app); - - /** - * called by the ScriptingEngine when it is initizalized. Throws a ConfigurationException - * when this type of ScriptingEngine is not supported. New methods and prototypes can be - * added to the scripting environment. New global vars should be returned in a HashMap - * with pairs of varname and ESObjects. This method should be synchronized, if it - * performs any other self-initialization outside the scripting environment. - */ - public abstract HashMap initScripting(Application app, ScriptingEngine engine) - throws ConfigurationException; - - /** - * - * - * @return ... - */ - public abstract String getName(); -} diff --git a/src/helma/extensions/demo/DemoExtension.java b/src/helma/extensions/demo/DemoExtension.java deleted file mode 100644 index dbc35cae..00000000 --- a/src/helma/extensions/demo/DemoExtension.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.extensions.demo; - - -import helma.extensions.ConfigurationException; -import helma.extensions.HelmaExtension; -import helma.framework.core.Application; -import helma.main.Server; -import helma.scripting.ScriptingEngine; -import helma.scripting.rhino.RhinoEngine; -import java.util.HashMap; - -/** - * a demo extension implementation, to activate this add extensions = - * helma.extensions.demo.DemoExtensions to your server.properties. - * a new global object demo that wraps helma.main.Server - * will be added to the scripting environment. - */ -public class DemoExtension extends HelmaExtension { - /** - * - * - * @param server ... - * - * @throws ConfigurationException ... - */ - public void init(Server server) throws ConfigurationException { - try { - // just a demo with the server class itself (which is always there, obviously) - Class check = Class.forName("helma.main.Server"); - } catch (ClassNotFoundException e) { - throw new ConfigurationException("helma-library not present in classpath. make sure helma.jar is included. get it from http://www.helma.org/"); - } - } - - /** - * - * - * @param app ... - * - * @throws ConfigurationException ... - */ - public void applicationStarted(Application app) throws ConfigurationException { - app.logEvent("DemoExtension init with app " + app.getName()); - } - - /** - * - * - * @param app ... - */ - public void applicationStopped(Application app) { - app.logEvent("DemoExtension stopped on app " + app.getName()); - } - - /** - * - * - * @param app ... - */ - public void applicationUpdated(Application app) { - app.logEvent("DemoExtension updated on app " + app.getName()); - } - - /** - * - * - * @param app ... - * @param engine ... - * - * @return ... - * - * @throws ConfigurationException ... - */ - public HashMap initScripting(Application app, ScriptingEngine engine) - throws ConfigurationException { - if (!(engine instanceof RhinoEngine)) { - throw new ConfigurationException("scripting engine " + engine.toString() + - " not supported in DemoExtension"); - } - - app.logEvent("initScripting DemoExtension with " + app.getName() + " and " + - engine.toString()); - - // initialize prototypes and global vars here - HashMap globals = new HashMap(); - - globals.put("demo", Server.getServer()); - - return globals; - } - - /** - * - * - * @return ... - */ - public String getName() { - return "DemoExtension"; - } -} diff --git a/src/helma/framework/ApplicationStoppedException.java b/src/helma/framework/ApplicationStoppedException.java deleted file mode 100644 index a07f20fd..00000000 --- a/src/helma/framework/ApplicationStoppedException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - - -/** - * This is thrown when a request is made to a stopped - * application - */ -public class ApplicationStoppedException extends RuntimeException { - /** - * Creates a new ApplicationStoppedException object. - */ - public ApplicationStoppedException() { - super("The application has been stopped"); - } -} diff --git a/src/helma/framework/CookieTrans.java b/src/helma/framework/CookieTrans.java deleted file mode 100644 index bf60d715..00000000 --- a/src/helma/framework/CookieTrans.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - -import java.io.Serializable; -import java.util.HashMap; -import javax.servlet.http.Cookie; - -/** - * Cookie Transmitter. A simple, serializable representation - * of an HTTP cookie. - */ -public final class CookieTrans implements Serializable { - String name; - String value; - String path; - String domain; - int days; - - CookieTrans(String name, String value) { - this.name = name; - this.value = value; - } - - void setValue(String value) { - this.value = value; - } - - void setDays(int days) { - this.days = days; - } - - void setPath(String path) { - this.path = path; - } - - void setDomain(String domain) { - this.domain = domain; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @return ... - */ - public String getValue() { - return value; - } - - /** - * - * - * @return ... - */ - public int getDays() { - return days; - } - - /** - * - * - * @return ... - */ - public String getPath() { - return path; - } - - /** - * - * - * @return ... - */ - public String getDomain() { - return domain; - } - - /** - * - * - * @param defaultPath ... - * @param defaultDomain ... - * - * @return ... - */ - public Cookie getCookie(String defaultPath, String defaultDomain) { - Cookie c = new Cookie(name, value); - - if (days > 0) { - // Cookie time to live, days -> seconds - c.setMaxAge(days * 60 * 60 * 24); - } - - if (path != null) { - c.setPath(path); - } else if (defaultPath != null) { - c.setPath(defaultPath); - } - - if (domain != null) { - c.setDomain(domain); - } else if (defaultDomain != null) { - c.setDomain(defaultDomain); - } - - return c; - } -} diff --git a/src/helma/framework/FrameworkException.java b/src/helma/framework/FrameworkException.java deleted file mode 100644 index be0a48a0..00000000 --- a/src/helma/framework/FrameworkException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - - -/** - * The basic exception class used to tell when certain things go - * wrong in evaluation of requests. - */ -public class FrameworkException extends RuntimeException { - /** - * Creates a new FrameworkException object. - * - * @param msg ... - */ - public FrameworkException(String msg) { - super(msg); - } -} diff --git a/src/helma/framework/IPathElement.java b/src/helma/framework/IPathElement.java deleted file mode 100644 index b56289e5..00000000 --- a/src/helma/framework/IPathElement.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - - -/** - * Interface that objects need to implement to build a Helma URL tree. Apart from methods - * to retrieve the identifier and its child and parent elements, this interface defines a method - * that determines which prototype to use to add scripts and skins to an object.

- * - * Please note that this interface is still work in progress. You should expect it to get some - * additional methods that allow for looping through child elements, for example, or retrieving the - * parent element.

- * - */ -public interface IPathElement { - /** - * Return the name to be used to get this element from its parent - */ - public String getElementName(); - - /** - * Retrieve a child element of this object by name. - */ - public IPathElement getChildElement(String name); - - /** - * Return the parent element of this object. - */ - public IPathElement getParentElement(); - - /** - * Get the name of the prototype to be used for this object. This will - * determine which scripts, actions and skins can be called on it - * within the Helma scripting and rendering framework. - */ - public String getPrototype(); -} diff --git a/src/helma/framework/IRemoteApp.java b/src/helma/framework/IRemoteApp.java deleted file mode 100644 index b4ce5481..00000000 --- a/src/helma/framework/IRemoteApp.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - -import java.rmi.*; -import java.util.Vector; - -/** - * RMI interface for an application. Currently only execute is used and supported. - */ -public interface IRemoteApp extends Remote { - /** - * - * - * @param param ... - * - * @return ... - * - * @throws RemoteException ... - */ - public ResponseTrans execute(RequestTrans param) throws RemoteException; - - /** - * - * - * @throws RemoteException ... - */ - public void ping() throws RemoteException; -} diff --git a/src/helma/framework/RedirectException.java b/src/helma/framework/RedirectException.java deleted file mode 100644 index f81fcee2..00000000 --- a/src/helma/framework/RedirectException.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - - -/** - * RedirectException is thrown internally when a response is redirected to a - * new URL. Although this is not an Error, it subclasses java.lang.Error - * because it's not meant to be caught by application code (similar to - * java.lang.ThreadDeath). - */ -public class RedirectException extends Error { - String url; - - /** - * Creates a new RedirectException object. - * - * @param url ... - */ - public RedirectException(String url) { - super("Redirection Request to " + url); - this.url = url; - } - - /** - * - * - * @return ... - */ - public String getMessage() { - return url; - } - - /** - * - * - * @param s ... - */ - public void printStackTrace(java.io.PrintStream s) { - // do nothing - } - - /** - * - * - * @param w ... - */ - public void printStackTrace(java.io.PrintWriter w) { - // do nothing - } -} diff --git a/src/helma/framework/RequestBean.java b/src/helma/framework/RequestBean.java deleted file mode 100644 index 1b6da6b7..00000000 --- a/src/helma/framework/RequestBean.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - -import helma.framework.core.Application; -import java.io.Serializable; -import java.util.Date; -import java.util.Map; - -/** - * - */ -public class RequestBean implements Serializable { - RequestTrans req; - - /** - * Creates a new RequestBean object. - * - * @param req ... - */ - public RequestBean(RequestTrans req) { - this.req = req; - } - - /** - * - * - * @param name ... - * - * @return ... - */ - public Object get(String name) { - return req.get(name); - } - - /** - * - * - * @return ... - */ - public boolean isGet() { - return req.isGet(); - } - - /** - * - * - * @return ... - */ - public boolean isPost() { - return req.isPost(); - } - - /** - * - * - * @return ... - */ - public String toString() { - return "[Request]"; - } - - // property related methods: - public String getAction() { - return req.action; - } - - /** - * - * - * @return ... - */ - public Map getData() { - return req.getRequestData(); - } - - /** - * - * - * @return ... - */ - public long getRuntime() { - return (System.currentTimeMillis() - req.startTime); - } - - /** - * - * - * @return ... - */ - public String getPassword() { - return req.getPassword(); - } - - /** - * - * - * @return ... - */ - public String getPath() { - return req.path; - } - - /** - * - * - * @return ... - */ - public String getUsername() { - return req.getUsername(); - } - -} diff --git a/src/helma/framework/RequestTrans.java b/src/helma/framework/RequestTrans.java deleted file mode 100644 index c906bec1..00000000 --- a/src/helma/framework/RequestTrans.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - -import helma.objectmodel.*; -import helma.util.Base64; -import helma.util.SystemMap; -import java.io.*; -import java.util.*; - -/** - * A Transmitter for a request from the servlet client. Objects of this - * class are directly exposed to JavaScript as global property req. - */ -public class RequestTrans implements Externalizable { - static final long serialVersionUID = 5398880083482000580L; - - // the uri path of the request - public String path; - - // the request's session id - public String session; - - // the map of form and cookie data - private Map values; - - // the request method - 0 for GET, 1 for POST - private byte httpMethod = 0; - - // timestamp of client-cached version, if present in request - private long ifModifiedSince = -1; - - // set of ETags the client sent with If-None-Match header - private Set etags; - - // when was execution started on this request? - public transient long startTime; - - // the name of the action being invoked - public transient String action; - private transient String httpUsername; - private transient String httpPassword; - - /** - * Create a new Request transmitter with an empty data map. - */ - public RequestTrans() { - httpMethod = 0; - values = new SystemMap(); - } - - /** - * Create a new request transmitter with the given data map. - */ - public RequestTrans(byte method) { - httpMethod = method; - values = new SystemMap(); - } - - /** - * Set a parameter value in this request transmitter. - */ - public void set(String name, Object value) { - values.put(name, value); - } - - /** - * Get a value from the requests map by key. - */ - public Object get(String name) { - try { - return values.get(name); - } catch (Exception x) { - return null; - } - } - - /** - * Get the data map for this request transmitter. - */ - public Map getRequestData() { - return values; - } - - /** - * The hash code is computed from the session id if available. This is used to - * detect multiple identic requests. - */ - public int hashCode() { - return (session == null) ? super.hashCode() : session.hashCode(); - } - - /** - * A request is considered equal to another one if it has the same user, path, - * and request data. This is used to evaluate multiple simultanous requests only once - */ - public boolean equals(Object what) { - try { - RequestTrans other = (RequestTrans) what; - - return (session.equals(other.session) && path.equalsIgnoreCase(other.path) && - values.equals(other.getRequestData())); - } catch (Exception x) { - return false; - } - } - - /** - * Return true if this object represents a HTTP GET Request. - */ - public boolean isGet() { - return httpMethod == 0; - } - - /** - * Return true if this object represents a HTTP GET Request. - */ - public boolean isPost() { - return httpMethod == 1; - } - - /** - * Custom externalization code for quicker serialization. - */ - public void readExternal(ObjectInput s) throws ClassNotFoundException, IOException { - path = s.readUTF(); - session = s.readUTF(); - values = (Map) s.readObject(); - httpMethod = s.readByte(); - ifModifiedSince = s.readLong(); - etags = (Set) s.readObject(); - } - - /** - * Custom externalization code for quicker serialization. - */ - public void writeExternal(ObjectOutput s) throws IOException { - s.writeUTF(path); - s.writeUTF(session); - s.writeObject(values); - s.writeByte(httpMethod); - s.writeLong(ifModifiedSince); - s.writeObject(etags); - } - - /** - * - * - * @param since ... - */ - public void setIfModifiedSince(long since) { - ifModifiedSince = since; - } - - /** - * - * - * @return ... - */ - public long getIfModifiedSince() { - return ifModifiedSince; - } - - /** - * - * - * @param etagHeader ... - */ - public void setETags(String etagHeader) { - etags = new HashSet(); - - if (etagHeader.indexOf(",") > -1) { - StringTokenizer st = new StringTokenizer(etagHeader, ", \r\n"); - - while (st.hasMoreTokens()) - etags.add(st.nextToken()); - } else { - etags.add(etagHeader); - } - } - - /** - * - * - * @return ... - */ - public Set getETags() { - return etags; - } - - /** - * - * - * @param etag ... - * - * @return ... - */ - public boolean hasETag(String etag) { - if ((etags == null) || (etag == null)) { - return false; - } - - return etags.contains(etag); - } - - /** - * - * - * @return ... - */ - public String getUsername() { - if (httpUsername != null) { - return httpUsername; - } - - String auth = (String) get("authorization"); - - if ((auth == null) || "".equals(auth)) { - return null; - } - - decodeHttpAuth(auth); - - return httpUsername; - } - - /** - * - * - * @return ... - */ - public String getPassword() { - if (httpPassword != null) { - return httpPassword; - } - - String auth = (String) get("authorization"); - - if ((auth == null) || "".equals(auth)) { - return null; - } - - decodeHttpAuth(auth); - - return httpPassword; - } - - private void decodeHttpAuth(String auth) { - if (auth == null) { - return; - } - - StringTokenizer tok; - - if (auth.startsWith("Basic ")) { - tok = new StringTokenizer(new String(Base64.decode((auth.substring(6)).toCharArray())), - ":"); - } else { - tok = new StringTokenizer(new String(Base64.decode(auth.toCharArray())), ":"); - } - - try { - httpUsername = tok.nextToken(); - } catch (NoSuchElementException e) { - httpUsername = null; - } - - try { - httpPassword = tok.nextToken(); - } catch (NoSuchElementException e) { - httpPassword = null; - } - } -} diff --git a/src/helma/framework/ResponseBean.java b/src/helma/framework/ResponseBean.java deleted file mode 100644 index 7966a49c..00000000 --- a/src/helma/framework/ResponseBean.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - -import helma.framework.core.Application; -import java.io.Serializable; -import java.util.Date; -import java.util.Map; - -/** - * - */ -public class ResponseBean implements Serializable { - ResponseTrans res; - - /** - * Creates a new ResponseBean object. - * - * @param res ... - */ - public ResponseBean(ResponseTrans res) { - this.res = res; - } - - /** - * - * - * @param what ... - */ - public void encode(Object what) { - res.encode(what); - } - - /** - * - * - * @param what ... - */ - public void encodeXml(Object what) { - res.encodeXml(what); - } - - /** - * - * - * @param what ... - */ - public void format(Object what) { - res.format(what); - } - - /** - * - * - * @param url ... - * - * @throws RedirectException ... - */ - public void redirect(String url) throws RedirectException { - res.redirect(url); - } - - /** - * - */ - public void reset() { - res.reset(); - } - - /** - * - * - * @param key ... - * @param value ... - */ - public void setCookie(String key, String value) { - res.setCookie(key, value, -1, null, null); - } - - /** - * - * - * @param key ... - * @param value ... - * @param days ... - */ - public void setCookie(String key, String value, int days) { - res.setCookie(key, value, days, null, null); - } - - /** - * - * - * @param key ... - * @param value ... - * @param days ... - * @param path ... - */ - public void setCookie(String key, String value, int days, String path) { - res.setCookie(key, value, days, path, null); - } - - /** - * - * - * @param key ... - * @param value ... - * @param days ... - * @param path ... - * @param domain ... - */ - public void setCookie(String key, String value, int days, String path, String domain) { - res.setCookie(key, value, days, path, domain); - } - - /** - * - * - * @param what ... - */ - public void write(String what) { - res.write(what); - } - - /** - * - * - * @param what ... - */ - public void writeln(String what) { - res.writeln(what); - } - - /** - * - * - * @param what ... - */ - public void writeBinary(byte[] what) { - res.writeBinary(what); - } - - /** - * - * - * @param message ... - */ - public void debug(String message) { - res.debug(message); - } - - /** - * - * - * @return ... - */ - public String toString() { - return "[Response]"; - } - - // property-related methods: - public boolean getCache() { - return res.cache; - } - - /** - * - * - * @param cache ... - */ - public void setcache(boolean cache) { - res.cache = cache; - } - - /** - * - * - * @return ... - */ - public String getCharset() { - return res.charset; - } - - /** - * - * - * @param charset ... - */ - public void setCharset(String charset) { - res.charset = charset; - } - - /** - * - * - * @return ... - */ - public String getContentType() { - return res.contentType; - } - - /** - * - * - * @param contentType ... - */ - public void setContentType(String contentType) { - res.contentType = contentType; - } - - /** - * - * - * @return ... - */ - public Map getData() { - return res.getResponseData(); - } - - /** - * - * - * @return ... - */ - public Map getHandlers() { - return res.getMacroHandlers(); - } - - /** - * - * - * @return ... - */ - public String getError() { - return res.error; - } - - /** - * - * - * @return ... - */ - public String getMessage() { - return res.message; - } - - /** - * - * - * @param message ... - */ - public void setMessage(String message) { - res.message = message; - } - - /** - * - * - * @return ... - */ - public String getRealm() { - return res.realm; - } - - /** - * - * - * @param realm ... - */ - public void setRealm(String realm) { - res.realm = realm; - } - - /** - * - * - * @param arr ... - */ - public void setSkinpath(Object[] arr) { - res.setSkinpath(arr); - } - - /** - * - * - * @return ... - */ - public Object[] getSkinpath() { - return res.getSkinpath(); - } - - /** - * - * - * @return ... - */ - public int getStatus() { - return res.status; - } - - /** - * - * - * @param status ... - */ - public void setStatus(int status) { - res.status = status; - } - - /** - * - * - * @return ... - */ - public Date getLastModified() { - long modified = res.getLastModified(); - - if (modified > -1) { - return new Date(modified); - } else { - return null; - } - } - - /** - * - * - * @param date ... - */ - public void setLastModified(Date date) { - if (date == null) { - res.setLastModified(-1); - } else { - res.setLastModified(date.getTime()); - } - } - - /** - * - * - * @return ... - */ - public String getETag() { - return res.getETag(); - } - - /** - * - * - * @param etag ... - */ - public void setETag(String etag) { - res.setETag(etag); - } - - /** - * - * - * @param what ... - */ - public void dependsOn(String what) { - res.dependsOn(what); - } - - /** - * - */ - public void digest() { - res.digestDependencies(); - } - - ///////////////////////////////////// - // The following are legacy methods used by - // Helma templates (*.hsp files) and shouldn't - // be used otherwise. - //////////////////////////////////// - public void pushStringBuffer() { - res.pushStringBuffer(); - } - - /** - * - * - * @return ... - */ - public String popStringBuffer() { - return res.popStringBuffer(); - } -} diff --git a/src/helma/framework/ResponseTrans.java b/src/helma/framework/ResponseTrans.java deleted file mode 100644 index f63361ec..00000000 --- a/src/helma/framework/ResponseTrans.java +++ /dev/null @@ -1,794 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework; - -import helma.framework.core.Skin; -import helma.objectmodel.*; -import helma.util.*; -import java.io.*; -import java.security.*; -import java.util.*; - -/** - * A Transmitter for a response to the servlet client. Objects of this - * class are directly exposed to JavaScript as global property res. - */ -public final class ResponseTrans implements Externalizable { - static final long serialVersionUID = -8627370766119740844L; - static final int INITIAL_BUFFER_SIZE = 2048; - - static final String newLine = System.getProperty("line.separator"); - - /** - * Set the MIME content type of the response. - */ - public String contentType = "text/html"; - - /** - * Set the charset (encoding) to use for the response. - */ - public String charset; - - /** - * used to allow or disable client side caching - */ - public boolean cache = true; - - /** - * Used for HTTP response code, if 0 code 200 OK will be used. - */ - public int status = 0; - - /** - * Used for HTTP authentication - */ - public String realm; - - // name of the skin to be rendered after completion, if any - public transient String skin = null; - - // the actual response - private byte[] response = null; - - // contains the redirect URL - private String redir = null; - - // the last-modified date, if it should be set in the response - private long lastModified = -1; - - // flag to signal that resource has not been modified - private boolean notModified = false; - - // Entity Tag for this response, used for conditional GETs - private String etag = null; - - // cookies - Map cookies; - - // the buffer used to build the response - private transient StringBuffer buffer = null; - - // these are used to implement the _as_string variants for Hop templates. - private transient Stack buffers; - - // the path used to tell where to look for skins - private transient Object[] skinpath = null; - - // hashmap for skin caching - private transient HashMap skincache; - - // buffer for debug messages - will be automatically appended to response - private transient StringBuffer debugBuffer; - - /** - * string fields that hold a user message - */ - public transient String message; - - /** - * string fields that hold an error message - */ - public transient String error; - - // the map of form and cookie data - private transient Map values; - - // the map of macro handlers - private transient Map handlers; - - // the request trans for this response - private transient RequestTrans reqtrans; - - // the message digest used to generate composed digests for ETag headers - private transient MessageDigest digest; - - // the appliciation checksum to make ETag headers sensitive to app changes - long applicationChecksum; - - /** - * Creates a new ResponseTrans object. - */ - public ResponseTrans() { - super(); - message = error = null; - values = new SystemMap(); - handlers = new SystemMap(); - } - - /** - * Creates a new ResponseTrans object. - * - * @param req ... - */ - public ResponseTrans(RequestTrans req) { - this(); - reqtrans = req; - } - - /** - * Get a value from the responses map by key. - */ - public Object get(String name) { - try { - return values.get(name); - } catch (Exception x) { - return null; - } - } - - /** - * Get the data map for this response transmitter. - */ - public Map getResponseData() { - return values; - } - - /** - * Get the macro handlers map for this response transmitter. - */ - public Map getMacroHandlers() { - return handlers; - } - - /** - * Reset the response object to its initial empty state. - */ - public void reset() { - if (buffer != null) { - buffer.setLength(0); - } - - buffers = null; - response = null; - redir = null; - skin = null; - message = error = null; - values.clear(); - lastModified = -1; - notModified = false; - etag = null; - - if (digest != null) { - digest.reset(); - } - } - - /** - * This is called before a skin is rendered as string (renderSkinAsString) to redirect the output - * to a new string buffer. - */ - public void pushStringBuffer() { - if (buffers == null) { - buffers = new Stack(); - } - - if (buffer != null) { - buffers.push(buffer); - } - - buffer = new StringBuffer(64); - } - - /** - * Returns the content of the current string buffer and switches back to the previos one. - */ - public String popStringBuffer() { - StringBuffer b = buffer; - - buffer = buffers.empty() ? null : (StringBuffer) buffers.pop(); - - return b.toString(); - } - - /** - * Get the response buffer, creating it if it doesn't exist - */ - public StringBuffer getBuffer() { - if (buffer == null) { - buffer = new StringBuffer(INITIAL_BUFFER_SIZE); - } - - return buffer; - } - - /** - * Append a string to the response unchanged. This is often called - * at the end of a request to write out the whole page, so if buffer - * is uninitialized we just set it to the string argument. - */ - public void write(Object what) { - if (what != null) { - String str = what.toString(); - - if (buffer == null) { - buffer = new StringBuffer(Math.max(str.length() + 100, INITIAL_BUFFER_SIZE)); - } - - buffer.append(str); - } - } - - /** - * Utility function that appends a
to whatever is written. - */ - public void writeln(Object what) { - write(what); - - // if what is null, buffer may still be uninitialized - if (buffer == null) { - buffer = new StringBuffer(INITIAL_BUFFER_SIZE); - } - - buffer.append("
"); - buffer.append(newLine); - } - - /** - * Append a part from a char array to the response buffer. - */ - public void writeCharArray(char[] c, int start, int length) { - if (buffer == null) { - buffer = new StringBuffer(Math.max(length, INITIAL_BUFFER_SIZE)); - } - - buffer.append(c, start, length); - } - - /** - * Insert string somewhere in the response buffer. Caller has to make sure - * that buffer exists and its length is larger than offset. str may be null, in which - * case nothing happens. - */ - public void debug(Object message) { - if (debugBuffer == null) { - debugBuffer = new StringBuffer(); - } - - String str = (message == null) ? "null" : message.toString(); - - debugBuffer.append("

"); - debugBuffer.append(str); - debugBuffer.append("

"); - } - - /** - * Replace special characters with entities, including <, > and ", thus allowing - * no HTML tags. - */ - public void encode(Object what) { - if (what != null) { - String str = what.toString(); - - if (buffer == null) { - buffer = new StringBuffer(Math.max(str.length() + 100, INITIAL_BUFFER_SIZE)); - } - - HtmlEncoder.encodeAll(str, buffer); - } - } - - /** - * Replace special characters with entities but pass through HTML tags - */ - public void format(Object what) { - if (what != null) { - String str = what.toString(); - - if (buffer == null) { - buffer = new StringBuffer(Math.max(str.length() + 100, INITIAL_BUFFER_SIZE)); - } - - HtmlEncoder.encode(str, buffer); - } - } - - /** - * Replace special characters with entities, including <, > and ", thus allowing - * no HTML tags. - */ - public void encodeXml(Object what) { - if (what != null) { - String str = what.toString(); - - if (buffer == null) { - buffer = new StringBuffer(Math.max(str.length() + 100, INITIAL_BUFFER_SIZE)); - } - - HtmlEncoder.encodeXml(str, buffer); - } - } - - /** - * Encode HTML entities, but leave newlines alone. This is for the content of textarea forms. - */ - public void encodeForm(Object what) { - if (what != null) { - String str = what.toString(); - - if (buffer == null) { - buffer = new StringBuffer(Math.max(str.length() + 100, INITIAL_BUFFER_SIZE)); - } - - HtmlEncoder.encodeAll(str, buffer, false); - } - } - - /** - * - * - * @param str ... - */ - public void append(String str) { - if (str != null) { - if (buffer == null) { - buffer = new StringBuffer(Math.max(str.length(), INITIAL_BUFFER_SIZE)); - } - - buffer.append(str); - } - } - - /** - * - * - * @param url ... - * - * @throws RedirectException ... - */ - public void redirect(String url) throws RedirectException { - redir = url; - throw new RedirectException(url); - } - - /** - * - * - * @return ... - */ - public String getRedirect() { - return redir; - } - - /** - * Allow to directly set the byte array for the response. Calling this more than once will - * overwrite the previous output. We take a generic object as parameter to be able to - * generate a better error message, but it must be byte[]. - */ - public void writeBinary(byte[] what) { - response = what; - } - - /** - * This has to be called after writing to this response has finished and before it is shipped back to the - * web server. Transforms the string buffer into a char array to minimize size. - */ - public synchronized void close(String cset) throws UnsupportedEncodingException { - // only use default charset if not explicitly set for this response. - if (charset == null) { - charset = cset; - } - - // if charset is not set, use western encoding - if (charset == null) { - charset = "ISO-8859-1"; - } - - boolean encodingError = false; - - // only close if the response hasn't been closed yet - if (response == null) { - // if debug buffer exists, append it to main buffer - if (debugBuffer != null) { - if (buffer == null) { - buffer = debugBuffer; - } else { - buffer.append(debugBuffer); - } - } - - // get the buffer's bytes in the specified encoding - if (buffer != null) { - try { - response = buffer.toString().getBytes(charset); - } catch (UnsupportedEncodingException uee) { - encodingError = true; - response = buffer.toString().getBytes(); - } - - // make sure this is done only once, even with more requsts attached - buffer = null; - } else { - response = new byte[0]; - } - } - - // if etag is not set, calc MD5 digest and check it - if ((etag == null) && (lastModified == -1) && (redir == null)) { - try { - digest = MessageDigest.getInstance("MD5"); - - // if (contentType != null) - // digest.update (contentType.getBytes()); - byte[] b = digest.digest(response); - - etag = "\"" + new String(Base64.encode(b)) + "\""; - - if ((reqtrans != null) && reqtrans.hasETag(etag)) { - response = new byte[0]; - notModified = true; - } - } catch (Exception ignore) { - // Etag creation failed for some reason. Ignore. - } - } - - notifyAll(); - - // if there was a problem with the encoding, let the app know - if (encodingError) { - throw new UnsupportedEncodingException(charset); - } - } - - /** - * If we just attached to evaluation we call this instead of close because only the primary thread - * is responsible for closing the result - */ - public synchronized void waitForClose() { - try { - if (response == null) { - wait(10000L); - } - } catch (InterruptedException ix) { - } - } - - /** - * - * - * @return ... - */ - public byte[] getContent() { - return (response == null) ? new byte[0] : response; - } - - /** - * - * - * @return ... - */ - public int getContentLength() { - if (response != null) { - return response.length; - } - - return 0; - } - - /** - * - * - * @return ... - */ - public String getContentType() { - if (charset != null) { - return contentType + "; charset=" + charset; - } - - return contentType; - } - - /** - * - * - * @param modified ... - */ - public void setLastModified(long modified) { - if ((modified > -1) && (reqtrans != null) && - (reqtrans.getIfModifiedSince() >= modified)) { - notModified = true; - throw new RedirectException(null); - } - - lastModified = modified; - } - - /** - * - * - * @return ... - */ - public long getLastModified() { - return lastModified; - } - - /** - * - * - * @param value ... - */ - public void setETag(String value) { - etag = (value == null) ? null : ("\"" + value + "\""); - - if ((etag != null) && (reqtrans != null) && reqtrans.hasETag(etag)) { - notModified = true; - throw new RedirectException(null); - } - } - - /** - * - * - * @return ... - */ - public String getETag() { - return etag; - } - - /** - * - * - * @return ... - */ - public boolean getNotModified() { - return notModified; - } - - /** - * - * - * @param what ... - */ - public void dependsOn(Object what) { - if (digest == null) { - try { - digest = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException nsa) { - // MD5 should always be available - } - } - - if (what == null) { - digest.update(new byte[0]); - } else if (what instanceof Date) { - digest.update(MD5Encoder.toBytes(((Date) what).getTime())); - } else if (what instanceof byte[]) { - digest.update((byte[]) what); - } else { - String str = what.toString(); - - if (str != null) { - digest.update(str.getBytes()); - } else { - digest.update(new byte[0]); - } - } - } - - /** - * - */ - public void digestDependencies() { - if (digest == null) { - return; - } - - byte[] b = digest.digest(MD5Encoder.toBytes(applicationChecksum)); - - /* StringBuffer buf = new StringBuffer(b.length*2); - for ( int i=0; i active requestevaluators - Hashtable activeRequests; - - // Two logs for each application: events and accesses - Logger eventLog; - - // Two logs for each application: events and accesses - Logger accessLog; - - // A transient node that is shared among all evaluators - protected INode cachenode; - - // some fields for statistics - protected volatile long requestCount = 0; - protected volatile long xmlrpcCount = 0; - protected volatile long errorCount = 0; - - // the URL-prefix to use for links into this application - private String baseURI; - // the name of the root prototype - private String rootPrototype; - - // Db mappings for some standard prototypes - private DbMapping rootMapping; - private DbMapping userRootMapping; - private DbMapping userMapping; - - // name of response encoding - String charset; - - // password file to use for authenticate() function - private CryptFile pwfile; - - // Map of java class names to object prototypes - SystemProperties classMapping; - - // Map of extensions allowed for public skins - Properties skinExtensions; - - // time we last read the properties file - private long lastPropertyRead = 0L; - - // the set of prototype/function pairs which are allowed to be called via XML-RPC - private HashSet xmlrpcAccess; - - // the name under which this app serves XML-RPC requests. Defaults to the app name - private String xmlrpcHandlerName; - - // the list of currently active cron jobs - private Map activeCronJobs = null; - // the list of custom cron jobs - Hashtable customCronJobs = null; - - /** - * Simple constructor for dead application instances. - */ - public Application(String name) { - this.name = name; - } - - /** - * Build an application with the given name in the app directory. No Server-wide - * properties are created or used. - */ - public Application(String name, File appDir, File dbDir) - throws RemoteException, IllegalArgumentException { - this(name, null, appDir, dbDir); - } - - /** - * Build an application with the given name and server instance. The - * app directories will be created if they don't exist already. - */ - public Application(String name, Server server) - throws RemoteException, IllegalArgumentException { - this(name, server, null, null); - } - - /** - * Build an application with the given name, server instance, app and - * db directories. - */ - public Application(String name, Server server, File customAppDir, File customDbDir) - throws RemoteException, IllegalArgumentException { - if ((name == null) || (name.trim().length() == 0)) { - throw new IllegalArgumentException("Invalid application name: " + name); - } - - this.name = name; - appDir = customAppDir; - dbDir = customDbDir; - - // system-wide properties, default to null - SystemProperties sysProps; - - // system-wide properties, default to null - SystemProperties sysDbProps; - - sysProps = sysDbProps = null; - home = null; - - if (server != null) { - home = server.getHopHome(); - - // if appDir and dbDir weren't explicitely passed, use the - // standard subdirectories of the Hop home directory - if (appDir == null) { - appDir = new File(server.getAppsHome(), name); - } - - if (dbDir == null) { - dbDir = new File(server.getDbHome(), name); - } - - // get system-wide properties - sysProps = server.getProperties(); - sysDbProps = server.getDbProperties(); - } - - // create the directories if they do not exist already - if (!appDir.exists()) { - appDir.mkdirs(); - } - - if (!dbDir.exists()) { - dbDir.mkdirs(); - } - - // give the Helma Thread group a name so the threads can be recognized - threadgroup = new ThreadGroup("TX-" + name); - - // create app-level properties - File propfile = new File(appDir, "app.properties"); - - props = new SystemProperties(propfile.getAbsolutePath(), sysProps); - - // create app-level db sources - File dbpropfile = new File(appDir, "db.properties"); - - dbProps = new SystemProperties(dbpropfile.getAbsolutePath(), sysDbProps); - - // the passwd file, to be used with the authenticate() function - CryptFile parentpwfile = null; - - if (home != null) { - parentpwfile = new CryptFile(new File(home, "passwd"), null); - } - - pwfile = new CryptFile(new File(appDir, "passwd"), parentpwfile); - - // the properties that map java class names to prototype names - File classMappingFile = new File(appDir, "class.properties"); - - classMapping = new SystemProperties(classMappingFile.getAbsolutePath()); - classMapping.setIgnoreCase(false); - - // get class name of root object if defined. Otherwise native Helma objectmodel will be used. - rootObjectClass = classMapping.getProperty("root"); - - updateProperties(); - - sessions = new Hashtable(); - dbSources = new Hashtable(); - modules = new SystemMap(); - - cachenode = new TransientNode("app"); - } - - /** - * Get the application ready to run, initializing the evaluators and type manager. - */ - public void init() - throws DatabaseException, ScriptingException, MalformedURLException { - Vector extensions = Server.getServer().getExtensions(); - - for (int i = 0; i < extensions.size(); i++) { - HelmaExtension ext = (HelmaExtension) extensions.get(i); - - try { - ext.applicationStarted(this); - } catch (ConfigurationException e) { - logEvent("couldn't init extension " + ext.getName() + ": " + - e.toString()); - } - } - - // read the sessions if wanted - if ("true".equalsIgnoreCase(getProperty("persistentSessions"))) { - loadSessionData(null); - } - - // create and init type mananger - typemgr = new TypeManager(this); - typemgr.createPrototypes(); - - // create and init evaluator/thread lists - freeThreads = new Stack(); - allThreads = new Vector(); - - // preallocate minThreads request evaluators - int minThreads = 0; - - try { - minThreads = Integer.parseInt(props.getProperty("minThreads")); - } catch (Exception ignore) { - // not parsable as number, keep 0 - } - - logEvent("Starting "+minThreads+" evaluator(s) for " + name); - - for (int i = 0; i < minThreads; i++) { - RequestEvaluator ev = new RequestEvaluator(this); - - ev.initScriptingEngine(); - freeThreads.push(ev); - allThreads.addElement(ev); - } - - activeRequests = new Hashtable(); - activeCronJobs = new WeakHashMap(); - customCronJobs = new Hashtable(); - - skinmgr = new SkinManager(this); - - rootMapping = getDbMapping("root"); - userMapping = getDbMapping("user"); - - SystemProperties p = new SystemProperties(); - String usernameField = userMapping.getNameField(); - - if (usernameField == null) { - usernameField = "name"; - } - - p.put("_children", "collection(user)"); - p.put("_children.accessname", usernameField); - userRootMapping = new DbMapping(this, "__userroot__", p); - userRootMapping.update(); - - nmgr = new NodeManager(this, dbDir.getAbsolutePath(), props); - } - - /** - * Create and start scheduler and cleanup thread - */ - public void start() { - starttime = System.currentTimeMillis(); - worker = new Thread(this, "Worker-" + name); - worker.setPriority(Thread.NORM_PRIORITY + 1); - worker.start(); - - // logEvent ("session cleanup and scheduler thread started"); - } - - /** - * This is called to shut down a running application. - */ - public void stop() { - stopped = true; - - // stop all threads, this app is going down - if (worker != null) { - worker.interrupt(); - } - - worker = null; - - // stop evaluators - if (allThreads != null) { - for (Enumeration e = allThreads.elements(); e.hasMoreElements();) { - RequestEvaluator ev = (RequestEvaluator) e.nextElement(); - - ev.stopThread(); - } - } - - // remove evaluators - allThreads.removeAllElements(); - freeThreads = null; - - // shut down node manager and embedded db - try { - nmgr.shutdown(); - } catch (DatabaseException dbx) { - System.err.println("Error shutting down embedded db: " + dbx); - } - - // null out type manager - typemgr = null; - - // tell the extensions that we're stopped. - Vector extensions = Server.getServer().getExtensions(); - - for (int i = 0; i < extensions.size(); i++) { - HelmaExtension ext = (HelmaExtension) extensions.get(i); - - ext.applicationStopped(this); - } - - // store the sessions if wanted - if ("true".equalsIgnoreCase(getProperty("persistentSessions"))) { - storeSessionData(null); - } - - // stop logs if they exist - if (eventLog != null) { - eventLog.close(); - } - - if (accessLog != null) { - accessLog.close(); - } - } - - /** - * Returns a free evaluator to handle a request. - */ - protected RequestEvaluator getEvaluator() { - if (stopped) { - throw new ApplicationStoppedException(); - } - - // first try - try { - return (RequestEvaluator) freeThreads.pop(); - } catch (EmptyStackException nothreads) { - int maxThreads = 12; - - try { - maxThreads = Integer.parseInt(props.getProperty("maxThreads")); - } catch (Exception ignore) { - // property not set, use default value - } - - synchronized (this) { - // allocate a new evaluator - if (allThreads.size() < maxThreads) { - logEvent("Starting evaluator " + (allThreads.size() + 1) + - " for application " + name); - - RequestEvaluator ev = new RequestEvaluator(this); - - allThreads.addElement(ev); - - return (ev); - } - } - } - - // we can't create a new evaluator, so we wait if one becomes available. - // give it 3 more tries, waiting 3 seconds each time. - for (int i = 0; i < 4; i++) { - try { - Thread.sleep(3000); - - return (RequestEvaluator) freeThreads.pop(); - } catch (EmptyStackException nothreads) { - // do nothing - } catch (InterruptedException inter) { - throw new RuntimeException("Thread interrupted."); - } - } - - // no luck, give up. - throw new RuntimeException("Maximum Thread count reached."); - } - - /** - * Returns an evaluator back to the pool when the work is done. - */ - protected void releaseEvaluator(RequestEvaluator ev) { - if (ev != null) { - ev.recycle(); - freeThreads.push(ev); - } - } - - /** - * This can be used to set the maximum number of evaluators which will be allocated. - * If evaluators are required beyound this number, an error will be thrown. - */ - public boolean setNumberOfEvaluators(int n) { - if ((n < 2) || (n > 511)) { - return false; - } - - int current = allThreads.size(); - - synchronized (allThreads) { - if (n > current) { - int toBeCreated = n - current; - - for (int i = 0; i < toBeCreated; i++) { - RequestEvaluator ev = new RequestEvaluator(this); - - freeThreads.push(ev); - allThreads.addElement(ev); - } - } else if (n < current) { - int toBeDestroyed = current - n; - - for (int i = 0; i < toBeDestroyed; i++) { - try { - RequestEvaluator re = (RequestEvaluator) freeThreads.pop(); - - allThreads.removeElement(re); - - // typemgr.unregisterRequestEvaluator (re); - re.stopThread(); - } catch (EmptyStackException empty) { - return false; - } - } - } - } - - return true; - } - - /** - * Return the number of currently active threads - */ - public int getActiveThreads() { - return 0; - } - - /** - * Execute a request coming in from a web client. - */ - public ResponseTrans execute(RequestTrans req) { - requestCount += 1; - - // get user for this request's session - Session session = checkSession(req.session); - - session.touch(); - - ResponseTrans res = null; - RequestEvaluator ev = null; - - // are we responsible for releasing the evaluator and closing the result? - boolean primaryRequest = false; - - try { - // first look if a request with same user/path/data is already being executed. - // if so, attach the request to its output instead of starting a new evaluation - // this helps to cleanly solve "doubleclick" kind of users - ev = (RequestEvaluator) activeRequests.get(req); - - if (ev != null) { - res = ev.attachRequest(req); - } - - if (res == null) { - primaryRequest = true; - - // if attachRequest returns null this means we came too late - // and the other request was finished in the meantime - // check if the properties file has been updated - updateProperties(); - - // get evaluator and invoke - ev = getEvaluator(); - res = ev.invoke(req, session); - } - } catch (ApplicationStoppedException stopped) { - // let the servlet know that this application has gone to heaven - throw stopped; - } catch (Exception x) { - errorCount += 1; - res = new ResponseTrans(); - res.write("Error in application: " + x.getMessage() + ""); - } finally { - if (primaryRequest) { - activeRequests.remove(req); - releaseEvaluator(ev); - - // response needs to be closed/encoded before sending it back - try { - res.close(charset); - } catch (UnsupportedEncodingException uee) { - logEvent("Unsupported response encoding: " + uee.getMessage()); - } - } else { - res.waitForClose(); - } - } - - return res; - } - - /** - * Called to execute a method via XML-RPC, usally by helma.main.ApplicationManager - * which acts as default handler/request dispatcher. - */ - public Object executeXmlRpc(String method, Vector args) - throws Exception { - xmlrpcCount += 1; - - Object retval = null; - RequestEvaluator ev = null; - - try { - // check if the properties file has been updated - updateProperties(); - - // get evaluator and invoke - ev = getEvaluator(); - retval = ev.invokeXmlRpc(method, args.toArray()); - } finally { - releaseEvaluator(ev); - } - - return retval; - } - - /** - * Reset the application's object cache, causing all objects to be refetched from - * the database. - */ - public void clearCache() { - nmgr.clearCache(); - } - - /** - * Returns the number of elements in the NodeManager's cache - */ - public int getCacheUsage() { - return nmgr.countCacheEntries(); - } - - /** - * Set the application's root element to an arbitrary object. After this is called - * with a non-null object, the helma node manager will be bypassed. This function - * can be used to script and publish any Java object structure with Helma. - */ - public void setDataRoot(Object root) { - this.rootObject = root; - } - - /** - * This method returns the root object of this application's object tree. - */ - public Object getDataRoot() { - // check if we have a custom root object class - if (rootObjectClass != null) { - // create custom root element. - if (rootObject == null) { - try { - if (classMapping.containsKey("root.factory.class") && - classMapping.containsKey("root.factory.method")) { - Class c = typemgr.loader.loadClass(classMapping.getProperty("root.factory.class")); - Method m = c.getMethod(classMapping.getProperty("root.factory.method"), - null); - - rootObject = m.invoke(c, null); - } else { - Class c = typemgr.loader.loadClass(classMapping.getProperty("root")); - - rootObject = c.newInstance(); - } - } catch (Exception e) { - throw new RuntimeException("Error creating root object: " + - e.toString()); - } - } - - return rootObject; - } - // no custom root object is defined - use standard helma objectmodel - else { - // INode root = nmgr.safe.getNode ("0", rootMapping); - // root.setDbMapping (rootMapping); - // rootObject = root; - rootObject = nmgr.safe.getNode("0", rootMapping); - - return rootObject; - } - } - - /** - * Returns the Object which contains registered users of this application. - */ - public INode getUserRoot() { - INode users = nmgr.safe.getNode("1", userRootMapping); - - users.setDbMapping(userRootMapping); - - return users; - } - - /** - * Returns the node manager for this application. The node manager is - * the gateway to the helma.objectmodel packages, which perform the mapping - * of objects to relational database tables or the embedded database. - */ - public NodeManager getNodeManager() { - return nmgr; - } - - /** - * Returns a wrapper containing the node manager for this application. The node manager is - * the gateway to the helma.objectmodel packages, which perform the mapping of objects to - * relational database tables or the embedded database. - */ - public WrappedNodeManager getWrappedNodeManager() { - return nmgr.safe; - } - - /** - * Return a transient node that is shared by all evaluators of this application ("app node") - */ - public INode getCacheNode() { - return cachenode; - } - - /** - * Returns a Node representing a registered user of this application by his or her user name. - */ - public INode getUserNode(String uid) { - try { - INode users = getUserRoot(); - - return users.getNode(uid); - } catch (Exception x) { - return null; - } - } - - /** - * Return a prototype for a given node. If the node doesn't specify a prototype, - * return the generic hopobject prototype. - */ - public Prototype getPrototype(Object obj) { - String protoname = getPrototypeName(obj); - - if (protoname == null) { - return typemgr.getPrototype("hopobject"); - } - - Prototype p = typemgr.getPrototype(protoname); - - if (p == null) { - p = typemgr.getPrototype("hopobject"); - } - - return p; - } - - /** - * Return the prototype with the given name, if it exists - */ - public Prototype getPrototypeByName(String name) { - return (Prototype) typemgr.prototypes.get(name); - } - - /** - * Return a collection containing all prototypes defined for this application - */ - public Collection getPrototypes() { - return typemgr.prototypes.values(); - } - - /** - * Return a skin for a given object. The skin is found by determining the prototype - * to use for the object, then looking up the skin for the prototype. - */ - public Skin getSkin(String protoname, String skinname, Object[] skinpath) { - Prototype proto = getPrototypeByName(protoname); - - if (proto == null) { - return null; - } - - return skinmgr.getSkin(proto, skinname, skinpath); - } - - /** - * Return the session currently associated with a given Hop session ID. - * Create a new session if necessary. - */ - public Session checkSession(String sessionID) { - Session session = getSession(sessionID); - - if (session == null) { - session = new Session(sessionID, this); - sessions.put(sessionID, session); - } - - return session; - } - - /** - * Remove the session from the sessions-table and logout the user. - */ - public void destroySession(String sessionID) { - logoutSession(getSession(sessionID)); - sessions.remove(sessionID); - } - - /** - * Remove the session from the sessions-table and logout the user. - */ - public void destroySession(Session session) { - logoutSession(session); - sessions.remove(session.getSessionID()); - } - - /** - * Return the whole session map. We return a clone of the table to prevent - * actual changes from the table itself, which is managed by the application. - * It is safe and allowed to manipulate the session objects contained in the table, though. - */ - public Map getSessions() { - return (Map) sessions.clone(); - } - - /** - * Return a list of Helma nodes (HopObjects - the database object representing the user, - * not the session object) representing currently logged in users. - */ - public List getActiveUsers() { - ArrayList list = new ArrayList(); - - // used to keep track of already added users - we only return - // one object per user, and users may have multiple sessions - HashSet usernames = new HashSet(); - - for (Enumeration e = sessions.elements(); e.hasMoreElements();) { - Session s = (Session) e.nextElement(); - - if (s == null) { - continue; - } else if (s.isLoggedIn() && !usernames.contains(s.getUID())) { - // returns a session if it is logged in and has not been - // returned before (so for each logged-in user we get one - // session object, even if this user is logged in several - // times (used to retrieve the active users list). - INode node = s.getUserNode(); - - // we check again because user may have been logged out between the first check - if (node != null) { - usernames.add(s.getUID()); - list.add(node); - } - } - } - - return list; - } - - /** - * Return a list of Helma nodes (HopObjects - the database object representing the user, - * not the session object) representing registered users of this application. - */ - public List getRegisteredUsers() { - ArrayList list = new ArrayList(); - INode users = getUserRoot(); - - // first try to get them from subnodes (db) - for (Enumeration e = users.getSubnodes(); e.hasMoreElements();) { - list.add((INode) e.nextElement()); - } - - // if none, try to get them from properties (internal db) - if (list.size() == 0) { - for (Enumeration e = users.properties(); e.hasMoreElements();) { - list.add(users.getNode((String) e.nextElement())); - } - } - - return list; - } - - /** - * Return an array of SessionBean objects currently associated with a given - * Helma user. - */ - public List getSessionsForUsername(String username) { - ArrayList list = new ArrayList(); - - if (username == null) { - return list; - } - - for (Enumeration e = sessions.elements(); e.hasMoreElements();) { - Session s = (Session) e.nextElement(); - - if (s == null) { - continue; - } else if (username.equals(s.getUID())) { - // append to list if session is logged in and fits the given username - list.add(new SessionBean(s)); - } - } - - return list; - } - - /** - * Return the session currently associated with a given Hop session ID. - */ - public Session getSession(String sessionID) { - if (sessionID == null) { - return null; - } - - return (Session) sessions.get(sessionID); - } - - /** - * Register a user with the given user name and password. - */ - public INode registerUser(String uname, String password) { - if (uname == null) { - return null; - } - - uname = uname.toLowerCase().trim(); - - if ("".equals(uname)) { - return null; - } - - INode unode = null; - - try { - INode users = getUserRoot(); - - unode = users.getNode(uname); - - if (unode != null) { - return null; - } - - unode = users.createNode(uname); - unode.setPrototype("user"); - unode.setDbMapping(userMapping); - - String usernameField = userMapping.getNameField(); - String usernameProp = null; - - if (usernameField != null) { - usernameProp = userMapping.columnNameToProperty(usernameField); - } - - if (usernameProp == null) { - usernameProp = "name"; - } - - unode.setName(uname); - unode.setString(usernameProp, uname); - unode.setString("password", password); - - return unode; - } catch (Exception x) { - logEvent("Error registering User: " + x); - - return null; - } - } - - /** - * Log in a user given his or her user name and password. - */ - public boolean loginSession(String uname, String password, Session session) { - // Check the name/password of a user and log it in to the current session - if (uname == null) { - return false; - } - - uname = uname.toLowerCase().trim(); - - if ("".equals(uname)) { - return false; - } - - try { - INode users = getUserRoot(); - Node unode = (Node) users.getNode(uname); - String pw = unode.getString("password"); - - if ((pw != null) && pw.equals(password)) { - // let the old user-object forget about this session - logoutSession(session); - session.login(unode); - - return true; - } - } catch (Exception x) { - return false; - } - - return false; - } - - /** - * Log out a session from this application. - */ - public void logoutSession(Session session) { - session.logout(); - } - - /** - * In contrast to login, this works outside the Hop user object framework. Instead, the user is - * authenticated against a passwd file in the application directory. This is to have some sort of - * authentication available *before* the application is up and running, i.e. for application setup tasks. - */ - public boolean authenticate(String uname, String password) { - if ((uname == null) || (password == null)) { - return false; - } - - return pwfile.authenticate(uname, password); - } - - /** - * Return the href to the root of this application. - */ - public String getRootHref() { - return getNodeHref(getDataRoot(), null); - } - - /** - * Return a path to be used in a URL pointing to the given element and action - */ - public String getNodeHref(Object elem, String actionName) { - StringBuffer b = new StringBuffer(baseURI); - - composeHref(elem, b, 0); - - if (actionName != null) { - b.append(UrlEncoded.encode(actionName)); - } - - return b.toString(); - } - - private final void composeHref(Object elem, StringBuffer b, int pathCount) { - if ((elem == null) || (pathCount > 20)) { - return; - } - - if ((rootPrototype != null) && rootPrototype.equals(getPrototypeName(elem))) { - return; - } - - Object parent = getParentElement(elem); - - if (parent == null) { - return; - } - - composeHref(getParentElement(elem), b, pathCount++); - b.append(UrlEncoded.encode(getElementName(elem))); - b.append("/"); - } - - /** - * Returns the baseURI for Hrefs in this application. - */ - public String getBaseURI() { - return baseURI; - } - - - /** - * This method sets the base URL of this application which will be prepended to - * the actual object path. - */ - public void setBaseURI(String uri) { - if (uri == null) { - this.baseURI = "/"; - } else if (!uri.endsWith("/")) { - this.baseURI = uri + "/"; - } else { - this.baseURI = uri; - } - } - - /** - * Return true if the baseURI property is defined in the application - * properties, false otherwise. - */ - public boolean hasExplicitBaseURI() { - return props.containsKey("baseuri"); - } - - /** - * Returns the prototype name that Hrefs in this application should start with. - */ - public String getRootPrototype() { - return rootPrototype; - } - - /** - * Tell other classes whether they should output logging information for this application. - */ - public boolean debug() { - return debug; - } - - /** - * - * - * @return ... - */ - public RequestEvaluator getCurrentRequestEvaluator() { - Thread thread = Thread.currentThread(); - int l = allThreads.size(); - - for (int i = 0; i < l; i++) { - RequestEvaluator r = (RequestEvaluator) allThreads.get(i); - - if ((r != null) && (r.rtx == thread)) { - return r; - } - } - - return null; - } - - /** - * Utility function invoker for the methods below. This *must* be called - * by an active RequestEvaluator thread. - */ - private Object invokeFunction(Object obj, String func, Object[] args) { - RequestEvaluator reval = getCurrentRequestEvaluator(); - - if (reval != null) { - try { - return reval.invokeDirectFunction(obj, func, args); - } catch (Exception x) { - if (debug) { - System.err.println("Error in Application.invokeFunction (" + func + - "): " + x); - } - } - } - - return null; - } - - /** - * Return the application's classloader - */ - public ClassLoader getClassLoader() { - return typemgr.loader; - } - - ////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// The following methods mimic the IPathElement interface. This allows us - /// to script any Java object: If the object implements IPathElement (as does - /// the Node class in Helma's internal objectmodel) then the corresponding - /// method is called in the object itself. Otherwise, a corresponding script function - /// is called on the object. - ////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Return the name to be used to get this element from its parent - */ - public String getElementName(Object obj) { - if (obj instanceof IPathElement) { - return ((IPathElement) obj).getElementName(); - } - - Object retval = invokeFunction(obj, "getElementName", null); - - if (retval != null) { - return retval.toString(); - } - - return null; - } - - /** - * Retrieve a child element of this object by name. - */ - public Object getChildElement(Object obj, String name) { - if (obj instanceof IPathElement) { - return ((IPathElement) obj).getChildElement(name); - } - - Object[] arg = new Object[1]; - - arg[0] = name; - - return invokeFunction(obj, "getChildElement", arg); - } - - /** - * Return the parent element of this object. - */ - public Object getParentElement(Object obj) { - if (obj instanceof IPathElement) { - return ((IPathElement) obj).getParentElement(); - } - - return invokeFunction(obj, "getParentElement", null); - } - - /** - * Get the name of the prototype to be used for this object. This will - * determine which scripts, actions and skins can be called on it - * within the Helma scripting and rendering framework. - */ - public String getPrototypeName(Object obj) { - if (obj == null) { - return "global"; - } - - // check if e implements the IPathElement interface - if (obj instanceof IPathElement) { - // e implements the getPrototype() method - return ((IPathElement) obj).getPrototype(); - } else { - // use java class name as prototype name - return classMapping.getProperty(obj.getClass().getName()); - } - } - - ////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// The following methods are the IPathElement interface for this application. - /// this is useful for scripting and url-building in the base-app. - ////////////////////////////////////////////////////////////////////////////////////////////////////////// - public String getElementName() { - return name; - } - - /** - * - * - * @param name ... - * - * @return ... - */ - public IPathElement getChildElement(String name) { - // as Prototype and the helma.scripting-classes don't offer enough information - // we use the classes from helma.doc-pacakge for introspection. - // the first time an url like /appname/api/ is parsed, the application is read again - // parsed for comments and exposed as an IPathElement - if (name.equals("api") && allThreads.size() > 0) { - return ((RequestEvaluator) allThreads.get(0)).scriptingEngine.getIntrospector(); - } - - return null; - } - - /** - * - * - * @return ... - */ - public IPathElement getParentElement() { - return helma.main.Server.getServer(); - } - - /** - * - * - * @return ... - */ - public String getPrototype() { - return "application"; - } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get the logger object for logging generic events - */ - public void logEvent(String msg) { - if ((eventLog == null) || eventLog.isClosed()) { - eventLog = getLogger("event"); - } - - eventLog.log(msg); - } - - /** - * Get the logger object for logging access events - */ - public void logAccess(String msg) { - if ((accessLog == null) || accessLog.isClosed()) { - accessLog = getLogger("access"); - } - - accessLog.log(msg); - } - - /** - * Get a logger object to log events for this application. - */ - public Logger getLogger(String logname) { - Logger log = null; - String logDir = props.getProperty("logdir", "log"); - - // allow log to be redirected to System.out by setting logdir to "console" - if ("console".equalsIgnoreCase(logDir)) { - return new Logger(System.out); - } - - File helper = new File(logDir); - - // construct the fully qualified log name - String fullLogname = name + "_" + logname; - - if ((home != null) && !helper.isAbsolute()) { - helper = new File(home, logDir); - } - - logDir = helper.getAbsolutePath(); - log = Logger.getLogger(logDir, fullLogname); - - return log; - } - - /** - * The run method performs periodic tasks like executing the scheduler method and - * kicking out expired user sessions. - */ - public void run() { - // interval between session cleanups - long sessionCleanupInterval = 60000; - long lastSessionCleanup = System.currentTimeMillis(); - - // logEvent ("Starting scheduler for "+name); - - // read in standard prototypes to make first request go faster - typemgr.updatePrototype("root"); - typemgr.updatePrototype("global"); - - // as first thing, invoke function onStart in the root object - RequestEvaluator eval = getEvaluator(); - try { - eval.invokeFunction((INode) null, "onStart", new Object[0]); - } catch (Exception ignore) { - logEvent("Error in " + name + "/onStart(): " + ignore); - } finally { - if (!stopped) { - releaseEvaluator(eval); - } - } - - // loop-local cron job data - List cronJobs = null; - long lastCronParse = 0; - - while (Thread.currentThread() == worker) { - - long now = System.currentTimeMillis(); - - // check if we should clean up user sessions - if ((now - lastSessionCleanup) > sessionCleanupInterval) { - - lastSessionCleanup = now; - - // get session timeout - int sessionTimeout = 30; - - try { - sessionTimeout = Math.max(0, - Integer.parseInt(props.getProperty("sessionTimeout", - "30"))); - } catch (Exception ignore) {} - - try { - - Hashtable cloned = (Hashtable) sessions.clone(); - - for (Enumeration e = cloned.elements(); e.hasMoreElements();) { - Session session = (Session) e.nextElement(); - - if ((now - session.lastTouched()) > (sessionTimeout * 60000)) { - NodeHandle userhandle = session.userHandle; - - if (userhandle != null) { - try { - Object[] param = { session.getSessionID() }; - - eval.invokeFunction(userhandle, "onLogout", param); - } catch (Exception ignore) { - } - } - - destroySession(session); - } - } - } catch (Exception cx) { - logEvent("Error cleaning up sessions: " + cx); - cx.printStackTrace(); - } - } - - if ((cronJobs == null) || (props.lastModified() > lastCronParse)) { - updateProperties(); - cronJobs = CronJob.parse(props); - lastCronParse = props.lastModified(); - } - - Date d = new Date(); - List jobs = new ArrayList(cronJobs); - - jobs.addAll(customCronJobs.values()); - CronJob.sort(jobs); - - for (Iterator i = jobs.iterator(); i.hasNext();) { - CronJob j = (CronJob) i.next(); - - if (j.appliesToDate(d)) { - // check if the job is already active ... - if (activeCronJobs.containsKey(j.getName())) { - logEvent(j + " is still active, skipped in this minute"); - - continue; - } - - RequestEvaluator thisEvaluator; - - try { - thisEvaluator = getEvaluator(); - } catch (RuntimeException rt) { - if (!stopped) { - logEvent("couldn't execute " + j + - ", maximum thread count reached"); - - continue; - } else { - break; - } - } - - // if the job has a long timeout or we're already late during this minute - // the job is run from an extra thread - if ((j.getTimeout() > 20000) || - (CronJob.millisToNextFullMinute() < 30000)) { - CronRunner r = new CronRunner(thisEvaluator, j); - - activeCronJobs.put(j.getName(), r); - r.start(); - } else { - try { - thisEvaluator.invokeFunction((INode) null, j.getFunction(), - new Object[0], j.getTimeout()); - } catch (Exception ex) { - logEvent("error running " + j + ": " + ex.toString()); - } finally { - if (!stopped) { - releaseEvaluator(thisEvaluator); - } - } - } - } - } - - - long sleepInterval = CronJob.millisToNextFullMinute(); - try { - String sleepProp = props.getProperty("schedulerInterval"); - if (sleepProp != null) { - sleepInterval = Math.max(1000, Integer.parseInt(sleepProp)*1000); - } - } catch (Exception ignore) {} - - // sleep until the next full minute - try { - Thread.sleep(sleepInterval); - } catch (InterruptedException x) { - logEvent("Scheduler for " + name + " interrupted"); - worker = null; - break; - } - } - - // when interrupted, shutdown running cron jobs - synchronized (activeCronJobs) { - for (Iterator i = activeCronJobs.keySet().iterator(); i.hasNext();) { - String jobname = (String) i.next(); - - ((CronRunner) activeCronJobs.get(jobname)).interrupt(); - activeCronJobs.remove(jobname); - } - } - - logEvent("Scheduler for " + name + " exiting"); - } - - /** - * Check whether a prototype is for scripting a java class, i.e. if there's an entry - * for it in the class.properties file. - */ - public boolean isJavaPrototype(String typename) { - for (Enumeration en = classMapping.elements(); en.hasMoreElements();) { - String value = (String) en.nextElement(); - - if (typename.equals(value)) { - return true; - } - } - - return false; - } - - /** - * Return the java class that a given prototype wraps, or null. - */ - public String getJavaClassForPrototype(String typename) { - - for (Iterator it = classMapping.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - - if (typename.equals(entry.getValue())) { - return (String) entry.getKey(); - } - } - - return null; - } - - - /** - * Return a DbSource object for a given name. A DbSource is a relational database defined - * in a db.properties file. - */ - public DbSource getDbSource(String name) { - String dbSrcName = name.toLowerCase(); - DbSource dbs = (DbSource) dbSources.get(dbSrcName); - - if (dbs != null) { - return dbs; - } - - if ((dbProps.getProperty(dbSrcName + ".url") != null) && - (dbProps.getProperty(dbSrcName + ".driver") != null)) { - try { - dbs = new DbSource(name, dbProps); - dbSources.put(dbSrcName, dbs); - } catch (Exception problem) { - logEvent("Error creating DbSource " + name); - logEvent("Reason: " + problem); - } - } - - return dbs; - } - - /** - * Return the name of this application - */ - public String getName() { - return name; - } - - /** - * Return the directory of this application - */ - public File getAppDir() { - return appDir; - } - - /** - * Return the directory of the Helma server - */ - public File getServerDir() { - return home; - } - - /** - * Get the DbMapping associated with a prototype name in this application - */ - public DbMapping getDbMapping(String typename) { - Prototype proto = typemgr.getPrototype(typename); - - if (proto == null) { - return null; - } - - return proto.getDbMapping(); - } - - private synchronized void updateProperties() { - // if so property file has been updated, re-read props. - if (props.lastModified() > lastPropertyRead) { - // force property update - props.update(); - - // character encoding to be used for responses - charset = props.getProperty("charset", "ISO-8859-1"); - - // debug flag - debug = "true".equalsIgnoreCase(props.getProperty("debug")); - - String reqTimeout = props.getProperty("requesttimeout", "60"); - try { - requestTimeout = Long.parseLong(reqTimeout) * 1000L; - } catch (Exception ignore) { - // go with default value - requestTimeout = 60000L; - } - - // set base URI - String base = props.getProperty("baseuri"); - - if (base != null) { - setBaseURI(base); - } else if (baseURI == null) { - baseURI = "/"; - } - - rootPrototype = props.getProperty("rootprototype"); - - // update the XML-RPC access list, containting prototype.method - // entries of functions that may be called via XML-RPC - String xmlrpcAccessProp = props.getProperty("xmlrpcaccess"); - HashSet xra = new HashSet(); - - if (xmlrpcAccessProp != null) { - StringTokenizer st = new StringTokenizer(xmlrpcAccessProp, ",; "); - - while (st.hasMoreTokens()) { - String token = st.nextToken().trim(); - - xra.add(token.toLowerCase()); - } - } - - xmlrpcAccess = xra; - - // if node manager exists, update it - if (nmgr != null) { - nmgr.updateProperties(props); - } - - // update extensions - Vector extensions = Server.getServer().getExtensions(); - - for (int i = 0; i < extensions.size(); i++) { - HelmaExtension ext = (HelmaExtension) extensions.get(i); - - try { - ext.applicationUpdated(this); - } catch (ConfigurationException e) { - } - } - - // set prop read timestamp - lastPropertyRead = props.lastModified(); - } - } - - /** - * Get a checksum that mirrors the state of this application in the sense - * that if anything in the applciation changes, the checksum hopefully will - * change, too. - */ - public long getChecksum() { - return starttime + typemgr.getChecksum() + props.getChecksum(); - } - - /** - * Proxy method to get a property from the applications properties. - */ - public String getProperty(String propname) { - return props.getProperty(propname); - } - - /** - * Proxy method to get a property from the applications properties. - */ - public String getProperty(String propname, String defvalue) { - return props.getProperty(propname, defvalue); - } - - /** - * - * - * @return ... - */ - public SystemProperties getProperties() { - return props; - } - - /** - * Return the XML-RPC handler name for this app. The contract is to - * always return the same string, even if it has been changed in the properties file - * during runtime, so the app gets unregistered correctly. - */ - public String getXmlRpcHandlerName() { - if (xmlrpcHandlerName == null) { - xmlrpcHandlerName = props.getProperty("xmlrpcHandlerName", this.name); - } - - return xmlrpcHandlerName; - } - - /** - * - */ - public int countThreads() { - return threadgroup.activeCount(); - } - - /** - * - */ - public int countEvaluators() { - return allThreads.size(); - } - - /** - * - */ - public int countFreeEvaluators() { - return freeThreads.size(); - } - - /** - * - */ - public int countActiveEvaluators() { - return allThreads.size() - freeThreads.size(); - } - - /** - * - */ - public int countMaxActiveEvaluators() { - // return typemgr.countRegisteredRequestEvaluators () -1; - // not available due to framework refactoring - return -1; - } - - /** - * - */ - public long getRequestCount() { - return requestCount; - } - - /** - * - */ - public long getXmlrpcCount() { - return xmlrpcCount; - } - - /** - * - */ - public long getErrorCount() { - return errorCount; - } - - /** - * - * - * @return ... - */ - public long getStarttime() { - return starttime; - } - - /** - * - * - * @return ... - */ - public String getCharset() { - return props.getProperty("charset", "ISO-8859-1"); - } - - /** - * Periodically called to log thread stats for this application - */ - public void printThreadStats() { - logEvent("Thread Stats for " + name + ": " + threadgroup.activeCount() + - " active"); - - Runtime rt = Runtime.getRuntime(); - long free = rt.freeMemory(); - long total = rt.totalMemory(); - - logEvent("Free memory: " + (free / 1024) + " kB"); - logEvent("Total memory: " + (total / 1024) + " kB"); - } - - /** - * Check if a method may be invoked via XML-RPC on a prototype. - */ - protected void checkXmlRpcAccess(String proto, String method) - throws Exception { - String key = proto + "." + method; - - // XML-RPC access items are case insensitive and stored in lower case - if (!xmlrpcAccess.contains(key.toLowerCase())) { - throw new Exception("Method " + key + " is not callable via XML-RPC"); - } - } - - /** - * - * - * @param f ... - */ - public void storeSessionData(File f) { - if (f == null) { - f = new File(dbDir, "sessions"); - } - - try { - OutputStream ostream = new BufferedOutputStream(new FileOutputStream(f)); - ObjectOutputStream p = new ObjectOutputStream(ostream); - - synchronized (sessions) { - p.writeInt(sessions.size()); - - for (Enumeration e = sessions.elements(); e.hasMoreElements();) { - p.writeObject((Session) e.nextElement()); - } - } - - p.flush(); - ostream.close(); - logEvent("stored " + sessions.size() + " sessions in file"); - } catch (Exception e) { - logEvent("error storing session data: " + e.toString()); - } - } - - /** - * loads the serialized session table from a given file or from dbdir/sessions - */ - public void loadSessionData(File f) { - if (f == null) { - f = new File(dbDir, "sessions"); - } - - // compute session timeout value - int sessionTimeout = 30; - - try { - sessionTimeout = Math.max(0, - Integer.parseInt(props.getProperty("sessionTimeout", - "30"))); - } catch (Exception ignore) { - System.out.println(ignore.toString()); - } - - long now = System.currentTimeMillis(); - - try { - // load the stored data: - InputStream istream = new BufferedInputStream(new FileInputStream(f)); - ObjectInputStream p = new ObjectInputStream(istream); - int size = p.readInt(); - int ct = 0; - Hashtable newSessions = new Hashtable(); - - while (ct < size) { - Session session = (Session) p.readObject(); - - if ((now - session.lastTouched()) < (sessionTimeout * 60000)) { - session.setApp(this); - newSessions.put(session.getSessionID(), session); - } - - ct++; - } - - p.close(); - istream.close(); - sessions = newSessions; - logEvent("loaded " + newSessions.size() + " sessions from file"); - } catch (Exception e) { - logEvent("error loading session data: " + e.toString()); - } - } - - class CronRunner extends Thread { - RequestEvaluator thisEvaluator; - CronJob job; - - public CronRunner(RequestEvaluator thisEvaluator, CronJob job) { - this.thisEvaluator = thisEvaluator; - this.job = job; - } - - public void run() { - try { - thisEvaluator.invokeFunction((INode) null, job.getFunction(), - new Object[0], job.getTimeout()); - } catch (Exception ex) { - // gets logged in RequestEvaluator - } finally { - if (!stopped) { - releaseEvaluator(thisEvaluator); - } - thisEvaluator = null; - activeCronJobs.remove(job.getName()); - } - } - } -} diff --git a/src/helma/framework/core/ApplicationBean.java b/src/helma/framework/core/ApplicationBean.java deleted file mode 100644 index 2055efdb..00000000 --- a/src/helma/framework/core/ApplicationBean.java +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.objectmodel.INode; -import helma.util.CronJob; -import helma.util.SystemMap; -import helma.util.WrappedMap; -import java.io.File; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class ApplicationBean implements Serializable { - Application app; - - WrappedMap properties = null; - - /** - * Creates a new ApplicationBean object. - * - * @param app ... - */ - public ApplicationBean(Application app) { - this.app = app; - } - - /** - * - */ - public void clearCache() { - app.clearCache(); - } - - /** - * - * - * @param msg ... - */ - public void log(Object msg) { - String str = (msg == null) ? "null" : msg.toString(); - - app.logEvent(str); - } - - /** - * - * - * @param logname ... - * @param msg ... - */ - public void log(String logname, Object msg) { - String str = (msg == null) ? "null" : msg.toString(); - - app.getLogger(logname).log(str); - } - - /** - * - * - * @param msg ... - */ - public void debug(Object msg) { - if (app.debug()) { - String str = (msg == null) ? "null" : msg.toString(); - - app.logEvent(str); - } - } - - /** - * - * - * @param logname ... - * @param msg ... - */ - public void debug(String logname, Object msg) { - if (app.debug()) { - String str = (msg == null) ? "null" : msg.toString(); - - app.getLogger(logname).log(str); - } - } - - /** - * - * - * @return ... - */ - public int countSessions() { - return app.sessions.size(); - } - - /** - * - * - * @param sessionID ... - * - * @return ... - */ - public SessionBean getSession(String sessionID) { - if (sessionID == null) { - return null; - } - - Session session = app.getSession(sessionID.trim()); - - if (session == null) { - return null; - } - - return new SessionBean(session); - } - - /** - * - * - * @param sessionID ... - * - * @return ... - */ - public SessionBean createSession(String sessionID) { - if (sessionID == null) { - return null; - } - - Session session = session = app.checkSession(sessionID.trim()); - - if (session == null) { - return null; - } - - return new SessionBean(session); - } - - /** - * - * - * @return ... - */ - public SessionBean[] getSessions() { - SessionBean[] theArray = new SessionBean[app.sessions.size()]; - int i = 0; - - for (Enumeration e = app.sessions.elements(); e.hasMoreElements();) { - SessionBean sb = new SessionBean((Session) e.nextElement()); - - theArray[i++] = sb; - } - - return theArray; - } - - /** - * - * - * @param username ... - * @param password ... - * - * @return ... - */ - public INode registerUser(String username, String password) { - if ((username == null) || (password == null) || "".equals(username.trim()) || - "".equals(password.trim())) { - return null; - } else { - return app.registerUser(username, password); - } - } - - /** - * - * - * @param username ... - * - * @return ... - */ - public INode getUser(String username) { - if ((username == null) || "".equals(username.trim())) { - return null; - } - - return app.getUserNode(username); - } - - /** - * - * - * @return ... - */ - public INode[] getActiveUsers() { - List activeUsers = app.getActiveUsers(); - - return (INode[]) activeUsers.toArray(new INode[0]); - } - - /** - * - * - * @return ... - */ - public INode[] getRegisteredUsers() { - List registeredUsers = app.getRegisteredUsers(); - - return (INode[]) registeredUsers.toArray(new INode[0]); - } - - /** - * - * - * @param usernode ... - * - * @return ... - */ - public SessionBean[] getSessionsForUser(INode usernode) { - if (usernode == null) { - return new SessionBean[0]; - } else { - return getSessionsForUser(usernode.getName()); - } - } - - /** - * - * - * @param username ... - * - * @return ... - */ - public SessionBean[] getSessionsForUser(String username) { - if ((username == null) || "".equals(username.trim())) { - return new SessionBean[0]; - } - - List userSessions = app.getSessionsForUsername(username); - - return (SessionBean[]) userSessions.toArray(new SessionBean[0]); - } - - /** - * - * - * @param functionName ... - */ - public void addCronJob(String functionName) { - CronJob job = new CronJob(functionName); - - job.setFunction(functionName); - app.customCronJobs.put(functionName, job); - } - - /** - * - * - * @param functionName ... - * @param year ... - * @param month ... - * @param day ... - * @param weekday ... - * @param hour ... - * @param minute ... - */ - public void addCronJob(String functionName, String year, String month, String day, - String weekday, String hour, String minute) { - CronJob job = CronJob.newJob(functionName, year, month, day, weekday, hour, minute); - - app.customCronJobs.put(functionName, job); - } - - /** - * - * - * @param functionName ... - */ - public void removeCronJob(String functionName) { - app.customCronJobs.remove(functionName); - } - - // getter methods for readonly properties of this application - public int getCacheusage() { - return app.getCacheUsage(); - } - - /** - * - * - * @return ... - */ - public INode getData() { - return app.getCacheNode(); - } - - /** - * - * - * @return ... - */ - public Map getModules() { - return app.modules; - } - - /** - * - * - * @return ... - */ - public String getDir() { - return app.getAppDir().getAbsolutePath(); - } - - /** - * - * - * @return ... - */ - public String getName() { - return app.getName(); - } - - /** - * - * - * @return ... - */ - public Date getUpSince() { - return new Date(app.starttime); - } - - /** - * - * - * @return ... - */ - public long getRequestCount() { - return app.getRequestCount(); - } - - /** - * - * - * @return ... - */ - public long getXmlrpcCount() { - return app.getXmlrpcCount(); - } - - /** - * - * - * @return ... - */ - public long getErrorCount() { - return app.getErrorCount(); - } - - /** - * - * - * @return ... - */ - public Application get__app__() { - return app; - } - - /** - * - * - * @return ... - */ - public Map getProperties() { - if (properties == null) { - properties = new WrappedMap(app.getProperties()); - properties.setReadonly(true); - } - return properties; - } - - /** - * - * - * @return ... - */ - public int getFreeThreads() { - return app.countFreeEvaluators(); - } - - /** - * - * - * @return ... - */ - public int getActiveThreads() { - return app.countActiveEvaluators(); - } - - /** - * - * - * @return ... - */ - public int getMaxThreads() { - return app.countEvaluators(); - } - - /** - * - * - * @param n ... - */ - public void setMaxThreads(int n) { - // add one to the number to compensate for the internal scheduler. - app.setNumberOfEvaluators(n + 1); - } - - /** - * - * - * @return ... - */ - public Map getSkinfiles() { - Map skinz = new SystemMap(); - - for (Iterator it = app.getPrototypes().iterator(); it.hasNext();) { - Prototype p = (Prototype) it.next(); - - skinz.put(p.getName(), p.getSkinMap()); - } - - return skinz; - } - - /** - * - * - * @param skinpath ... - * - * @return ... - */ - public Map getSkinfilesInPath(Object[] skinpath) { - Map skinz = new SystemMap(); - - for (Iterator it = app.getPrototypes().iterator(); it.hasNext();) { - Prototype p = (Prototype) it.next(); - - skinz.put(p.getName(), p.getSkinMap(skinpath)); - } - - return skinz; - } - - /** - * - * - * @return ... - */ - public String getAppDir() { - return app.getAppDir().getAbsolutePath(); - } - - /** - * - * - * @return ... - */ - public String getServerDir() { - File f = app.getServerDir(); - - if (f == null) { - f = app.getAppDir(); - } - - return f.getAbsolutePath(); - } - - /** - * - * - * @return ... - */ - public String toString() { - return "[Application " + app.getName() + "]"; - } -} diff --git a/src/helma/framework/core/Prototype.java b/src/helma/framework/core/Prototype.java deleted file mode 100644 index 5fcab75d..00000000 --- a/src/helma/framework/core/Prototype.java +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.framework.*; -import helma.objectmodel.*; -import helma.objectmodel.db.DbMapping; -import helma.scripting.*; -import helma.util.Updatable; -import helma.util.SystemMap; -import java.io.*; -import java.util.*; - -/** - * The Prototype class represents Script prototypes/type defined in a Helma - * application. This class manages a prototypes templates, functions and actions - * as well as optional information about the mapping of this type to a - * relational database table. - */ -public final class Prototype { - String name; - Application app; - File directory; - File[] files; - long lastDirectoryListing; - long checksum; - HashMap code; - HashMap zippedCode; - HashMap skins; - HashMap zippedSkins; - HashMap updatables; - - // a map of this prototype's skins as raw strings - // used for exposing skins to application (script) code (via app.skinfiles). - SkinMap skinMap; - DbMapping dbmap; - - // lastCheck is the time the prototype's files were last checked - private long lastChecksum; - - // lastUpdate is the time at which any of the prototype's files were - // found updated the last time - private long lastUpdate; - private Prototype parent; - - // Tells us whether this prototype is used to script a generic Java object, - // as opposed to a Helma objectmodel node object. - boolean isJavaPrototype; - - /** - * Creates a new Prototype object. - * - * @param name ... - * @param dir ... - * @param app ... - */ - public Prototype(String name, File dir, Application app) { - // app.logEvent ("Constructing Prototype "+app.getName()+"/"+name); - this.app = app; - this.name = name; - this.directory = dir; - - code = new HashMap(); - zippedCode = new HashMap(); - skins = new HashMap(); - zippedSkins = new HashMap(); - updatables = new HashMap(); - - skinMap = new SkinMap(); - - isJavaPrototype = app.isJavaPrototype(name); - lastUpdate = lastChecksum = 0; - } - - /** - * Return the application this prototype is a part of - */ - public Application getApplication() { - return app; - } - - /** - * Return this prototype's directory. - */ - public File getDirectory() { - return directory; - } - - /** - * Get the list of files in this prototype's directory - */ - public File[] getFiles() { - if ((files == null) || (directory.lastModified() != lastDirectoryListing)) { - lastDirectoryListing = directory.lastModified(); - files = directory.listFiles(); - - if (files == null) { - files = new File[0]; - } - } - - return files; - } - - /** - * Get a checksum over the files in this prototype's directory - */ - public long getChecksum() { - // long start = System.currentTimeMillis(); - File[] f = getFiles(); - long c = directory.lastModified(); - - for (int i = 0; i < f.length; i++) - c += f[i].lastModified(); - - checksum = c; - - // System.err.println ("CHECKSUM "+name+": "+(System.currentTimeMillis()-start)); - return checksum; - } - - /** - * - * - * @return ... - */ - public boolean isUpToDate() { - return checksum == lastChecksum; - } - - /** - * Set the parent prototype of this prototype, i.e. the prototype this - * prototype inherits from. - */ - public void setParentPrototype(Prototype parent) { - // this is not allowed for the hopobject and global prototypes - if ("hopobject".equalsIgnoreCase(name) || "global".equalsIgnoreCase(name)) { - return; - } - - this.parent = parent; - } - - /** - * Get the parent prototype from which we inherit, or null - * if we are top of the line. - */ - public Prototype getParentPrototype() { - return parent; - } - - /** - * Check if the given prototype is within this prototype's parent chain. - */ - public final boolean isInstanceOf(String pname) { - if (name.equals(pname)) { - return true; - } - - if ((parent != null) && !"hopobject".equalsIgnoreCase(parent.getName())) { - return parent.isInstanceOf(pname); - } - - return false; - } - - /** - * Register an object as handler for all our parent prototypes. - */ - public final void registerParents(Map handlers, Object obj) { - - Prototype p = parent; - - while ((p != null) && !"hopobject".equalsIgnoreCase(p.getName())) { - handlers.put(p.name, obj); - - p = p.parent; - } - } - - /** - * - * - * @param dbmap ... - */ - public void setDbMapping(DbMapping dbmap) { - this.dbmap = dbmap; - } - - /** - * - * - * @return ... - */ - public DbMapping getDbMapping() { - return dbmap; - } - - /** - * Get a Skinfile for this prototype. This only works for skins - * residing in the prototype directory, not for skin files in - * other locations or database stored skins. - */ - public SkinFile getSkinFile(String sfname) { - SkinFile sf = (SkinFile) skins.get(sfname); - - if (sf == null) { - sf = (SkinFile) zippedSkins.get(sfname); - } - - return sf; - } - - /** - * Get a skin for this prototype. This only works for skins - * residing in the prototype directory, not for skins files in - * other locations or database stored skins. - */ - public Skin getSkin(String sfname) { - SkinFile sf = getSkinFile(sfname); - - if (sf != null) { - return sf.getSkin(); - } else { - return null; - } - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * Get the last time any script has been re-read for this prototype. - */ - public long getLastUpdate() { - return lastUpdate; - } - - /** - * Signal that some script in this prototype has been - * re-read from disk and needs to be re-compiled by - * the evaluators. - */ - public void markUpdated() { - lastUpdate = System.currentTimeMillis(); - } - - /** - * Signal that the prototype's scripts have been checked for - * changes. - */ - public void markChecked() { - // lastCheck = System.currentTimeMillis (); - lastChecksum = checksum; - } - - /** - * Return a clone of this prototype's actions container. Synchronized - * to not return a map in a transient state where it is just being - * updated by the type manager. - */ - public synchronized Map getCode() { - return (Map) code.clone(); - } - - /** - * Return a clone of this prototype's functions container. Synchronized - * to not return a map in a transient state where it is just being - * updated by the type manager. - */ - public synchronized Map getZippedCode() { - return (Map) zippedCode.clone(); - } - - /** - * - * - * @param action ... - */ - public synchronized void addActionFile(ActionFile action) { - File f = action.getFile(); - - if (f != null) { - code.put(action.getSourceName(), action); - updatables.put(f.getName(), action); - } else { - zippedCode.put(action.getSourceName(), action); - } - } - - /** - * - * - * @param template ... - */ - public synchronized void addTemplate(Template template) { - File f = template.getFile(); - - if (f != null) { - code.put(template.getSourceName(), template); - updatables.put(f.getName(), template); - } else { - zippedCode.put(template.getSourceName(), template); - } - } - - /** - * - * - * @param funcfile ... - */ - public synchronized void addFunctionFile(FunctionFile funcfile) { - File f = funcfile.getFile(); - - if (f != null) { - code.put(funcfile.getSourceName(), funcfile); - updatables.put(f.getName(), funcfile); - } else { - zippedCode.put(funcfile.getSourceName(), funcfile); - } - } - - /** - * - * - * @param skinfile ... - */ - public synchronized void addSkinFile(SkinFile skinfile) { - File f = skinfile.getFile(); - - if (f != null) { - skins.put(skinfile.getName(), skinfile); - updatables.put(f.getName(), skinfile); - } else { - zippedSkins.put(skinfile.getName(), skinfile); - } - } - - /** - * - * - * @param action ... - */ - public synchronized void removeActionFile(ActionFile action) { - File f = action.getFile(); - - if (f != null) { - code.remove(action.getSourceName()); - updatables.remove(f.getName()); - } else { - zippedCode.remove(action.getSourceName()); - } - } - - /** - * - * - * @param funcfile ... - */ - public synchronized void removeFunctionFile(FunctionFile funcfile) { - File f = funcfile.getFile(); - - if (f != null) { - code.remove(funcfile.getSourceName()); - updatables.remove(f.getName()); - } else { - zippedCode.remove(funcfile.getSourceName()); - } - } - - /** - * - * - * @param template ... - */ - public synchronized void removeTemplate(Template template) { - File f = template.getFile(); - - if (f != null) { - code.remove(template.getSourceName()); - updatables.remove(f.getName()); - } else { - zippedCode.remove(template.getSourceName()); - } - } - - /** - * - * - * @param skinfile ... - */ - public synchronized void removeSkinFile(SkinFile skinfile) { - File f = skinfile.getFile(); - - if (f != null) { - skins.remove(skinfile.getName()); - updatables.remove(f.getName()); - } else { - zippedSkins.remove(skinfile.getName()); - } - } - - /** - * Return a string representing this prototype. - */ - public String toString() { - return "[Prototype " + app.getName() + "/" + name + "]"; - } - - /** - * - * - * @return ... - */ - public SkinMap getSkinMap() { - return skinMap; - } - - // not yet implemented - public SkinMap getSkinMap(Object[] skinpath) { - return new SkinMap(skinpath); - } - - // a map that dynamically expands to all skins in this prototype - final class SkinMap extends SystemMap { - long lastSkinmapLoad = 0; - Object[] skinpath; - - SkinMap() { - super(); - skinpath = null; - } - - SkinMap(Object[] path) { - super(); - skinpath = path; - } - - public boolean containsKey(Object key) { - checkForUpdates(); - - return super.containsKey(key); - } - - public boolean containsValue(Object value) { - checkForUpdates(); - - return super.containsValue(value); - } - - public Set entrySet() { - checkForUpdates(); - - return super.entrySet(); - } - - public boolean equals(Object obj) { - checkForUpdates(); - - return super.equals(obj); - } - - public Object get(Object key) { - if (key == null) { - return null; - } - - checkForUpdates(); - - SkinFile sf = (SkinFile) super.get(key); - - if (sf == null) { - return null; - } - - return sf.getSkin().getSource(); - } - - public int hashCode() { - checkForUpdates(); - - return super.hashCode(); - } - - public boolean isEmpty() { - checkForUpdates(); - - return super.isEmpty(); - } - - public Set keySet() { - checkForUpdates(); - - return super.keySet(); - } - - public Object put(Object key, Object value) { - // checkForUpdates (); - return super.put(key, value); - } - - public void putAll(Map t) { - // checkForUpdates (); - super.putAll(t); - } - - public Object remove(Object key) { - checkForUpdates(); - - return super.remove(key); - } - - public int size() { - checkForUpdates(); - - return super.size(); - } - - public Collection values() { - checkForUpdates(); - - return super.values(); - } - - private void checkForUpdates() { - if ( /* lastCheck < System.currentTimeMillis()- 2000l*/ - !isUpToDate()) { - app.typemgr.updatePrototype(Prototype.this); - } - - if (lastUpdate > lastSkinmapLoad) { - load(); - } - } - - private synchronized void load() { - if (lastUpdate == lastSkinmapLoad) { - return; - } - - super.clear(); - - // System.err.println ("LOADING SKIN VALUES: "+Prototype.this); - for (Iterator i = skins.entrySet().iterator(); i.hasNext();) { - Map.Entry e = (Map.Entry) i.next(); - - super.put(e.getKey(), e.getValue()); - } - - // if skinpath is not null, overload/add skins from there - if (skinpath != null) { - for (int i = skinpath.length - 1; i >= 0; i--) { - if ((skinpath[i] != null) && skinpath[i] instanceof String) { - Map m = app.skinmgr.getSkinFiles((String) skinpath[i], - Prototype.this); - - if (m != null) { - super.putAll(m); - } - } - } - } - - lastSkinmapLoad = lastUpdate; - } - - public String toString() { - return "[SkinMap " + name + "]"; - } - } -} diff --git a/src/helma/framework/core/RemoteApplication.java b/src/helma/framework/core/RemoteApplication.java deleted file mode 100644 index 10a7ec6d..00000000 --- a/src/helma/framework/core/RemoteApplication.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.framework.*; -import helma.objectmodel.db.*; -import java.rmi.*; -import java.rmi.server.*; -import java.util.Vector; - -/** - * Proxy class for Aplication that listens to requests via RMI. - */ -public class RemoteApplication extends UnicastRemoteObject implements IRemoteApp, - IReplicationListener { - Application app; - - /** - * Creates a new RemoteApplication object. - * - * @param app ... - * - * @throws RemoteException ... - */ - public RemoteApplication(Application app) throws RemoteException { - this.app = app; - } - - /** - * ping method to let clients know if the server is reachable - */ - public void ping() { - // do nothing - } - - /** - * Execute a request coming in from a web client. - */ - public ResponseTrans execute(RequestTrans req) { - return app.execute(req); - } - - /** - * Update HopObjects in this application's cache. This is used to replicate - * application caches in a distributed app environment - */ - public void replicateCache(Vector add, Vector delete) { - if (!"true".equalsIgnoreCase(app.getProperty("allowReplication"))) { - app.logEvent("Rejecting cache replication event: allowReplication property is not set to true"); - throw new RuntimeException("Replication event rejected: setup does not allow replication."); - } - - app.nmgr.replicateCache(add, delete); - } -} diff --git a/src/helma/framework/core/RequestEvaluator.java b/src/helma/framework/core/RequestEvaluator.java deleted file mode 100644 index fab68f17..00000000 --- a/src/helma/framework/core/RequestEvaluator.java +++ /dev/null @@ -1,933 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.framework.*; -import helma.objectmodel.*; -import helma.objectmodel.db.*; -import helma.scripting.*; -import helma.util.*; -import java.lang.reflect.*; -import java.util.*; - -/** - * This class does the work for incoming requests. It holds a transactor thread - * and an EcmaScript evaluator to get the work done. Incoming threads are - * blocked until the request has been serviced by the evaluator, or the timeout - * specified by the application has passed. In the latter case, the evaluator thread - * is killed and an error message is returned. - */ -public final class RequestEvaluator implements Runnable { - static final int NONE = 0; // no request - static final int HTTP = 1; // via HTTP gateway - static final int XMLRPC = 2; // via XML-RPC - static final int INTERNAL = 3; // generic function call, e.g. by scheduler - public final Application app; - protected ScriptingEngine scriptingEngine; - public RequestTrans req; - public ResponseTrans res; - volatile Transactor rtx; - - // the object on which to invoke a function, if specified - Object thisObject; - - // the method to be executed - String method; - - // the session object associated with the current request - Session session; - - // arguments passed to the function - Object[] args; - - // the object path of the request we're evaluating - RequestPath requestPath; - - // the result of the operation - Object result; - - // the exception thrown by the evaluator, if any. - Exception exception; - - // the type of request to be serviced - int reqtype; - protected int skinDepth; - - /** - * Create a new RequestEvaluator for this application. - */ - public RequestEvaluator(Application app) { - this.app = app; - } - - protected void initScriptingEngine() { - if (scriptingEngine == null) { - String engineClassName = app.getProperty("scriptingEngine", - "helma.scripting.rhino.RhinoEngine"); - - try { - Class clazz = app.getClassLoader().loadClass(engineClassName); - - scriptingEngine = (ScriptingEngine) clazz.newInstance(); - scriptingEngine.init(app, this); - } catch (Exception x) { - Throwable t = x; - - if (x instanceof InvocationTargetException) { - t = ((InvocationTargetException) x).getTargetException(); - } - - app.logEvent("******************************************"); - app.logEvent("*** Error creating scripting engine: "); - app.logEvent("*** " + t.toString()); - app.logEvent("******************************************"); - } - } - } - - /** - * - */ - public void run() { - // first, set a local variable to the current transactor thread so we know - // when it's time to quit because another thread took over. - Transactor localrtx = (Transactor) Thread.currentThread(); - - try { - do { - // long startCheck = System.currentTimeMillis (); - app.typemgr.checkPrototypes(); - initScriptingEngine(); - scriptingEngine.updatePrototypes(); - - // System.err.println ("Type check overhead: "+(System.currentTimeMillis ()-startCheck)+" millis"); - // object refs to ressolve request path - Object root; - - // System.err.println ("Type check overhead: "+(System.currentTimeMillis ()-startCheck)+" millis"); - // object refs to ressolve request path - Object currentElement; - - requestPath = new RequestPath(app); - - switch (reqtype) { - case HTTP: - - int tries = 0; - boolean done = false; - String error = null; - - while (!done) { - currentElement = null; - - try { - // used for logging - StringBuffer txname = new StringBuffer(app.getName()); - - txname.append("/"); - txname.append((error == null) ? req.path : "error"); - - // begin transaction - localrtx.begin(txname.toString()); - - String action = null; - - root = app.getDataRoot(); - - HashMap globals = new HashMap(); - - globals.put("root", root); - globals.put("session", new SessionBean(session)); - globals.put("req", new RequestBean(req)); - globals.put("res", new ResponseBean(res)); - globals.put("app", new ApplicationBean(app)); - globals.put("path", requestPath); - req.startTime = System.currentTimeMillis(); - - // enter execution context - scriptingEngine.enterContext(globals); - - if (error != null) { - res.error = error; - } - - if (session.message != null) { - // bring over the message from a redirect - res.message = session.message; - session.message = null; - } - - try { - if (error != null) { - // there was an error in the previous loop, call error handler - currentElement = root; - - // do not reset the requestPath so error handler can use the original one - // get error handler action - String errorAction = app.props.getProperty("error", - "error"); - - action = getAction(currentElement, errorAction); - - if (action == null) { - throw new RuntimeException(error); - } - } else if ((req.path == null) || - "".equals(req.path.trim())) { - currentElement = root; - requestPath.add(null, currentElement); - - action = getAction(currentElement, null); - - if (action == null) { - throw new FrameworkException("Action not found"); - } - } else { - // march down request path... - StringTokenizer st = new StringTokenizer(req.path, - "/"); - int ntokens = st.countTokens(); - - // limit path to < 50 tokens - if (ntokens > 50) { - throw new RuntimeException("Path too long"); - } - - String[] pathItems = new String[ntokens]; - - for (int i = 0; i < ntokens; i++) - pathItems[i] = st.nextToken(); - - currentElement = root; - requestPath.add(null, currentElement); - - - for (int i = 0; i < ntokens; i++) { - if (currentElement == null) { - throw new FrameworkException("Object not found."); - } - - if (pathItems[i].length() == 0) { - continue; - } - - // if we're at the last element of the path, - // try to interpret it as action name. - if (i == (ntokens - 1)) { - action = getAction(currentElement, - pathItems[i]); - } - - if (action == null) { - currentElement = getChildElement(currentElement, - pathItems[i]); - - // add object to request path if suitable - if (currentElement != null) { - // add to requestPath array - requestPath.add(pathItems[i], currentElement); - } - } - } - - if (currentElement == null) { - throw new FrameworkException("Object not found."); - } - - if (action == null) { - action = getAction(currentElement, null); - } - - if (action == null) { - throw new FrameworkException("Action not found"); - } - } - } catch (FrameworkException notfound) { - if (error != null) { - - // we already have an error and the error template wasn't found, - // display it instead of notfound message - throw new RuntimeException(); - } - - // The path could not be resolved. Check if there is a "not found" action - // specified in the property file. - res.status = 404; - - String notFoundAction = app.props.getProperty("notFound", - "notfound"); - - currentElement = root; - action = getAction(currentElement, notFoundAction); - - if (action == null) { - throw new FrameworkException(notfound.getMessage()); - } - } - - // register path objects with their prototype names in - // res.handlers - Map macroHandlers = res.getMacroHandlers(); - int l = requestPath.size(); - Prototype[] protos = new Prototype[l]; - - for (int i=0; i=0; i--) { - if (protos[i] != null) { - protos[i].registerParents(macroHandlers, requestPath.get(i)); - } - } - - ///////////////////////////////////////////////////////////////////////////// - // end of path resolution section - ///////////////////////////////////////////////////////////////////////////// - // beginning of execution section - try { - // set the req.action property, cutting off the _action suffix - req.action = action.substring(0, action.length() - 7); - - // set the application checksum in response to make ETag - // generation sensitive to changes in the app - res.setApplicationChecksum(app.getChecksum()); - - // reset skin recursion detection counter - skinDepth = 0; - - // try calling onRequest() function on object before - // calling the actual action - try { - if (scriptingEngine.hasFunction(currentElement, - "onRequest")) { - scriptingEngine.invoke(currentElement, - "onRequest", - new Object[0], false); - } - } catch (RedirectException redir) { - throw redir; - } - - // reset skin recursion detection counter - skinDepth = 0; - - // do the actual action invocation - scriptingEngine.invoke(currentElement, action, - new Object[0], false); - } catch (RedirectException redirect) { - // res.redirect = redirect.getMessage (); - // if there is a message set, save it on the user object for the next request - if (res.message != null) { - session.message = res.message; - } - - done = true; - } - - // check if we're still the one and only or if the waiting thread has given up on us already - commitTransaction(); - done = true; - } catch (ConcurrencyException x) { - res.reset(); - - if (++tries < 8) { - // try again after waiting some period - abortTransaction(true); - - try { - // wait a bit longer with each try - int base = 800 * tries; - - Thread.sleep((long) (base + (Math.random() * base * 2))); - } catch (Exception ignore) { - } - - continue; - } else { - abortTransaction(false); - - if (error == null) { - app.errorCount += 1; - - // set done to false so that the error will be processed - done = false; - error = "Couldn't complete transaction due to heavy object traffic (tried " + - tries + " times)"; - } else { - // error in error action. use traditional minimal error message - res.write("Error in application '" + - app.getName() + "':

" +
-                                                  error + "
"); - done = true; - } - } - } catch (Exception x) { - abortTransaction(false); - - // If the transactor thread has been killed by the invoker thread we don't have to - // bother for the error message, just quit. - if (localrtx != rtx) { - break; - } - - res.reset(); - - // check if we tried to process the error already - if (error == null) { - app.errorCount += 1; - app.logEvent("Exception in " + - Thread.currentThread() + ": " + x); - - // Dump the profiling data to System.err - if (app.debug && !(x instanceof ScriptingException)) { - x.printStackTrace (); - } - - // set done to false so that the error will be processed - done = false; - error = x.getMessage(); - - if ((error == null) || (error.length() == 0)) { - error = x.toString(); - } - - if (error == null) { - error = "Unspecified error"; - } - } else { - // error in error action. use traditional minimal error message - res.write("Error in application '" + - app.getName() + "':

" +
-                                              error + "
"); - done = true; - } - } - } - - break; - - case XMLRPC: - - try { - localrtx.begin(app.getName() + ":xmlrpc:" + method); - - root = app.getDataRoot(); - - HashMap globals = new HashMap(); - - globals.put("root", root); - globals.put("res", new ResponseBean(res)); - globals.put("app", new ApplicationBean(app)); - - scriptingEngine.enterContext(globals); - - currentElement = root; - - if (method.indexOf(".") > -1) { - StringTokenizer st = new StringTokenizer(method, "."); - int cnt = st.countTokens(); - - for (int i = 1; i < cnt; i++) { - String next = st.nextToken(); - - currentElement = getChildElement(currentElement, - next); - } - - if (currentElement == null) { - throw new FrameworkException("Method name \"" + - method + - "\" could not be resolved."); - } - - method = st.nextToken(); - } - - // check XML-RPC access permissions - String proto = app.getPrototypeName(currentElement); - - app.checkXmlRpcAccess(proto, method); - - // reset skin recursion detection counter - skinDepth = 0; - - result = scriptingEngine.invoke(currentElement, method, args, - true); - commitTransaction(); - } catch (Exception x) { - abortTransaction(false); - - app.logEvent("Exception in " + Thread.currentThread() + ": " + - x); - - // If the transactor thread has been killed by the invoker thread we don't have to - // bother for the error message, just quit. - if (localrtx != rtx) { - return; - } - - this.exception = x; - } - - break; - - case INTERNAL: - - // Just a human readable descriptor of this invocation - String funcdesc = app.getName() + ":internal:" + method; - - // if thisObject is an instance of NodeHandle, get the node object itself. - if ((thisObject != null) && thisObject instanceof NodeHandle) { - thisObject = ((NodeHandle) thisObject).getNode(app.nmgr.safe); - - // see if a valid node was returned - if (thisObject == null) { - reqtype = NONE; - - break; - } - } - - // avoid going into transaction if called function doesn't exist - boolean functionexists = true; - - functionexists = scriptingEngine.hasFunction(thisObject, method); - - if (!functionexists) { - // function doesn't exist, nothing to do here. - reqtype = NONE; - } else { - try { - localrtx.begin(funcdesc); - - root = app.getDataRoot(); - - HashMap globals = new HashMap(); - - globals.put("root", root); - globals.put("res", new ResponseBean(res)); - globals.put("app", new ApplicationBean(app)); - - scriptingEngine.enterContext(globals); - - // reset skin recursion detection counter - skinDepth = 0; - - result = scriptingEngine.invoke(thisObject, method, args, - false); - commitTransaction(); - } catch (Exception x) { - abortTransaction(false); - - app.logEvent("Exception in " + Thread.currentThread() + - ": " + x); - - // If the transactor thread has been killed by the invoker thread we don't have to - // bother for the error message, just quit. - if (localrtx != rtx) { - return; - } - - this.exception = x; - } - } - - break; - } - - // exit execution context - scriptingEngine.exitContext(); - - // make sure there is only one thread running per instance of this class - // if localrtx != rtx, the current thread has been aborted and there's no need to notify - if (localrtx != rtx) { - localrtx.closeConnections(); - - return; - } - - notifyAndWait(); - } while (localrtx == rtx); - } finally { - localrtx.closeConnections(); - } - } - - /** - * Called by the transactor thread when it has successfully fulfilled a request. - */ - synchronized void commitTransaction() throws Exception { - Transactor localrtx = (Transactor) Thread.currentThread(); - - if (localrtx == rtx) { - reqtype = NONE; - localrtx.commit(); - } else { - throw new TimeoutException(); - } - } - - synchronized void abortTransaction(boolean retry) { - Transactor localrtx = (Transactor) Thread.currentThread(); - - if (!retry && (localrtx == rtx)) { - reqtype = NONE; - } - - try { - localrtx.abort(); - } catch (Exception ignore) { - } - } - - /** - * Tell waiting thread that we're done, then wait for next request - */ - synchronized void notifyAndWait() { - Transactor localrtx = (Transactor) Thread.currentThread(); - - if (reqtype != NONE) { - return; // is there a new request already? - } - - notifyAll(); - - try { - // wait for request, max 10 min - wait(1000 * 60 * 10); - - // if no request arrived, release ressources and thread - if ((reqtype == NONE) && (rtx == localrtx)) { - // comment this in to release not just the thread, but also the scripting engine. - // currently we don't do this because of the risk of memory leaks (objects from - // framework referencing into the scripting engine) - // scriptingEngine = null; - rtx = null; - } - } catch (InterruptedException ir) { - } - } - - /** - * - * - * @param req ... - * @param session ... - * - * @return ... - * - * @throws Exception ... - */ - public synchronized ResponseTrans invoke(RequestTrans req, Session session) - throws Exception { - this.reqtype = HTTP; - this.req = req; - this.session = session; - this.res = new ResponseTrans(req); - - app.activeRequests.put(req, this); - - checkThread(); - wait(app.requestTimeout); - - if (reqtype != NONE) { - app.logEvent("Stopping Thread for Request " + app.getName() + "/" + req.path); - stopThread(); - res.reset(); - res.write("Error in application '" + app.getName() + - "':

Request timed out.
"); - } - - return res; - } - - /** - * This checks if the Evaluator is already executing an equal request. If so, attach to it and - * wait for it to complete. Otherwise return null, so the application knows it has to run the request. - */ - public synchronized ResponseTrans attachRequest(RequestTrans req) - throws InterruptedException { - if ((this.req == null) || (res == null) || !this.req.equals(req)) { - return null; - } - - // we already know our response object - ResponseTrans r = res; - - if (reqtype != NONE) { - wait(app.requestTimeout); - } - - return r; - } - - /** - * - * - * @param method ... - * @param args ... - * - * @return ... - * - * @throws Exception ... - */ - public synchronized Object invokeXmlRpc(String method, Object[] args) - throws Exception { - this.reqtype = XMLRPC; - this.session = null; - this.method = method; - this.args = args; - this.res = new ResponseTrans(); - result = null; - exception = null; - - checkThread(); - wait(app.requestTimeout); - - if (reqtype != NONE) { - stopThread(); - } - - // reset res for garbage collection (res.data may hold reference to evaluator) - res = null; - - if (exception != null) { - throw (exception); - } - - return result; - } - - /** - * - * - * @param obj ... - * @param functionName ... - * @param args ... - * - * @return ... - * - * @throws Exception ... - */ - public Object invokeDirectFunction(Object obj, String functionName, Object[] args) - throws Exception { - return scriptingEngine.invoke(obj, functionName, args, false); - } - - /** - * - * - * @param object ... - * @param functionName ... - * @param args ... - * - * @return ... - * - * @throws Exception ... - */ - public synchronized Object invokeFunction(Object object, String functionName, - Object[] args) - throws Exception { - // give internal call more time (15 minutes) to complete - return invokeFunction(object, functionName, args, 60000L * 15); - } - - /** - * - * - * @param object ... - * @param functionName ... - * @param args ... - * @param timeout ... - * - * @return ... - * - * @throws Exception ... - */ - public synchronized Object invokeFunction(Object object, String functionName, - Object[] args, long timeout) - throws Exception { - reqtype = INTERNAL; - session = null; - thisObject = object; - method = functionName; - this.args = args; - this.res = new ResponseTrans(); - result = null; - exception = null; - - checkThread(); - wait(timeout); - - if (reqtype != NONE) { - stopThread(); - } - - // reset res for garbage collection (res.data may hold reference to evaluator) - res = null; - - if (exception != null) { - throw (exception); - } - - return result; - } - - /** - * - * - * @param session ... - * @param functionName ... - * @param args ... - * - * @return ... - * - * @throws Exception ... - */ - public synchronized Object invokeFunction(Session session, String functionName, - Object[] args) - throws Exception { - reqtype = INTERNAL; - this.session = session; - thisObject = null; - method = functionName; - this.args = args; - res = new ResponseTrans(); - result = null; - exception = null; - - checkThread(); - wait(app.requestTimeout); - - if (reqtype != NONE) { - stopThread(); - } - - // reset res for garbage collection (res.data may hold reference to evaluator) - res = null; - - if (exception != null) { - throw (exception); - } - return result; - } - - private Object getChildElement(Object obj, String name) throws ScriptingException { - if (scriptingEngine.hasFunction(obj, "getChildElement")) { - return scriptingEngine.invoke(obj, "getChildElement", new Object[] {name}, false); - } - - if (obj instanceof IPathElement) { - return ((IPathElement) obj).getChildElement(name); - } - - return null; - } - - /** - * Stop this request evaluator's current thread. If currently active kill the request, otherwise just - * notify. - */ - public synchronized void stopThread() { - app.logEvent("Stopping Thread " + rtx); - - Transactor t = rtx; - - // let the scripting engine know that the - // current transaction is being aborted. - if (scriptingEngine != null) { - scriptingEngine.abort(); - } - - rtx = null; - - if (t != null) { - if (reqtype != NONE) { - reqtype = NONE; - t.kill(); - - try { - t.abort(); - } catch (Exception ignore) { - } - } else { - notifyAll(); - } - - t.closeConnections(); - } - } - - private synchronized void checkThread() throws InterruptedException { - if (app.stopped) { - throw new ApplicationStoppedException(); - } - - if ((rtx == null) || !rtx.isAlive()) { - // app.logEvent ("Starting Thread"); - rtx = new Transactor(this, app.threadgroup, app.nmgr); - rtx.setContextClassLoader(app.getClassLoader()); - rtx.start(); - } else { - notifyAll(); - } - } - - /** - * Null out some fields, mostly for the sake of garbage collection. - */ - public void recycle() { - res = null; - req = null; - session = null; - args = null; - requestPath = null; - result = null; - exception = null; - } - - /** - * Check if an action with a given name is defined for a scripted object. If it is, - * return the action's function name. Otherwise, return null. - */ - public String getAction(Object obj, String action) { - if (obj == null) { - return null; - } - - String act = (action == null) ? "main_action" : (action + "_action"); - - if (scriptingEngine.hasFunction(obj, act)) { - return act; - } - - return null; - } - -} diff --git a/src/helma/framework/core/RequestPath.java b/src/helma/framework/core/RequestPath.java deleted file mode 100644 index c4e99b7e..00000000 --- a/src/helma/framework/core/RequestPath.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import java.util.*; -import helma.util.UrlEncoded; - -/** - * Represents a URI request path that has been resolved to an object path. - * Offers methods to access objects in the path by index and prototype names, - * and to render the path as URI again. - */ -public class RequestPath { - - Application app; - - List objects; - List ids; - - Map primaryProtos; - Map secondaryProtos; - - /** - * Creates a new RequestPath object. - * - * @param app the application we're running in - */ - public RequestPath(Application app) { - this.app = app; - objects = new ArrayList(); - ids = new ArrayList(); - primaryProtos = new HashMap(); - secondaryProtos = new HashMap(); - } - - /** - * Adds an item to the end of the path. - * - * @param id the item id representing the path in the URL - * @param obj the object to which the id resolves - */ - public void add(String id, Object obj) { - ids.add(id); - objects.add(obj); - - Prototype proto = app.getPrototype(obj); - - if (proto != null) { - primaryProtos.put(proto.getName(), obj); - proto.registerParents(secondaryProtos, obj); - } - } - - /** - * Returns the number of objects in the request path. - */ - public int size() { - return objects.size(); - } - - /** - * Gets an object in the path by index. - * - * @param idx the index of the object in the request path - */ - public Object get(int idx) { - if (idx < 0 || idx >= objects.size()) { - return null; - } - - return objects.get(idx); - } - - /** - * Gets an object in the path by prototype name. - * - * @param typeName the prototype name of the object in the request path - */ - public Object getByPrototypeName(String typeName) { - // search primary prototypes first - Object obj = primaryProtos.get(typeName); - - if (obj != null) { - return obj; - } - - // if that fails, consult secondary prototype map - return secondaryProtos.get(typeName); - } - - /** - * Returns the string representation of this path usable for links. - */ - public String href(String action) { - StringBuffer buffer = new StringBuffer(app.getBaseURI()); - - int start = 1; - String rootPrototype = app.getRootPrototype(); - - if (rootPrototype != null) { - Object rootObject = getByPrototypeName(rootPrototype); - - if (rootObject != null) { - start = objects.indexOf(rootObject) + 1; - } - } - - for (int i=start; iSession object and - * exposes it to the scripting framework. - */ -public class SessionBean implements Serializable { - // the wrapped session object - Session session; - - /** - * Creates a new SessionBean around a Session object. - * - * @param session ... - */ - public SessionBean(Session session) { - this.session = session; - } - - /** - * - * - * @return ... - */ - public String toString() { - return session.toString(); - } - - /** - * Attempts to log in a user with the given username/password credentials. - * If username and password match, the user node is associated with the session - * and bound to the session.user property. - * - * @param username the username - * @param password the password - * - * @return true if the user exists and the password matches the user's password property. - */ - public boolean login(String username, String password) { - boolean success = session.getApp().loginSession(username, password, session); - - return success; - } - - /** - * Directly associates the session with a user object without requiring - * a username/password pair. This is for applications that use their own - * authentication mechanism. - * - * @param userNode the HopObject node representing the user. - */ - public void login(INode userNode) { - session.login(userNode); - } - - /** - * Disassociate this session from any user object it may have been associated with. - */ - public void logout() { - session.getApp().logoutSession(session); - } - - /** - * Touching the session marks it as active, avoiding session timeout. - * Usually, sessions are touched when the user associated with it sends - * a request. This method may be used to artificially keep a session alive. - */ - public void touch() { - session.touch(); - } - - /** - * Returns the time this session was last touched. - * - * @return ... - */ - public Date lastActive() { - return new Date(session.lastTouched()); - } - - /** - * Returns the time this session was created. - * - * @return ... - */ - public Date onSince() { - return new Date(session.onSince()); - } - - // property-related methods: - - /** - * Get the cache/data node for this session. This object may be used - * to store transient per-session data. It is reflected to the scripting - * environment as session.data. - */ - public INode getdata() { - return session.getCacheNode(); - } - - /** - * Gets the user object for this session. This method returns null unless - * one of the session.login methods was previously invoked. - * - * @return ... - */ - public INode getuser() { - return session.getUserNode(); - } - - /** - * Returns the unique identifier for a session object (session cookie). - * - * @return ... - */ - public String get_id() { - return session.getSessionID(); - } - - /** - * Returns the unique identifier for a session object (session cookie). - * - * @return ... - */ - public String getcookie() { - return session.getSessionID(); - } - - /** - * Returns the time this session was last touched. - * - * @return ... - */ - public Date getlastActive() { - return new Date(session.lastTouched()); - } - - /** - * Returns a date object representing the time a user's session was started. - * - * @return ... - */ - public Date getonSince() { - return new Date(session.onSince()); - } - - /** - * Gets the date at which the session was created or a login or - * logout was performed the last time. - * - * @return ... - */ - public Date getLastModified() { - return new Date(session.lastModified()); - } - - /** - * Sets the date at which the session was created or a login or - * logout was performed the last time. - * - * @param date ... - */ - public void setLastModified(Date date) { - session.setLastModified(date); - } -} diff --git a/src/helma/framework/core/Skin.java b/src/helma/framework/core/Skin.java deleted file mode 100644 index 6c2db476..00000000 --- a/src/helma/framework/core/Skin.java +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.framework.*; -import helma.objectmodel.ConcurrencyException; -import helma.objectmodel.INode; -import helma.scripting.*; -import helma.util.HtmlEncoder; -import helma.util.SystemMap; -import helma.util.WrappedMap; -import java.io.*; -import java.net.URLEncoder; -import java.util.*; - -/** - * This represents a Helma skin, i.e. a template created from containing Macro tags - * that will be dynamically evaluated.. It uses the request path array - * from the RequestEvaluator object to resolve Macro handlers by type name. - */ -public final class Skin { - static final int HANDLER = 0; - static final int MACRO = 1; - static final int PARAMNAME = 2; - static final int PARAMVALUE = 3; - static final int ENCODE_NONE = 0; - static final int ENCODE_HTML = 1; - static final int ENCODE_XML = 2; - static final int ENCODE_FORM = 3; - static final int ENCODE_URL = 4; - static final int ENCODE_ALL = 5; - private Macro[] macros; - private Application app; - private char[] source; - private int sourceLength; - private HashSet sandbox; - - /** - * Create a skin without any restrictions on which macros are allowed to be called from it - */ - public Skin(String content, Application app) { - this.app = app; - sandbox = null; - source = content.toCharArray(); - sourceLength = source.length; - parse(); - } - - /** - * Create a skin with a sandbox which contains the names of macros allowed to be called - */ - public Skin(String content, Application app, HashSet sandbox) { - this.app = app; - this.sandbox = sandbox; - source = content.toCharArray(); - sourceLength = source.length; - parse(); - } - - /** - * Create a skin without any restrictions on the macros from a char array. - */ - public Skin(char[] content, int length, Application app) { - this.app = app; - this.sandbox = null; - source = content; - sourceLength = length; - parse(); - } - - /** - * Parse a skin object from source text - */ - private void parse() { - ArrayList partBuffer = new ArrayList(); - - for (int i = 0; i < (sourceLength - 1); i++) { - if ((source[i] == '<') && (source[i + 1] == '%')) { - // found macro start tag - int j = i + 2; - - // search macr end tag - while ((j < (sourceLength - 1)) && - ((source[j] != '%') || (source[j + 1] != '>'))) { - j++; - } - - if (j > (i + 2)) { - partBuffer.add(new Macro(i, j + 2)); - } - - i = j + 1; - } - } - - macros = new Macro[partBuffer.size()]; - partBuffer.toArray(macros); - } - - /** - * Get the raw source text this skin was parsed from - */ - public String getSource() { - return new String(source, 0, sourceLength); - } - - /** - * Render this skin - */ - public void render(RequestEvaluator reval, Object thisObject, Map paramObject) - throws RedirectException { - // check for endless skin recursion - if (++reval.skinDepth > 50) { - throw new RuntimeException("Recursive skin invocation suspected"); - } - - if (macros == null) { - reval.res.writeCharArray(source, 0, sourceLength); - reval.skinDepth--; - - return; - } - - try { - int written = 0; - Map handlerCache = null; - - if (macros.length > 3) { - handlerCache = new HashMap(); - } - - for (int i = 0; i < macros.length; i++) { - if (macros[i].start > written) { - reval.res.writeCharArray(source, written, macros[i].start - written); - } - - macros[i].render(reval, thisObject, paramObject, handlerCache); - written = macros[i].end; - } - - if (written < sourceLength) { - reval.res.writeCharArray(source, written, sourceLength - written); - } - } finally { - reval.skinDepth--; - } - } - - /** - * Check if a certain macro is present in this skin. The macro name is in handler.name notation - */ - public boolean containsMacro(String macroname) { - for (int i = 0; i < macros.length; i++) { - if (macros[i] instanceof Macro) { - Macro m = (Macro) macros[i]; - - if (macroname.equals(m.fullName)) { - return true; - } - } - } - - return false; - } - - /** - * Adds a macro to the list of allowed macros. The macro is in handler.name notation. - */ - public void allowMacro(String macroname) { - if (sandbox == null) { - sandbox = new HashSet(); - } - - sandbox.add(macroname); - } - - class Macro { - final int start; - final int end; - String handler; - String name; - String fullName; - String prefix; - String suffix; - String defaultValue; - int encoding = ENCODE_NONE; - Map parameters = null; - - public Macro(int start, int end) { - this.start = start; - this.end = end; - - int state = HANDLER; - boolean escape = false; - char quotechar = '\u0000'; - String lastParamName = null; - StringBuffer b = new StringBuffer(); - - for (int i = start + 2; i < (end - 2); i++) { - switch (source[i]) { - case '.': - - if (state == HANDLER) { - handler = b.toString().trim(); - b.setLength(0); - state = MACRO; - } else { - b.append(source[i]); - } - - break; - - case '\\': - - if (escape) { - b.append(source[i]); - } - - escape = !escape; - - break; - - case '"': - case '\'': - - if (!escape && (state == PARAMVALUE)) { - if (quotechar == source[i]) { - String paramValue = b.toString(); - - if (!setSpecialParameter(lastParamName, paramValue)) { - addGenericParameter(lastParamName, paramValue); - } - - lastParamName = null; - b.setLength(0); - state = PARAMNAME; - quotechar = '\u0000'; - } else if (quotechar == '\u0000') { - quotechar = source[i]; - b.setLength(0); - } else { - b.append(source[i]); - } - } else { - b.append(source[i]); - } - - escape = false; - - break; - - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - - if ((state == MACRO) || ((state == HANDLER) && (b.length() > 0))) { - name = b.toString().trim(); - b.setLength(0); - state = PARAMNAME; - } else if ((state == PARAMVALUE) && (quotechar == '\u0000')) { - String paramValue = b.toString(); - - if (!setSpecialParameter(lastParamName, paramValue)) { - addGenericParameter(lastParamName, paramValue); - } - - lastParamName = null; - b.setLength(0); - state = PARAMNAME; - } else if (state == PARAMVALUE) { - b.append(source[i]); - } else { - b.setLength(0); - } - - break; - - case '=': - - if (state == PARAMNAME) { - lastParamName = b.toString().trim(); - b.setLength(0); - state = PARAMVALUE; - } else { - b.append(source[i]); - } - - break; - - default: - b.append(source[i]); - escape = false; - } - } - - if (b.length() > 0) { - if ((lastParamName != null) && (b.length() > 0)) { - String paramValue = b.toString(); - - if (!setSpecialParameter(lastParamName, paramValue)) { - addGenericParameter(lastParamName, paramValue); - } - } else if (state <= MACRO) { - name = b.toString().trim(); - } - } - - if (handler == null) { - fullName = name; - } else { - fullName = handler + "." + name; - } - } - - private boolean setSpecialParameter(String name, String value) { - if ("prefix".equals(name)) { - prefix = value; - - return true; - } else if ("suffix".equals(name)) { - suffix = value; - - return true; - } else if ("encoding".equals(name)) { - if ("html".equalsIgnoreCase(value)) { - encoding = ENCODE_HTML; - } else if ("xml".equalsIgnoreCase(value)) { - encoding = ENCODE_XML; - } else if ("form".equalsIgnoreCase(value)) { - encoding = ENCODE_FORM; - } else if ("url".equalsIgnoreCase(value)) { - encoding = ENCODE_URL; - } else if ("all".equalsIgnoreCase(value)) { - encoding = ENCODE_ALL; - } - - return true; - } else if ("default".equals(name)) { - defaultValue = value; - - return true; - } - - return false; - } - - private void addGenericParameter(String name, String value) { - if (parameters == null) { - parameters = new HashMap(); - } - - parameters.put(name, value); - } - - /** - * Render the macro given a handler object - */ - public void render(RequestEvaluator reval, Object thisObject, Map paramObject, - Map handlerCache) throws RedirectException { - if ((sandbox != null) && !sandbox.contains(fullName)) { - //String h = (handler == null) ? "global" : handler; - - reval.res.write("[Macro " + fullName + " not allowed in sandbox]"); - - return; - } else if ("response".equalsIgnoreCase(handler)) { - renderFromResponse(reval); - - return; - } else if ("request".equalsIgnoreCase(handler)) { - renderFromRequest(reval); - - return; - } else if ("param".equalsIgnoreCase(handler)) { - renderFromParam(reval, paramObject); - - return; - } else if ("session".equalsIgnoreCase(handler)) { - renderFromSession(reval); - - return; - } - - try { - Object handlerObject = null; - - // flag to tell whether we found our invocation target object - boolean objectFound = true; - - if (handler != null) { - // try to get handler from handlerCache first - if (handlerCache != null) { - handlerObject = handlerCache.get(handler); - } - - if (handlerObject == null) { - // if handler object wasn't found in cache retrieve it - if ((handlerObject == null) && (thisObject != null)) { - // not a global macro - need to find handler object - // was called with this object - check it or its parents for matching prototype - if (!handler.equals("this") && - !handler.equals(app.getPrototypeName(thisObject))) { - // the handler object is not what we want - Object n = thisObject; - - // walk down parent chain to find handler object - while (n != null) { - Prototype proto = app.getPrototype(n); - - if ((proto != null) && proto.isInstanceOf(handler)) { - handlerObject = n; - - break; - } - - n = app.getParentElement(n); - } - } else { - // we already have the right handler object - handlerObject = thisObject; - } - } - - if (handlerObject == null) { - // eiter because thisObject == null or the right object wasn't found - // in the object's parent path. Check if a matching macro handler - // is registered with the response object (res.handlers). - handlerObject = reval.res.getMacroHandlers().get(handler); - } - - // the macro handler object couldn't be found - if (handlerObject == null) { - objectFound = false; - } - // else put the found handler object into the cache so we don't have to look again - else if (handlerCache != null) { - handlerCache.put(handler, handlerObject); - } - } - } else { - // this is a global macro with no handler specified - handlerObject = null; - } - - if (objectFound) { - // check if a function called name_macro is defined. - // if so, the macro evaluates to the function. Otherwise, - // a property/field with the name is used, if defined. - String funcName = name + "_macro"; - - if (reval.scriptingEngine.hasFunction(handlerObject, funcName)) { - StringBuffer buffer = reval.res.getBuffer(); - - // remember length of response buffer before calling macro - int bufLength = buffer.length(); - - // remember length of buffer with prefix written out - int preLength = 0; - - if (prefix != null) { - buffer.append(prefix); - preLength = prefix.length(); - } - - // System.err.println ("Getting macro from function"); - // pass a clone/copy of the parameter map so if the script changes it, - Object[] arguments = new Object[1]; - if (parameters == null) { - arguments[0] = new SystemMap(4); - } else { - arguments[0] = new WrappedMap(parameters, WrappedMap.COPY_ON_WRITE); - // arguments[0] = new SystemMap(parameters); - } - - Object value = reval.scriptingEngine.invoke(handlerObject, - funcName, arguments, - false); - - // check if macro wrote out to response buffer - if (buffer.length() == (bufLength + preLength)) { - // function didn't write out anything itself. - // erase previously written prefix - if (preLength > 0) { - buffer.setLength(bufLength); - } - - // write out macro's return value - writeResponse(value, buffer, true); - } else { - if (encoding != ENCODE_NONE) { - // if an encoding is specified, re-encode the macro's output - String output = buffer.substring(bufLength + preLength); - - buffer.setLength(bufLength); - writeResponse(output, buffer, false); - } else { - // no re-encoding needed, just append suffix - if (suffix != null) { - buffer.append(suffix); - } - } - - writeResponse(value, buffer, false); - } - } else { - // System.err.println ("Getting macro from property"); - Object value = reval.scriptingEngine.get(handlerObject, name); - - writeResponse(value, reval.res.getBuffer(), true); - } - } else { - String msg = "[HopMacro unhandled: " + fullName + "]"; - - reval.res.write(" " + msg + " "); - app.logEvent(msg); - } - } catch (RedirectException redir) { - throw redir; - } catch (ConcurrencyException concur) { - throw concur; - } catch (TimeoutException timeout) { - throw timeout; - } catch (Exception x) { - // x.printStackTrace(); - String msg = x.getMessage(); - - if ((msg == null) || (msg.length() < 10)) { - msg = x.toString(); - } - - msg = "[HopMacro error in " + fullName + ": " + msg + "]"; - reval.res.write(" " + msg + " "); - app.logEvent(msg); - } - } - - private void renderFromResponse(RequestEvaluator reval) { - Object value = null; - - if ("message".equals(name)) { - value = reval.res.message; - } else if ("error".equals(name)) { - value = reval.res.error; - } - - if (value == null) { - value = reval.res.get(name); - } - - writeResponse(value, reval.res.getBuffer(), true); - } - - private void renderFromRequest(RequestEvaluator reval) { - if (reval.req == null) { - return; - } - - Object value = reval.req.get(name); - - writeResponse(value, reval.res.getBuffer(), true); - } - - private void renderFromSession(RequestEvaluator reval) { - if (reval.session == null) { - return; - } - - Object value = reval.session.getCacheNode().getString(name); - - writeResponse(value, reval.res.getBuffer(), true); - } - - private void renderFromParam(RequestEvaluator reval, Map paramObject) { - if (paramObject == null) { - reval.res.write("[HopMacro error: Skin requires a parameter object]"); - } else { - Object value = paramObject.get(name); - - writeResponse(value, reval.res.getBuffer(), true); - } - } - - /** - * Utility method for writing text out to the response object. - */ - void writeResponse(Object value, StringBuffer buffer, boolean useDefault) { - String text; - - if (value == null) { - if (useDefault) { - text = defaultValue; - } else { - return; - } - } else { - // do not render doubles as doubles unless - // they actually have a decimal place. This is necessary because - // all numbers are handled as Double in JavaScript. - if (value instanceof Double) { - Double d = (Double) value; - if (d.longValue() == d.doubleValue()) { - text = Long.toString(d.longValue()); - } else { - text = d.toString(); - } - } else { - text = value.toString(); - } - } - - if ((text != null) && (text.length() > 0)) { - // only write prefix/suffix if value is not null, if we write the default - // value provided by the macro tag, we assume it's already complete - if (prefix != null && value != null) { - buffer.append(prefix); - } - - switch (encoding) { - case ENCODE_NONE: - buffer.append(text); - - break; - - case ENCODE_HTML: - HtmlEncoder.encode(text, buffer); - - break; - - case ENCODE_XML: - HtmlEncoder.encodeXml(text, buffer); - - break; - - case ENCODE_FORM: - HtmlEncoder.encodeFormValue(text, buffer); - - break; - - case ENCODE_URL: - buffer.append(URLEncoder.encode(text)); - - break; - - case ENCODE_ALL: - HtmlEncoder.encodeAll(text, buffer); - - break; - } - - if (suffix != null && value != null) { - buffer.append(suffix); - } - } - } - - public String toString() { - return "[HopMacro: " + fullName + "]"; - } - - /** - * Return the full name of the macro in handler.name notation - */ - public String getFullName() { - return fullName; - } - } -} diff --git a/src/helma/framework/core/SkinFile.java b/src/helma/framework/core/SkinFile.java deleted file mode 100644 index 8b681df4..00000000 --- a/src/helma/framework/core/SkinFile.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.util.Updatable; -import java.io.*; -import java.util.*; - -/** - * This represents a File containing a Hop skin - */ -public final class SkinFile implements Updatable { - String name; - Prototype prototype; - Application app; - File file; - Skin skin; - long lastmod = 0; - - /** - * Creates a new SkinFile object. - * - * @param file ... - * @param name ... - * @param proto ... - */ - public SkinFile(File file, String name, Prototype proto) { - this.prototype = proto; - this.file = file; - this.name = name; - this.app = proto.app; - skin = null; - } - - /** - * Create a skinfile without a file, passing the skin body directly. This is used for - * Skins contained in zipped applications. The whole update mechanism is bypassed - * by immediately setting the skin member. - */ - public SkinFile(String body, String name, Prototype proto) { - this.prototype = proto; - this.app = proto.app; - this.name = name; - this.file = null; - skin = new Skin(body, app); - } - - /** - * Create a skinfile that doesn't belong to a prototype, or at - * least it doesn't know about its prototype and isn't managed by the prototype. - */ - public SkinFile(File file, String name, Application app) { - this.app = app; - this.file = file; - this.name = name; - this.prototype = null; - skin = null; - } - - /** - * Tell the type manager whether we need an update. this is the case when - * the file has been modified or deleted. - */ - public boolean needsUpdate() { - // if skin object is null we only need to call update if the file doesn't - // exist anymore, while if the skin is initialized, we'll catch both - // cases (file deleted and file changed) by just calling lastModified(). - return (skin != null) ? (lastmod != file.lastModified()) : (!file.exists()); - } - - /** - * - */ - public void update() { - if (!file.exists()) { - // remove skin from prototype - remove(); - } else { - // we only need to update if the skin has already been initialized - if (skin != null) { - read(); - } - } - } - - private void read() { - try { - FileReader reader = new FileReader(file); - char[] c = new char[(int) file.length()]; - int length = reader.read(c); - - reader.close(); - skin = new Skin(c, length, app); - } catch (IOException x) { - app.logEvent("Error reading Skin " + file + ": " + x); - } - - lastmod = file.lastModified(); - } - - /** - * - */ - public void remove() { - if (prototype != null) { - prototype.removeSkinFile(this); - } - } - - /** - * - * - * @return ... - */ - public File getFile() { - return file; - } - - /** - * - * - * @return ... - */ - public Skin getSkin() { - if (skin == null) { - read(); - } - - return skin; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @return ... - */ - public String toString() { - return prototype.getName() + "/" + file.getName(); - } -} diff --git a/src/helma/framework/core/SkinManager.java b/src/helma/framework/core/SkinManager.java deleted file mode 100644 index b28a4fb2..00000000 --- a/src/helma/framework/core/SkinManager.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.objectmodel.INode; -import java.io.*; -import java.util.*; - -/** - * Manages skins for a Helma application - */ -public final class SkinManager implements FilenameFilter { - Application app; - - /** - * Creates a new SkinManager object. - * - * @param app ... - */ - public SkinManager(Application app) { - this.app = app; - } - - protected Skin getSkin(Prototype proto, String skinname, Object[] skinpath) { - if (proto == null) { - return null; - } - - Skin skin = null; - - // First check if the skin has been already used within the execution of this request - // check for skinsets set via res.skinpath property - do { - if (skinpath != null) { - for (int i = 0; i < skinpath.length; i++) { - skin = getSkinInternal(skinpath[i], proto.getName(), skinname); - - if (skin != null) { - return skin; - } - } - } - - // skin for this prototype wasn't found in the skinsets. - // the next step is to look if it is defined as skin file in the application directory - skin = proto.getSkin(skinname); - - if (skin != null) { - return skin; - } - - // still not found. See if there is a parent prototype which might define the skin. - proto = proto.getParentPrototype(); - } while (proto != null); - - // looked every where, nothing to be found - return null; - } - - protected Skin getSkinInternal(Object skinset, String prototype, String skinname) { - if ((prototype == null) || (skinset == null)) { - return null; - } - - // check if the skinset object is a HopObject (db based skin) - // or a String (file based skin) - if (skinset instanceof INode) { - INode n = ((INode) skinset).getNode(prototype); - - if (n != null) { - n = n.getNode(skinname); - - if (n != null) { - String skin = n.getString("skin"); - - if (skin != null) { - return new Skin(skin, app); - } - } - } - } else { - // Skinset is interpreted as directory name from which to - // retrieve the skin - File f = new File(skinset.toString(), prototype); - - f = new File(f, skinname + ".skin"); - - if (f.exists() && f.canRead()) { - SkinFile sf = new SkinFile(f, skinname, app); - - return sf.getSkin(); - } - } - - // Inheritance is taken care of in the above getSkin method. - // the sequence is prototype.skin-from-db, prototype.skin-from-file, parent.from-db, parent.from-file etc. - return null; - } - - protected Map getSkinFiles(String skinDir, Prototype proto) { - File dir = new File(skinDir.toString(), proto.getName()); - String[] skinNames = dir.list(this); - - if ((skinNames == null) || (skinNames.length == 0)) { - return null; - } - - HashMap map = new HashMap(); - - for (int i = 0; i < skinNames.length; i++) { - String name = skinNames[i].substring(0, skinNames[i].length() - 5); - File file = new File(dir, skinNames[i]); - - map.put(name, new SkinFile(file, name, proto)); - } - - return map; - } - - /** - * Implements java.io.FilenameFilter.accept() - */ - public boolean accept(File d, String n) { - return n.endsWith(".skin"); - } -} diff --git a/src/helma/framework/core/TypeManager.java b/src/helma/framework/core/TypeManager.java deleted file mode 100644 index e4ca1113..00000000 --- a/src/helma/framework/core/TypeManager.java +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.objectmodel.*; -import helma.objectmodel.db.DbMapping; -import helma.scripting.*; -import helma.util.*; -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.*; - -/** - * The type manager periodically checks the prototype definitions for its - * applications and updates the evaluators if anything has changed. - */ -public final class TypeManager { - final static String[] standardTypes = { "user", "global", "root", "hopobject" }; - final static String templateExtension = ".hsp"; - final static String scriptExtension = ".js"; - final static String actionExtension = ".hac"; - final static String skinExtension = ".skin"; - Application app; - File appDir; - HashMap prototypes; // map of prototypes - HashMap zipfiles; // map of zipped script files - HashSet jarfiles; // set of Java archives - long lastCheck = 0; - long appDirMod = 0; - - // a checksum that changes whenever something in the application files changes. - long checksum; - - // the hopobject prototype - Prototype hopobjectProto; - - // the global prototype - Prototype globalProto; - - // app specific class loader, includes jar files in the app directory - AppClassLoader loader; - - /** - * Creates a new TypeManager object. - * - * @param app ... - * - * @throws MalformedURLException ... - * @throws RuntimeException ... - */ - public TypeManager(Application app) throws MalformedURLException { - this.app = app; - appDir = app.appDir; - - // make sure the directories for the standard prototypes exist, and lament otherwise - if (appDir.list().length == 0) { - for (int i = 0; i < standardTypes.length; i++) { - File f = new File(appDir, standardTypes[i]); - - if (!f.exists() && !f.mkdir()) { - app.logEvent("Warning: directory " + f.getAbsolutePath() + - " could not be created."); - } else if (!f.isDirectory()) { - app.logEvent("Warning: " + f.getAbsolutePath() + - " is not a directory."); - } - } - } - - prototypes = new HashMap(); - zipfiles = new HashMap(); - jarfiles = new HashSet(); - - URL helmajar = TypeManager.class.getResource("/"); - - if (helmajar == null) { - // Helma classes are in jar file, get helma.jar URL - URL[] urls = ((URLClassLoader) TypeManager.class.getClassLoader()).getURLs(); - - for (int i = 0; i < urls.length; i++) { - String url = urls[i].toString().toLowerCase(); - if (url.endsWith("helma.jar")) { - helmajar = urls[i]; - break; - } - } - } - - if (helmajar == null) { - throw new RuntimeException("helma.jar not found in embedding classpath"); - } - - loader = new AppClassLoader(app.getName(), new URL[] { helmajar }); - } - - /** - * Run through application's prototype directories and create prototypes, but don't - * compile or evaluate any scripts. - */ - public void createPrototypes() { - // create standard prototypes. - createPrototype("root"); - createPrototype("user"); - - // get references to hopobject and global protos, - // since we need it regularly when setting parent prototypes. - hopobjectProto = createPrototype("hopobject"); - globalProto = createPrototype("global"); - - // loop through directories and create prototypes - checkFiles(); - } - - /** - * Run through application's prototype directories and check if anything has been updated. - * If so, update prototypes and scripts. - */ - public synchronized void checkPrototypes() { - if ((System.currentTimeMillis() - lastCheck) < 1000L) { - return; - } - - try { - checkFiles(); - } catch (Exception ignore) { - } - - lastCheck = System.currentTimeMillis(); - } - - /** - * Run through application's prototype directories and check if - * there are any prototypes to be created. - */ - public void checkFiles() { - // check if any files have been created/removed since last time we - // checked... - if (appDir.lastModified() > appDirMod) { - appDirMod = appDir.lastModified(); - - String[] list = appDir.list(); - - if (list == null) { - throw new RuntimeException("Can't read app directory " + appDir + - " - check permissions"); - } - - for (int i = 0; i < list.length; i++) { - if (list[i].endsWith(".zip")) { - ZippedAppFile zipped = (ZippedAppFile) zipfiles.get(list[i]); - - if (zipped == null) { - File f = new File(appDir, list[i]); - - if (!f.isDirectory() && f.exists()) { - zipped = new ZippedAppFile(f, app); - zipfiles.put(list[i], zipped); - } - } - - continue; - } - - if (list[i].endsWith(".jar")) { - if (!jarfiles.contains(list[i])) { - jarfiles.add(list[i]); - - File f = new File(appDir, list[i]); - - try { - loader.addURL(new URL("file:" + f.getAbsolutePath())); - } catch (MalformedURLException ignore) { - } - } - - continue; - } - - if (list[i].indexOf('.') > -1) { - continue; - } - - Prototype proto = getPrototype(list[i]); - - // if prototype doesn't exist, create it - if ((proto == null) && isValidTypeName(list[i])) { - File f = new File(appDir, list[i]); - - if (f.isDirectory()) { - // create new prototype - createPrototype(list[i], f); - } - } - } - } - - // calculate this app's checksum by adding all checksums from all prototypes - long newChecksum = 0; - - // loop through zip files to check for updates - for (Iterator it = zipfiles.values().iterator(); it.hasNext();) { - ZippedAppFile zipped = (ZippedAppFile) it.next(); - - if (zipped.needsUpdate()) { - zipped.update(); - } - - newChecksum += zipped.lastmod; - } - - // loop through prototypes and check if type.properties needs updates - // it's important that we do this _after_ potentially new prototypes - // have been created in the previous loop. - for (Iterator i = prototypes.values().iterator(); i.hasNext();) { - Prototype proto = (Prototype) i.next(); - - // calculate this app's type checksum - newChecksum += proto.getChecksum(); - - // update prototype's type mapping - DbMapping dbmap = proto.getDbMapping(); - - if ((dbmap != null) && dbmap.needsUpdate()) { - dbmap.update(); - - // this is now done in dbmap.update()!!! - /*if ((proto != hopobjectProto) && (proto != globalProto)) { - // set parent prototype, in case it has changed. - String parentName = dbmap.getExtends(); - - if (parentName != null) { - proto.setParentPrototype(getPrototype(parentName)); - } else if (!app.isJavaPrototype(proto.getName())) { - proto.setParentPrototype(hopobjectProto); - } - } */ - } - } - - checksum = newChecksum; - } - - protected void removeZipFile(String zipname) { - zipfiles.remove(zipname); - - for (Iterator i = prototypes.values().iterator(); i.hasNext();) { - Prototype proto = (Prototype) i.next(); - - // update prototype's type mapping - DbMapping dbmap = proto.getDbMapping(); - SystemProperties props = dbmap.getProperties(); - - props.removeProps(zipname); - } - } - - private boolean isValidTypeName(String str) { - if (str == null) { - return false; - } - - char[] c = str.toCharArray(); - - for (int i = 0; i < c.length; i++) - if (!Character.isJavaIdentifierPart(c[i])) { - return false; - } - - return true; - } - - /** - * Return a checksum over all files in all prototypes in this application. - * The checksum can be used to find out quickly if any file has changed. - */ - public long getChecksum() { - return checksum; - } - - /** - * Get a prototype defined for this application - */ - public Prototype getPrototype(String typename) { - return (Prototype) prototypes.get(typename); - } - - /** - * Get a prototype, creating it if it doesn't already exist. Note - * that it doesn't create a DbMapping - this is left to the - * caller (e.g. ZippedAppFile). - */ - public Prototype createPrototype(String typename) { - return createPrototype(typename, new File(appDir, typename)); - } - - /** - * Create a prototype from a directory containing scripts and other stuff - */ - public Prototype createPrototype(String typename, File dir) { - Prototype proto = new Prototype(typename, dir, app); - - // Create and register type properties file - File propfile = new File(dir, "type.properties"); - SystemProperties props = new SystemProperties(propfile.getAbsolutePath()); - DbMapping dbmap = new DbMapping(app, typename, props); - - // we don't need to put the DbMapping into proto.updatables, because - // dbmappings are checked separately in checkFiles for each request - // proto.updatables.put ("type.properties", dbmap); - proto.setDbMapping(dbmap); - - // put the prototype into our map - prototypes.put(typename, proto); - - return proto; - } - - /** - * Update a prototype to the files in the prototype directory. - */ - public void updatePrototype(String name) { - // System.err.println ("UPDATE PROTO: "+app.getName()+"/"+name); - Prototype proto = getPrototype(name); - - updatePrototype(proto); - } - - /** - * Update a prototype to the files in the prototype directory. - */ - public void updatePrototype(Prototype proto) { - if ((proto == null) || proto.isUpToDate()) { - return; - } - - synchronized (proto) { - // check again because another thread may have checked the - // prototype while we were waiting for access to the synchronized section - - /* if (System.currentTimeMillis() - proto.getLastCheck() < 1000) - return; */ - File dir = proto.getDirectory(); - HashSet updateSet = null; - HashSet createSet = null; - - // our plan is to do as little as possible, so first check if - // anything the prototype knows about has changed on disk - for (Iterator i = proto.updatables.values().iterator(); i.hasNext();) { - Updatable upd = (Updatable) i.next(); - - if (upd.needsUpdate()) { - if (updateSet == null) { - updateSet = new HashSet(); - } - - updateSet.add(upd); - } - } - - // next we check if files have been created or removed since last update - // if (proto.getLastCheck() < dir.lastModified ()) { - File[] list = proto.getFiles(); - - for (int i = 0; i < list.length; i++) { - String fn = list[i].getName(); - - // ignore files starting with ".". - if (fn.startsWith(".")) { - continue; - } - - if (!proto.updatables.containsKey(fn)) { - if (fn.endsWith(templateExtension) || fn.endsWith(scriptExtension) || - fn.endsWith(actionExtension) || fn.endsWith(skinExtension) || - "type.properties".equalsIgnoreCase(fn)) { - if (createSet == null) { - createSet = new HashSet(); - } - - createSet.add(list[i]); - } - } - } - - // } - // if nothing needs to be updated, mark prototype as checked and return - if ((updateSet == null) && (createSet == null)) { - proto.markChecked(); - - return; - } - - // first go through new files and create new items - if (createSet != null) { - Object[] newFiles = createSet.toArray(); - - for (int i = 0; i < newFiles.length; i++) { - File file = (File) newFiles[i]; - String filename = file.getName(); - int dot = filename.lastIndexOf("."); - String tmpname = filename.substring(0, dot); - - if (filename.endsWith(templateExtension)) { - try { - Template t = new Template(file, tmpname, proto); - - proto.addTemplate(t); - } catch (Throwable x) { - app.logEvent("Error updating prototype: " + x); - } - } else if (filename.endsWith(scriptExtension)) { - try { - FunctionFile ff = new FunctionFile(file, proto); - - proto.addFunctionFile(ff); - } catch (Throwable x) { - app.logEvent("Error updating prototype: " + x); - } - } else if (filename.endsWith(actionExtension)) { - try { - ActionFile af = new ActionFile(file, tmpname, proto); - - proto.addActionFile(af); - } catch (Throwable x) { - app.logEvent("Error updating prototype: " + x); - } - } else if (filename.endsWith(skinExtension)) { - SkinFile sf = new SkinFile(file, tmpname, proto); - - proto.addSkinFile(sf); - } - } - } - - // next go through existing updatables - if (updateSet != null) { - for (Iterator i = updateSet.iterator(); i.hasNext();) { - Updatable upd = (Updatable) i.next(); - - try { - upd.update(); - } catch (Exception x) { - if (upd instanceof DbMapping) { - app.logEvent("Error updating db mapping for type " + - proto.getName() + ": " + x); - } else { - app.logEvent("Error updating " + upd + " of prototye type " + - proto.getName() + ": " + x); - } - } - } - } - - // mark prototype as checked and updated. - proto.markChecked(); - proto.markUpdated(); - } - // end of synchronized (proto) - } -} diff --git a/src/helma/framework/core/ZippedAppFile.java b/src/helma/framework/core/ZippedAppFile.java deleted file mode 100644 index a312970e..00000000 --- a/src/helma/framework/core/ZippedAppFile.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.core; - -import helma.framework.*; -import helma.objectmodel.db.DbMapping; -import helma.scripting.*; -import helma.util.SystemProperties; -import helma.util.Updatable; -import java.io.*; -import java.util.*; -import java.util.zip.*; - -/** - * This represents a Zip-File which may contain other Updatables for one or more prototypes. - */ -public class ZippedAppFile implements Updatable { - Application app; - File file; - long lastmod; - Set updatables; - - /** - * Creates a new ZippedAppFile object. - * - * @param file ... - * @param app ... - */ - public ZippedAppFile(File file, Application app) { - this.app = app; - this.file = file; - - // System.err.println ("CREATING ZIP FILE "+this); - } - - /** - * Tell the type manager whether we need an update. this is the case when - * the file has been modified or deleted. - */ - public boolean needsUpdate() { - return !file.exists() || (lastmod != file.lastModified()); - } - - /** - * - */ - public void update() { - if (!file.exists()) { - remove(); - } else { - ZipFile zip = null; - - // collect created protos - we need this to check DbMappings for each created - // prototype afterwards - HashSet newPrototypes = new HashSet(); - - try { - lastmod = file.lastModified(); - - // System.err.println ("UPDATING ZIP FILE "+this); - zip = new ZipFile(file); - updatables = new HashSet(); - - for (Enumeration en = zip.entries(); en.hasMoreElements();) { - ZipEntry entry = (ZipEntry) en.nextElement(); - String ename = entry.getName(); - StringTokenizer st = new StringTokenizer(ename, "/"); - - int tokens = st.countTokens(); - if (tokens == 1) { - String fname = st.nextToken(); - - if ("app.properties".equalsIgnoreCase(fname)) { - app.props.addProps(file.getName(), zip.getInputStream(entry)); - } else if ("db.properties".equalsIgnoreCase(fname)) { - app.dbProps.addProps(file.getName(), zip.getInputStream(entry)); - } - - } else if (tokens == 2) { - String dir = st.nextToken(); - String fname = st.nextToken(); - - // System.err.println ("ZIPENTRY: "+ dir +" ~ "+fname); - Prototype proto = app.typemgr.getPrototype(dir); - - if (proto == null) { - proto = app.typemgr.createPrototype(dir); - newPrototypes.add(proto); - } - - if (fname.endsWith(".hac")) { - String name = fname.substring(0, fname.lastIndexOf(".")); - String sourceName = file.getName() + "/" + ename; - String content = getZipEntryContent(zip, entry); - - // System.err.println ("["+content+"]"); - ActionFile act = new ActionFile(content, name, sourceName, - proto); - - proto.addActionFile(act); - updatables.add(act); - - // mark prototype as updated - proto.markUpdated(); - } else if (fname.endsWith(".hsp")) { - String name = fname.substring(0, fname.lastIndexOf(".")); - String sourceName = file.getName() + "/" + ename; - String content = getZipEntryContent(zip, entry); - - // System.err.println ("["+content+"]"); - Template tmp = new Template(content, name, sourceName, proto); - - proto.addTemplate(tmp); - updatables.add(tmp); - - // mark prototype as updated - proto.markUpdated(); - } else if (fname.endsWith(".skin")) { - String name = fname.substring(0, fname.lastIndexOf(".")); - String content = getZipEntryContent(zip, entry); - - // System.err.println ("["+content+"]"); - SkinFile skin = new SkinFile(content, name, proto); - - proto.addSkinFile(skin); - updatables.add(skin); - } else if (fname.endsWith(".js")) { - String sourceName = file.getName() + "/" + ename; - String content = getZipEntryContent(zip, entry); - - // System.err.println ("["+content+"]"); - FunctionFile ff = new FunctionFile(content, sourceName, proto); - - proto.addFunctionFile(ff); - updatables.add(ff); - - // mark prototype as updated - proto.markUpdated(); - } else if ("type.properties".equalsIgnoreCase(fname)) { - DbMapping dbmap = proto.getDbMapping(); - SystemProperties props = dbmap.getProperties(); - - props.addProps(file.getName(), zip.getInputStream(entry)); - - // mark prototype as updated - proto.markUpdated(); - } - } - } - } catch (Throwable x) { - System.err.println("Error updating ZipFile: " + x); - } finally { - try { - zip.close(); - } catch (Exception ignore) { - } - } - } - } - - /** - * - */ - public void remove() { - if (updatables != null) { - for (Iterator it = updatables.iterator(); it.hasNext();) - ((Updatable) it.next()).remove(); - } - - app.typemgr.removeZipFile(file.getName()); - - // System.err.println ("REMOVING ZIP FILE "+this); - } - - /** - * - * - * @param zip ... - * @param entry ... - * - * @return ... - * - * @throws IOException ... - */ - public String getZipEntryContent(ZipFile zip, ZipEntry entry) - throws IOException { - int size = (int) entry.getSize(); - char[] c = new char[size]; - InputStreamReader reader = new InputStreamReader(zip.getInputStream(entry)); - - reader.read(c); - - return new String(c); - } - - /** - * - * - * @return ... - */ - public String toString() { - return file.getName(); - } -} diff --git a/src/helma/framework/demo/SimplePathElement.java b/src/helma/framework/demo/SimplePathElement.java deleted file mode 100644 index 96695810..00000000 --- a/src/helma/framework/demo/SimplePathElement.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.framework.demo; - -import helma.framework.IPathElement; - -/** - * This is an example implementation for the helma.framework.IPathElement interface. - * It creates any child element which is requested on the fly without ever asking. - */ -public class SimplePathElement implements IPathElement { - String name; - String prototype; - IPathElement parent; - - /** - * Constructor for the root element. - */ - public SimplePathElement() { - name = "root"; - prototype = "root"; - parent = null; - } - - /** - * Constructor for non-root elements. - */ - public SimplePathElement(String n, IPathElement p) { - name = n; - prototype = "hopobject"; - parent = p; - } - - /** - * Returns a child element for this object, creating it on the fly. - */ - public IPathElement getChildElement(String n) { - return new SimplePathElement(n, this); - } - - /** - * Returns this object's parent element - */ - public IPathElement getParentElement() { - return parent; - } - - /** - * Returns the element name to be used for this object. - */ - public String getElementName() { - return name; - } - - /** - * Returns the name of the scripting prototype to be used for this object. - * This will be "root" for the root element and "hopobject for everything else. - */ - public String getPrototype() { - return prototype; - } - - /** - * Returns a string representation of this element. - */ - public String toString() { - return "SimplePathElement " + name; - } -} diff --git a/src/helma/image/ImageGenerator.java b/src/helma/image/ImageGenerator.java deleted file mode 100644 index 2ba6b8e2..00000000 --- a/src/helma/image/ImageGenerator.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.image; - -import java.awt.*; -import java.awt.image.*; -import java.net.MalformedURLException; -import java.net.URL; - -/** - * Factory class for generating Image objects from various sources. - * - */ -public class ImageGenerator { - /** - * Creates a new ImageGenerator object. - */ - public ImageGenerator() { - // nothing to do - } - - /** - * - * - * @param w ... - * @param h ... - * - * @return ... - */ - public ImageWrapper createPaintableImage(int w, int h) { - BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics g = img.getGraphics(); - ImageWrapper rimg = new SunImageWrapper(img, g, w, h, this); - - return rimg; - } - - /** - * - * - * @param src ... - * - * @return ... - */ - public ImageWrapper createPaintableImage(byte[] src) { - ImageWrapper rimg = null; - Image img1 = Toolkit.getDefaultToolkit().createImage(src); - ImageLoader loader = new ImageLoader(img1); - - try { - loader.getDimensions(); - - int w = loader.getWidth(); - int h = loader.getHeight(); - Image img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics g = img.getGraphics(); - - g.drawImage(img1, 0, 0, null); - rimg = new SunImageWrapper(img, g, w, h, this); - } finally { - loader.done(); - } - - return rimg; - } - - /** - * - * - * @param src ... - * - * @return ... - */ - public ImageWrapper createImage(byte[] src) { - ImageWrapper rimg = null; - Image img = Toolkit.getDefaultToolkit().createImage(src); - ImageLoader loader = new ImageLoader(img); - - try { - loader.getDimensions(); - - int w = loader.getWidth(); - int h = loader.getHeight(); - - rimg = new SunImageWrapper(img, null, w, h, this); - } finally { - loader.done(); - } - - return rimg; - } - - /** - * - * - * @param urlstring ... - * - * @return ... - * - * @throws MalformedURLException ... - */ - public ImageWrapper createPaintableImage(String urlstring) - throws MalformedURLException { - ImageWrapper rimg = null; - URL url = new URL(urlstring); - Image img1 = Toolkit.getDefaultToolkit().createImage(url); - ImageLoader loader = new ImageLoader(img1); - - try { - loader.getDimensions(); - - int w = loader.getWidth(); - int h = loader.getHeight(); - Image img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics g = img.getGraphics(); - - g.drawImage(img1, 0, 0, null); - rimg = new SunImageWrapper(img, g, w, h, this); - } finally { - loader.done(); - } - - return rimg; - } - - /** - * - * - * @param iw ... - * @param filter ... - * - * @return ... - */ - public ImageWrapper createPaintableImage(ImageWrapper iw, ImageFilter filter) { - ImageWrapper rimg = null; - FilteredImageSource fis = new FilteredImageSource(iw.getSource(), filter); - Image img1 = Toolkit.getDefaultToolkit().createImage(fis); - ImageLoader loader = new ImageLoader(img1); - - try { - loader.getDimensions(); - - int w = loader.getWidth(); - int h = loader.getHeight(); - Image img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics g = img.getGraphics(); - - g.drawImage(img1, 0, 0, null); - rimg = new SunImageWrapper(img, g, w, h, this); - } finally { - loader.done(); - } - - return rimg; - } - - /** - * - * - * @param filename ... - * - * @return ... - */ - public Image createImage(String filename) { - Image img = null; - - img = Toolkit.getDefaultToolkit().createImage(filename); - - ImageLoader loader = new ImageLoader(img); - - loader.getDimensions(); - loader.done(); - - return img; - } - - /** - * - * - * @param producer ... - * - * @return ... - */ - public Image createImage(ImageProducer producer) { - Image img = null; - - img = Toolkit.getDefaultToolkit().createImage(producer); - - ImageLoader loader = new ImageLoader(img); - - loader.getDimensions(); - loader.done(); - - return img; - } - - class ImageLoader implements ImageObserver { - Image img; - int w; - int h; - boolean waiting; - boolean firstFrameLoaded; - - ImageLoader(Image img) { - this.img = img; - waiting = true; - firstFrameLoaded = false; - } - - synchronized void getDimensions() { - w = img.getWidth(this); - h = img.getHeight(this); - - if ((w == -1) || (h == -1)) { - try { - wait(45000); - } catch (InterruptedException x) { - waiting = false; - - return; - } finally { - waiting = false; - } - } - - // if width and height haven't been set, throw tantrum - if ((w == -1) || (h == -1)) { - throw new RuntimeException("Error loading image"); - } - } - - synchronized void done() { - waiting = false; - notifyAll(); - } - - int getWidth() { - return w; - } - - int getHeight() { - return h; - } - - public synchronized boolean imageUpdate(Image img, int infoflags, int x, int y, - int width, int height) { - // check if there was an error - if (!waiting || ((infoflags & ERROR) > 0) || ((infoflags & ABORT) > 0)) { - // we either timed out or there was an error. - notifyAll(); - - return false; - } - - if (((infoflags & WIDTH) > 0) || ((infoflags & HEIGHT) > 0)) { - if ((infoflags & WIDTH) > 0) { - w = width; - } - - if ((infoflags & HEIGHT) > 0) { - h = height; - } - - if ((w > -1) && (h > -1) && firstFrameLoaded) { - notifyAll(); - - return false; - } - } - - if (((infoflags & ALLBITS) > 0) || ((infoflags & FRAMEBITS) > 0)) { - firstFrameLoaded = true; - notifyAll(); - - return false; - } - - return true; - } - } -} diff --git a/src/helma/image/ImageWrapper.java b/src/helma/image/ImageWrapper.java deleted file mode 100644 index f827ce0a..00000000 --- a/src/helma/image/ImageWrapper.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.image; - -import java.awt.*; -import java.awt.image.*; -import java.io.*; -import java.rmi.*; -import java.rmi.server.*; -import java.util.*; - -/** - * Abstract base class for Image Wrappers. - */ -public abstract class ImageWrapper { - Image img; - Graphics g; - int width; - int height; - int fontstyle; - int fontsize; - String fontname; - ImageGenerator imggen; - - /** - * Creates a new ImageWrapper object. - * - * @param img ... - * @param g ... - * @param width ... - * @param height ... - * @param imggen ... - */ - public ImageWrapper(Image img, Graphics g, int width, int height, - ImageGenerator imggen) { - this.img = img; - this.g = g; - this.width = width; - this.height = height; - this.imggen = imggen; - - if (g != null) { - Font f = g.getFont(); - - fontname = f.getName(); - fontstyle = f.getStyle(); - fontsize = f.getSize(); - } - } - - /** - * Return the Graphics object to directly paint to this Image. - * - * @return the Graphics object used by this image - */ - public Graphics getGraphics() { - return g; - } - - /** - * Returns the Image object represented by this ImageWrapper. - * - * @return the image object - */ - public Image getImage() { - return img; - } - - - /** - * Set the font used to write on this image. - */ - public void setFont(String name, int style, int size) { - this.fontname = name; - this.fontstyle = style; - this.fontsize = size; - g.setFont(new Font(name, style, size)); - } - - /** - * Set the color used to write/paint to this image. - * - * @param red ... - * @param green ... - * @param blue ... - */ - public void setColor(int red, int green, int blue) { - g.setColor(new Color(red, green, blue)); - } - - /** - * Set the color used to write/paint to this image. - * - * @param color ... - */ - public void setColor(int color) { - g.setColor(new Color(color)); - } - - /** - * Draw a string to this image at the given coordinates. - * - * @param str ... - * @param x ... - * @param y ... - */ - public void drawString(String str, int x, int y) { - g.drawString(str, x, y); - } - - /** - * Draw a line to this image from x1/y1 to x2/y2. - * - * @param x1 ... - * @param y1 ... - * @param x2 ... - * @param y2 ... - */ - public void drawLine(int x1, int y1, int x2, int y2) { - g.drawLine(x1, y1, x2, y2); - } - - /** - * Draw a rectangle to this image. - * - * @param x ... - * @param y ... - * @param w ... - * @param h ... - */ - public void drawRect(int x, int y, int w, int h) { - g.drawRect(x, y, w, h); - } - - /** - * Draw another image to this image. - * - * @param filename ... - * @param x ... - * @param y ... - */ - public void drawImage(String filename, int x, int y) { - try { - Image i = imggen.createImage(filename); - - g.drawImage(i, x, y, null); - } catch (Exception ignore) { - } - } - - /** - * Draw a filled rectangle to this image. - * - * @param x ... - * @param y ... - * @param w ... - * @param h ... - */ - public void fillRect(int x, int y, int w, int h) { - g.fillRect(x, y, w, h); - } - - /** - * get the width of this image. - * - * @return ... - */ - public int getWidth() { - return width; - } - - /** - * get the height of this image. - * - * @return ... - */ - public int getHeight() { - return height; - } - - /** - * crop this image. - * - * @param x ... - * @param y ... - * @param w ... - * @param h ... - */ - public void crop(int x, int y, int w, int h) { - ImageFilter filter = new CropImageFilter(x, y, w, h); - - img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(img.getSource(), - filter)); - } - - /** - * resize this image - * - * @param w ... - * @param h ... - */ - public void resize(int w, int h) { - img = img.getScaledInstance(w, h, Image.SCALE_SMOOTH); - width = w; - height = h; - } - - /** - * resize this image, using a fast and cheap algorithm - * - * @param w ... - * @param h ... - */ - public void resizeFast(int w, int h) { - img = img.getScaledInstance(w, h, Image.SCALE_FAST); - width = w; - height = h; - } - - /** - * reduce the colors used in this image. Necessary before saving as GIF. - * - * @param colors ... - */ - public abstract void reduceColors(int colors); - - /** - * Save this image. Image format is deduced from filename. - * - * @param filename ... - */ - public abstract void saveAs(String filename); - - /** - * Get ImageProducer of the wrapped image - */ - public ImageProducer getSource() { - return img.getSource(); - } - - /** - * Draw a string to this image, breaking lines when necessary. - * - * @param str ... - */ - public void fillString(String str) { - Filler filler = new Filler(0, 0, width, height); - - filler.layout(str); - } - - /** - * Draw a line to a rectangular section of this image, breaking lines when necessary. - * - * @param str ... - * @param x ... - * @param y ... - * @param w ... - * @param h ... - */ - public void fillString(String str, int x, int y, int w, int h) { - Filler filler = new Filler(x, y, w, h); - - filler.layout(str); - } - - class Filler { - int x; - int y; - int w; - int h; - int addedSpace = 0; - int xLeft; - int yLeft; - int realHeight; - transient Vector lines; - - public Filler(int x, int y, int w, int h) { - this.x = x; - this.y = y; - this.w = w; - this.h = h; - } - - public void layout(String str) { - int size = fontsize; - - lines = new Vector(); - - while (!splitMessage(str, size) && (size > 10)) { - lines.setSize(0); - size = Math.max(2, size - 1); - } - - Font oldfont = g.getFont(); - - g.setFont(new Font(fontname, fontstyle, size)); - - int l = lines.size(); - - for (int i = 0; i < l; i++) { - ((Line) lines.elementAt(i)).paint(g, xLeft / 2, (yLeft / 2) + y); - } - - g.setFont(oldfont); - } - - private boolean splitMessage(String string, int size) { - Font font = new Font(fontname, fontstyle, size); - FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font); - int longestLine = 0; - int heightSoFar = 0; - int heightIncrement = (int) (0.84f * metrics.getHeight()); - StringTokenizer tk = new StringTokenizer(string); - StringBuffer buffer = new StringBuffer(); - int spaceWidth = metrics.stringWidth(" "); - int currentWidth = 0; - int maxWidth = w - 2; - int maxHeight = (h + addedSpace) - 2; - - while (tk.hasMoreTokens()) { - String nextToken = tk.nextToken(); - int nextWidth = metrics.stringWidth(nextToken); - - if ((((currentWidth + nextWidth) >= maxWidth) && (currentWidth != 0))) { - Line line = new Line(buffer.toString(), x, heightSoFar, metrics); - - lines.addElement(line); - - if (line.textwidth > longestLine) { - longestLine = line.textwidth; - } - - buffer = new StringBuffer(); - - currentWidth = 0; - heightSoFar += heightIncrement; - } - - buffer.append(nextToken); - buffer.append(" "); - currentWidth += (nextWidth + spaceWidth); - - if (((1.18 * heightSoFar) > maxHeight) && (fontsize > 10)) { - return false; - } - } - - if (!"".equals(buffer.toString().trim())) { - Line line = new Line(buffer.toString(), x, heightSoFar, metrics); - - lines.addElement(line); - - if (line.textwidth > longestLine) { - longestLine = line.textwidth; - } - - if ((longestLine > maxWidth) && (fontsize > 10)) { - return false; - } - - heightSoFar += heightIncrement; - } - - xLeft = w - longestLine; - yLeft = (addedSpace + h) - heightSoFar; - realHeight = heightSoFar; - - return ((1.18 * heightSoFar) <= maxHeight); - } - } - - class Line implements Serializable { - String text; - int xoff; - int yoff; - FontMetrics fm; - public int textwidth; - public int len; - int ascent; - - public Line(String text, int xoff, int yoff, FontMetrics fm) { - this.text = text.trim(); - len = text.length(); - this.xoff = xoff; - this.yoff = yoff; - this.fm = fm; - textwidth = (len == 0) ? 0 : fm.stringWidth(this.text); - ascent = (int) (0.9f * fm.getAscent()); - } - - public void paint(Graphics g, int xadd, int yadd) { - g.drawString(text, xoff + xadd, yoff + ascent + yadd); - } - - public boolean contains(int y) { - return (y < (yoff + fm.getHeight())) ? true : false; - } - } -} diff --git a/src/helma/image/Quantize.java b/src/helma/image/Quantize.java deleted file mode 100644 index 3666e620..00000000 --- a/src/helma/image/Quantize.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * @(#)Quantize.java 0.90 9/19/00 Adam Doppelt - */ -package helma.image; - -/** - * An efficient color quantization algorithm, adapted from the C++ - * implementation quantize.c in ImageMagick. The pixels for - * an image are placed into an oct tree. The oct tree is reduced in - * size, and the pixels from the original image are reassigned to the - * nodes in the reduced tree.

- * - * Here is the copyright notice from ImageMagick: - * - *

-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%  Permission is hereby granted, free of charge, to any person obtaining a    %
-%  copy of this software and associated documentation files ("ImageMagick"),  %
-%  to deal in ImageMagick without restriction, including without limitation   %
-%  the rights to use, copy, modify, merge, publish, distribute, sublicense,   %
-%  and/or sell copies of ImageMagick, and to permit persons to whom the       %
-%  ImageMagick is furnished to do so, subject to the following conditions:    %
-%                                                                             %
-%  The above copyright notice and this permission notice shall be included in %
-%  all copies or substantial portions of ImageMagick.                         %
-%                                                                             %
-%  The software is provided "as is", without warranty of any kind, express or %
-%  implied, including but not limited to the warranties of merchantability,   %
-%  fitness for a particular purpose and noninfringement.  In no event shall   %
-%  E. I. du Pont de Nemours and Company be liable for any claim, damages or   %
-%  other liability, whether in an action of contract, tort or otherwise,      %
-%  arising from, out of or in connection with ImageMagick or the use or other %
-%  dealings in ImageMagick.                                                   %
-%                                                                             %
-%  Except as contained in this notice, the name of the E. I. du Pont de       %
-%  Nemours and Company shall not be used in advertising or otherwise to       %
-%  promote the sale, use or other dealings in ImageMagick without prior       %
-%  written authorization from the E. I. du Pont de Nemours and Company.       %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- * - * - * @version 0.90 19 Sep 2000 - * @author Adam Doppelt - */ -public class Quantize { - -/* -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% QQQ U U AAA N N TTTTT IIIII ZZZZZ EEEEE % -% Q Q U U A A NN N T I ZZ E % -% Q Q U U AAAAA N N N T I ZZZ EEEEE % -% Q QQ U U A A N NN T I ZZ E % -% QQQQ UUU A A N N T IIIII ZZZZZ EEEEE % -% % -% % -% Reduce the Number of Unique Colors in an Image % -% % -% % -% Software Design % -% John Cristy % -% July 1992 % -% % -% % -% Copyright 1998 E. I. du Pont de Nemours and Company % -% % -% Permission is hereby granted, free of charge, to any person obtaining a % -% copy of this software and associated documentation files ("ImageMagick"), % -% to deal in ImageMagick without restriction, including without limitation % -% the rights to use, copy, modify, merge, publish, distribute, sublicense, % -% and/or sell copies of ImageMagick, and to permit persons to whom the % -% ImageMagick is furnished to do so, subject to the following conditions: % -% % -% The above copyright notice and this permission notice shall be included in % -% all copies or substantial portions of ImageMagick. % -% % -% The software is provided "as is", without warranty of any kind, express or % -% implied, including but not limited to the warranties of merchantability, % -% fitness for a particular purpose and noninfringement. In no event shall % -% E. I. du Pont de Nemours and Company be liable for any claim, damages or % -% other liability, whether in an action of contract, tort or otherwise, % -% arising from, out of or in connection with ImageMagick or the use or other % -% dealings in ImageMagick. % -% % -% Except as contained in this notice, the name of the E. I. du Pont de % -% Nemours and Company shall not be used in advertising or otherwise to % -% promote the sale, use or other dealings in ImageMagick without prior % -% written authorization from the E. I. du Pont de Nemours and Company. % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% Realism in computer graphics typically requires using 24 bits/pixel to -% generate an image. Yet many graphic display devices do not contain -% the amount of memory necessary to match the spatial and color -% resolution of the human eye. The QUANTIZE program takes a 24 bit -% image and reduces the number of colors so it can be displayed on -% raster device with less bits per pixel. In most instances, the -% quantized image closely resembles the original reference image. -% -% A reduction of colors in an image is also desirable for image -% transmission and real-time animation. -% -% Function Quantize takes a standard RGB or monochrome images and quantizes -% them down to some fixed number of colors. -% -% For purposes of color allocation, an image is a set of n pixels, where -% each pixel is a point in RGB space. RGB space is a 3-dimensional -% vector space, and each pixel, pi, is defined by an ordered triple of -% red, green, and blue coordinates, (ri, gi, bi). -% -% Each primary color component (red, green, or blue) represents an -% intensity which varies linearly from 0 to a maximum value, cmax, which -% corresponds to full saturation of that color. Color allocation is -% defined over a domain consisting of the cube in RGB space with -% opposite vertices at (0,0,0) and (cmax,cmax,cmax). QUANTIZE requires -% cmax = 255. -% -% The algorithm maps this domain onto a tree in which each node -% represents a cube within that domain. In the following discussion -% these cubes are defined by the coordinate of two opposite vertices: -% The vertex nearest the origin in RGB space and the vertex farthest -% from the origin. -% -% The tree's root node represents the the entire domain, (0,0,0) through -% (cmax,cmax,cmax). Each lower level in the tree is generated by -% subdividing one node's cube into eight smaller cubes of equal size. -% This corresponds to bisecting the parent cube with planes passing -% through the midpoints of each edge. -% -% The basic algorithm operates in three phases: Classification, -% Reduction, and Assignment. Classification builds a color -% description tree for the image. Reduction collapses the tree until -% the number it represents, at most, the number of colors desired in the -% output image. Assignment defines the output image's color map and -% sets each pixel's color by reclassification in the reduced tree. -% Our goal is to minimize the numerical discrepancies between the original -% colors and quantized colors (quantization error). -% -% Classification begins by initializing a color description tree of -% sufficient depth to represent each possible input color in a leaf. -% However, it is impractical to generate a fully-formed color -% description tree in the classification phase for realistic values of -% cmax. If colors components in the input image are quantized to k-bit -% precision, so that cmax= 2k-1, the tree would need k levels below the -% root node to allow representing each possible input color in a leaf. -% This becomes prohibitive because the tree's total number of nodes is -% 1 + sum(i=1,k,8k). -% -% A complete tree would require 19,173,961 nodes for k = 8, cmax = 255. -% Therefore, to avoid building a fully populated tree, QUANTIZE: (1) -% Initializes data structures for nodes only as they are needed; (2) -% Chooses a maximum depth for the tree as a function of the desired -% number of colors in the output image (currently log2(colormap size)). -% -% For each pixel in the input image, classification scans downward from -% the root of the color description tree. At each level of the tree it -% identifies the single node which represents a cube in RGB space -% containing the pixel's color. It updates the following data for each -% such node: -% -% n1: Number of pixels whose color is contained in the RGB cube -% which this node represents; -% -% n2: Number of pixels whose color is not represented in a node at -% lower depth in the tree; initially, n2 = 0 for all nodes except -% leaves of the tree. -% -% Sr, Sg, Sb: Sums of the red, green, and blue component values for -% all pixels not classified at a lower depth. The combination of -% these sums and n2 will ultimately characterize the mean color of a -% set of pixels represented by this node. -% -% E: The distance squared in RGB space between each pixel contained -% within a node and the nodes' center. This represents the quantization -% error for a node. -% -% Reduction repeatedly prunes the tree until the number of nodes with -% n2 > 0 is less than or equal to the maximum number of colors allowed -% in the output image. On any given iteration over the tree, it selects -% those nodes whose E count is minimal for pruning and merges their -% color statistics upward. It uses a pruning threshold, Ep, to govern -% node selection as follows: -% -% Ep = 0 -% while number of nodes with (n2 > 0) > required maximum number of colors -% prune all nodes such that E <= Ep -% Set Ep to minimum E in remaining nodes -% -% This has the effect of minimizing any quantization error when merging -% two nodes together. -% -% When a node to be pruned has offspring, the pruning procedure invokes -% itself recursively in order to prune the tree from the leaves upward. -% n2, Sr, Sg, and Sb in a node being pruned are always added to the -% corresponding data in that node's parent. This retains the pruned -% node's color characteristics for later averaging. -% -% For each node, n2 pixels exist for which that node represents the -% smallest volume in RGB space containing those pixel's colors. When n2 -% > 0 the node will uniquely define a color in the output image. At the -% beginning of reduction, n2 = 0 for all nodes except a the leaves of -% the tree which represent colors present in the input image. -% -% The other pixel count, n1, indicates the total number of colors -% within the cubic volume which the node represents. This includes n1 - -% n2 pixels whose colors should be defined by nodes at a lower level in -% the tree. -% -% Assignment generates the output image from the pruned tree. The -% output image consists of two parts: (1) A color map, which is an -% array of color descriptions (RGB triples) for each color present in -% the output image; (2) A pixel array, which represents each pixel as -% an index into the color map array. -% -% First, the assignment phase makes one pass over the pruned color -% description tree to establish the image's color map. For each node -% with n2 > 0, it divides Sr, Sg, and Sb by n2 . This produces the -% mean color of all pixels that classify no lower than this node. Each -% of these colors becomes an entry in the color map. -% -% Finally, the assignment phase reclassifies each pixel in the pruned -% tree to identify the deepest node containing the pixel's color. The -% pixel's value in the pixel array becomes the index of this node's mean -% color in the color map. -% -% With the permission of USC Information Sciences Institute, 4676 Admiralty -% Way, Marina del Rey, California 90292, this code was adapted from module -% ALCOLS written by Paul Raveling. -% -% The names of ISI and USC are not used in advertising or publicity -% pertaining to distribution of the software without prior specific -% written permission from ISI. -% -*/ - - final static boolean QUICK = true; - - final static int MAX_RGB = 255; - final static int MAX_NODES = 266817; - final static int MAX_TREE_DEPTH = 8; - - // these are precomputed in advance - static int SQUARES[]; - static int SHIFT[]; - - static { - SQUARES = new int[MAX_RGB + MAX_RGB + 1]; - for (int i= -MAX_RGB; i <= MAX_RGB; i++) { - SQUARES[i + MAX_RGB] = i * i; - } - - SHIFT = new int[MAX_TREE_DEPTH + 1]; - for (int i = 0; i < MAX_TREE_DEPTH + 1; ++i) { - SHIFT[i] = 1 << (15 - i); - } - } - - /** - * Reduce the image to the given number of colors. The pixels are - * reduced in place. - * @return The new color palette. - */ - public static int[] quantizeImage(int pixels[][], int max_colors) { - Cube cube = new Cube(pixels, max_colors); - cube.classification(); - cube.reduction(); - cube.assignment(); - return cube.colormap; - } - - static class Cube { - int pixels[][]; - int max_colors; - int colormap[]; - - Node root; - int depth; - - // counter for the number of colors in the cube. this gets - // recalculated often. - int colors; - - // counter for the number of nodes in the tree - int nodes; - - Cube(int pixels[][], int max_colors) { - this.pixels = pixels; - this.max_colors = max_colors; - - int i = max_colors; - // tree_depth = log max_colors - // 4 - for (depth = 1; i != 0; depth++) { - i /= 4; - } - if (depth > 1) { - --depth; - } - if (depth > MAX_TREE_DEPTH) { - depth = MAX_TREE_DEPTH; - } else if (depth < 2) { - depth = 2; - } - - root = new Node(this); - } - - /* - * Procedure Classification begins by initializing a color - * description tree of sufficient depth to represent each - * possible input color in a leaf. However, it is impractical - * to generate a fully-formed color description tree in the - * classification phase for realistic values of cmax. If - * colors components in the input image are quantized to k-bit - * precision, so that cmax= 2k-1, the tree would need k levels - * below the root node to allow representing each possible - * input color in a leaf. This becomes prohibitive because the - * tree's total number of nodes is 1 + sum(i=1,k,8k). - * - * A complete tree would require 19,173,961 nodes for k = 8, - * cmax = 255. Therefore, to avoid building a fully populated - * tree, QUANTIZE: (1) Initializes data structures for nodes - * only as they are needed; (2) Chooses a maximum depth for - * the tree as a function of the desired number of colors in - * the output image (currently log2(colormap size)). - * - * For each pixel in the input image, classification scans - * downward from the root of the color description tree. At - * each level of the tree it identifies the single node which - * represents a cube in RGB space containing It updates the - * following data for each such node: - * - * number_pixels : Number of pixels whose color is contained - * in the RGB cube which this node represents; - * - * unique : Number of pixels whose color is not represented - * in a node at lower depth in the tree; initially, n2 = 0 - * for all nodes except leaves of the tree. - * - * total_red/green/blue : Sums of the red, green, and blue - * component values for all pixels not classified at a lower - * depth. The combination of these sums and n2 will - * ultimately characterize the mean color of a set of pixels - * represented by this node. - */ - void classification() { - int pixels[][] = this.pixels; - - int width = pixels.length; - int height = pixels[0].length; - - // convert to indexed color - for (int x = width; x-- > 0; ) { - for (int y = height; y-- > 0; ) { - int pixel = pixels[x][y]; - int red = (pixel >> 16) & 0xFF; - int green = (pixel >> 8) & 0xFF; - int blue = (pixel >> 0) & 0xFF; - - // a hard limit on the number of nodes in the tree - if (nodes > MAX_NODES) { - System.out.println("pruning"); - root.pruneLevel(); - --depth; - } - - // walk the tree to depth, increasing the - // number_pixels count for each node - Node node = root; - for (int level = 1; level <= depth; ++level) { - int id = (((red > node.mid_red ? 1 : 0) << 0) | - ((green > node.mid_green ? 1 : 0) << 1) | - ((blue > node.mid_blue ? 1 : 0) << 2)); - if (node.child[id] == null) { - new Node(node, id, level); - } - node = node.child[id]; - node.number_pixels += SHIFT[level]; - } - - ++node.unique; - node.total_red += red; - node.total_green += green; - node.total_blue += blue; - } - } - } - - /* - * reduction repeatedly prunes the tree until the number of - * nodes with unique > 0 is less than or equal to the maximum - * number of colors allowed in the output image. - * - * When a node to be pruned has offspring, the pruning - * procedure invokes itself recursively in order to prune the - * tree from the leaves upward. The statistics of the node - * being pruned are always added to the corresponding data in - * that node's parent. This retains the pruned node's color - * characteristics for later averaging. - */ - void reduction() { - int threshold = 1; - while (colors > max_colors) { - colors = 0; - threshold = root.reduce(threshold, Integer.MAX_VALUE); - } - } - - /** - * The result of a closest color search. - */ - static class Search { - int distance; - int color_number; - } - - /* - * Procedure assignment generates the output image from the - * pruned tree. The output image consists of two parts: (1) A - * color map, which is an array of color descriptions (RGB - * triples) for each color present in the output image; (2) A - * pixel array, which represents each pixel as an index into - * the color map array. - * - * First, the assignment phase makes one pass over the pruned - * color description tree to establish the image's color map. - * For each node with n2 > 0, it divides Sr, Sg, and Sb by n2. - * This produces the mean color of all pixels that classify no - * lower than this node. Each of these colors becomes an entry - * in the color map. - * - * Finally, the assignment phase reclassifies each pixel in - * the pruned tree to identify the deepest node containing the - * pixel's color. The pixel's value in the pixel array becomes - * the index of this node's mean color in the color map. - */ - void assignment() { - colormap = new int[colors]; - - colors = 0; - root.colormap(); - - int pixels[][] = this.pixels; - - int width = pixels.length; - int height = pixels[0].length; - - Search search = new Search(); - - // convert to indexed color - for (int x = width; x-- > 0; ) { - for (int y = height; y-- > 0; ) { - int pixel = pixels[x][y]; - int red = (pixel >> 16) & 0xFF; - int green = (pixel >> 8) & 0xFF; - int blue = (pixel >> 0) & 0xFF; - - // walk the tree to find the cube containing that color - Node node = root; - for ( ; ; ) { - int id = (((red > node.mid_red ? 1 : 0) << 0) | - ((green > node.mid_green ? 1 : 0) << 1) | - ((blue > node.mid_blue ? 1 : 0) << 2) ); - if (node.child[id] == null) { - break; - } - node = node.child[id]; - } - - if (QUICK) { - // if QUICK is set, just use that - // node. Strictly speaking, this isn't - // necessarily best match. - pixels[x][y] = node.color_number; - } else { - // Find the closest color. - search.distance = Integer.MAX_VALUE; - node.parent.closestColor(red, green, blue, search); - pixels[x][y] = search.color_number; - } - } - } - } - - /** - * A single Node in the tree. - */ - static class Node { - Cube cube; - - // parent node - Node parent; - - // child nodes - Node child[]; - int nchild; - - // our index within our parent - int id; - // our level within the tree - int level; - // our color midpoint - int mid_red; - int mid_green; - int mid_blue; - - // the pixel count for this node and all children - int number_pixels; - - // the pixel count for this node - int unique; - // the sum of all pixels contained in this node - int total_red; - int total_green; - int total_blue; - - // used to build the colormap - int color_number; - - Node(Cube cube) { - this.cube = cube; - this.parent = this; - this.child = new Node[8]; - this.id = 0; - this.level = 0; - - this.number_pixels = Integer.MAX_VALUE; - - this.mid_red = (MAX_RGB + 1) >> 1; - this.mid_green = (MAX_RGB + 1) >> 1; - this.mid_blue = (MAX_RGB + 1) >> 1; - } - - Node(Node parent, int id, int level) { - this.cube = parent.cube; - this.parent = parent; - this.child = new Node[8]; - this.id = id; - this.level = level; - - // add to the cube - ++cube.nodes; - if (level == cube.depth) { - ++cube.colors; - } - - // add to the parent - ++parent.nchild; - parent.child[id] = this; - - // figure out our midpoint - int bi = (1 << (MAX_TREE_DEPTH - level)) >> 1; - mid_red = parent.mid_red + ((id & 1) > 0 ? bi : -bi); - mid_green = parent.mid_green + ((id & 2) > 0 ? bi : -bi); - mid_blue = parent.mid_blue + ((id & 4) > 0 ? bi : -bi); - } - - /** - * Remove this child node, and make sure our parent - * absorbs our pixel statistics. - */ - void pruneChild() { - --parent.nchild; - parent.unique += unique; - parent.total_red += total_red; - parent.total_green += total_green; - parent.total_blue += total_blue; - parent.child[id] = null; - --cube.nodes; - cube = null; - parent = null; - } - - /** - * Prune the lowest layer of the tree. - */ - void pruneLevel() { - if (nchild != 0) { - for (int id = 0; id < 8; id++) { - if (child[id] != null) { - child[id].pruneLevel(); - } - } - } - if (level == cube.depth) { - pruneChild(); - } - } - - /** - * Remove any nodes that have fewer than threshold - * pixels. Also, as long as we're walking the tree: - * - * - figure out the color with the fewest pixels - * - recalculate the total number of colors in the tree - */ - int reduce(int threshold, int next_threshold) { - if (nchild != 0) { - for (int id = 0; id < 8; id++) { - if (child[id] != null) { - next_threshold = child[id].reduce(threshold, next_threshold); - } - } - } - if (number_pixels <= threshold) { - pruneChild(); - } else { - if (unique != 0) { - cube.colors++; - } - if (number_pixels < next_threshold) { - next_threshold = number_pixels; - } - } - return next_threshold; - } - - /* - * colormap traverses the color cube tree and notes each - * colormap entry. A colormap entry is any node in the - * color cube tree where the number of unique colors is - * not zero. - */ - void colormap() { - if (nchild != 0) { - for (int id = 0; id < 8; id++) { - if (child[id] != null) { - child[id].colormap(); - } - } - } - if (unique != 0) { - int r = ((total_red + (unique >> 1)) / unique); - int g = ((total_green + (unique >> 1)) / unique); - int b = ((total_blue + (unique >> 1)) / unique); - cube.colormap[cube.colors] = ((( 0xFF) << 24) | - ((r & 0xFF) << 16) | - ((g & 0xFF) << 8) | - ((b & 0xFF) << 0)); - color_number = cube.colors++; - } - } - - /* ClosestColor traverses the color cube tree at a - * particular node and determines which colormap entry - * best represents the input color. - */ - void closestColor(int red, int green, int blue, Search search) { - if (nchild != 0) { - for (int id = 0; id < 8; id++) { - if (child[id] != null) { - child[id].closestColor(red, green, blue, search); - } - } - } - - if (unique != 0) { - int color = cube.colormap[color_number]; - int distance = distance(color, red, green, blue); - if (distance < search.distance) { - search.distance = distance; - search.color_number = color_number; - } - } - } - - /** - * Figure out the distance between this node and som color. - */ - final static int distance(int color, int r, int g, int b) { - return (SQUARES[((color >> 16) & 0xFF) - r + MAX_RGB] + - SQUARES[((color >> 8) & 0xFF) - g + MAX_RGB] + - SQUARES[((color >> 0) & 0xFF) - b + MAX_RGB]); - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - if (parent == this) { - buf.append("root"); - } else { - buf.append("node"); - } - buf.append(' '); - buf.append(level); - buf.append(" ["); - buf.append(mid_red); - buf.append(','); - buf.append(mid_green); - buf.append(','); - buf.append(mid_blue); - buf.append(']'); - return new String(buf); - } - } - } -} diff --git a/src/helma/image/SunImageWrapper.java b/src/helma/image/SunImageWrapper.java deleted file mode 100644 index b1e0dd5c..00000000 --- a/src/helma/image/SunImageWrapper.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.image; - -import Acme.JPM.Encoders.GifEncoder; -import com.sun.jimi.core.*; -import com.sun.jimi.core.util.*; -import java.awt.*; -import java.awt.image.*; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * A wrapper for an image that uses the Sun version of JIMI available at - * http://java.sun.com/products/jimi. - */ -public class SunImageWrapper extends ImageWrapper { - /** - * Creates a new SunImageWrapper object. - * - * @param img ... - * @param g ... - * @param width ... - * @param height ... - * @param imggen ... - */ - public SunImageWrapper(Image img, Graphics g, int width, int height, - ImageGenerator imggen) { - super(img, g, width, height, imggen); - } - - /** - * Reduce the colors used in this image. Useful and necessary before saving - * the image as GIF file. - * - * @param colors the number of colors to use, usually <= 256. - */ - public void reduceColors(int colors) { - try { - // first, try to use JIMI's ColorReducer class. It is able to - // preserve transparency on GIF files, but does throw exceptions on some GIFs. - img = new ColorReducer(colors, false).getColorReducedImage(img); - } catch (Exception excpt) { - // JIMI sometimes fails to reduce colors, throwing an exception. - // Use our alternative Quantizer in this case. - System.err.println("Using alternative color reducer ("+excpt+")"); - try { - int[][] pixels = getPixels(); - int[] palette = Quantize.quantizeImage(pixels, colors); - int w = pixels.length; - int h = pixels[0].length; - int[] pix = new int[w * h]; - - // convert to RGB - for (int x = w; x-- > 0;) { - for (int y = h; y-- > 0;) { - pix[(y * w) + x] = palette[pixels[x][y]]; - } - } - - img = imggen.createImage(new MemoryImageSource(w, h, pix, 0, w)); - } catch (IOException ioxcpt) { - System.err.println("Error in reduceColors(): "+ioxcpt); - } - } - } - - /** - * Snag the pixels from an image. - */ - int[][] getPixels() throws IOException { - int[] pix = new int[width * height]; - PixelGrabber grabber = new PixelGrabber(img, 0, 0, width, height, pix, 0, width); - - try { - if (grabber.grabPixels() != true) { - throw new IOException("Grabber returned false: " + grabber.status()); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - - int[][] pixels = new int[width][height]; - - for (int x = width; x-- > 0;) { - for (int y = height; y-- > 0;) { - pixels[x][y] = pix[(y * width) + x]; - } - } - - return pixels; - } - - /** - * - * - * @param filename ... - */ - public void saveAs(String filename) { - try { - if (filename.toLowerCase().endsWith(".gif")) { - // sun's jimi package doesn't encode gifs, use Acme encoder - FileOutputStream fout = new FileOutputStream(filename); - - // Acme gif encoder - GifEncoder enc = new GifEncoder(img, fout); - - enc.encode(); - fout.close(); - } else { - Jimi.putImage(img, filename); - } - } catch (Exception x) { - throw new RuntimeException(x.getMessage()); - } - } -} diff --git a/src/helma/main/ApplicationManager.java b/src/helma/main/ApplicationManager.java deleted file mode 100644 index d8fd62a0..00000000 --- a/src/helma/main/ApplicationManager.java +++ /dev/null @@ -1,469 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main; - -import helma.framework.*; -import helma.framework.core.*; -import helma.objectmodel.*; -import helma.servlet.*; -import helma.util.SystemProperties; -import helma.util.StringUtils; -import org.apache.xmlrpc.XmlRpcHandler; -import org.mortbay.http.*; -import org.mortbay.http.handler.*; -import org.mortbay.jetty.servlet.*; -import org.mortbay.util.*; -import java.io.*; -import java.lang.reflect.*; -import java.rmi.*; -import java.rmi.server.*; -import java.util.*; -import javax.servlet.Servlet; - -/** - * This class is responsible for starting and stopping Helma applications. - */ -public class ApplicationManager implements XmlRpcHandler { - private Hashtable descriptors; - private Hashtable applications; - private Hashtable xmlrpcHandlers; - private int port; - private File hopHome; - private SystemProperties props; - private Server server; - private long lastModified; - - /** - * Creates a new ApplicationManager object. - * - * @param hopHome The Helma home directory - * @param props the properties defining the running apps - * @param server the server instance - * @param port The RMI port we're binding to - */ - public ApplicationManager(File hopHome, SystemProperties props, - Server server, int port) { - this.hopHome = hopHome; - this.props = props; - this.server = server; - this.port = port; - descriptors = new Hashtable(); - applications = new Hashtable(); - xmlrpcHandlers = new Hashtable(); - lastModified = 0; - } - - /** - * Called regularely check applications property file - * to create and start new applications. - */ - protected void checkForChanges() { - if (props.lastModified() > lastModified) { - try { - for (Enumeration e = props.keys(); e.hasMoreElements();) { - String appName = (String) e.nextElement(); - - if ((appName.indexOf(".") == -1) && - (applications.get(appName) == null)) { - AppDescriptor appDesc = new AppDescriptor(appName); - appDesc.start(); - appDesc.bind(); - } - } - - // then stop deleted ones - for (Enumeration e = descriptors.elements(); e.hasMoreElements();) { - AppDescriptor appDesc = (AppDescriptor) e.nextElement(); - - // check if application has been removed and should be stopped - if (!props.containsKey(appDesc.appName)) { - appDesc.stop(); - } else if (server.http != null) { - // If application continues to run, remount - // as the mounting options may have changed. - appDesc.unbind(); - AppDescriptor ndesc = new AppDescriptor(appDesc.appName); - ndesc.app = appDesc.app; - ndesc.bind(); - descriptors.put(ndesc.appName, ndesc); - - } - } - } catch (Exception mx) { - Server.getLogger().log("Error checking applications: " + mx); - } - - lastModified = System.currentTimeMillis(); - } - } - - - /** - * Start an application by name - */ - public void start(String appName) { - AppDescriptor desc = new AppDescriptor(appName); - desc.start(); - } - - /** - * Bind an application by name - */ - public void register(String appName) { - AppDescriptor desc = (AppDescriptor) descriptors.get(appName); - if (desc != null) { - desc.bind(); - } - } - - /** - * Stop an application by name - */ - public void stop(String appName) { - AppDescriptor desc = (AppDescriptor) descriptors.get(appName); - if (desc != null) { - desc.stop(); - } - } - - - /** - * Start all applications listed in the properties - */ - public void startAll() { - try { - for (Enumeration e = props.keys(); e.hasMoreElements();) { - String appName = (String) e.nextElement(); - - if (appName.indexOf(".") == -1) { - String appValue = props.getProperty(appName); - - if (appValue != null && appValue.length() > 0) { - appName = appValue; - } - - AppDescriptor desc = new AppDescriptor(appName); - desc.start(); - } - } - - for (Enumeration e = descriptors.elements(); e.hasMoreElements();) { - AppDescriptor appDesc = (AppDescriptor) e.nextElement(); - appDesc.bind(); - } - - lastModified = System.currentTimeMillis(); - } catch (Exception mx) { - Server.getLogger().log("Error starting applications: " + mx); - mx.printStackTrace(); - } - } - - /** - * Stop all running applications. - */ - public void stopAll() { - for (Enumeration en = descriptors.elements(); en.hasMoreElements();) { - AppDescriptor appDesc = (AppDescriptor) en.nextElement(); - - appDesc.stop(); - } - } - - /** - * Get an array containing all currently running applications. - */ - public Object[] getApplications() { - return applications.values().toArray(); - } - - /** - * Get an application by name. - */ - public Application getApplication(String name) { - return (Application) applications.get(name); - } - - /** - * Implements org.apache.xmlrpc.XmlRpcHandler.execute() - */ - public Object execute(String method, Vector params) - throws Exception { - int dot = method.indexOf("."); - - if (dot == -1) { - throw new Exception("Method name \"" + method + - "\" does not specify a handler application"); - } - - if ((dot == 0) || (dot == (method.length() - 1))) { - throw new Exception("\"" + method + "\" is not a valid XML-RPC method name"); - } - - String handler = method.substring(0, dot); - String method2 = method.substring(dot + 1); - Application app = (Application) xmlrpcHandlers.get(handler); - - if (app == null) { - app = (Application) xmlrpcHandlers.get("*"); - // use the original method name, the handler is resolved within the app. - method2 = method; - } - - if (app == null) { - throw new Exception("Handler \"" + handler + "\" not found for " + method); - } - - return app.executeXmlRpc(method2, params); - } - - private String getMountpoint(String mountpoint) { - mountpoint = mountpoint.trim(); - - if ("".equals(mountpoint)) { - return "/"; - } else if (!mountpoint.startsWith("/")) { - return "/" + mountpoint; - } - - return mountpoint; - } - - private String joinMountpoint(String prefix, String suffix) { - if (prefix.endsWith("/") || suffix.startsWith("/")) { - return prefix+suffix; - } else { - return prefix+"/"+suffix; - } - } - - private String getPathPattern(String mountpoint) { - if (!mountpoint.startsWith("/")) { - mountpoint = "/"+mountpoint; - } - - if ("/".equals(mountpoint)) { - return "/"; - } - - if (mountpoint.endsWith("/")) { - return mountpoint + "*"; - } - - return mountpoint + "/*"; - } - - /** - * Inner class that describes an application and its start settings. - */ - class AppDescriptor { - - Application app; - - String appName; - File appDir; - File dbDir; - String mountpoint; - String pathPattern; - String staticDir; - String staticMountpoint; - String xmlrpcHandlerName; - String cookieDomain; - String uploadLimit; - String debug; - String charset; - boolean encode; - - /** - * Creates an AppDescriptor from the properties. - */ - AppDescriptor(String name) { - appName = name; - mountpoint = getMountpoint(props.getProperty(name+".mountpoint", - appName)); - pathPattern = getPathPattern(mountpoint); - staticDir = props.getProperty(name+".static"); - staticMountpoint = getPathPattern(props.getProperty(name+".staticMountpoint", - joinMountpoint(mountpoint, "static"))); - cookieDomain = props.getProperty(name+".cookieDomain"); - uploadLimit = props.getProperty(name+".uploadLimit"); - debug = props.getProperty(name+".debug"); - encode = "true".equalsIgnoreCase(props.getProperty(name + - ".responseEncoding")); - String appDirName = props.getProperty(name + ".appdir"); - appDir = (appDirName == null) ? null : new File(appDirName); - String dbDirName = props.getProperty(name + ".dbdir"); - dbDir = (dbDirName == null) ? null : new File(dbDirName); - } - - - void start() { - Server.getLogger().log("Building application " + appName); - - try { - // create the application instance - app = new Application(appName, server, appDir, dbDir); - - // register ourselves - descriptors.put(appName, this); - applications.put(appName, app); - - // the application is started later in the register method, when it's bound - app.init(); - app.start(); - } catch (Exception x) { - Server.getLogger().log("Error creating application " + appName + ": " + x); - x.printStackTrace(); - } - } - - void stop() { - Server.getLogger().log("Stopping application " + appName); - - // unbind application - unbind(); - - // stop application - try { - app.stop(); - Server.getLogger().log("Stopped application " + appName); - } catch (Exception x) { - Server.getLogger().log("Couldn't stop app: " + x); - } - - descriptors.remove(appName); - applications.remove(appName); - } - - void bind() { - try { - Server.getLogger().log("Binding application " + appName); - - // bind to RMI server - if (port > 0) { - Naming.rebind("//:" + port + "/" + appName, new RemoteApplication(app)); - } - - // bind to Jetty HTTP server - if (server.http != null) { - // if using embedded webserver (not AJP) set application URL prefix - if (!app.hasExplicitBaseURI()) { - app.setBaseURI(mountpoint); - } - - ServletHttpContext context = new ServletHttpContext(); - - context.setContextPath(pathPattern); - server.http.addContext(context); - - if (encode) { - context.addHandler(new ContentEncodingHandler()); - } - - ServletHolder holder = context.addServlet(appName, "/*", - "helma.servlet.EmbeddedServletClient"); - - holder.setInitParameter("application", appName); - // holder.setInitParameter("mountpoint", mountpoint); - - if (cookieDomain != null) { - holder.setInitParameter("cookieDomain", cookieDomain); - } - - if (uploadLimit != null) { - holder.setInitParameter("uploadLimit", uploadLimit); - } - - if (debug != null) { - holder.setInitParameter("debug", debug); - } - - holder.setInitParameter("charset", app.getCharset()); - - context.start(); - - if (staticDir != null) { - - File staticContent = new File(staticDir); - if (!staticContent.isAbsolute()) { - staticContent = new File(server.getHopHome(), staticDir); - } - - Server.getLogger().log("Serving static from " + - staticContent.getAbsolutePath()); - Server.getLogger().log("Mounting static at " + - staticMountpoint); - - HttpContext cx = server.http.addContext(staticMountpoint); - - cx.setResourceBase(staticContent.getAbsolutePath()); - - ResourceHandler handler = new ResourceHandler(); - - cx.addHandler(handler); - cx.start(); - } - } - - // register as XML-RPC handler - xmlrpcHandlerName = app.getXmlRpcHandlerName(); - xmlrpcHandlers.put(xmlrpcHandlerName, app); - // app.start(); - } catch (Exception x) { - Server.getLogger().log("Couldn't bind app: " + x); - x.printStackTrace(); - } - } - - void unbind() { - Server.getLogger().log("Unbinding application " + appName); - - try { - // unbind from RMI server - if (port > 0) { - Naming.unbind("//:" + port + "/" + appName); - } - - // unbind from Jetty HTTP server - if (server.http != null) { - HttpContext context = server.http.getContext(null, pathPattern); - - if (context != null) { - context.stop(); - context.destroy(); - } - - if (staticDir != null) { - context = server.http.getContext(null, staticMountpoint); - - if (context != null) { - context.stop(); - context.destroy(); - } - } - } - - // unregister as XML-RPC handler - xmlrpcHandlers.remove(xmlrpcHandlerName); - } catch (Exception x) { - Server.getLogger().log("Couldn't unbind app: " + x); - } - - } - - } -} diff --git a/src/helma/main/HelmaSecurityManager.java b/src/helma/main/HelmaSecurityManager.java deleted file mode 100644 index 31a32c6e..00000000 --- a/src/helma/main/HelmaSecurityManager.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main; - -import helma.framework.core.AppClassLoader; -import java.io.FileDescriptor; -import java.net.InetAddress; -import java.security.Permission; -import java.util.HashSet; - -/** - * Liberal security manager for Helma system that makes sure application code - * is not allowed to exit the VM and set a security manager. - * - * This class can be subclassed to implement actual security policies. It contains - * a utility method getApplication that can be used to determine - * the name of the application trying to execute the action in question, if any. - */ -public class HelmaSecurityManager extends SecurityManager { - // The set of actions forbidden to application code. - // We are pretty permissive, forbidding only System.exit() - // and setting the security manager. - private final static HashSet forbidden = new HashSet(); - - static { - forbidden.add("exitVM"); - forbidden.add("setSecurityManager"); - } - - /** - * - * - * @param p ... - */ - public void checkPermission(Permission p) { - if (p instanceof RuntimePermission) { - if (forbidden.contains(p.getName())) { - Class[] classes = getClassContext(); - - for (int i = 0; i < classes.length; i++) { - if (classes[i].getClassLoader() instanceof AppClassLoader) { - throw new SecurityException(p.getName() + - " not allowed for application code"); - } - } - } - } - } - - /** - * - * - * @param p ... - * @param context ... - */ - public void checkPermission(Permission p, Object context) { - } - - /** - * - */ - public void checkCreateClassLoader() { - } - - /** - * - * - * @param thread ... - */ - public void checkAccess(Thread thread) { - } - - /** - * - * - * @param group ... - */ - public void checkAccess(ThreadGroup group) { - } - - /** - * - * - * @param status ... - */ - public void checkExit(int status) { - Class[] classes = getClassContext(); - - for (int i = 0; i < classes.length; i++) { - if (classes[i].getClassLoader() instanceof AppClassLoader) { - throw new SecurityException("operation not allowed for application code"); - } - } - } - - /** - * - * - * @param cmd ... - */ - public void checkExec(String cmd) { - } - - /** - * - * - * @param lib ... - */ - public void checkLink(String lib) { - } - - /** - * - * - * @param fdesc ... - */ - public void checkRead(FileDescriptor fdesc) { - } - - /** - * - * - * @param file ... - */ - public void checkRead(String file) { - } - - /** - * - * - * @param file ... - * @param context ... - */ - public void checkRead(String file, Object context) { - } - - /** - * - * - * @param fdesc ... - */ - public void checkWrite(FileDescriptor fdesc) { - } - - /** - * - * - * @param file ... - */ - public void checkWrite(String file) { - } - - /** - * - * - * @param file ... - */ - public void checkDelete(String file) { - } - - /** - * - * - * @param host ... - * @param port ... - */ - public void checkConnect(String host, int port) { - } - - /** - * - * - * @param host ... - * @param port ... - * @param context ... - */ - public void checkConnect(String host, int port, Object context) { - } - - /** - * - * - * @param port ... - */ - public void checkListen(int port) { - } - - /** - * - * - * @param host ... - * @param port ... - */ - public void checkAccept(String host, int port) { - } - - /** - * - * - * @param addr ... - */ - public void checkMulticast(InetAddress addr) { - } - - /** - * - * - * @param addr ... - * @param ttl ... - */ - public void checkMulticast(InetAddress addr, byte ttl) { - } - - /** - * - */ - public void checkPropertiesAccess() { - } - - /** - * - * - * @param key ... - */ - public void checkPropertyAccess(String key) { - } - - /** - * - * - * @param window ... - * - * @return ... - */ - public boolean checkTopLevelWindow(Object window) { - return true; - } - - /** - * - */ - public void checkPrintJobAccess() { - } - - /** - * - */ - public void checkSystemClipboardAccess() { - } - - /** - * - */ - public void checkAwtEventQueueAccess() { - } - - /** - * - * - * @param pkg ... - */ - public void checkPackageAccess(String pkg) { - } - - /** - * - * - * @param pkg ... - */ - public void checkPackageDefinition(String pkg) { - } - - /** - * - */ - public void checkSetFactory() { - } - - /** - * - * - * @param clazz ... - * @param which ... - */ - public void checkMemberAccess(Class clazz, int which) { - } - - /** - * - * - * @param target ... - */ - public void checkSecurityAccess(String target) { - } - - /** - * Utility method that returns the name of the application trying - * to execute the code in question. Returns null if the current code - * does not belong to any application. - */ - protected String getApplication() { - Class[] classes = getClassContext(); - - for (int i = 0; i < classes.length; i++) { - if (classes[i].getClassLoader() instanceof AppClassLoader) { - return ((AppClassLoader) classes[i].getClassLoader()).getAppName(); - } - } - - // no application class loader found in stack - return null - return null; - } -} diff --git a/src/helma/main/HelmaShutdownHook.java b/src/helma/main/HelmaShutdownHook.java deleted file mode 100644 index 7a55365d..00000000 --- a/src/helma/main/HelmaShutdownHook.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main; - -import helma.util.Logger; -import java.util.List; - -/** - * ShutdownHook that shuts down all running Helma applications on exit. - */ -public class HelmaShutdownHook extends Thread { - ApplicationManager appmgr; - - /** - * Creates a new HelmaShutdownHook object. - * - * @param appmgr ... - */ - public HelmaShutdownHook(ApplicationManager appmgr) { - this.appmgr = appmgr; - } - - /** - * - */ - public void run() { - System.err.println("Shutting down Helma - please stand by"); - - Logger logger = Server.getLogger(); - - if (logger != null) { - logger.log("Shutting down Helma"); - } - - appmgr.stopAll(); - - List loggers = Logger.getLoggers(); - int l = loggers.size(); - - for (int i = 0; i < l; i++) - ((Logger) loggers.get(i)).close(); - - Logger.wakeup(); - } -} diff --git a/src/helma/main/HelmaSocketFactory.java b/src/helma/main/HelmaSocketFactory.java deleted file mode 100644 index 7968d61a..00000000 --- a/src/helma/main/HelmaSocketFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main; - -import helma.util.*; -import java.io.IOException; -import java.net.*; -import java.rmi.server.*; - -/** - * An RMI socket factory that has a "paranoid" option to filter clients. - * We only do direct connections, no HTTP proxy stuff, since this is - * server-to-server. - */ -public class HelmaSocketFactory extends RMISocketFactory { - private InetAddressFilter filter; - - /** - * Creates a new HelmaSocketFactory object. - */ - public HelmaSocketFactory() { - filter = new InetAddressFilter(); - } - - /** - * - * - * @param address ... - */ - public void addAddress(String address) { - try { - filter.addAddress(address); - } catch (IOException x) { - Server.getLogger().log("Could not add " + address + - " to Socket Filter: invalid address."); - } - } - - /** - * - * - * @param host ... - * @param port ... - * - * @return ... - * - * @throws IOException ... - */ - public Socket createSocket(String host, int port) throws IOException { - return new Socket(host, port); - } - - /** - * - * - * @param port ... - * - * @return ... - * - * @throws IOException ... - */ - public ServerSocket createServerSocket(int port) throws IOException { - return new ParanoidServerSocket(port, filter); - } -} diff --git a/src/helma/main/Server.java b/src/helma/main/Server.java deleted file mode 100644 index e8757eb3..00000000 --- a/src/helma/main/Server.java +++ /dev/null @@ -1,755 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main; - -import helma.extensions.HelmaExtension; -import helma.framework.*; -import helma.framework.core.*; -import helma.objectmodel.db.DbSource; -import helma.util.*; -import org.apache.xmlrpc.*; -import org.mortbay.http.*; -import org.mortbay.http.ajp.*; -import org.mortbay.util.*; -import java.io.*; -import java.net.*; -import java.rmi.*; -import java.rmi.registry.*; -import java.rmi.server.*; -import java.util.*; - -/** - * Helma server main class. - */ -public class Server implements IPathElement, Runnable { - public static final String version = "1.3.0 alpha (2003/06/26)"; - - // server-wide properties - static SystemProperties appsProps; - static SystemProperties dbProps; - static SystemProperties sysProps; - - // static server instance - private static Server server; - protected static File hopHome = null; - - // our logger - private static Logger logger; - public final long starttime; - - // if true we only accept RMI and XML-RPC connections from - // explicitly listed hosts. - public boolean paranoid; - private ApplicationManager appManager; - private Vector extensions; - private Thread mainThread; - - // server ports - InetAddrPort rmiPort = null; - InetAddrPort xmlrpcPort = null; - InetAddrPort websrvPort = null; - InetAddrPort ajp13Port = null; - - // map of server-wide database sources - Hashtable dbSources; - - // the embedded web server - // protected Serve websrv; - protected HttpServer http; - - // the AJP13 Listener, used for connecting from external webserver to servlet via JK - protected AJP13Listener ajp13; - - // the XML-RPC server - protected WebServer xmlrpc; - - /** - * Constructs a new Server instance with an array of command line options. - */ - public Server(String[] args) { - starttime = System.currentTimeMillis(); - - String homeDir = null; - - boolean usageError = false; - - // file names of various property files - String propfile = null; - String dbPropfile = "db.properties"; - String appsPropfile = null; - - // parse arguments - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-h") && ((i + 1) < args.length)) { - homeDir = args[++i]; - } else if (args[i].equals("-f") && ((i + 1) < args.length)) { - propfile = args[++i]; - } else if (args[i].equals("-p") && ((i + 1) < args.length)) { - try { - rmiPort = new InetAddrPort(args[++i]); - } catch (Exception portx) { - usageError = true; - } - } else if (args[i].equals("-x") && ((i + 1) < args.length)) { - try { - xmlrpcPort = new InetAddrPort(args[++i]); - } catch (Exception portx) { - usageError = true; - } - } else if (args[i].equals("-w") && ((i + 1) < args.length)) { - try { - websrvPort = new InetAddrPort(args[++i]); - } catch (Exception portx) { - usageError = true; - } - } else if (args[i].equals("-jk") && ((i + 1) < args.length)) { - try { - ajp13Port = new InetAddrPort(args[++i]); - } catch (Exception portx) { - usageError = true; - } - } else if (args[i].equals("-i") && ((i + 1) < args.length)) { - // eat away the -i parameter which is meant for helma.main.launcher.Main - i++; - } else { - System.err.println("Unknown command line token: " + args[i]); - usageError = true; - } - } - - // get main property file from home dir or vice versa, depending on what we have. - // get property file from hopHome - if (propfile == null) { - if (homeDir != null) { - propfile = new File(homeDir, "server.properties").getAbsolutePath(); - } else { - propfile = new File("server.properties").getAbsolutePath(); - } - } - - // create system properties - sysProps = new SystemProperties(propfile); - - // check if there's a property setting for those ports not specified via command line - if ((websrvPort == null) && (sysProps.getProperty("webPort") != null)) { - try { - websrvPort = new InetAddrPort(sysProps.getProperty("webPort")); - } catch (Exception fmt) { - System.err.println("Error parsing web server port property: " + fmt); - } - } - - if ((ajp13Port == null) && (sysProps.getProperty("ajp13Port") != null)) { - try { - ajp13Port = new InetAddrPort(sysProps.getProperty("ajp13Port")); - } catch (Exception fmt) { - System.err.println("Error parsing AJP1.3 server port property: " + fmt); - } - } - - if ((rmiPort == null) && (sysProps.getProperty("rmiPort") != null)) { - try { - rmiPort = new InetAddrPort(sysProps.getProperty("rmiPort")); - } catch (Exception fmt) { - System.err.println("Error parsing RMI server port property: " + fmt); - } - } - - if ((xmlrpcPort == null) && (sysProps.getProperty("xmlrpcPort") != null)) { - try { - xmlrpcPort = new InetAddrPort(sysProps.getProperty("xmlrpcPort")); - } catch (Exception fmt) { - System.err.println("Error parsing XML-RPC server port property: " + fmt); - } - } - - // check server ports. If no port is set, issue a warning and exit. - if (!usageError && websrvPort == null && ajp13Port == null && - rmiPort == null && xmlrpcPort == null) { - System.out.println(" Error: No server port specified."); - usageError = true; - } - - // if there's a usage error, output message and exit - if (usageError) { - System.out.println(""); - System.out.println("Usage: java helma.main.Server [options]"); - System.out.println("Possible options:"); - System.out.println(" -h dir Specify hop home directory"); - System.out.println(" -f file Specify server.properties file"); - System.out.println(" -w [ip:]port Specify embedded web server address/port"); - System.out.println(" -x [ip:]port Specify XML-RPC address/port"); - System.out.println(" -jk [ip:]port Specify AJP13 address/port"); - System.out.println(" -p [ip:]port Specify RMI address/port"); - System.out.println(""); - System.out.println("Supported formats for server ports:"); - System.out.println(" "); - System.out.println(" :"); - System.out.println(" :"); - System.out.println(""); - System.err.println("Usage Error - exiting"); - System.out.println(""); - System.exit(0); - } - - // check if any of the specified server ports is in use already - try { - if (websrvPort != null) { - checkRunning(websrvPort); - } - - if (rmiPort != null) { - checkRunning(rmiPort); - } - - if (xmlrpcPort != null) { - checkRunning(xmlrpcPort); - } - - if (ajp13Port != null) { - checkRunning(ajp13Port); - } - } catch (Exception running) { - System.out.println(running.getMessage()); - System.exit(1); - } - - // get hopHome from property file - if (homeDir == null) { - homeDir = sysProps.getProperty("hophome"); - } - - if (homeDir == null) { - homeDir = new File(propfile).getParent(); - } - - // create hopHome File object - hopHome = new File(homeDir); - - // try to transform hopHome directory to its cononical representation - try { - hopHome = hopHome.getCanonicalFile(); - } catch (IOException iox) { - System.err.println("Error calling getCanonicalFile() on hopHome: " + iox); - } - - // set the current working directory to the helma home dir. - // note that this is not a real cwd, which is not supported - // by java. It makes sure relative to absolute path name - // conversion is done right, so for Helma code, this should - // work. - System.setProperty("user.dir", hopHome.getPath()); - - // from now on it's safe to call getLogger() because hopHome is set up - String startMessage = "Starting Helma " + version + " on Java " + - System.getProperty("java.version"); - - getLogger().log(startMessage); - - // also print a msg to System.out - System.out.println(startMessage); - - getLogger().log("propfile = " + propfile); - getLogger().log("hopHome = " + hopHome); - - File helper = new File(hopHome, "db.properties"); - - dbPropfile = helper.getAbsolutePath(); - dbProps = new SystemProperties(dbPropfile); - DbSource.setDefaultProps(dbProps); - getLogger().log("dbPropfile = " + dbPropfile); - - appsPropfile = sysProps.getProperty("appsPropFile"); - - if ((appsPropfile != null) && !"".equals(appsPropfile.trim())) { - helper = new File(appsPropfile); - } else { - helper = new File(hopHome, "apps.properties"); - } - - appsPropfile = helper.getAbsolutePath(); - appsProps = new SystemProperties(appsPropfile); - getLogger().log("appsPropfile = " + appsPropfile); - - paranoid = "true".equalsIgnoreCase(sysProps.getProperty("paranoid")); - - String language = sysProps.getProperty("language"); - String country = sysProps.getProperty("country"); - String timezone = sysProps.getProperty("timezone"); - - if ((language != null) && (country != null)) { - Locale.setDefault(new Locale(language, country)); - } - - if (timezone != null) { - TimeZone.setDefault(TimeZone.getTimeZone(timezone)); - } - - getLogger().log("Locale = " + Locale.getDefault()); - getLogger().log("TimeZone = " + - TimeZone.getDefault().getDisplayName(Locale.getDefault())); - - dbSources = new Hashtable(); - - // try to load the extensions - extensions = new Vector(); - - if (sysProps.getProperty("extensions") != null) { - StringTokenizer tok = new StringTokenizer(sysProps.getProperty("extensions"), - ","); - - while (tok.hasMoreTokens()) { - String extClassName = tok.nextToken().trim(); - - try { - Class extClass = Class.forName(extClassName); - HelmaExtension ext = (HelmaExtension) extClass.newInstance(); - - ext.init(this); - extensions.add(ext); - getLogger().log("Loaded: " + extClassName); - } catch (Throwable e) { - getLogger().log("Error loading extension " + extClassName + ": " + e.toString()); - } - } - } - } - - /** - * static main entry point. - */ - public static void main(String[] args) throws IOException { - // check if we are running on a Java 2 VM - otherwise exit with an error message - String javaVersion = System.getProperty("java.version"); - - if ((javaVersion == null) || javaVersion.startsWith("1.1") || - javaVersion.startsWith("1.0")) { - System.err.println("This version of Helma requires Java 1.2 or greater."); - - if (javaVersion == null) { // don't think this will ever happen, but you never know - System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version."); - } else { - System.err.println("Your Java Runtime is version " + javaVersion + - ". Please update to a more recent version."); - } - - System.exit(1); - } - - // create new server instance - server = new Server(args); - - // start the server main thread - server.start(); - } - - protected void start() { - // Start running, finishing setup and then entering a loop to check changes - // in the apps.properties file. - mainThread = new Thread(this); - mainThread.start(); - } - - protected void stop() { - mainThread = null; - } - - /** - * The main method of the Server. Basically, we set up Applications and than - * periodically check for changes in the apps.properties file, shutting down - * apps or starting new ones. - */ - public void run() { - try { - if ((websrvPort != null) || (ajp13Port != null)) { - http = new HttpServer(); - - // disable Jetty logging FIXME: seems to be a jetty bug; as soon - // as the logging is disabled, the more is logged - Log.instance().disableLog(); - Log.instance().add(new LogSink() { - public String getOptions() { - return null; - } - - public void log(String formattedLog) { - } - - public void log(String tag, Object msg, Frame frame, long time) { - } - - public void setOptions(String options) { - } - - public boolean isStarted() { - return true; - } - - public void start() { - } - - public void stop() { - } - }); - } - - // start embedded web server if port is specified - if (websrvPort != null) { - http.addListener(websrvPort); - } - - // activate the ajp13-listener - if (ajp13Port != null) { - // create AJP13Listener - ajp13 = new AJP13Listener(ajp13Port); - ajp13.setHttpServer(http); - - String jkallow = sysProps.getProperty("allowAJP13"); - - // by default the AJP13-connection just accepts requests from 127.0.0.1 - if (jkallow == null) { - jkallow = "127.0.0.1"; - } - - StringTokenizer st = new StringTokenizer(jkallow, " ,;"); - String[] jkallowarr = new String[st.countTokens()]; - int cnt = 0; - - while (st.hasMoreTokens()) { - jkallowarr[cnt] = st.nextToken(); - cnt++; - } - - ajp13.setRemoteServers(jkallowarr); - getLogger().log("Starting AJP13-Listener on port " + (ajp13Port)); - } - - if (xmlrpcPort != null) { - String xmlparser = sysProps.getProperty("xmlparser"); - - if (xmlparser != null) { - XmlRpc.setDriver(xmlparser); - } - - if (xmlrpcPort.getInetAddress() != null) { - xmlrpc = new WebServer(xmlrpcPort.getPort(), xmlrpcPort.getInetAddress()); - } else { - xmlrpc = new WebServer(xmlrpcPort.getPort()); - } - - if (paranoid) { - xmlrpc.setParanoid(true); - - String xallow = sysProps.getProperty("allowXmlRpc"); - - if (xallow != null) { - StringTokenizer st = new StringTokenizer(xallow, " ,;"); - - while (st.hasMoreTokens()) - xmlrpc.acceptClient(st.nextToken()); - } - } - - getLogger().log("Starting XML-RPC server on port " + (xmlrpcPort)); - } - - if (rmiPort != null) { - if (paranoid) { - HelmaSocketFactory factory = new HelmaSocketFactory(); - String rallow = sysProps.getProperty("allowWeb"); - if (rallow == null) { - rallow = sysProps.getProperty("allowRMI"); - } - - if (rallow != null) { - StringTokenizer st = new StringTokenizer(rallow, " ,;"); - - while (st.hasMoreTokens()) - factory.addAddress(st.nextToken()); - } - - RMISocketFactory.setSocketFactory(factory); - } - - getLogger().log("Starting RMI server on port " + rmiPort); - LocateRegistry.createRegistry(rmiPort.getPort()); - - // create application manager which binds to the given RMI port - appManager = new ApplicationManager(hopHome, appsProps, this, rmiPort.getPort()); - } else { - // create application manager with RMI port 0 - appManager = new ApplicationManager(hopHome, appsProps, this, 0); - } - - if (xmlrpc != null) { - xmlrpc.addHandler("$default", appManager); - } - - // add shutdown hook to close running apps and servers on exit - Runtime.getRuntime().addShutdownHook(new HelmaShutdownHook(appManager)); - } catch (Exception gx) { - getLogger().log("Error initializing embedded database: " + gx); - gx.printStackTrace(); - - return; - } - - // set the security manager. - // the default implementation is helma.main.HelmaSecurityManager. - try { - String secManClass = sysProps.getProperty("securityManager"); - - if (secManClass != null) { - SecurityManager secMan = (SecurityManager) Class.forName(secManClass) - .newInstance(); - - System.setSecurityManager(secMan); - getLogger().log("Setting security manager to " + secManClass); - } - } catch (Exception x) { - getLogger().log("Error setting security manager: " + x); - } - - // start applications - appManager.startAll(); - - // start embedded web server - if (http != null) { - try { - http.start(); - } catch (MultiException m) { - getLogger().log("Error starting embedded web server: " + m); - } - } - - if (ajp13 != null) { - try { - ajp13.start(); - } catch (Exception m) { - getLogger().log("Error starting AJP13 listener: " + m); - } - } - - while (Thread.currentThread() == mainThread) { - try { - Thread.sleep(3000L); - } catch (InterruptedException ie) { - } - - try { - appManager.checkForChanges(); - } catch (Exception x) { - getLogger().log("Caught in app manager loop: " + x); - } - } - } - - /** - * Get an Iterator over the applications currently running on this Server. - */ - public Object[] getApplications() { - return appManager.getApplications(); - } - - /** - * Get an Application by name - */ - public Application getApplication(String name) { - return appManager.getApplication(name); - } - - /** - * Get a logger to use for output in this server. - */ - public static Logger getLogger() { - if (logger == null) { - String logDir = sysProps.getProperty("logdir", "log"); - - if ("console".equalsIgnoreCase(logDir)) { - logger = new Logger(System.out); - } else { - File helper = new File(logDir); - - if ((hopHome != null) && !helper.isAbsolute()) { - helper = new File(hopHome, logDir); - } - - logDir = helper.getAbsolutePath(); - logger = Logger.getLogger(logDir, "hop"); - } - } - - return logger; - } - - /** - * Get the Home directory of this server. - */ - public File getHopHome() { - return hopHome; - } - - /** - * Get the main Server instance. - */ - public static Server getServer() { - return server; - } - - /** - * Get the Server's XML-RPC web server. - */ - public static WebServer getXmlRpcServer() { - return server.xmlrpc; - } - - /** - * A primitive method to check whether a server is already running on our port. - */ - private void checkRunning(InetAddrPort addrPort) throws Exception { - InetAddress addr = addrPort.getInetAddress(); - if (addr == null) { - addr = InetAddress.getLocalHost(); - } - try { - new Socket(addr, addrPort.getPort()); - } catch (IOException x) { - // we couldn't connect to the socket because no server - // is running on it yet. Everything's ok. - return; - } - - // if we got so far, another server is already running on this port and db - throw new Exception("Error: Server already running on this port: " + addrPort); - } - - /** - * - * - * @param key ... - * - * @return ... - */ - public String getProperty(String key) { - return (String) sysProps.get(key); - } - - /** - * - * - * @return ... - */ - public SystemProperties getProperties() { - return sysProps; - } - - /** - * - * - * @return ... - */ - public SystemProperties getDbProperties() { - return dbProps; - } - - /** - * - * - * @return ... - */ - public File getAppsHome() { - String appHome = sysProps.getProperty("appHome", ""); - - if (appHome.trim().length() != 0) { - return new File(appHome); - } else { - return new File(hopHome, "apps"); - } - } - - /** - * - * - * @return ... - */ - public File getDbHome() { - String dbHome = sysProps.getProperty("dbHome", ""); - - if (dbHome.trim().length() != 0) { - return new File(dbHome); - } else { - return new File(hopHome, "db"); - } - } - - /** - * - * - * @return ... - */ - public Vector getExtensions() { - return extensions; - } - - /** - * - * - * @param name ... - */ - public void startApplication(String name) { - appManager.start(name); - appManager.register(name); - } - - /** - * - * - * @param name ... - */ - public void stopApplication(String name) { - appManager.stop(name); - } - - /** - * method from helma.framework.IPathElement - */ - public String getElementName() { - return "root"; - } - - /** - * method from helma.framework.IPathElement, - * returning active applications - */ - public IPathElement getChildElement(String name) { - return appManager.getApplication(name); - } - - /** - * method from helma.framework.IPathElement - */ - public IPathElement getParentElement() { - return null; - } - - /** - * method from helma.framework.IPathElement - */ - public String getPrototype() { - return "root"; - } -} diff --git a/src/helma/main/launcher/FilteredClassLoader.java b/src/helma/main/launcher/FilteredClassLoader.java deleted file mode 100644 index 696382ed..00000000 --- a/src/helma/main/launcher/FilteredClassLoader.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main.launcher; - -import java.net.URL; -import java.net.URLClassLoader; -import java.security.CodeSource; -import java.security.PermissionCollection; -import java.security.Permissions; -import java.security.Policy; -import java.util.Hashtable; - -/** - * ClassLoader that is able to exclude certain packages from loading. - */ -public class FilteredClassLoader extends URLClassLoader { - /** - * Create a server wide class loader that doesn't see the scripting engine(s) - * embedded in helma.jar. These files should be loaded by the per-application - * class loaders so that special security policies can be applied to them and - * so that they can load classes from jar files in the app directories. - */ - public FilteredClassLoader(URL[] urls) { - super(urls, null); - } - - /** - * Mask classes that implement the scripting engine(s) contained in helma.jar - */ - protected Class findClass(String name) throws ClassNotFoundException { - if ((name != null) && (name.startsWith("helma")) && - (name.endsWith("PhantomEngine"))) { - throw new ClassNotFoundException(name); - } - - return super.findClass(name); - } -} diff --git a/src/helma/main/launcher/Main.java b/src/helma/main/launcher/Main.java deleted file mode 100644 index fc0d8f42..00000000 --- a/src/helma/main/launcher/Main.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.main.launcher; - -import java.io.File; -import java.io.FilenameFilter; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLDecoder; -import java.security.Policy; -import java.util.ArrayList; - -/** - * Helma bootstrap class. Figures out Helma home directory, sets up class path and - * lauchnes main class. This class must be invoked from a jar file in order to work. - */ -public class Main { - public static final String[] jars = { - "helma.jar", "jetty.jar", "crimson.jar", - "xmlrpc.jar", "servlet.jar", "regexp.jar", - "mail.jar", "activation.jar", - "netcomponents.jar", "jimi.jar", - "apache-dom.jar", "jdom.jar" - }; - - /** - * - * - * @param args ... - * - * @throws Exception ... - */ - public static void main(String[] args) throws Exception { - // check if home directory is set via command line arg. If not, - // we'll get it from the location of the jar file this class - // has been loaded from. - String installDir = null; - - // first, try to get helma home dir from command line options - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-i") && ((i + 1) < args.length)) { - installDir = args[i + 1]; - } - } - - URLClassLoader apploader = (URLClassLoader) ClassLoader.getSystemClassLoader(); - - // try to get Helma installation directory - if (installDir == null) { - try { - URL launcherUrl = apploader.findResource("helma/main/launcher/Main.class"); - - // this is a JAR URL of the form - // jar:!/{entry} - // we strip away the jar: prefix and the !/{entry} suffix - // to get the original jar file URL - - String jarUrl = launcherUrl.toString(); - - if (!jarUrl.startsWith("jar:") || jarUrl.indexOf("!") < 0) { - throw new RuntimeException(" Unable to get JAR URL from "+jarUrl); - } - - jarUrl = jarUrl.substring(4); - - int excl = jarUrl.indexOf("!"); - - jarUrl = jarUrl.substring(0, excl); - launcherUrl = new URL(jarUrl); - - File f = new File(launcherUrl.getPath()); - - installDir = f.getParentFile().getCanonicalPath(); - - } catch (Exception x) { - // unable to get Helma installation dir from launcher jar - System.err.println("Unable to get Helma installation directory: "); - System.err.println(x.getMessage()); - System.exit(2); - } - } - - // decode installDir in case it is URL-encoded - installDir = URLDecoder.decode(installDir); - - // set up the class path - File libdir = new File(installDir, "lib"); - ArrayList jarlist = new ArrayList(); - - for (int i = 0; i < jars.length; i++) { - File jar = new File(libdir, jars[i]); - - jarlist.add(new URL("file:" + jar.getAbsolutePath())); - } - - // add all jar files from the lib/ext directory - File extdir = new File(libdir, "ext"); - File[] files = extdir.listFiles(new FilenameFilter() { - public boolean accept(File dir, String name) { - String n = name.toLowerCase(); - - return n.endsWith(".jar") || n.endsWith(".zip"); - } - }); - - if (files != null) { - for (int i = 0; i < files.length; i++) { - // WORKAROUND: add the files in lib/ext before - // lib/apache-dom.jar, since otherwise putting a full version - // of Xerces in lib/ext would cause a version conflict with the - // xerces classes in lib/apache-dom.jar. Generally, having some pieces - // of Xerces in lib/apache-dom.jar is kind of problematic. - jarlist.add(jars.length - 3, new URL("file:" + - files[i].getAbsolutePath())); - System.err.println("Adding to classpath: " + files[i].getAbsolutePath()); - } - } - - URL[] urls = new URL[jarlist.size()]; - - jarlist.toArray(urls); - - FilteredClassLoader loader = new FilteredClassLoader(urls); - - // set the new class loader as context class loader - Thread.currentThread().setContextClassLoader(loader); - - // get the main server class - Class clazz = loader.loadClass("helma.main.Server"); - Class[] cargs = new Class[] { args.getClass() }; - Method main = clazz.getMethod("main", cargs); - Object[] nargs = new Object[] { args }; - - // run - main.invoke(null, nargs); - } -} diff --git a/src/helma/main/launcher/manifest.txt b/src/helma/main/launcher/manifest.txt deleted file mode 100644 index 37df267c..00000000 --- a/src/helma/main/launcher/manifest.txt +++ /dev/null @@ -1,3 +0,0 @@ -Main-Class: helma.main.launcher.Main - - diff --git a/src/helma/objectmodel/ConcurrencyException.java b/src/helma/objectmodel/ConcurrencyException.java deleted file mode 100644 index d495e9c2..00000000 --- a/src/helma/objectmodel/ConcurrencyException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - - -/** - * Thrown when more than one thrad tries to modify a Node. The evaluator - * will normally catch this and try again after a period of time. - */ -public class ConcurrencyException extends RuntimeException { - /** - * Creates a new ConcurrencyException object. - * - * @param msg ... - */ - public ConcurrencyException(String msg) { - super(msg); - } -} diff --git a/src/helma/objectmodel/DatabaseException.java b/src/helma/objectmodel/DatabaseException.java deleted file mode 100644 index 1dfe2396..00000000 --- a/src/helma/objectmodel/DatabaseException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - - -/** - * Thrown on any kind of Database-Error - */ -public class DatabaseException extends RuntimeException { - /** - * Creates a new DatabaseException object. - * - * @param msg ... - */ - public DatabaseException(String msg) { - super(msg); - } -} diff --git a/src/helma/objectmodel/IDatabase.java b/src/helma/objectmodel/IDatabase.java deleted file mode 100644 index a9a7e2da..00000000 --- a/src/helma/objectmodel/IDatabase.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import helma.objectmodel.INode; -import helma.objectmodel.db.IDGenerator; -import java.io.IOException; -import org.xml.sax.SAXException; -import javax.xml.parsers.ParserConfigurationException; - -/** - * Interface that is implemented by Database wrappers - */ -public interface IDatabase { - // db-related - public void shutdown(); - - // id-related - public String nextID() throws ObjectNotFoundException; - - /** - * - * - * @param transaction ... - * - * @return ... - * - * @throws IOException ... - */ - public IDGenerator getIDGenerator(ITransaction transaction) - throws IOException, ObjectNotFoundException; - - /** - * - * - * @param transaction ... - * @param idgen ... - * - * @throws IOException ... - */ - public void saveIDGenerator(ITransaction transaction, IDGenerator idgen) - throws IOException; - - // node-related - public INode getNode(ITransaction transaction, String key) - throws IOException, ObjectNotFoundException, - SAXException, ParserConfigurationException; - - /** - * - * - * @param transaction ... - * @param key ... - * @param node ... - * - * @throws IOException ... - */ - public void saveNode(ITransaction transaction, String key, INode node) - throws IOException; - - /** - * - * - * @param transaction ... - * @param key ... - * - * @throws IOException ... - */ - public void deleteNode(ITransaction transaction, String key) - throws IOException; - - // transaction-related - public ITransaction beginTransaction(); - - /** - * - * - * @param transaction ... - * - * @throws DatabaseException ... - */ - public void commitTransaction(ITransaction transaction) - throws DatabaseException; - - /** - * - * - * @param transaction ... - * - * @throws DatabaseException ... - */ - public void abortTransaction(ITransaction transaction) - throws DatabaseException; -} diff --git a/src/helma/objectmodel/INode.java b/src/helma/objectmodel/INode.java deleted file mode 100644 index d03cb6bd..00000000 --- a/src/helma/objectmodel/INode.java +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import helma.framework.IPathElement; -import helma.objectmodel.db.DbMapping; -import java.io.*; -import java.util.*; - -/** - * Interface that all Nodes implement. Currently, there are two implementations: - * Transient nodes which only exist in memory, and persistent Nodes, which are - * stored in a database (either the internal Object DB or an external relational DB). - */ -public interface INode extends INodeState, IPathElement { - /** - * id-related methods - */ - public String getID(); - - /** - * - * - * @return ... - */ - public String getName(); - - /** - * - * - * @param dbmap ... - */ - public void setDbMapping(DbMapping dbmap); - - /** - * - * - * @return ... - */ - public DbMapping getDbMapping(); - - /** - * - * - * @return ... - */ - public int getState(); - - /** - * - * - * @param s ... - */ - public void setState(int s); - - /** - * - * - * @param name ... - */ - public void setName(String name); - - /** - * - * - * @return ... - */ - public long lastModified(); - - /** - * - * - * @return ... - */ - public long created(); - - /** - * - * - * @return ... - */ - public boolean isAnonymous(); // is this a named node, or an anonymous node in a collection? - - /** - * - * - * @return ... - */ - public String getPrototype(); - - /** - * - * - * @param prototype ... - */ - public void setPrototype(String prototype); - - /** - * - * - * @return ... - */ - public INode getCacheNode(); - - /** - * - */ - public void clearCacheNode(); - - /** - * - * - * @return ... - */ - public String getFullName(); - - /** - * - * - * @param root ... - * - * @return ... - */ - public String getFullName(INode root); - - /** - * node-related methods - */ - public INode getParent(); - - /** - * - * - * @param rel ... - */ - public void setSubnodeRelation(String rel); - - /** - * - * - * @return ... - */ - public String getSubnodeRelation(); - - /** - * - * - * @return ... - */ - public int numberOfNodes(); - - /** - * - * - * @param node ... - * - * @return ... - */ - public INode addNode(INode node); - - /** - * - * - * @param node ... - * @param where ... - * - * @return ... - */ - public INode addNode(INode node, int where); - - /** - * - * - * @param name ... - * - * @return ... - */ - public INode createNode(String name); - - /** - * - * - * @param name ... - * @param where ... - * - * @return ... - */ - public INode createNode(String name, int where); - - /** - * - * - * @return ... - */ - public Enumeration getSubnodes(); - - /** - * - * - * @param name ... - * - * @return ... - */ - public INode getSubnode(String name); - - /** - * - * - * @param index ... - * - * @return ... - */ - public INode getSubnodeAt(int index); - - /** - * - * - * @param node ... - * - * @return ... - */ - public int contains(INode node); - - /** - * - * - * @return ... - */ - public boolean remove(); - - /** - * - * - * @param node ... - */ - public void removeNode(INode node); - - /** - * property-related methods - */ - public Enumeration properties(); - - /** - * - * - * @param name ... - * - * @return ... - */ - public IProperty get(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public String getString(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public boolean getBoolean(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public Date getDate(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public long getInteger(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public double getFloat(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public INode getNode(String name); - - /** - * - * - * @param name ... - * - * @return ... - */ - public Object getJavaObject(String name); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setString(String name, String value); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setBoolean(String name, boolean value); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setDate(String name, Date value); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setInteger(String name, long value); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setFloat(String name, double value); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setNode(String name, INode value); - - /** - * - * - * @param name ... - * @param value ... - */ - public void setJavaObject(String name, Object value); - - /** - * - * - * @param name ... - */ - public void unset(String name); -} diff --git a/src/helma/objectmodel/INodeState.java b/src/helma/objectmodel/INodeState.java deleted file mode 100644 index df91a6a6..00000000 --- a/src/helma/objectmodel/INodeState.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import java.io.*; -import java.util.*; - -/** - * Interface that defines states of nodes - */ -public interface INodeState { - public final static int TRANSIENT = -3; - public final static int VIRTUAL = -2; - public final static int INVALID = -1; - public final static int CLEAN = 0; - public final static int NEW = 1; - public final static int MODIFIED = 2; - public final static int DELETED = 3; -} diff --git a/src/helma/objectmodel/IProperty.java b/src/helma/objectmodel/IProperty.java deleted file mode 100644 index 95198079..00000000 --- a/src/helma/objectmodel/IProperty.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import java.util.Date; - -/** - * Interface that is implemented by node properties. - */ -public interface IProperty { - public static final int STRING = 1; - public static final int BOOLEAN = 2; - public static final int DATE = 3; - public static final int INTEGER = 4; - public static final int FLOAT = 5; - public static final int NODE = 6; - public static final int JAVAOBJECT = 7; - - /** - * - * - * @return ... - */ - public String getName(); - - /** - * - * - * @return ... - */ - public int getType(); - - /** - * - * - * @return ... - */ - public Object getValue(); - - /** - * - * - * @return ... - */ - public INode getNodeValue(); - - /** - * - * - * @return ... - */ - public String getStringValue(); - - /** - * - * - * @return ... - */ - public boolean getBooleanValue(); - - /** - * - * - * @return ... - */ - public long getIntegerValue(); - - /** - * - * - * @return ... - */ - public double getFloatValue(); - - /** - * - * - * @return ... - */ - public Date getDateValue(); - - /** - * - * - * @return ... - */ - public Object getJavaObjectValue(); -} diff --git a/src/helma/objectmodel/ITransaction.java b/src/helma/objectmodel/ITransaction.java deleted file mode 100644 index 6455926d..00000000 --- a/src/helma/objectmodel/ITransaction.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - - -/** - * This interface is kept for databases that are able - * to run transactions. Transactions were used for the - * Berkeley database and might be used in other future - * databases, so we leave transactions in. - */ -public interface ITransaction { -} diff --git a/src/helma/objectmodel/NodeEvent.java b/src/helma/objectmodel/NodeEvent.java deleted file mode 100644 index d4e3f5a2..00000000 --- a/src/helma/objectmodel/NodeEvent.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import java.io.*; - -/** - * This is passed to NodeListeners when a node is modified. - */ -public class NodeEvent implements Serializable { - public static final int CONTENT_CHANGED = 0; - public static final int PROPERTIES_CHANGED = 1; - public static final int NODE_REMOVED = 2; - public static final int NODE_RENAMED = 3; - public static final int SUBNODE_ADDED = 4; - public static final int SUBNODE_REMOVED = 5; - public int type; - public String id; - public transient INode node; - public transient Object arg; - - /** - * Creates a new NodeEvent object. - * - * @param node ... - * @param type ... - */ - public NodeEvent(INode node, int type) { - super(); - this.node = node; - this.id = node.getID(); - this.type = type; - } - - /** - * Creates a new NodeEvent object. - * - * @param node ... - * @param type ... - * @param arg ... - */ - public NodeEvent(INode node, int type, Object arg) { - super(); - this.node = node; - this.id = node.getID(); - this.type = type; - this.arg = arg; - } - - /** - * - * - * @return ... - */ - public String toString() { - switch (type) { - case CONTENT_CHANGED: - return "NodeEvent: content changed"; - - case PROPERTIES_CHANGED: - return "NodeEvent: properties changed"; - - case NODE_REMOVED: - return "NodeEvent: node removed"; - - case NODE_RENAMED: - return "NodeEvent: node moved"; - - case SUBNODE_ADDED: - return "NodeEvent: subnode added"; - - case SUBNODE_REMOVED: - return "NodeEvent: subnode removed"; - } - - return "NodeEvent: invalid type"; - } -} diff --git a/src/helma/objectmodel/ObjectNotFoundException.java b/src/helma/objectmodel/ObjectNotFoundException.java deleted file mode 100644 index 81e44f94..00000000 --- a/src/helma/objectmodel/ObjectNotFoundException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - - -/** - * Thrown when an object could not found in the database where - * it was expected. - */ -public class ObjectNotFoundException extends Exception { - /** - * Creates a new ObjectNotFoundException object. - * - * @param msg ... - */ - public ObjectNotFoundException(String msg) { - super(msg); - } -} diff --git a/src/helma/objectmodel/Property.java b/src/helma/objectmodel/Property.java deleted file mode 100644 index 3fca8396..00000000 --- a/src/helma/objectmodel/Property.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import helma.util.*; -import java.io.*; -import java.text.*; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -/** - * A property implementation for Nodes stored inside a database. - */ -public final class Property implements IProperty, Serializable { - protected String propname; - protected TransientNode node; - public String svalue; - public boolean bvalue; - public long lvalue; - public double dvalue; - public INode nvalue; - public Object jvalue; - public int type; - - /** - * Creates a new Property object. - * - * @param node ... - */ - public Property(TransientNode node) { - this.node = node; - } - - /** - * Creates a new Property object. - * - * @param propname ... - * @param node ... - */ - public Property(String propname, TransientNode node) { - this.propname = propname; - this.node = node; - } - - /** - * - * - * @return ... - */ - public String getName() { - return propname; - } - - /** - * - * - * @return ... - */ - public Object getValue() { - switch (type) { - case STRING: - return svalue; - - case BOOLEAN: - return new Boolean(bvalue); - - case INTEGER: - return new Long(lvalue); - - case FLOAT: - return new Double(dvalue); - - case DATE: - return new Date(lvalue); - - case NODE: - return nvalue; - - case JAVAOBJECT: - return jvalue; - } - - return null; - } - - /** - * - * - * @param value ... - */ - public void setStringValue(String value) { - if (type == NODE) { - this.nvalue = null; - } - - if (type == JAVAOBJECT) { - this.jvalue = null; - } - - type = STRING; - this.svalue = value; - } - - /** - * - * - * @param value ... - */ - public void setIntegerValue(long value) { - if (type == NODE) { - this.nvalue = null; - } - - if (type == JAVAOBJECT) { - this.jvalue = null; - } - - type = INTEGER; - this.lvalue = value; - } - - /** - * - * - * @param value ... - */ - public void setFloatValue(double value) { - if (type == NODE) { - this.nvalue = null; - } - - if (type == JAVAOBJECT) { - this.jvalue = null; - } - - type = FLOAT; - this.dvalue = value; - } - - /** - * - * - * @param value ... - */ - public void setDateValue(Date value) { - if (type == NODE) { - this.nvalue = null; - } - - if (type == JAVAOBJECT) { - this.jvalue = null; - } - - type = DATE; - this.lvalue = value.getTime(); - } - - /** - * - * - * @param value ... - */ - public void setBooleanValue(boolean value) { - if (type == NODE) { - this.nvalue = null; - } - - if (type == JAVAOBJECT) { - this.jvalue = null; - } - - type = BOOLEAN; - this.bvalue = value; - } - - /** - * - * - * @param value ... - */ - public void setNodeValue(INode value) { - if (type == JAVAOBJECT) { - this.jvalue = null; - } - - type = NODE; - this.nvalue = value; - } - - /** - * - * - * @param value ... - */ - public void setJavaObjectValue(Object value) { - if (type == NODE) { - this.nvalue = null; - } - - type = JAVAOBJECT; - this.jvalue = value; - } - - /** - * - * - * @return ... - */ - public String getStringValue() { - switch (type) { - case STRING: - return svalue; - - case BOOLEAN: - return "" + bvalue; - - case DATE: - - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yy HH:mm"); - - return format.format(new Date(lvalue)); - - case INTEGER: - return Long.toString(lvalue); - - case FLOAT: - return Double.toString(dvalue); - - case NODE: - return nvalue.getName(); - - case JAVAOBJECT: - return (jvalue == null) ? null : jvalue.toString(); - } - - return ""; - } - - /** - * - * - * @return ... - */ - public String toString() { - return getStringValue(); - } - - /** - * - * - * @return ... - */ - public long getIntegerValue() { - if (type == INTEGER) { - return lvalue; - } - - return 0; - } - - /** - * - * - * @return ... - */ - public double getFloatValue() { - if (type == FLOAT) { - return dvalue; - } - - return 0.0; - } - - /** - * - * - * @return ... - */ - public Date getDateValue() { - if (type == DATE) { - return new Date(lvalue); - } - - return null; - } - - /** - * - * - * @return ... - */ - public boolean getBooleanValue() { - if (type == BOOLEAN) { - return bvalue; - } - - return false; - } - - /** - * - * - * @return ... - */ - public INode getNodeValue() { - if (type == NODE) { - return nvalue; - } - - return null; - } - - /** - * - * - * @return ... - */ - public Object getJavaObjectValue() { - if (type == JAVAOBJECT) { - return jvalue; - } - - return null; - } - - /** - * - * - * @return ... - */ - public int getType() { - return type; - } -} diff --git a/src/helma/objectmodel/TransientNode.java b/src/helma/objectmodel/TransientNode.java deleted file mode 100644 index f50c250b..00000000 --- a/src/helma/objectmodel/TransientNode.java +++ /dev/null @@ -1,976 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel; - -import helma.framework.IPathElement; -import helma.objectmodel.db.DbMapping; -import helma.objectmodel.db.Relation; -import helma.util.*; -import java.io.*; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * A transient implementation of INode. An instance of this class can't be - * made persistent by reachability from a persistent node. To make a persistent-capable - * object, class helma.objectmodel.db.Node has to be used. - */ -public class TransientNode implements INode, Serializable { - private static long idgen = 0; - protected Hashtable propMap; - protected Hashtable nodeMap; - protected Vector nodes; - protected TransientNode parent; - protected Vector links; // links to this node - protected Vector proplinks; // nodes using this node as property - transient String prototype; - protected long created; - protected long lastmodified; - protected String id; - protected String name; - - // is the main identity a named property or an anonymous node in a collection? - protected boolean anonymous = false; - transient DbMapping dbmap; - INode cacheNode; - - /** - * Creates a new TransientNode object. - */ - public TransientNode() { - id = generateID(); - name = id; - created = lastmodified = System.currentTimeMillis(); - } - - /** - * Make a new TransientNode object with a given name - */ - public TransientNode(String n) { - id = generateID(); - name = ((n == null) || "".equals(n)) ? id : n; - created = lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @return ... - */ - public static String generateID() { - // make transient ids differ from persistent ones - // and are unique within on runtime session - return "t" + idgen++; - } - - /** - * - * - * @param dbmap ... - */ - public void setDbMapping(DbMapping dbmap) { - this.dbmap = dbmap; - } - - /** - * - * - * @return ... - */ - public DbMapping getDbMapping() { - return dbmap; - } - - /** - * navigation-related - */ - public String getID() { - return id; - } - - /** - * - * - * @return ... - */ - public boolean isAnonymous() { - return anonymous; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @return ... - */ - public String getElementName() { - return anonymous ? id : name; - } - - /** - * - * - * @return ... - */ - public int getState() { - return TRANSIENT; - } - - /** - * - * - * @param s ... - */ - public void setState(int s) { - // state always is TRANSIENT on this kind of node - } - - /** - * - * - * @return ... - */ - public String getFullName() { - return getFullName(null); - } - - /** - * - * - * @param root ... - * - * @return ... - */ - public String getFullName(INode root) { - String divider = null; - StringBuffer b = new StringBuffer(); - TransientNode p = this; - - while ((p != null) && (p.parent != null) && (p != root)) { - if (divider != null) { - b.insert(0, divider); - } else { - divider = "/"; - } - - b.insert(0, p.getElementName()); - p = p.parent; - } - - return b.toString(); - } - - /** - * - * - * @param name ... - */ - public void setName(String name) { - // if (name.indexOf('/') > -1) - // throw new RuntimeException ("The name of the node must not contain \"/\"."); - if ((name == null) || (name.trim().length() == 0)) { - this.name = id; - } else { - this.name = name; - } - } - - /** - * - * - * @return ... - */ - public String getPrototype() { - // if prototype is null, it's a vanilla HopObject. - if (prototype == null) { - return "hopobject"; - } - - return prototype; - } - - /** - * - * - * @param proto ... - */ - public void setPrototype(String proto) { - this.prototype = proto; - } - - /** - * - * - * @return ... - */ - public INode getParent() { - return parent; - } - - /** - * INode-related - */ - public void setSubnodeRelation(String rel) { - throw new RuntimeException("Can't set subnode relation for non-persistent Node."); - } - - /** - * - * - * @return ... - */ - public String getSubnodeRelation() { - return null; - } - - /** - * - * - * @return ... - */ - public int numberOfNodes() { - return (nodes == null) ? 0 : nodes.size(); - } - - /** - * - * - * @param elem ... - * - * @return ... - */ - public INode addNode(INode elem) { - return addNode(elem, numberOfNodes()); - } - - /** - * - * - * @param elem ... - * @param where ... - * - * @return ... - */ - public INode addNode(INode elem, int where) { - if ((where < 0) || (where > numberOfNodes())) { - where = numberOfNodes(); - } - - String n = elem.getName(); - - if (n.indexOf('/') > -1) { - throw new RuntimeException("The name of a node must not contain \"/\" (slash)."); - } - - // IServer.getLogger().log ("adding: "+node+" -- "+node.getContentLength ()); - if ((nodeMap != null) && (nodeMap.get(elem.getID()) != null)) { - nodes.removeElement(elem); - where = Math.min(where, numberOfNodes()); - nodes.insertElementAt(elem, where); - - return elem; - } - - if (nodeMap == null) { - nodeMap = new Hashtable(); - } - - if (nodes == null) { - nodes = new Vector(); - } - - nodeMap.put(elem.getID(), elem); - nodes.insertElementAt(elem, where); - - if (elem instanceof TransientNode) { - TransientNode node = (TransientNode) elem; - - if (node.parent == null) { - node.parent = this; - node.anonymous = true; - } - } - - lastmodified = System.currentTimeMillis(); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, node)); - return elem; - } - - /** - * - * - * @return ... - */ - public INode createNode() { - return createNode(null, 0); // where is ignored since this is an anonymous node - } - - /** - * - * - * @param where ... - * - * @return ... - */ - public INode createNode(int where) { - return createNode(null, where); - } - - /** - * - * - * @param nm ... - * - * @return ... - */ - public INode createNode(String nm) { - return createNode(nm, numberOfNodes()); // where is usually ignored (if nm != null) - } - - /** - * - * - * @param nm ... - * @param where ... - * - * @return ... - */ - public INode createNode(String nm, int where) { - boolean anon = false; - - if ((nm == null) || "".equals(nm.trim())) { - anon = true; - } - - INode n = new TransientNode(nm); - - if (anon) { - addNode(n, where); - } else { - setNode(nm, n); - } - - return n; - } - - /** - * register a node that links to this node. - */ - - /* protected void registerLink (TransientNode from) { - if (links == null) - links = new Vector (); - if (!links.contains (from)) - links.addElement (from); - } */ - public IPathElement getParentElement() { - return getParent(); - } - - /** - * - * - * @param name ... - * - * @return ... - */ - public IPathElement getChildElement(String name) { - return getNode(name); - } - - /** - * - * - * @param name ... - * - * @return ... - */ - public INode getSubnode(String name) { - StringTokenizer st = new StringTokenizer(name, "/"); - TransientNode retval = this; - TransientNode runner; - - while (st.hasMoreTokens() && (retval != null)) { - runner = retval; - - String next = st.nextToken().trim().toLowerCase(); - - if ("".equals(next)) { - retval = this; - } else { - retval = (runner.nodeMap == null) ? null - : (TransientNode) runner.nodeMap.get(next); - } - - if (retval == null) { - retval = (TransientNode) runner.getNode(next); - } - } - - return retval; - } - - /** - * - * - * @param index ... - * - * @return ... - */ - public INode getSubnodeAt(int index) { - return (nodes == null) ? null : (INode) nodes.elementAt(index); - } - - /** - * - * - * @param n ... - * - * @return ... - */ - public int contains(INode n) { - if ((n == null) || (nodes == null)) { - return -1; - } - - return nodes.indexOf(n); - } - - /** - * - * - * @return ... - */ - public boolean remove() { - if (anonymous) { - parent.unset(name); - } else { - parent.removeNode(this); - } - - return true; - } - - /** - * - * - * @param node ... - */ - public void removeNode(INode node) { - // IServer.getLogger().log ("removing: "+ node); - releaseNode(node); - - TransientNode n = (TransientNode) node; - - if ((n.getParent() == this) && n.anonymous) { - int l = (n.links == null) ? 0 : n.links.size(); // notify nodes that link to n that n is going down. - - for (int i = 0; i < l; i++) { - TransientNode link = (TransientNode) n.links.elementAt(i); - - link.releaseNode(n); - } - - if (n.proplinks != null) { - // clean up all nodes that use n as a property - for (Enumeration e1 = n.proplinks.elements(); e1.hasMoreElements();) - try { - Property p = (Property) e1.nextElement(); - - p.node.propMap.remove(p.propname.toLowerCase()); - } catch (Exception ignore) { - } - } - - // remove all subnodes, giving them a chance to destroy themselves. - Vector v = new Vector(); // removeElement modifies the Vector we are enumerating, so we are extra careful. - - for (Enumeration e3 = n.getSubnodes(); e3.hasMoreElements();) { - v.addElement(e3.nextElement()); - } - - int m = v.size(); - - for (int i = 0; i < m; i++) { - n.removeNode((TransientNode) v.elementAt(i)); - } - } else { - // - n.links.removeElement(this); - } - } - - /** - * "Physically" remove a subnode from the subnodes table. - * the logical stuff necessary for keeping data consistent is done elsewhere (in removeNode). - */ - protected void releaseNode(INode node) { - if ((nodes == null) || (nodeMap == null)) { - - return; - } - - int runner = nodes.indexOf(node); - - // this is due to difference between .equals() and == - while ((runner > -1) && (nodes.elementAt(runner) != node)) - runner = nodes.indexOf(node, Math.min(nodes.size() - 1, runner + 1)); - - if (runner > -1) { - nodes.removeElementAt(runner); - } - - // nodes.remove (node); - nodeMap.remove(node.getName().toLowerCase()); - - // Server.throwNodeEvent (new NodeEvent (node, NodeEvent.NODE_REMOVED)); - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_REMOVED, node)); - lastmodified = System.currentTimeMillis(); - - // IServer.getLogger().log ("released node "+node +" from "+this+" oldobj = "+what); - } - - /** - * - * - * @return ... - */ - public Enumeration getSubnodes() { - return (nodes == null) ? new Vector().elements() : nodes.elements(); - } - - /** - * property-related - */ - public Enumeration properties() { - return (propMap == null) ? new EmptyEnumeration() : propMap.keys(); - } - - private Property getProperty(String propname) { - Property prop = (propMap == null) ? null : (Property) propMap.get(propname); - - // check if we have to create a virtual node - if ((prop == null) && (dbmap != null)) { - Relation rel = dbmap.getPropertyRelation(propname); - - if ((rel != null) && rel.isVirtual()) { - prop = makeVirtualNode(propname, rel); - } - } - - return prop; - } - - private Property makeVirtualNode(String propname, Relation rel) { - INode node = new helma.objectmodel.db.Node(rel.getPropName(), rel.getPrototype(), - dbmap.getWrappedNodeManager()); - - // node.setState (TRANSIENT); - // make a db mapping good enough that the virtual node finds its subnodes - // DbMapping dbm = new DbMapping (); - // dbm.setSubnodeRelation (rel); - // dbm.setPropertyRelation (rel); - node.setDbMapping(rel.getVirtualMapping()); - setNode(propname, node); - - return (Property) propMap.get(propname); - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public IProperty get(String propname) { - propname = propname.toLowerCase(); - - return getProperty(propname); - } - - /** - * - * - * @param propname ... - * @param defaultValue ... - * - * @return ... - */ - public String getString(String propname, String defaultValue) { - String propValue = getString(propname); - - return (propValue == null) ? defaultValue : propValue; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public String getString(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getStringValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public long getInteger(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getIntegerValue(); - } catch (Exception ignore) { - } - - return 0; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public double getFloat(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getFloatValue(); - } catch (Exception ignore) { - } - - return 0.0; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public Date getDate(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getDateValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public boolean getBoolean(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getBooleanValue(); - } catch (Exception ignore) { - } - - return false; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public INode getNode(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getNodeValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public Object getJavaObject(String propname) { - propname = propname.toLowerCase(); - - Property prop = getProperty(propname); - - try { - return prop.getJavaObjectValue(); - } catch (Exception ignore) { - } - - return null; - } - - // create a property if it doesn't exist for this name - private Property initProperty(String propname) { - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - Property prop = (Property) propMap.get(p2); - - if (prop == null) { - prop = new Property(propname, this); - propMap.put(p2, prop); - } - - return prop; - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setString(String propname, String value) { - // IServer.getLogger().log ("setting String prop"); - Property prop = initProperty(propname); - - prop.setStringValue(value); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setInteger(String propname, long value) { - // IServer.getLogger().log ("setting bool prop"); - Property prop = initProperty(propname); - - prop.setIntegerValue(value); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setFloat(String propname, double value) { - // IServer.getLogger().log ("setting bool prop"); - Property prop = initProperty(propname); - - prop.setFloatValue(value); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setBoolean(String propname, boolean value) { - // IServer.getLogger().log ("setting bool prop"); - Property prop = initProperty(propname); - - prop.setBooleanValue(value); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setDate(String propname, Date value) { - // IServer.getLogger().log ("setting date prop"); - Property prop = initProperty(propname); - - prop.setDateValue(value); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setJavaObject(String propname, Object value) { - // IServer.getLogger().log ("setting date prop"); - Property prop = initProperty(propname); - - prop.setJavaObjectValue(value); - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setNode(String propname, INode value) { - // IServer.getLogger().log ("setting date prop"); - Property prop = initProperty(propname); - - prop.setNodeValue(value); - - // check if the main identity of this node is as a named property - // or as an anonymous node in a collection - if (value instanceof TransientNode) { - TransientNode n = (TransientNode) value; - - if (n.parent == null) { - n.name = propname; - n.parent = this; - n.anonymous = false; - } - } - - lastmodified = System.currentTimeMillis(); - } - - /** - * - * - * @param propname ... - */ - public void unset(String propname) { - if (propMap == null) { - return; - } - - try { - propMap.remove(propname.toLowerCase()); - - lastmodified = System.currentTimeMillis(); - } catch (Exception ignore) { - } - } - - /* public String getUrl (INode root, INode users, String tmpname, String rootproto) { - throw new RuntimeException ("HREFs on transient (non-db based) Nodes not supported"); - } */ - public long lastModified() { - return lastmodified; - } - - /** - * - * - * @return ... - */ - public long created() { - return created; - } - - /** - * - * - * @return ... - */ - public String toString() { - return "TransientNode " + name; - } - - /** - * Get the cache node for this node. This can - * be used to store transient cache data per node - * from Javascript. - */ - public synchronized INode getCacheNode() { - if (cacheNode == null) { - cacheNode = new TransientNode(); - } - - return cacheNode; - } - - /** - * Reset the cache node for this node. - */ - public synchronized void clearCacheNode() { - cacheNode = null; - } -} diff --git a/src/helma/objectmodel/db/DbColumn.java b/src/helma/objectmodel/db/DbColumn.java deleted file mode 100644 index f2ce4dfc..00000000 --- a/src/helma/objectmodel/db/DbColumn.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - - -/** - * A class that encapsulates the Column name and data type of a - * column in a relational table. - */ -public final class DbColumn { - private final String name; - private final int type; - private final Relation relation; - - private final boolean isId; - private final boolean isPrototype; - private final boolean isName; - - private final boolean isMapped; - - /** - * Constructor - */ - public DbColumn(String name, int type, Relation rel, DbMapping dbmap) { - this.name = name; - this.type = type; - this.relation = rel; - - if (relation != null) { - relation.setColumnType(type); - } - - isId = name.equalsIgnoreCase(dbmap.getIDField()); - isPrototype = name.equalsIgnoreCase(dbmap.getPrototypeField()); - isName = name.equalsIgnoreCase(dbmap.getNameField()); - - isMapped = relation != null || isId || isPrototype || isName; - } - - /** - * Get the column name. - */ - public String getName() { - return name; - } - - /** - * Get this columns SQL data type. - */ - public int getType() { - return type; - } - - /** - * Return the relation associated with this column. May be null. - */ - public Relation getRelation() { - return relation; - } - - /** - * Returns true if this column serves as ID field for the prototype. - */ - public boolean isIdField() { - return isId; - } - - /** - * Returns true if this column serves as prototype field for the prototype. - */ - public boolean isPrototypeField() { - return isPrototype; - } - - /** - * Returns true if this column serves as name field for the prototype. - */ - public boolean isNameField() { - return isName; - } - - /** - * Returns true if this field is mapped by the prototype's db mapping. - */ - public boolean isMapped() { - return isMapped; - } - -} diff --git a/src/helma/objectmodel/db/DbKey.java b/src/helma/objectmodel/db/DbKey.java deleted file mode 100644 index b8d7ddd1..00000000 --- a/src/helma/objectmodel/db/DbKey.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.io.Serializable; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.IOException; - - -/** - * This is the internal representation of a database key. It is constructed - * from the logical table (type) name and the object's primary key - * within the table. Currently only single keys are supported. - */ -public final class DbKey implements Key, Serializable { - // the name of the prototype which defines the storage of this object. - // this is the name of the object's prototype, or one of its ancestors. - // If null, the object is stored in the embedded db. - private String storageName; - - // the id that defines this key's object within the above storage space - private String id; - - // lazily initialized hashcode - private transient int hashcode = 0; - - static final long serialVersionUID = 1618863960930966588L; - - /** - * make a key for a persistent Object, describing its datasource and id. - */ - public DbKey(DbMapping dbmap, String id) { - this.id = id; - this.storageName = (dbmap == null) ? null : dbmap.getStorageTypeName(); - } - - /** - * - * - * @param what the other key to be compared with this one - * - * @return true if both keys are identical - */ - public boolean equals(Object what) { - if (what == this) { - return true; - } - - if (!(what instanceof DbKey)) { - return false; - } - - DbKey k = (DbKey) what; - - // storageName is an interned string (by DbMapping, from where we got it) - // so we can compare by using == instead of the equals method. - return (storageName == k.storageName) && ((id == k.id) || id.equals(k.id)); - } - - /** - * - * - * @return this key's hash code - */ - public int hashCode() { - if (hashcode == 0) { - hashcode = (storageName == null) ? (17 + (37 * id.hashCode())) - : (17 + (37 * storageName.hashCode()) + - (+37 * id.hashCode())); - } - - return hashcode; - } - - /** - * - * - * @return the key of this key's object's parent object - */ - public Key getParentKey() { - return null; - } - - /** - * - * - * @return the unique storage name for this key's object - */ - public String getStorageName() { - return storageName; - } - - /** - * - * - * @return this key's object's id - */ - public String getID() { - return id; - } - - /** - * - * - * @return a string representation for this key - */ - public String toString() { - return (storageName == null) ? ("[" + id + "]") : (storageName + "[" + id + "]"); - } - - // We implement write/readObject to set storageName - // to the interned version of the string. - - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.writeObject(storageName); - stream.writeObject(id); - } - - private void readObject(ObjectInputStream stream) - throws IOException, ClassNotFoundException { - storageName = (String) stream.readObject(); - id = (String) stream.readObject(); - // if storageName is not null, set it to the interned version - if (storageName != null) { - storageName = storageName.intern(); - } - } - -} diff --git a/src/helma/objectmodel/db/DbMapping.java b/src/helma/objectmodel/db/DbMapping.java deleted file mode 100644 index 1ffc7621..00000000 --- a/src/helma/objectmodel/db/DbMapping.java +++ /dev/null @@ -1,1211 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.framework.core.Application; -import helma.framework.core.Prototype; -import helma.util.SystemProperties; -import helma.util.Updatable; -import java.sql.*; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.StringTokenizer; - -/** - * A DbMapping describes how a certain type of Nodes is to mapped to a - * relational database table. Basically it consists of a set of JavaScript property-to- - * Database row bindings which are represented by instances of the Relation class. - */ -public final class DbMapping implements Updatable { - // DbMappings belong to an application - Application app; - - // prototype name of this mapping - private String typename; - - // properties from where the mapping is read - SystemProperties props; - - // name of data dbSource to which this mapping writes - DbSource dbSource; - - // name of datasource - String dbSourceName; - - // name of db table - String tableName; - - // list of properties to try for parent - ParentInfo[] parentInfo; - - // Relations describing subnodes and properties. - Relation subRelation; - Relation propRelation; - - // if this defines a subnode mapping with groupby layer, - // we need a DbMapping for those groupby nodes - DbMapping groupbyMapping; - - // Map of property names to Relations objects - HashMap prop2db; - - // Map of db columns to Relations objects. - // Case insensitive, keys are stored in upper case so - // lookups must do a toUpperCase(). - HashMap db2prop; - - // list of columns to fetch from db - DbColumn[] columns = null; - - // Map of db columns by name - HashMap columnMap; - - // Array of aggressively loaded references - Relation[] joins; - - // pre-rendered select statement - String selectString = null; - String insertString = null; - String updateString = null; - - // db field used as primary key - private String idField; - - // db field used as object name - String nameField; - - // db field used to identify name of prototype to use for object instantiation - String protoField; - - // name of parent prototype, if any - String extendsProto; - - // dbmapping of parent prototype, if any - DbMapping parentMapping; - - // descriptor for key generation method - private String idgen; - - // remember last key generated for this table - long lastID; - - // timestamp of last modification of the mapping (type.properties) - // init value is -1 so we know we have to run update once even if - // the underlying properties file is non-existent - long lastTypeChange = -1; - - // timestamp of last modification of an object of this type - long lastDataChange; - - /** - * Create an empty DbMapping - */ - public DbMapping(Application app) { - this.app = app; - this.typename = null; - - prop2db = new HashMap(); - db2prop = new HashMap(); - - parentInfo = null; - - idField = null; - } - - /** - * Create a DbMapping from a type.properties property file - */ - public DbMapping(Application app, String typename, SystemProperties props) { - this.app = app; - // create a unique instance of the string. This is useful so - // we can compare types just by using == instead of equals. - this.typename = typename == null ? null : typename.intern(); - - prop2db = new HashMap(); - db2prop = new HashMap(); - - columnMap = new HashMap(); - - parentInfo = null; - - idField = null; - - this.props = props; - } - - /** - * Tell the type manager whether we need update() to be called - */ - public boolean needsUpdate() { - return props.lastModified() != lastTypeChange; - } - - - /** - * Read the mapping from the Properties. Return true if the properties were changed. - * The read is split in two, this method and the rewire method. The reason is that in order - * for rewire to work, all other db mappings must have been initialized and registered. - */ - public synchronized void update() { - // read in properties - tableName = props.getProperty("_table"); - idgen = props.getProperty("_idgen"); - - dbSourceName = props.getProperty("_db"); - - if (dbSourceName != null) { - dbSource = app.getDbSource(dbSourceName); - - if (dbSource == null) { - app.logEvent("*** Data Source for prototype " + typename + - " does not exist: " + dbSourceName); - app.logEvent("*** accessing or storing a " + typename + - " object will cause an error."); - } else if (tableName == null) { - app.logEvent("*** No table name specified for prototype " + typename); - app.logEvent("*** accessing or storing a " + typename + - " object will cause an error."); - - // mark mapping as invalid by nulling the dbSource field - dbSource = null; - } - } - - // if id field is null, we assume "ID" as default. We don't set it - // however, so that if null we check the parent prototype first. - idField = props.getProperty("_id"); - - nameField = props.getProperty("_name"); - - protoField = props.getProperty("_prototype"); - - String parentSpec = props.getProperty("_parent"); - - if (parentSpec != null) { - // comma-separated list of properties to be used as parent - StringTokenizer st = new StringTokenizer(parentSpec, ",;"); - - parentInfo = new ParentInfo[st.countTokens()]; - - for (int i = 0; i < parentInfo.length; i++) - parentInfo[i] = new ParentInfo(st.nextToken().trim()); - } else { - parentInfo = null; - } - - lastTypeChange = props.lastModified(); - - // see if this prototype extends (inherits from) any other prototype - extendsProto = props.getProperty("_extends"); - - if (extendsProto != null) { - parentMapping = app.getDbMapping(extendsProto); - if (parentMapping != null && parentMapping.needsUpdate()) { - parentMapping.update(); - } - } else { - parentMapping = null; - } - - // set the parent prototype in the corresponding Prototype object! - // this was previously done by TypeManager, but we need to do it - // ourself because DbMapping.update() may be called by other code than - // the TypeManager. - if (typename != null && - !"global".equalsIgnoreCase(typename) && - !"hopobject".equalsIgnoreCase(typename)) { - Prototype proto = app.getPrototypeByName(typename); - if (proto != null) { - if (extendsProto != null) { - proto.setParentPrototype(app.getPrototypeByName(extendsProto)); - } else if (!app.isJavaPrototype(typename)) { - proto.setParentPrototype(app.getPrototypeByName("hopobject")); - } - } - } - - // null the cached columns and select string - columns = null; - columnMap.clear(); - selectString = insertString = updateString = null; - - HashMap p2d = new HashMap(); - HashMap d2p = new HashMap(); - ArrayList joinList = new ArrayList(); - - for (Enumeration e = props.keys(); e.hasMoreElements();) { - String propName = (String) e.nextElement(); - - try { - // ignore internal properties (starting with "_") and sub-options (containing a ".") - if (!propName.startsWith("_") && (propName.indexOf(".") < 0)) { - String dbField = props.getProperty(propName); - - // check if a relation for this propery already exists. If so, reuse it - Relation rel = (Relation) prop2db.get(propName.toLowerCase()); - - if (rel == null) { - rel = new Relation(dbField, propName, this, props); - } - - rel.update(dbField, props); - - // key enumerations from SystemProperties are all lower case, which is why - // even though we don't do a toLowerCase() here, - // we have to when we lookup things in p2d later. - p2d.put(propName, rel); - - if ((rel.columnName != null) && - ((rel.reftype == Relation.PRIMITIVE) || - (rel.reftype == Relation.REFERENCE))) { - Relation old = (Relation) d2p.put(rel.columnName.toUpperCase(), rel); - // check if we're overwriting another relation - // if so, primitive relations get precendence to references - if (old != null) { - app.logEvent("*** Duplicate mapping for "+typename+"."+rel.columnName); - if (old.reftype == Relation.PRIMITIVE) { - d2p.put(old.columnName.toUpperCase(), old); - } - } - } - - // check if a reference is aggressively fetched - if ((rel.reftype == Relation.REFERENCE || - rel.reftype == Relation.COMPLEX_REFERENCE) && - rel.aggressiveLoading) { - joinList.add(rel); - } - - // app.logEvent ("Mapping "+propName+" -> "+dbField); - } - } catch (Exception x) { - app.logEvent("Error in type.properties: " + x.getMessage()); - } - } - - prop2db = p2d; - db2prop = d2p; - - joins = new Relation[joinList.size()]; - joins = (Relation[]) joinList.toArray(joins); - - String subnodeMapping = props.getProperty("_children"); - - if (subnodeMapping != null) { - try { - // check if subnode relation already exists. If so, reuse it - if (subRelation == null) { - subRelation = new Relation(subnodeMapping, "_children", this, props); - } - - subRelation.update(subnodeMapping, props); - - // if subnodes are accessed via access name or group name, - // the subnode relation is also the property relation. - if ((subRelation.accessName != null) || (subRelation.groupby != null)) { - propRelation = subRelation; - } else { - propRelation = null; - } - } catch (Exception x) { - app.logEvent("Error reading _subnodes relation for " + typename + ": " + - x.getMessage()); - - // subRelation = null; - } - } else { - subRelation = propRelation = null; - } - - if (groupbyMapping != null) { - initGroupbyMapping(); - groupbyMapping.lastTypeChange = this.lastTypeChange; - } - } - - /** - * Method in interface Updatable. - */ - public void remove() { - // do nothing, removing of type properties is not implemented. - } - - /** - * Get a JDBC connection for this DbMapping. - */ - public Connection getConnection() throws ClassNotFoundException, SQLException { - if (dbSourceName == null) { - if (parentMapping != null) { - return parentMapping.getConnection(); - } else { - throw new SQLException("Tried to get Connection from non-relational embedded data source."); - } - } - - if (tableName == null) { - throw new SQLException("Invalid DbMapping, _table not specified: " + this); - } - - // if dbSource was previously not available, check again - if (dbSource == null) { - dbSource = app.getDbSource(dbSourceName); - } - - if (dbSource == null) { - throw new SQLException("Datasource is not defined: " + dbSourceName + "."); - } - - return dbSource.getConnection(); - } - - /** - * Get the DbSource object for this DbMapping. The DbSource describes a JDBC - * data source including URL, JDBC driver, username and password. - */ - public DbSource getDbSource() { - if (dbSource == null) { - if ((tableName != null) && (dbSourceName != null)) { - dbSource = app.getDbSource(dbSourceName); - } else if (parentMapping != null) { - return parentMapping.getDbSource(); - } - } - - return dbSource; - } - - /** - * Get the table name used for this type mapping. - */ - public String getTableName() { - if ((tableName == null) && (parentMapping != null)) { - return parentMapping.getTableName(); - } - - return tableName; - } - - /** - * Get the application this DbMapping belongs to. - */ - public Application getApplication() { - return app; - } - - /** - * Get the name of this mapping's application - */ - public String getAppName() { - return app.getName(); - } - - /** - * Get the name of the object type this DbMapping belongs to. - */ - public String getTypeName() { - return typename; - } - - /** - * Get the name of this type's parent type, if any. - */ - public String getExtends() { - return extendsProto; - } - - /** - * Get the primary key column name for objects using this mapping. - */ - public String getIDField() { - if ((idField == null) && (parentMapping != null)) { - return parentMapping.getIDField(); - } - - return (idField == null) ? "ID" : idField; - } - - /** - * Get the column used for (internal) names of objects of this type. - */ - public String getNameField() { - if ((nameField == null) && (parentMapping != null)) { - return parentMapping.getNameField(); - } - - return nameField; - } - - /** - * Get the column used for names of prototype. - */ - public String getPrototypeField() { - if ((protoField == null) && (parentMapping != null)) { - return parentMapping.getPrototypeField(); - } - - return protoField; - } - - /** - * Translate a database column name to an object property name according to this mapping. - */ - public String columnNameToProperty(String columnName) { - if (columnName == null) { - return null; - } - - return _columnNameToProperty(columnName.toUpperCase()); - } - - private String _columnNameToProperty(final String columnName) { - Relation rel = (Relation) db2prop.get(columnName); - - if ((rel == null) && (parentMapping != null)) { - return parentMapping._columnNameToProperty(columnName); - } - - if ((rel != null) && - ((rel.reftype == Relation.PRIMITIVE) || - (rel.reftype == Relation.REFERENCE))) { - return rel.propName; - } - - return null; - } - - /** - * Translate an object property name to a database column name according to this mapping. - */ - public String propertyToColumnName(String propName) { - if (propName == null) { - return null; - } - - // FIXME: prop2db stores keys in lower case, because it gets them - // from a SystemProperties object which converts keys to lower case. - return _propertyToColumnName(propName.toLowerCase()); - } - - private String _propertyToColumnName(final String propName) { - Relation rel = (Relation) prop2db.get(propName); - - if ((rel == null) && (parentMapping != null)) { - return parentMapping._propertyToColumnName(propName); - } - - if ((rel != null) && - ((rel.reftype == Relation.PRIMITIVE) || - (rel.reftype == Relation.REFERENCE))) { - return rel.columnName; - } - - return null; - } - - /** - * Translate a database column name to an object property name according to this mapping. - */ - public Relation columnNameToRelation(String columnName) { - if (columnName == null) { - return null; - } - - return _columnNameToRelation(columnName.toUpperCase()); - } - - private Relation _columnNameToRelation(final String columnName) { - Relation rel = (Relation) db2prop.get(columnName); - - if ((rel == null) && (parentMapping != null)) { - return parentMapping._columnNameToRelation(columnName); - } - - return rel; - } - - /** - * Translate an object property name to a database column name according to this mapping. - */ - public Relation propertyToRelation(String propName) { - if (propName == null) { - return null; - } - - // FIXME: prop2db stores keys in lower case, because it gets them - // from a SystemProperties object which converts keys to lower case. - return _propertyToRelation(propName.toLowerCase()); - } - - private Relation _propertyToRelation(String propName) { - Relation rel = (Relation) prop2db.get(propName); - - if ((rel == null) && (parentMapping != null)) { - return parentMapping._propertyToRelation(propName); - } - - return rel; - } - - /** - * This returns the parent info array, which tells an object of this type how to - * determine its parent object. - */ - public synchronized ParentInfo[] getParentInfo() { - if ((parentInfo == null) && (parentMapping != null)) { - return parentMapping.getParentInfo(); - } - - return parentInfo; - } - - /** - * - * - * @return ... - */ - public DbMapping getSubnodeMapping() { - if (subRelation != null) { - return subRelation.otherType; - } - - if (parentMapping != null) { - return parentMapping.getSubnodeMapping(); - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public DbMapping getExactPropertyMapping(String propname) { - Relation rel = getExactPropertyRelation(propname); - - return (rel != null) ? rel.otherType : null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public DbMapping getPropertyMapping(String propname) { - Relation rel = getPropertyRelation(propname); - - if (rel != null) { - // if this is a virtual node, it doesn't have a dbmapping - if (rel.virtual && (rel.prototype == null)) { - return null; - } else { - return rel.otherType; - } - } - - return null; - } - - /** - * If subnodes are grouped by one of their properties, return the - * db-mapping with the right relations to create the group-by nodes - */ - public synchronized DbMapping getGroupbyMapping() { - if ((subRelation == null) || (subRelation.groupby == null)) { - return null; - } - - if (groupbyMapping == null) { - initGroupbyMapping(); - } - - return groupbyMapping; - } - - /** - * Initialize the dbmapping used for group-by nodes. - */ - private void initGroupbyMapping() { - // if a prototype is defined for groupby nodes, use that - // if mapping doesn' exist or isn't defined, create a new (anonymous internal) one - groupbyMapping = new DbMapping(app); - - // If a mapping is defined, make the internal mapping inherit from - // the defined named prototype. - if (subRelation.groupbyPrototype != null) { - groupbyMapping.parentMapping = app.getDbMapping(subRelation.groupbyPrototype); - } - - groupbyMapping.subRelation = subRelation.getGroupbySubnodeRelation(); - - if (propRelation != null) { - groupbyMapping.propRelation = propRelation.getGroupbyPropertyRelation(); - } else { - groupbyMapping.propRelation = subRelation.getGroupbyPropertyRelation(); - } - - groupbyMapping.typename = subRelation.groupbyPrototype; - } - - /** - * - * - * @param rel ... - */ - public void setPropertyRelation(Relation rel) { - propRelation = rel; - } - - /** - * - * - * @return ... - */ - public Relation getSubnodeRelation() { - if ((subRelation == null) && (parentMapping != null)) { - return parentMapping.getSubnodeRelation(); - } - - return subRelation; - } - - /** - * - * - * @return ... - */ - public Relation getPropertyRelation() { - if ((propRelation == null) && (parentMapping != null)) { - return parentMapping.getPropertyRelation(); - } - - return propRelation; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public Relation getPropertyRelation(String propname) { - if (propname == null) { - return getPropertyRelation(); - } - - // first try finding an exact match for the property name - Relation rel = getExactPropertyRelation(propname); - - // if not defined, return the generic property mapping - if (rel == null) { - rel = getPropertyRelation(); - } - - return rel; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public Relation getExactPropertyRelation(String propname) { - if (propname == null) { - return null; - } - - Relation rel = (Relation) prop2db.get(propname.toLowerCase()); - - if ((rel == null) && (parentMapping != null)) { - rel = parentMapping.getExactPropertyRelation(propname); - } - - return rel; - } - - /** - * - * - * @return ... - */ - public String getSubnodeGroupby() { - if ((subRelation == null) && (parentMapping != null)) { - return parentMapping.getSubnodeGroupby(); - } - - return (subRelation == null) ? null : subRelation.groupby; - } - - /** - * - * - * @return ... - */ - public String getIDgen() { - if ((idgen == null) && (parentMapping != null)) { - return parentMapping.getIDgen(); - } - - return idgen; - } - - /** - * - * - * @return ... - */ - public WrappedNodeManager getWrappedNodeManager() { - if (app == null) { - throw new RuntimeException("Can't get node manager from internal db mapping"); - } - - return app.getWrappedNodeManager(); - } - - /** - * Tell whether this data mapping maps to a relational database table. This returns true - * if a datasource is specified, even if it is not a valid one. Otherwise, objects with invalid - * mappings would be stored in the embedded db instead of an error being thrown, which is - * not what we want. - */ - public boolean isRelational() { - if (dbSourceName != null) { - return true; - } - - if (parentMapping != null) { - return parentMapping.isRelational(); - } - - return false; - } - - /** - * Return an array of DbColumns for the relational table mapped by this DbMapping. - */ - public synchronized DbColumn[] getColumns() - throws ClassNotFoundException, SQLException { - if (!isRelational()) { - throw new SQLException("Can't get columns for non-relational data mapping " + - this); - } - - if ((dbSource == null) && (parentMapping != null)) { - return parentMapping.getColumns(); - } - - // Use local variable cols to avoid synchronization (schema may be nulled elsewhere) - if (columns == null) { - // we do two things here: set the SQL type on the Relation mappings - // and build a string of column names. - Connection con = getConnection(); - Statement stmt = con.createStatement(); - String t = getTableName(); - - if (t == null) { - throw new SQLException("Table name is null in getColumns() for " + this); - } - - ResultSet rs = stmt.executeQuery(new StringBuffer("SELECT * FROM ").append(t) - .append(" WHERE 1 = 0") - .toString()); - - if (rs == null) { - throw new SQLException("Error retrieving columns for " + this); - } - - ResultSetMetaData meta = rs.getMetaData(); - - // ok, we have the meta data, now loop through mapping... - int ncols = meta.getColumnCount(); - ArrayList list = new ArrayList(ncols); - - for (int i = 0; i < ncols; i++) { - String colName = meta.getColumnName(i + 1); - Relation rel = columnNameToRelation(colName); - - DbColumn col = new DbColumn(colName, meta.getColumnType(i + 1), rel, this); - // if (col.isMapped()) { - list.add(col); - // } - } - columns = new DbColumn[list.size()]; - columns = (DbColumn[]) list.toArray(columns); - } - - return columns; - } - - /** - * Return the array of relations that are fetched with objects of this type. - */ - public Relation[] getJoins() { - return joins; - } - - /** - * - * - * @param columnName ... - * - * @return ... - * - * @throws ClassNotFoundException ... - * @throws SQLException ... - */ - public DbColumn getColumn(String columnName) - throws ClassNotFoundException, SQLException { - - DbColumn col = (DbColumn) columnMap.get(columnName); - - if (col == null) { - DbColumn[] cols = columns; - - if (cols == null) { - cols = getColumns(); - } - - for (int i = 0; i < cols.length; i++) { - if (columnName.equalsIgnoreCase(cols[i].getName())) { - col = cols[i]; - - break; - } - } - - columnMap.put(columnName, col); - } - - return col; - } - - /** - * Get a StringBuffer initialized to the first part of the select statement - * for objects defined by this DbMapping - * - * @return the StringBuffer containing the first part of the select query - * - * @throws SQLException if the table meta data could not be retrieved - * @throws ClassNotFoundException if the JDBC driver class was not found - */ - public StringBuffer getSelect() throws SQLException, ClassNotFoundException { - String sel = selectString; - - if (sel != null) { - return new StringBuffer(sel); - } - - StringBuffer s = new StringBuffer("SELECT "); - - /* DbColumn[] cols = columns; - - if (cols == null) { - cols = getColumns(); - } - - for (int i = 0; i < cols.length; i++) { - s.append(cols[i].getName()); - if (i < cols.length-1) { - s.append(','); - } - } - - for (int i = 0; i < joins.length; i++) { - } */ - - s.append ("*"); - - s.append(" FROM "); - - s.append(getTableName()); - s.append(" "); - - for (int i = 0; i < joins.length; i++) { - if (!joins[i].otherType.isRelational()) { - continue; - } - s.append("LEFT JOIN "); - s.append(joins[i].otherType.getTableName()); - s.append(" AS _HLM_"); - s.append(joins[i].propName); - s.append(" ON "); - joins[i].renderJoinConstraints(s); - } - - // cache rendered string for later calls. - selectString = s.toString(); - - return s; - } - - /** - * - * - * @return ... - */ - public StringBuffer getInsert() { - String ins = insertString; - - if (ins != null) { - return new StringBuffer(ins); - } - - StringBuffer s = new StringBuffer("INSERT INTO "); - - s.append(getTableName()); - s.append(" ( "); - s.append(getIDField()); - - // cache rendered string for later calls. - insertString = s.toString(); - - return s; - } - - /** - * - * - * @return ... - */ - public StringBuffer getUpdate() { - String upd = updateString; - - if (upd != null) { - return new StringBuffer(upd); - } - - StringBuffer s = new StringBuffer("UPDATE "); - - s.append(getTableName()); - s.append(" SET "); - - // cache rendered string for later calls. - updateString = s.toString(); - - return s; - } - - /** - * Return true if values for the column identified by the parameter need - * to be quoted in SQL queries. - */ - public boolean needsQuotes(String columnName) throws SQLException { - if ((tableName == null) && (parentMapping != null)) { - return parentMapping.needsQuotes(columnName); - } - - try { - DbColumn col = getColumn(columnName); - - // This is not a mapped column. In case of doubt, add quotes. - if (col == null) { - return true; - } - - switch (col.getType()) { - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: - return true; - - default: - return false; - } - } catch (Exception x) { - throw new SQLException(x.getMessage()); - } - } - - /** - * - * - * @return ... - */ - public String toString() { - if (typename == null) { - return "[unspecified internal DbMapping]"; - } else { - return ("[" + app.getName() + "." + typename + "]"); - } - } - - /** - * - * - * @return ... - */ - public long getLastTypeChange() { - return lastTypeChange; - } - - /** - * - * - * @return ... - */ - public long getLastDataChange() { - return lastDataChange; - } - - /** - * - */ - public void notifyDataChange() { - lastDataChange = System.currentTimeMillis(); - - if ((parentMapping != null) && (dbSource == null)) { - parentMapping.notifyDataChange(); - } - } - - /** - * - * - * @param dbmax ... - * - * @return ... - */ - public synchronized long getNewID(long dbmax) { - if ((parentMapping != null) && (dbSource == null)) { - return parentMapping.getNewID(dbmax); - } - - lastID = Math.max(dbmax + 1, lastID + 1); - - return lastID; - } - - /** - * - * - * @return ... - */ - public Enumeration getPropertyEnumeration() { - HashSet set = new HashSet(); - - collectPropertyNames(set); - - final Iterator it = set.iterator(); - - return new Enumeration() { - public boolean hasMoreElements() { - return it.hasNext(); - } - - public Object nextElement() { - return it.next(); - } - }; - } - - private void collectPropertyNames(HashSet basket) { - // fetch propnames from parent mapping first, than add our own. - if (parentMapping != null) { - parentMapping.collectPropertyNames(basket); - } - - if (!prop2db.isEmpty()) { - basket.addAll(prop2db.keySet()); - } - } - - /** - * Return the name of the prototype which specifies the storage location - * (dbsource + tablename) for this type, or null if it is stored in the embedded - * db. - */ - public String getStorageTypeName() { - if ((tableName == null) && (parentMapping != null)) { - return parentMapping.getStorageTypeName(); - } - - return (dbSourceName == null) ? null : typename; - } - - /** - * Tell if another DbMapping is storage-compatible to this one, i.e. it is stored in the same table or - * embedded database. - */ - public boolean isStorageCompatible(DbMapping other) { - if (other == null) { - return !isRelational(); - } - - if (isRelational()) { - return getTableName().equals(other.getTableName()) && - getDbSource().equals(other.getDbSource()); - } - - return !other.isRelational(); - } - - /** - * Return true if this db mapping represents the prototype indicated - * by the string argument, either itself or via one of its parent prototypes. - */ - public boolean isInstanceOf(String other) { - if ((typename != null) && typename.equals(other)) { - return true; - } - - DbMapping p = parentMapping; - - while (p != null) { - if ((p.typename != null) && p.typename.equals(other)) { - return true; - } - - p = p.parentMapping; - } - - return false; - } - - /** - * - * - * @return ... - */ - public DbMapping getParentMapping() { - return parentMapping; - } - - /** - * - * - * @return ... - */ - public SystemProperties getProperties() { - return props; - } -} diff --git a/src/helma/objectmodel/db/DbSource.java b/src/helma/objectmodel/db/DbSource.java deleted file mode 100644 index b5a2a627..00000000 --- a/src/helma/objectmodel/db/DbSource.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.util.SystemProperties; -import java.sql.*; -import java.util.Hashtable; - -/** - * This class describes a releational data source (URL, driver, user and password). - */ -public class DbSource { - private static SystemProperties defaultProps = null; - private String name; - private SystemProperties props; - protected String url; - private String driver; - protected String user; - private String password; - private long lastRead = 0L; - - /** - * Creates a new DbSource object. - * - * @param name ... - * @param props ... - * - * @throws ClassNotFoundException ... - */ - public DbSource(String name, SystemProperties props) - throws ClassNotFoundException { - this.name = name; - this.props = props; - init(); - } - - /** - * - * - * @return ... - * - * @throws ClassNotFoundException ... - * @throws SQLException ... - */ - public Connection getConnection() throws ClassNotFoundException, SQLException { - Transactor tx = (Transactor) Thread.currentThread(); - Connection con = tx.getConnection(this); - boolean fileUpdated = props.lastModified() > lastRead; - - if (!fileUpdated && (defaultProps != null)) { - fileUpdated = defaultProps.lastModified() > lastRead; - } - - if ((con == null) || con.isClosed() || fileUpdated) { - init(); - Class.forName(driver); - con = DriverManager.getConnection(url, user, password); - - // If we wanted to use SQL transactions, we'd set autoCommit to - // false here and make commit/rollback invocations in Transactor methods; - // System.err.println ("Created new Connection to "+url); - tx.registerConnection(this, con); - } - - return con; - } - - private void init() throws ClassNotFoundException { - lastRead = (defaultProps == null) ? props.lastModified() - : Math.max(props.lastModified(), - defaultProps.lastModified()); - url = props.getProperty(name + ".url"); - driver = props.getProperty(name + ".driver"); - Class.forName(driver); - user = props.getProperty(name + ".user"); - password = props.getProperty(name + ".password"); - } - - /** - * - * - * @return ... - */ - public String getDriverName() { - return driver; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @param props ... - */ - public static void setDefaultProps(SystemProperties props) { - defaultProps = props; - } -} diff --git a/src/helma/objectmodel/db/ExternalizableVector.java b/src/helma/objectmodel/db/ExternalizableVector.java deleted file mode 100644 index 04e1bbe9..00000000 --- a/src/helma/objectmodel/db/ExternalizableVector.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.io.*; -import java.util.ArrayList; - -/** - * A subclass of Vector that implements the Externalizable interface in order - * to be able to control how it is serialized and deserialized. - */ -public class ExternalizableVector extends ArrayList implements Externalizable { - static final long serialVersionUID = 2316243615310540423L; - - /** - * - * - * @param in ... - * - * @throws IOException ... - */ - public synchronized void readExternal(ObjectInput in) - throws IOException { - try { - int size = in.readInt(); - - for (int i = 0; i < size; i++) - add(in.readObject()); - } catch (ClassNotFoundException x) { - throw new IOException(x.toString()); - } - } - - /** - * - * - * @param out ... - * - * @throws IOException ... - */ - public synchronized void writeExternal(ObjectOutput out) - throws IOException { - int size = size(); - - out.writeInt(size); - - for (int i = 0; i < size; i++) - out.writeObject(get(i)); - } -} diff --git a/src/helma/objectmodel/db/IDGenerator.java b/src/helma/objectmodel/db/IDGenerator.java deleted file mode 100644 index 68fd7006..00000000 --- a/src/helma/objectmodel/db/IDGenerator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.io.Serializable; - -/** - * An object that generates IDs (Strings) that are unique across the whole system. - * It does this keeping a simple long value which is incremented for each new ID. - * This is the key generation for nodes stored in the internal database, but it can - * also be used for relational nodes if no other mechanism is available. (Sequences - * in Oracle are supported, while auto-IDs are not, since the HOP has to know - * the keys of new objects.) - */ -public final class IDGenerator implements Serializable { - static final long serialVersionUID = 753408631669789263L; - private long counter; - transient volatile boolean dirty; - - /** - * Builds a new IDGenerator starting with 0. - */ - public IDGenerator() { - this.counter = 0L; - dirty = false; - } - - /** - * Builds a new IDGenerator starting with value. - */ - public IDGenerator(long value) { - this.counter = value; - dirty = false; - } - - /** - * Delivers a unique id and increases counter by 1. - */ - public synchronized String newID() { - counter += 1L; - dirty = true; - - return Long.toString(counter); - } - - /** - * Set the counter to a new value - */ - protected synchronized void setValue(long value) { - counter = value; - dirty = true; - } - - /** - * Get the current counter value - */ - public long getValue() { - return counter; - } - - /** - * - * - * @return ... - */ - public String toString() { - return "helma.objectmodel.db.IDGenerator[counter=" + counter + ",dirty=" + dirty + - "]"; - } -} diff --git a/src/helma/objectmodel/db/IReplicationListener.java b/src/helma/objectmodel/db/IReplicationListener.java deleted file mode 100644 index 55e0ee58..00000000 --- a/src/helma/objectmodel/db/IReplicationListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.rmi.*; -import java.util.Vector; - -/** - * RMI interface for an application. Currently only execute is used and supported. - */ -public interface IReplicationListener extends Remote { - /** - * Update HopObjects in this application's cache. This is used to replicate - * application caches in a distributed app environment - */ - public void replicateCache(Vector add, Vector delete) - throws RemoteException; -} diff --git a/src/helma/objectmodel/db/Key.java b/src/helma/objectmodel/db/Key.java deleted file mode 100644 index 185eadf4..00000000 --- a/src/helma/objectmodel/db/Key.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - - -/** - * This is the interface for the internal representation of an object key. - * - */ -public interface Key { - - /** - * Get the key's parent key - * - * @return ... - */ - public Key getParentKey(); - - /** - * Get the key's ID part - * - * @return ... - */ - public String getID(); - - /** - * Get the key's storage id - * - * @return ... - */ - public String getStorageName(); - -} diff --git a/src/helma/objectmodel/db/MultiKey.java b/src/helma/objectmodel/db/MultiKey.java deleted file mode 100644 index aece2c58..00000000 --- a/src/helma/objectmodel/db/MultiKey.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.io.Serializable; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.IOException; -import java.util.Map; - -/** - * This is the internal representation of a database key with multiple - * columns. It is constructed from the logical table (type) name and the - * column name/column value pairs that identify the key's object - * - * NOTE: This class doesn't fully support the Key interface - getID always - * returns null since there is no unique key (at least we don't know about it). - */ -public final class MultiKey implements Key, Serializable { - // the name of the prototype which defines the storage of this object. - // this is the name of the object's prototype, or one of its ancestors. - // If null, the object is stored in the embedded db. - private String storageName; - - // the id that defines this key's object within the above storage space - private Map parts; - - // lazily initialized hashcode - private transient int hashcode = 0; - - static final long serialVersionUID = -9173409137561990089L; - - - /** - * make a key for a persistent Object, describing its datasource and key parts. - */ - public MultiKey(DbMapping dbmap, Map parts) { - this.parts = parts; - this.storageName = (dbmap == null) ? null : dbmap.getStorageTypeName(); - } - - /** - * - * - * @param what the other key to be compared with this one - * - * @return true if both keys are identical - */ - public boolean equals(Object what) { - if (what == this) { - return true; - } - - if (!(what instanceof MultiKey)) { - return false; - } - - MultiKey k = (MultiKey) what; - - // storageName is an interned string (by DbMapping, from where we got it) - // so we can compare by using == instead of the equals method. - return (storageName == k.storageName) && - ((parts == k.parts) || parts.equals(k.parts)); - } - - /** - * - * - * @return this key's hash code - */ - public int hashCode() { - if (hashcode == 0) { - hashcode = (storageName == null) ? (17 + (37 * parts.hashCode())) - : (17 + (37 * storageName.hashCode()) + - (+37 * parts.hashCode())); - } - - return hashcode; - } - - /** - * - * - * @return the key of this key's object's parent object - */ - public Key getParentKey() { - return null; - } - - /** - * - * - * @return the unique storage name for this key's object - */ - public String getStorageName() { - return storageName; - } - - /** - * - * - * @return this key's object's id - */ - public String getID() { - return null; - } - - /** - * - * - * @return a string representation for this key - */ - public String toString() { - return (storageName == null) ? ("[" + parts + "]") : (storageName + "[" + parts + "]"); - } - - // We implement write/readObject to set storageName - // to the interned version of the string. - - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.writeObject(storageName); - stream.writeObject(parts); - } - - private void readObject(ObjectInputStream stream) - throws IOException, ClassNotFoundException { - storageName = (String) stream.readObject(); - parts = (Map) stream.readObject(); - // if storageName is not null, set it to the interned version - if (storageName != null) { - storageName = storageName.intern(); - } - } - -} diff --git a/src/helma/objectmodel/db/Node.java b/src/helma/objectmodel/db/Node.java deleted file mode 100644 index 18135794..00000000 --- a/src/helma/objectmodel/db/Node.java +++ /dev/null @@ -1,2469 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.framework.IPathElement; -import helma.objectmodel.*; -import helma.util.*; -import java.io.*; -import java.math.BigDecimal; -import java.sql.*; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * An implementation of INode that can be stored in the internal database or - * an external relational database. - */ -public final class Node implements INode, Serializable { - static final long serialVersionUID = -3740339688506633675L; - - // The handle to the node's parent - protected NodeHandle parentHandle; - - // Ordered list of subnodes of this node - private List subnodes; - - // Named subnodes (properties) of this node - private Hashtable propMap; - - // Other nodes that link to this node. Used for reference counting/checking - private List links; - protected long created; - protected long lastmodified; - private String id; - private String name; - - // is this node's main identity as a named property or an - // anonymous node in a subnode collection? - protected boolean anonymous = false; - - // the serialization version this object was read from (see readObject()) - protected short version = 0; - private transient String prototype; - private transient NodeHandle handle; - private transient INode cacheNode; - transient WrappedNodeManager nmgr; - transient DbMapping dbmap; - transient Key primaryKey = null; - transient String subnodeRelation = null; - transient long lastSubnodeFetch = 0; - transient long lastSubnodeChange = 0; - transient long lastNameCheck = 0; - transient long lastParentSet = 0; - transient long lastSubnodeCount = 0; // these two are only used - transient int subnodeCount = -1; // for aggressive loading relational subnodes - transient private volatile Transactor lock; - transient private int state; - - /** - * This constructor is only used for NullNode instance. Do not use for ordinary Nodes. - */ - Node() { - created = lastmodified = System.currentTimeMillis(); - nmgr = null; - } - - /** - * Creates a new Node with the given name. Only used by NodeManager for "root nodes" and - * not in a Transaction context, which is why we can immediately mark it as CLEAN. - * ADD: used by wrapped database to re-create an existing Node. - */ - public Node(String name, String id, String prototype, WrappedNodeManager nmgr) { - this.nmgr = nmgr; - this.id = id; - this.name = ((name == null) || "".equals(name)) ? id : name; - - if (prototype != null) { - setPrototype(prototype); - } - - created = lastmodified = System.currentTimeMillis(); - markAs(CLEAN); - } - - /** - * Constructor used to create a Node with a given name from a wrapped database. - */ - public Node(String name, String id, String prototype, WrappedNodeManager nmgr, - long created, long lastmodified) { - this(name, id, prototype, nmgr); - this.created = created; - this.lastmodified = lastmodified; - } - - /** - * Constructor used for virtual nodes. - */ - public Node(Node home, String propname, WrappedNodeManager nmgr, String prototype) { - this.nmgr = nmgr; - setParent(home); - - // this.dbmap = null; - // generate a key for the virtual node that can't be mistaken for a Database Key - primaryKey = new SyntheticKey(home.getKey(), propname); - this.id = primaryKey.getID(); - this.name = propname; - this.anonymous = false; - setPrototype(prototype); - this.state = VIRTUAL; - } - - /** - * Creates a new Node with the given name. This is used for ordinary transient nodes. - */ - public Node(String n, String prototype, WrappedNodeManager nmgr) { - this.nmgr = nmgr; - this.prototype = prototype; - dbmap = nmgr.getDbMapping(prototype); - - // the id is only generated when the node is actually checked into db, - // or when it's explicitly requested. - id = null; - this.name = (n == null) ? "" : n; - created = lastmodified = System.currentTimeMillis(); - state = TRANSIENT; - } - - /** - * Initializer used for nodes being stored in a relational database table. - */ - public void init(DbMapping dbm, String id, String name, String protoName, - Hashtable propMap, WrappedNodeManager nmgr) { - this.nmgr = nmgr; - - // see what prototype/DbMapping this object should use - this.dbmap = dbm; - // set the prototype name - this.prototype = protoName; - - this.id = id; - - this.name = name; - // If name was not set from resultset, create a synthetical name now. - if ((name == null) || (name.length() == 0)) { - this.name = dbmap.getTypeName() + " " + id; - } - - this.propMap = propMap; - - // set lastmodified and created timestamps and mark as clean - created = lastmodified = System.currentTimeMillis(); - markAs(CLEAN); - } - - /** - * Read this object instance from a stream. This does some smart conversion to - * update from previous serialization formats. - */ - private void readObject(ObjectInputStream in) throws IOException { - try { - // as a general rule of thumb, if a string can be null use read/writeObject, - // if not it's save to use read/writeUTF. - // version indicates the serialization version - version = in.readShort(); - - String rawParentID = null; - - if (version < 9) { - throw new IOException("Can't read pre 1.3.0 HopObject"); - } - - id = (String) in.readObject(); - name = (String) in.readObject(); - state = in.readInt(); - parentHandle = (NodeHandle) in.readObject(); - created = in.readLong(); - lastmodified = in.readLong(); - - subnodes = (ExternalizableVector) in.readObject(); - links = (ExternalizableVector) in.readObject(); - propMap = (Hashtable) in.readObject(); - anonymous = in.readBoolean(); - prototype = (String) in.readObject(); - - } catch (ClassNotFoundException x) { - throw new IOException(x.toString()); - } - } - - /** - * Write out this instance to a stream - */ - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeShort(9); // serialization version - out.writeObject(id); - out.writeObject(name); - out.writeInt(state); - out.writeObject(parentHandle); - out.writeLong(created); - out.writeLong(lastmodified); - - DbMapping smap = (dbmap == null) ? null : dbmap.getSubnodeMapping(); - - if ((smap != null) && smap.isRelational()) { - out.writeObject(null); - } else { - out.writeObject(subnodes); - } - - out.writeObject(links); - out.writeObject(propMap); - out.writeBoolean(anonymous); - out.writeObject(prototype); - } - - /** - * used by Xml deserialization - */ - public void setPropMap(Hashtable propMap) { - this.propMap = propMap; - } - - /** - * used by Xml deserialization - */ - public void setSubnodes(List subnodes) { - this.subnodes = subnodes; - } - - protected synchronized void checkWriteLock() { - // System.err.println ("registering writelock for "+this.getName ()+" ("+lock+") to "+Thread.currentThread ()); - if (state == TRANSIENT) { - return; // no need to lock transient node - } - - Transactor current = (Transactor) Thread.currentThread(); - - if (!current.isActive()) { - throw new helma.framework.TimeoutException(); - } - - if (state == INVALID) { - nmgr.logEvent("Got Invalid Node: " + this); - Thread.dumpStack(); - throw new ConcurrencyException("Node " + this + - " was invalidated by another thread."); - } - - if ((lock != null) && (lock != current) && lock.isAlive() && lock.isActive()) { - nmgr.logEvent("Concurrency conflict for " + this + ", lock held by " + lock); - throw new ConcurrencyException("Tried to modify " + this + - " from two threads at the same time."); - } - - current.visitNode(this); - lock = current; - } - - protected synchronized void clearWriteLock() { - lock = null; - } - - protected void markAs(int s) { - if ((state == INVALID) || (state == VIRTUAL) || (state == TRANSIENT)) { - return; - } - - state = s; - - if (Thread.currentThread() instanceof Transactor) { - Transactor tx = (Transactor) Thread.currentThread(); - - if (s == CLEAN) { - clearWriteLock(); - tx.dropNode(this); - } else { - tx.visitNode(this); - - if (s == NEW) { - clearWriteLock(); - tx.visitCleanNode(this); - } - } - } - } - - /** - * - * - * @return ... - */ - public int getState() { - return state; - } - - /** - * - * - * @param s ... - */ - public void setState(int s) { - this.state = s; - } - - /** - * Mark node as invalid so it is re-fetched from the database - */ - public void invalidate() { - // This doesn't make sense for transient nodes - if ((state == TRANSIENT) || (state == NEW)) { - return; - } - - checkWriteLock(); - nmgr.evictNode(this); - } - - /** - * Check for a child mapping and evict the object specified by key from the cache - */ - public void invalidateNode(String key) { - // This doesn't make sense for transient nodes - if ((state == TRANSIENT) || (state == NEW)) { - return; - } - - Relation rel = getDbMapping().getSubnodeRelation(); - - if (rel != null) { - if (rel.usesPrimaryKey()) { - nmgr.evictNodeByKey(new DbKey(getDbMapping().getSubnodeMapping(), key)); - } else { - nmgr.evictNodeByKey(new SyntheticKey(getKey(), key)); - } - } - } - - /** - * Get the ID of this Node. This is the primary database key and used as part of the - * key for the internal node cache. - */ - public String getID() { - // if we are transient, we generate an id on demand. It's possible that we'll never need - // it, but if we do it's important to keep the one we have. - if ((state == TRANSIENT) && (id == null)) { - id = TransientNode.generateID(); - } - - return id; - } - - /** - * Returns true if this node is accessed by id from its aprent, false if it - * is accessed by name - */ - public boolean isAnonymous() { - return anonymous; - } - - /** - * Return this node' name, which may or may not have some meaning - */ - public String getName() { - return name; - } - - /** - * Get something to identify this node within a URL. This is the ID for anonymous nodes - * and a property value for named properties. - */ - public String getElementName() { - // if subnodes are also mounted as properties, try to get the "nice" prop value - // instead of the id by turning the anonymous flag off. - long lastmod = Math.max(dbmap.getLastTypeChange(), lastmodified); - if ((parentHandle != null) && (lastNameCheck < lastmod)) { - try { - Node p = parentHandle.getNode(nmgr); - DbMapping parentmap = p.getDbMapping(); - Relation prel = parentmap.getPropertyRelation(); - - if ((prel != null) && prel.hasAccessName()) { - String propname = dbmap.columnNameToProperty(prel.accessName); - String propvalue = getString(propname); - - if ((propvalue != null) && (propvalue.length() > 0)) { - setName(propvalue); - anonymous = false; - - // nameProp = localrel.propName; - } else if (!anonymous && (p.contains(this) > -1)) { - anonymous = true; - } - } else if (!anonymous && (p.contains(this) > -1)) { - anonymous = true; - } - } catch (Exception ignore) { - // FIXME: add proper NullPointer checks in try statement - // just fall back to default method - } - - lastNameCheck = System.currentTimeMillis(); - } - - return (anonymous || (name == null) || (name.length() == 0)) ? id : name; - } - - /** - * - * - * @return ... - */ - public String getFullName() { - return getFullName(null); - } - - /** - * - * - * @param root ... - * - * @return ... - */ - public String getFullName(INode root) { - String divider = null; - StringBuffer b = new StringBuffer(); - INode p = this; - int loopWatch = 0; - - while ((p != null) && (p.getParent() != null) && (p != root)) { - if (divider != null) { - b.insert(0, divider); - } else { - divider = "/"; - } - - b.insert(0, p.getElementName()); - p = p.getParent(); - - loopWatch++; - - if (loopWatch > 10) { - b.insert(0, "..."); - - break; - } - } - - return b.toString(); - } - - /** - * - * - * @return ... - */ - public String getPrototype() { - // if prototype is null, it's a vanilla HopObject. - if (prototype == null) { - return "hopobject"; - } - - return prototype; - } - - /** - * - * - * @param proto ... - */ - public void setPrototype(String proto) { - this.prototype = proto; - } - - /** - * - * - * @param dbmap ... - */ - public void setDbMapping(DbMapping dbmap) { - if (this.dbmap != dbmap) { - this.dbmap = dbmap; - - // primaryKey = null; - } - } - - /** - * - * - * @return ... - */ - public DbMapping getDbMapping() { - return dbmap; - } - - /** - * - * - * @return ... - */ - public Key getKey() { - if (state == TRANSIENT) { - Thread.dumpStack(); - throw new RuntimeException("getKey called on transient Node: " + this); - } - - if ((dbmap == null) && (prototype != null) && (nmgr != null)) { - dbmap = nmgr.getDbMapping(prototype); - } - - if (primaryKey == null) { - primaryKey = new DbKey(dbmap, id); - } - - return primaryKey; - } - - /** - * - * - * @return ... - */ - public NodeHandle getHandle() { - if (handle == null) { - handle = new NodeHandle(this); - } - - return handle; - } - - /** - * - * - * @param rel ... - */ - public void setSubnodeRelation(String rel) { - if (((rel == null) && (this.subnodeRelation == null)) || - ((rel != null) && rel.equalsIgnoreCase(this.subnodeRelation))) { - return; - } - - checkWriteLock(); - this.subnodeRelation = rel; - - DbMapping smap = (dbmap == null) ? null : dbmap.getSubnodeMapping(); - - if ((smap != null) && smap.isRelational()) { - subnodes = null; - subnodeCount = -1; - } - } - - /** - * - * - * @return ... - */ - public String getSubnodeRelation() { - return subnodeRelation; - } - - /** - * - * - * @param name ... - */ - public void setName(String name) { - // "/" is used as delimiter, so it's not a legal char - if (name.indexOf('/') > -1) { - return; - } - - // throw new RuntimeException ("The name of the node must not contain \"/\"."); - if ((name == null) || (name.trim().length() == 0)) { - this.name = id; // use id as name - } else { - this.name = name; - } - } - - /** - * Register a node as parent of the present node. We can't refer to the node directly, so we use - * the ID + DB map combo. - */ - protected void setParent(Node parent) { - parentHandle = (parent == null) ? null : parent.getHandle(); - } - - /** - * Set the parent handle which can be used to get the actual parent node. - */ - public void setParentHandle(NodeHandle parent) { - parentHandle = parent; - } - - /** - * This version of setParent additionally marks the node as anonymous or non-anonymous, - * depending on the string argument. This is the version called from the scripting framework, - * while the one argument version is called from within the objectmodel classes only. - */ - public void setParent(Node parent, String propertyName) { - // we only do that for relational nodes. - if (!isRelational()) { - return; - } - - NodeHandle oldParentHandle = parentHandle; - - parentHandle = (parent == null) ? null : parent.getHandle(); - - // mark parent as set, otherwise getParent will try to - // determine the parent again when called. - lastParentSet = System.currentTimeMillis(); - - if ((parentHandle == null) || parentHandle.equals(oldParentHandle)) { - // nothing changed, no need to find access property - return; - } - - if ((parent != null) && (propertyName == null)) { - // see if we can find out the propertyName by ourselfes by looking at the - // parent's property relation - String newname = null; - DbMapping parentmap = parent.getDbMapping(); - - if (parentmap != null) { - // first try to retrieve name via generic property relation of parent - Relation prel = parentmap.getPropertyRelation(); - - if ((prel != null) && (prel.otherType == dbmap) && - (prel.accessName != null)) { - // reverse look up property used to access this via parent - Relation proprel = dbmap.columnNameToRelation(prel.accessName); - - if ((proprel != null) && (proprel.propName != null)) { - newname = getString(proprel.propName); - } - } - } - - // did we find a new name for this - if (newname == null) { - this.anonymous = true; - } else { - this.anonymous = false; - this.name = newname; - } - } else { - this.anonymous = false; - this.name = propertyName; - } - } - - /** - * Get parent, retrieving it if necessary. - */ - public INode getParent() { - // check what's specified in the type.properties for this node. - ParentInfo[] parentInfo = null; - - if (isRelational() && - (lastParentSet < Math.max(dbmap.getLastTypeChange(), lastmodified))) { - parentInfo = dbmap.getParentInfo(); - } - - // check if current parent candidate matches presciption, - // if not, try to get one that does. - if ((parentInfo != null) && (state != TRANSIENT)) { - for (int i = 0; i < parentInfo.length; i++) { - ParentInfo pinfo = parentInfo[i]; - INode pn = null; - - // see if there is an explicit relation defined for this parent info - // we only try to fetch a node if an explicit relation is specified for the prop name - Relation rel = dbmap.propertyToRelation(pinfo.propname); - - if ((rel != null) && (rel.reftype == Relation.REFERENCE)) { - pn = getNode(pinfo.propname); - } - - // the parent of this node is the app's root node... - if ((pn == null) && pinfo.isroot) { - pn = nmgr.getNode("0", nmgr.getDbMapping("root")); - } - - // if we found a parent node, check if we ought to use a virtual or groupby node as parent - if (pn != null) { - // see if dbmapping specifies anonymity for this node - if (pinfo.virtualname != null) { - pn = pn.getNode(pinfo.virtualname); - } - - DbMapping dbm = (pn == null) ? null : pn.getDbMapping(); - - try { - if ((dbm != null) && (dbm.getSubnodeGroupby() != null)) { - // check for groupby - rel = dbmap.columnNameToRelation(dbm.getSubnodeGroupby()); - pn = pn.getSubnode(getString(rel.propName)); - } - - if (pn != null) { - setParent((Node) pn); - // anonymous = !pinfo.named; - lastParentSet = System.currentTimeMillis(); - - return pn; - } - } catch (Exception ignore) { - } - } - } - } - - // fall back to heuristic parent (the node that fetched this one from db) - if (parentHandle == null) { - return null; - } - - return parentHandle.getNode(nmgr); - } - - /** - * Get parent, using cached info if it exists. - */ - public Node getCachedParent() { - if (parentHandle == null) { - return null; - } - - return parentHandle.getNode(nmgr); - } - - /** - * INode-related - */ - public INode addNode(INode elem) { - return addNode(elem, numberOfNodes()); - } - - /** - * - * - * @param elem ... - * @param where ... - * - * @return ... - */ - public INode addNode(INode elem, int where) { - Node node = null; - - if (elem instanceof Node) { - node = (Node) elem; - } else { - throw new RuntimeException("Can't add fixed-transient node to a persistent node"); - } - - // only lock nodes if parent node is not transient - if (state != TRANSIENT) { - // only lock parent if it has to be modified for a change in subnodes - if (!ignoreSubnodeChange()) { - checkWriteLock(); - } - - node.checkWriteLock(); - } - - // if subnodes are defined via realation, make sure its constraints are enforced. - if ((dbmap != null) && (dbmap.getSubnodeRelation() != null)) { - dbmap.getSubnodeRelation().setConstraints(this, node); - } - - // if the new node is marked as TRANSIENT and this node is not, mark new node as NEW - if ((state != TRANSIENT) && (node.state == TRANSIENT)) { - node.makePersistentCapable(); - } - - // if (n.indexOf('/') > -1) - // throw new RuntimeException ("\"/\" found in Node name."); - // only mark this node as modified if subnodes are not in relational db - // pointing to this node. - if (!ignoreSubnodeChange() && ((state == CLEAN) || (state == DELETED))) { - markAs(MODIFIED); - } - - if ((node.state == CLEAN) || (node.state == DELETED)) { - node.markAs(MODIFIED); - } - - loadNodes(); - - // check if this node has a group-by subnode-relation - if (dbmap != null) { - Relation srel = dbmap.getSubnodeRelation(); - - if ((srel != null) && (srel.groupby != null)) { - try { - Relation groupbyRel = srel.otherType.columnNameToRelation(srel.groupby); - String groupbyProp = (groupbyRel != null) ? groupbyRel.propName - : srel.groupby; - String groupbyValue = node.getString(groupbyProp); - INode groupbyNode = getNode(groupbyValue); - - // if group-by node doesn't exist, we'll create it - if (groupbyNode == null) { - groupbyNode = getGroupbySubnode(groupbyValue, true); - } - - groupbyNode.addNode(node); - - return node; - } catch (Exception x) { - System.err.println("Error adding groupby: " + x); - - // x.printStackTrace (); - return null; - } - } - } - - if ((where < 0) || (where > numberOfNodes())) { - where = numberOfNodes(); - } - - NodeHandle nhandle = node.getHandle(); - - if ((subnodes != null) && subnodes.contains(nhandle)) { - // Node is already subnode of this - just move to new position - subnodes.remove(nhandle); - where = Math.min(where, numberOfNodes()); - subnodes.add(where, nhandle); - } else { - if (subnodes == null) { - subnodes = new ExternalizableVector(); - } - - subnodes.add(where, nhandle); - - // check if properties are subnodes (_properties.aresubnodes=true) - if ((dbmap != null) && (node.dbmap != null)) { - Relation prel = dbmap.getPropertyRelation(); - - if ((prel != null) && (prel.accessName != null)) { - Relation localrel = node.dbmap.columnNameToRelation(prel.accessName); - - // if no relation from db column to prop name is found, assume that both are equal - String propname = (localrel == null) ? prel.accessName - : localrel.propName; - String prop = node.getString(propname); - - if ((prop != null) && (prop.length() > 0)) { - INode old = getNode(prop); - - if ((old != null) && (old != node)) { - unset(prop); - removeNode(old); - } - - setNode(prop, node); - } - } - } - - if (!"root".equalsIgnoreCase(node.getPrototype())) { - // avoid calling getParent() because it would return bogus results for the not-anymore transient node - Node nparent = (node.parentHandle == null) ? null - : node.parentHandle.getNode(nmgr); - - // if the node doesn't have a parent yet, or it has one but it's transient while we are - // persistent, make this the nodes new parent. - if ((nparent == null) || - ((state != TRANSIENT) && (nparent.getState() == TRANSIENT))) { - node.setParent(this); - node.anonymous = true; - } else if ((nparent != null) && ((nparent != this) || !node.anonymous)) { - // this makes the additional job of addLink, registering that we have a link to a node in our - // subnodes that actually sits somewhere else. This means that addLink and addNode - // are actually the same now. - node.registerLinkFrom(this); - } - } - } - - lastmodified = System.currentTimeMillis(); - lastSubnodeChange = lastmodified; - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, node)); - return node; - } - - /** - * - * - * @return ... - */ - public INode createNode() { - // create new node at end of subnode array - return createNode(null, numberOfNodes()); - } - - /** - * - * - * @param where ... - * - * @return ... - */ - public INode createNode(int where) { - return createNode(null, where); - } - - /** - * - * - * @param nm ... - * - * @return ... - */ - public INode createNode(String nm) { - // parameter where is ignored if nm != null so we try to avoid calling numberOfNodes() - return createNode(nm, (nm == null) ? numberOfNodes() : 0); - } - - /** - * - * - * @param nm ... - * @param where ... - * - * @return ... - */ - public INode createNode(String nm, int where) { - checkWriteLock(); - - boolean anon = false; - - if ((nm == null) || "".equals(nm.trim())) { - anon = true; - } - - Node n = new Node(nm, null, nmgr); - - if (anon) { - addNode(n, where); - } else { - setNode(nm, n); - } - - return n; - } - - /** - * register a node that links to this node so we can notify it when we cease to exist. - * this is only necessary if we are a non-relational node, since for relational nodes - * the referring object will notice that we've gone at runtime. - */ - protected void registerLinkFrom(Node from) { - if (isRelational()) { - return; - } - - if (from.getState() == TRANSIENT) { - return; - } - - if (links == null) { - links = new ExternalizableVector(); - } - - Object fromHandle = from.getHandle(); - - if (!links.contains(fromHandle)) { - links.add(fromHandle); - } - } - - /** - * This implements the getChild() method of the IPathElement interface - */ - public IPathElement getChildElement(String name) { - if (dbmap != null) { - // if a dbmapping is provided, check what it tells us about - // getting this specific child element - Relation rel = dbmap.getExactPropertyRelation(name); - - if (rel != null) { - return (IPathElement) getNode(name); - } - - rel = dbmap.getSubnodeRelation(); - - if ((rel != null) && (rel.groupby == null) && (rel.accessName != null)) { - if ((rel.otherType != null) && rel.otherType.isRelational()) { - return (IPathElement) nmgr.getNode(this, name, rel); - } else { - return (IPathElement) getNode(name); - } - } - - return (IPathElement) getSubnode(name); - } else { - // no dbmapping - just try child collection first, then named property. - IPathElement child = (IPathElement) getSubnode(name); - - if (child == null) { - child = (IPathElement) getNode(name); - } - - return child; - } - } - - /** - * This implements the getParentElement() method of the IPathElement interface - */ - public IPathElement getParentElement() { - return getParent(); - } - - /** - * - * - * @param subid ... - * - * @return ... - */ - public INode getSubnode(String subid) { - // System.err.println ("GETSUBNODE : "+this+" > "+subid); - if ("".equals(subid)) { - return this; - } - - Node retval = null; - - if (subid != null) { - loadNodes(); - - if ((subnodes == null) || (subnodes.size() == 0)) { - return null; - } - - NodeHandle nhandle = null; - int l = subnodes.size(); - - for (int i = 0; i < l; i++) - try { - NodeHandle shandle = (NodeHandle) subnodes.get(i); - - if (subid.equals(shandle.getID())) { - // System.err.println ("FOUND SUBNODE: "+shandle); - nhandle = shandle; - - break; - } - } catch (Exception x) { - break; - } - - if (nhandle != null) { - retval = nhandle.getNode(nmgr); - } - - // This would be an alternative way to do it, without loading the subnodes: - // if (dbmap != null && dbmap.getSubnodeRelation () != null) - // retval = nmgr.getNode (this, subid, dbmap.getSubnodeRelation ()); - if ((retval != null) && (retval.parentHandle == null) && - !"root".equalsIgnoreCase(retval.getPrototype())) { - retval.setParent(this); - retval.anonymous = true; - } - } - - return retval; - } - - /** - * - * - * @param index ... - * - * @return ... - */ - public INode getSubnodeAt(int index) { - loadNodes(); - - if (subnodes == null) { - return null; - } - - /* - DbMapping smap = null; - - if (dbmap != null) { - smap = dbmap.getSubnodeMapping(); - } - */ - - Node retval = null; - - if (subnodes.size() > index) { - // check if there is a group-by relation - retval = ((NodeHandle) subnodes.get(index)).getNode(nmgr); - - if ((retval != null) && (retval.parentHandle == null) && - !"root".equalsIgnoreCase(retval.getPrototype())) { - retval.setParent(this); - retval.anonymous = true; - } - } - - return retval; - } - - /** - * - * - * @param sid ... - * @param create ... - * - * @return ... - */ - public Node getGroupbySubnode(String sid, boolean create) { - loadNodes(); - - if (subnodes == null) { - subnodes = new ExternalizableVector(); - } - - NodeHandle ghandle = new NodeHandle(new SyntheticKey(getKey(), sid)); - - if (subnodes.contains(ghandle) || create) { - try { - DbMapping groupbyMapping = dbmap.getGroupbyMapping(); - boolean relational = groupbyMapping.getSubnodeMapping().isRelational(); - - if (relational || create) { - Node node = relational ? new Node(this, sid, nmgr, null) - : new Node("groupby-" + sid, null, nmgr); - - // set "groupname" property to value of groupby field - node.setString("groupname", sid); - - if (relational) { - node.setDbMapping(groupbyMapping); - } else { - setNode(sid, node); - subnodes.add(node.getHandle()); - } - - node.setPrototype(groupbyMapping.getTypeName()); - nmgr.evictKey(node.getKey()); - - return node; - } - } catch (Exception noluck) { - nmgr.logEvent("Error creating group-by node for " + sid + ": " + noluck); - noluck.printStackTrace(); - } - } - - return null; - } - - /** - * - * - * @return ... - */ - public boolean remove() { - checkWriteLock(); - - try { - if (!anonymous) { - getParent().unset(name); - } else { - getParent().removeNode(this); - } - } catch (Exception x) { - return false; - } - - return true; - } - - /** - * - * - * @param node ... - */ - public void removeNode(INode node) { - // nmgr.logEvent ("removing: "+ node); - Node n = (Node) node; - - checkWriteLock(); - n.checkWriteLock(); - - // need to query parent before releaseNode is called, since this may change the parent - // to the next option described in the type.properties _parent info - INode parent = n.getParent(); - - releaseNode(n); - - if (parent == this) { - n.deepRemoveNode(); - } else { - // removed just a link, not the main node. - if (n.links != null) { - n.links.remove(getHandle()); - - if (n.state == CLEAN) { - n.markAs(MODIFIED); - } - } - } - } - - /** - * "Locally" remove a subnode from the subnodes table. - * The logical stuff necessary for keeping data consistent is done in removeNode(). - */ - protected void releaseNode(Node node) { - if (subnodes != null) { - subnodes.remove(node.getHandle()); - } - - lastSubnodeChange = System.currentTimeMillis(); - - // check if the subnode is in relational db and has a link back to this - // which needs to be unset - /* - if (dbmap != null) { - Relation srel = dbmap.getSubnodeRelation(); - } - */ - - // check if subnodes are also accessed as properties. If so, also unset the property - if ((dbmap != null) && (node.dbmap != null)) { - Relation prel = dbmap.getPropertyRelation(); - - if ((prel != null) && (prel.accessName != null)) { - Relation localrel = node.dbmap.columnNameToRelation(prel.accessName); - - // if no relation from db column to prop name is found, assume that both are equal - String propname = (localrel == null) ? prel.accessName : localrel.propName; - String prop = node.getString(propname); - - if ((prop != null) && (getNode(prop) == node)) { - unset(prop); - } - } - } - - // If subnodes are relational no need to mark this node as modified - if (ignoreSubnodeChange()) { - return; - } - - // Server.throwNodeEvent (new NodeEvent (node, NodeEvent.NODE_REMOVED)); - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_REMOVED, node)); - lastmodified = System.currentTimeMillis(); - - // nmgr.logEvent ("released node "+node +" from "+this+" oldobj = "+what); - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * Delete the node from the db. This mainly tries to notify all nodes referring to this that - * it's going away. For nodes from the embedded db it also does a cascading delete, since - * it can tell which nodes are actual children and which are just linked in. - */ - protected void deepRemoveNode() { - // notify nodes that link to this node being deleted. - int l = (links == null) ? 0 : links.size(); - - for (int i = 0; i < l; i++) { - NodeHandle lhandle = (NodeHandle) links.get(i); - Node link = lhandle.getNode(nmgr); - - if (link != null) { - link.releaseNode(this); - } - } - - // tell all nodes that are properties of n that they are no longer used as such - if (propMap != null) { - for (Enumeration e2 = propMap.elements(); e2.hasMoreElements();) { - Property p = (Property) e2.nextElement(); - - if ((p != null) && (p.getType() == Property.NODE)) { - p.unregisterNode(); - } - } - } - - // cascading delete of all subnodes. This is never done for relational subnodes, because - // the parent info is not 100% accurate for them. - if (subnodes != null) { - Vector v = new Vector(); - - // remove modifies the Vector we are enumerating, so we are extra careful. - for (Enumeration e3 = getSubnodes(); e3.hasMoreElements();) { - v.add(e3.nextElement()); - } - - int m = v.size(); - - for (int i = 0; i < m; i++) { - // getParent() is heuristical/implicit for relational nodes, so we don't base - // a cascading delete on that criterium for relational nodes. - Node n = (Node) v.get(i); - - if (!n.isRelational()) { - removeNode(n); - } - } - } - - // mark the node as deleted - setParent(null); - markAs(DELETED); - } - - /** - * - * - * @param n ... - * - * @return ... - */ - public int contains(INode n) { - if (n == null) { - return -1; - } - - loadNodes(); - - if (subnodes == null) { - return -1; - } - - // if the node contains relational groupby subnodes, the subnodes vector contains the names instead of ids. - if (!(n instanceof Node)) { - return -1; - } - - Node node = (Node) n; - - return subnodes.indexOf(node.getHandle()); - } - - /** - * Count the subnodes of this node. If they're stored in a relational data source, we - * may actually load their IDs in order to do this. - */ - public int numberOfNodes() { - // If the subnodes are loaded aggressively, we really just - // do a count statement, otherwise we just return the size of the id index. - // (after loading it, if it's coming from a relational data source). - DbMapping smap = (dbmap == null) ? null : dbmap.getSubnodeMapping(); - - if ((smap != null) && smap.isRelational()) { - // check if subnodes need to be rechecked - Relation subRel = dbmap.getSubnodeRelation(); - - // do not fetch subnodes for nodes that haven't been persisted yet or are in - // the process of being persistified - except if "manual" subnoderelation is set. - if (subRel.aggressiveLoading && subRel.getGroup() == null && - (((state != TRANSIENT) && (state != NEW)) || - (subnodeRelation != null))) { - // we don't want to load *all* nodes if we just want to count them - long lastChange = subRel.aggressiveCaching ? lastSubnodeChange - : smap.getLastDataChange(); - - // also reload if the type mapping has changed. - lastChange = Math.max(lastChange, dbmap.getLastTypeChange()); - - if ((lastChange < lastSubnodeFetch) && (subnodes != null)) { - // we can use the nodes vector to determine number of subnodes - subnodeCount = subnodes.size(); - lastSubnodeCount = System.currentTimeMillis(); - } else if ((lastChange >= lastSubnodeCount) || (subnodeCount < 0)) { - // count nodes in db without fetching anything - subnodeCount = nmgr.countNodes(this, subRel); - lastSubnodeCount = System.currentTimeMillis(); - } - - return subnodeCount; - } - } - - loadNodes(); - - return (subnodes == null) ? 0 : subnodes.size(); - } - - /** - * Make sure the subnode index is loaded for subnodes stored in a relational data source. - * Depending on the subnode.loadmode specified in the type.properties, we'll load just the - * ID index or the actual nodes. - */ - protected void loadNodes() { - // Don't do this for transient nodes which don't have an explicit subnode relation set - if (((state == TRANSIENT) || (state == NEW)) && (subnodeRelation == null)) { - return; - } - - DbMapping smap = (dbmap == null) ? null : dbmap.getSubnodeMapping(); - - if ((smap != null) && smap.isRelational()) { - // check if subnodes need to be reloaded - Relation subRel = dbmap.getSubnodeRelation(); - - synchronized (this) { - long lastChange = subRel.aggressiveCaching ? lastSubnodeChange - : smap.getLastDataChange(); - - // also reload if the type mapping has changed. - lastChange = Math.max(lastChange, dbmap.getLastTypeChange()); - - if ((lastChange >= lastSubnodeFetch) || (subnodes == null)) { - if (subRel.aggressiveLoading) { - subnodes = nmgr.getNodes(this, dbmap.getSubnodeRelation()); - } else { - subnodes = nmgr.getNodeIDs(this, dbmap.getSubnodeRelation()); - } - - lastSubnodeFetch = System.currentTimeMillis(); - } - } - } - } - - /** - * - * - * @param startIndex ... - * @param length ... - * - * @throws Exception ... - */ - public void prefetchChildren(int startIndex, int length) - throws Exception { - if (length < 1) { - return; - } - - if (startIndex < 0) { - return; - } - - loadNodes(); - - if (subnodes == null) { - return; - } - - if (startIndex >= subnodes.size()) { - return; - } - - int l = Math.min(subnodes.size() - startIndex, length); - - if (l < 1) { - return; - } - - Key[] keys = new Key[l]; - - for (int i = 0; i < l; i++) { - keys[i] = ((NodeHandle) subnodes.get(i + startIndex)).getKey(); - } - - nmgr.nmgr.prefetchNodes(this, dbmap.getSubnodeRelation(), keys); - } - - /** - * - * - * @return ... - */ - public Enumeration getSubnodes() { - loadNodes(); - class Enum implements Enumeration { - int count = 0; - - public boolean hasMoreElements() { - return count < numberOfNodes(); - } - - public Object nextElement() { - return getSubnodeAt(count++); - } - } - - return new Enum(); - } - - /** - * - * - * @return ... - */ - public List getSubnodeList() { - return subnodes; - } - - private boolean ignoreSubnodeChange() { - // return true if a change in subnodes can be ignored because it is - // stored in the subnodes themselves. - Relation rel = (dbmap == null) ? null : dbmap.getSubnodeRelation(); - - return ((rel != null) && (rel.otherType != null) && rel.otherType.isRelational()); - } - - /** - * Get all properties of this node. - */ - public Enumeration properties() { - if ((dbmap != null) && dbmap.isRelational()) { - // return the properties defined in type.properties, if there are any - return dbmap.getPropertyEnumeration(); - } - - Relation prel = (dbmap == null) ? null : dbmap.getPropertyRelation(); - - if ((prel != null) && prel.hasAccessName() && (prel.otherType != null) && - prel.otherType.isRelational()) { - // return names of objects from a relational db table - return nmgr.getPropertyNames(this, prel).elements(); - } else if (propMap != null) { - // return the actually explicitly stored properties - return propMap.keys(); - } - - // sorry, no properties for this Node - return new EmptyEnumeration(); - - // NOTE: we don't enumerate node properties here - // return propMap == null ? new Vector ().elements () : propMap.elements (); - } - - /** - * - * - * @return ... - */ - public Hashtable getPropMap() { - return propMap; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public IProperty get(String propname) { - return getProperty(propname); - } - - /** - * - * - * @return ... - */ - public String getParentInfo() { - return "anonymous:" + anonymous + ",parentHandle" + parentHandle + ",parent:" + - getParent(); - } - - protected Property getProperty(String propname) { - // nmgr.logEvent ("GETTING PROPERTY: "+propname); - if (propname == null) { - return null; - } - - Property prop = (propMap == null) ? null - : (Property) propMap.get(propname.toLowerCase()); - - // See if this could be a relationally linked node which still doesn't know - // (i.e, still thinks it's just the key as a string) - DbMapping pmap = (dbmap == null) ? null : dbmap.getExactPropertyMapping(propname); - - if ((pmap != null) && (prop != null) && (prop.getType() != IProperty.NODE)) { - // this is a relational node stored by id but we still think it's just a string. Fix it - prop.convertToNodeReference(pmap); - } - - // the property does not exist in our propmap - see if we should create it on the fly, - // either because it is mapped to an object from relational database or defined as - // collection aka virtual node - if (dbmap != null) { - // the explicitly defined property mapping - Relation propRel = dbmap.getPropertyRelation(propname); - - // property was not found in propmap - if (prop == null) { - // if no property relation is defined for this specific property name, - // use the generic property relation, if one is defined. - if (propRel == null) { - propRel = dbmap.getPropertyRelation(); - } - - // so if we have a property relation and it does in fact link to another object... - if ((propRel != null) && (propRel.isCollection() || propRel.isComplexReference())) { - // in some cases we just want to create and set a generic node without consulting - // the NodeManager if it exists: When we get a collection (aka virtual node) - // from a transient node for the first time, or when we get a collection whose - // content objects are stored in the embedded XML data storage. - if ((state == TRANSIENT) && propRel.virtual) { - Node pn = new Node(propname, propRel.getPrototype(), nmgr); - - pn.setDbMapping(propRel.getVirtualMapping()); - pn.setParent(this); - setNode(propname, pn); - prop = (Property) propMap.get(propname); - } - // if this is from relational database only fetch if this node - // is itself persistent. - else if ((state != TRANSIENT) && propRel.createOnDemand()) { - // this may be a relational node stored by property name - Node pn = nmgr.getNode(this, propname, propRel); - - if (pn != null) { - if ((pn.parentHandle == null) && - !"root".equalsIgnoreCase(pn.getPrototype())) { - pn.setParent(this); - pn.name = propname; - pn.anonymous = false; - } - - prop = new Property(propname, this, pn); - } - } - } - } else if (propRel != null && propRel.isVirtual()) { - // prop was found and explicit property relation is collection - - // this is a collection node containing objects stored in the embedded db - Node pn = (Node) prop.getNodeValue(); - if (pn != null) { - // do set DbMapping for embedded db collection nodes - pn.setDbMapping(propRel.getVirtualMapping()); - // also set node manager in case this is a mountpoint node - // that came in through replication - pn.nmgr = nmgr; - } - } - } - - return prop; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public String getString(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getStringValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public long getInteger(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getIntegerValue(); - } catch (Exception ignore) { - } - - return 0; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public double getFloat(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getFloatValue(); - } catch (Exception ignore) { - } - - return 0.0; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public Date getDate(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getDateValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public boolean getBoolean(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getBooleanValue(); - } catch (Exception ignore) { - } - - return false; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public INode getNode(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getNodeValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * - * - * @param propname ... - * - * @return ... - */ - public Object getJavaObject(String propname) { - // propname = propname.toLowerCase (); - Property prop = getProperty(propname); - - try { - return prop.getJavaObjectValue(); - } catch (Exception ignore) { - } - - return null; - } - - /** - * Directly set a property on this node - * - * @param propname ... - * @param value ... - */ - protected void set(String propname, Object value, int type) { - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - - if (prop != null) { - prop.setValue(value, type); - } else { - prop = new Property(propname, this); - prop.setValue(value, type); - propMap.put(p2, prop); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setString(String propname, String value) { - // nmgr.logEvent ("setting String prop"); - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - String oldvalue = null; - - if (prop != null) { - oldvalue = prop.getStringValue(); - - // check if the value has changed - if ((value != null) && value.equals(oldvalue)) { - return; - } - - prop.setStringValue(value); - } else { - prop = new Property(propname, this); - prop.setStringValue(value); - propMap.put(p2, prop); - } - - // check if this may have an effect on the node's URL when using accessname - // but only do this if we already have a parent set, i.e. if we are already stored in the db - Node parent = (parentHandle == null) ? null : (Node) getParent(); - - if ((dbmap != null) && (parent != null) && (parent.getDbMapping() != null)) { - // check if this node is already registered with the old name; if so, remove it. - // then set parent's property to this node for the new name value - DbMapping parentmap = parent.getDbMapping(); - Relation propRel = parentmap.getPropertyRelation(); - String dbcolumn = dbmap.propertyToColumnName(propname); - - if ((propRel != null) && (propRel.accessName != null) && - propRel.accessName.equals(dbcolumn)) { - INode n = parent.getNode(value); - - if ((n != null) && (n != this)) { - parent.unset(value); - parent.removeNode(n); - } - - if (oldvalue != null) { - n = parent.getNode(oldvalue); - - if (n == this) { - parent.unset(oldvalue); - parent.addNode(this); - - // let the node cache know this key's not for this node anymore. - nmgr.evictKey(new SyntheticKey(parent.getKey(), oldvalue)); - } - } - - parent.setNode(value, this); - setName(value); - } - } - - // check if the property we're setting specifies the prototype of this object. - if ((dbmap != null) && (dbmap.getPrototypeField() != null)) { - String pn = dbmap.columnNameToProperty(dbmap.getPrototypeField()); - - if (propname.equals(pn)) { - DbMapping newmap = nmgr.getDbMapping(value); - - if (newmap != null) { - // see if old and new prototypes have same storage - otherwise type change is ignored - String oldStorage = dbmap.getStorageTypeName(); - String newStorage = newmap.getStorageTypeName(); - - if (((oldStorage == null) && (newStorage == null)) || - ((oldStorage != null) && oldStorage.equals(newStorage))) { - dbmap.notifyDataChange(); - newmap.notifyDataChange(); - this.dbmap = newmap; - this.prototype = value; - } - } - } - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setInteger(String propname, long value) { - // nmgr.logEvent ("setting bool prop"); - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - - if (prop != null) { - prop.setIntegerValue(value); - } else { - prop = new Property(propname, this); - prop.setIntegerValue(value); - propMap.put(p2, prop); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setFloat(String propname, double value) { - // nmgr.logEvent ("setting bool prop"); - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - - if (prop != null) { - prop.setFloatValue(value); - } else { - prop = new Property(propname, this); - prop.setFloatValue(value); - propMap.put(p2, prop); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setBoolean(String propname, boolean value) { - // nmgr.logEvent ("setting bool prop"); - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - - if (prop != null) { - prop.setBooleanValue(value); - } else { - prop = new Property(propname, this); - prop.setBooleanValue(value); - propMap.put(p2, prop); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setDate(String propname, Date value) { - // nmgr.logEvent ("setting date prop"); - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - - if (prop != null) { - prop.setDateValue(value); - } else { - prop = new Property(propname, this); - prop.setDateValue(value); - propMap.put(p2, prop); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setJavaObject(String propname, Object value) { - // nmgr.logEvent ("setting jobject prop"); - checkWriteLock(); - - if (propMap == null) { - propMap = new Hashtable(); - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Property prop = (Property) propMap.get(p2); - - if (prop != null) { - prop.setJavaObjectValue(value); - } else { - prop = new Property(propname, this); - prop.setJavaObjectValue(value); - propMap.put(p2, prop); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /** - * - * - * @param propname ... - * @param value ... - */ - public void setNode(String propname, INode value) { - // nmgr.logEvent ("setting node prop"); - // check if types match, otherwise throw exception - DbMapping nmap = (dbmap == null) ? null : dbmap.getPropertyMapping(propname); - - if ((nmap != null) && (nmap != value.getDbMapping())) { - if (value.getDbMapping() == null) { - value.setDbMapping(nmap); - } else if (!nmap.isStorageCompatible(value.getDbMapping())) { - throw new RuntimeException("Can't set " + propname + - " to object with prototype " + - value.getPrototype() + ", was expecting " + - nmap.getTypeName()); - } - } - - if (state != TRANSIENT) { - checkWriteLock(); - } - - Node n = null; - - if (value instanceof Node) { - n = (Node) value; - } else { - throw new RuntimeException("Can't add fixed-transient node to a persistent node"); - } - - // if the new node is marked as TRANSIENT and this node is not, mark new node as NEW - if ((state != TRANSIENT) && (n.state == TRANSIENT)) { - n.makePersistentCapable(); - } - - if (state != TRANSIENT) { - n.checkWriteLock(); - } - - // check if the main identity of this node is as a named property - // or as an anonymous node in a collection - if ((n.parentHandle == null) && !"root".equalsIgnoreCase(n.getPrototype())) { - n.setParent(this); - n.name = propname; - n.anonymous = false; - } - - propname = propname.trim(); - - String p2 = propname.toLowerCase(); - - Relation rel = (dbmap == null) ? null : dbmap.getPropertyRelation(propname); - - if (rel != null && (rel.countConstraints() > 1 || rel.isComplexReference())) { - rel.setConstraints(this, n); - if (rel.isComplexReference()) { - Key key = new MultiKey(n.getDbMapping(), rel.getKeyParts(this)); - nmgr.nmgr.registerNode(n, key); - return; - } - } - - Property prop = (propMap == null) ? null : (Property) propMap.get(p2); - - if (prop != null) { - if ((prop.getType() == IProperty.NODE) && - n.getHandle().equals(prop.getNodeHandle())) { - // nothing to do, just clean up locks and return - if (state == CLEAN) { - clearWriteLock(); - } - - if (n.state == CLEAN) { - n.clearWriteLock(); - } - - return; - } - } else { - prop = new Property(propname, this); - } - - prop.setNodeValue(n); - - if ((rel == null) || (rel.reftype == Relation.REFERENCE) || rel.virtual || - (rel.otherType == null) || !rel.otherType.isRelational()) { - // the node must be stored as explicit property - if (propMap == null) { - propMap = new Hashtable(); - } - - propMap.put(p2, prop); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } - - /* if (rel != null && rel.reftype == Relation.REFERENCE && !rel.usesPrimaryKey ()) { - // if the relation for this property doesn't use the primary key of the value object, make a - // secondary key object with the proper db column - String kval = n.getString (rel.otherType.columnNameToProperty (rel.getRemoteField ()), false); - prop.nhandle = new NodeHandle (new DbKey (n.getDbMapping (), kval, rel.getRemoteField ())); - } */ - - // don't check node in transactor cache if node is transient - - // this is done anyway when the node becomes persistent. - if (n.state != TRANSIENT) { - // check node in with transactor cache - // String nID = n.getID(); - // DbMapping dbm = n.getDbMapping (); - Transactor tx = (Transactor) Thread.currentThread(); - - // tx.visitCleanNode (new DbKey (dbm, nID), n); - // UPDATE: using n.getKey() instead of manually constructing key. HW 2002/09/13 - tx.visitCleanNode(n.getKey(), n); - - // if the field is not the primary key of the property, also register it - if ((rel != null) && (rel.accessName != null) && (state != TRANSIENT)) { - Key secKey = new SyntheticKey(getKey(), propname); - - nmgr.evictKey(secKey); - tx.visitCleanNode(secKey, n); - } - } - - lastmodified = System.currentTimeMillis(); - - if (n.state == DELETED) { - n.markAs(MODIFIED); - } - } - - /** - * Remove a property. Note that this works only for explicitly set properties, not for those - * specified via property relation. - */ - public void unset(String propname) { - if (propMap == null) { - return; - } - - try { - // if node is relational, leave a null property so that it is - // updated in the DB. Otherwise, remove the property. - Property p; - boolean relational = (dbmap != null) && dbmap.isRelational(); - - if (relational) { - p = (Property) propMap.get(propname.toLowerCase()); - } else { - p = (Property) propMap.remove(propname.toLowerCase()); - } - - if (p != null) { - checkWriteLock(); - - if (p.getType() == Property.NODE) { - p.unregisterNode(); - } - - if (relational) { - p.setStringValue(null); - } - - // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); - lastmodified = System.currentTimeMillis(); - - if (state == CLEAN) { - markAs(MODIFIED); - } - } else if (dbmap != null) { - // check if this is a complex constraint and we have to - // unset constraints. - Relation rel = dbmap.getExactPropertyRelation(propname); - - if (rel != null && (rel.isComplexReference())) { - p = getProperty(propname); - rel.unsetConstraints(this, p.getNodeValue()); - } - } - } catch (Exception ignore) { - } - } - - /** - * - * - * @return ... - */ - public long lastModified() { - return lastmodified; - } - - /** - * - * - * @return ... - */ - public long created() { - return created; - } - - /** - * - * - * @return ... - */ - public String toString() { - return "HopObject " + name; - } - - /** - * Tell whether this node is stored inside a relational db. This doesn't mean - * it actually is stored in a relational db, just that it would be, if the node was - * persistent - */ - public boolean isRelational() { - return (dbmap != null) && dbmap.isRelational(); - } - - /** - * Recursively turn node status from TRANSIENT to NEW so that the Transactor will - * know it has to insert this node. - */ - protected void makePersistentCapable() { - if (state == TRANSIENT) { - state = NEW; - - // generate a real, persistent ID for this object - id = nmgr.generateID(dbmap); - getHandle().becomePersistent(); - - Transactor current = (Transactor) Thread.currentThread(); - - current.visitNode(this); - current.visitCleanNode(this); - - for (Enumeration e = getSubnodes(); e.hasMoreElements();) { - Node n = (Node) e.nextElement(); - - if (n.state == TRANSIENT) { - n.makePersistentCapable(); - } - } - - for (Enumeration e = properties(); e.hasMoreElements();) { - IProperty next = get((String) e.nextElement()); - - if ((next != null) && (next.getType() == IProperty.NODE)) { - // check if this property actually needs to be persisted. - if (dbmap != null) { - Relation rel = dbmap.getExactPropertyRelation(next.getName()); - if (rel != null && !rel.needsPersistence()) { - continue; - } - } - - Node n = (Node) next.getNodeValue(); - - if ((n != null) && (n.state == TRANSIENT)) { - n.makePersistentCapable(); - } - } - } - } - } - - /** - * Get the cache node for this node. This can be - * used to store transient cache data per node from Javascript. - */ - public synchronized INode getCacheNode() { - if (cacheNode == null) { - cacheNode = new TransientNode(); - } - - return cacheNode; - } - - /** - * Reset the cache node for this node. - */ - public synchronized void clearCacheNode() { - cacheNode = null; - } - - /** - * This method walks down node path to the first non-virtual node and return it. - * limit max depth to 3, since there shouldn't be more then 2 layers of virtual nodes. - */ - public Node getNonVirtualParent() { - Node node = this; - - for (int i = 0; i < 5; i++) { - if (node == null) { - break; - } - - if (node.getState() != Node.VIRTUAL) { - return node; - } - - node = (Node) node.getParent(); - } - - return null; - } - - /** - * Instances of this class may be used to mark an entry in the object cache as null. - * This method tells the caller whether this is the case. - */ - public boolean isNullNode() { - return nmgr == null; - } - - /** - * We overwrite hashCode to make it dependant from the prototype. That way, when the prototype - * changes, the node will automatically get a new ESNode wrapper, since they're cached in a hashtable. - * You gotta love these hash code tricks ;-) - */ - public int hashCode() { - if (prototype == null) { - return super.hashCode(); - } else { - return super.hashCode() + prototype.hashCode(); - } - } - - /** - * - */ - public void dump() { - System.err.println("subnodes: " + subnodes); - System.err.println("properties: " + propMap); - System.err.println("links: " + links); - } -} diff --git a/src/helma/objectmodel/db/NodeHandle.java b/src/helma/objectmodel/db/NodeHandle.java deleted file mode 100644 index 35610fa2..00000000 --- a/src/helma/objectmodel/db/NodeHandle.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.objectmodel.*; -import java.io.Serializable; - -/** - * This class is a handle or reference to a Node. This is to abstract from different - * methods of reference: Transient Nodes are referred to directly, while persistent - * nodes are referred to via key/node manager. - * - * A handle is used to refer to a node in a safe way over a longer period. - * While a direct reference may point to a node that has been evicted from the cache - * and reinstanciated since being set, NodeHandle will always return an up-to-date - * instance of its node. - */ -public final class NodeHandle implements INodeState, Serializable { - static final long serialVersionUID = 3067763116576910931L; - - // direct reference to the node - private Node node; - - // the node's key - private Key key; - - /** - * Builds a handle for a node - */ - public NodeHandle(Node node) { - int state = node.getState(); - - if (state == TRANSIENT) { - this.node = node; - key = null; - } else { - this.node = null; - key = node.getKey(); - } - } - - /** - * Builds a handle given a node's retrieval information. At the time this is called, - * the node is ususally not yet created. It will be fetched on demand when accessed by - * application code. - */ - public NodeHandle(Key key) { - this.node = null; - this.key = key; - } - - /** - * Get the node described by this node handle - */ - public Node getNode(WrappedNodeManager nodemgr) { - if (node != null) { - return node; - } - - return nodemgr.getNode(key); - } - - /** - * Get the key for the node described by this handle. - * This may only be called on persistent Nodes. - */ - public Key getKey() { - if (key == null) { - throw new RuntimeException("getKey called on transient Node"); - } - - return key; - } - - /** - * Get the ID for the node described by this handle. - * This may only be called on persistent Nodes. - */ - public String getID() { - if (key == null) { - return node.getID(); - } - - return key.getID(); - } - - private Object getObject() { - if (node != null) { - return node; - } else { - return key; - } - } - - /** - * - * - * @param other ... - * - * @return ... - */ - public boolean equals(Object other) { - try { - return getObject().equals(((NodeHandle) other).getObject()); - } catch (Exception x) { - return false; - } - } - - /** - * This is to notify the handle that the underlying node is becoming - * persistent and we have to refer to it via the key from now on. - */ - protected void becomePersistent() { - if (node != null) { - key = node.getKey(); - node = null; - } - } - - /** - * - * - * @return ... - */ - public String toString() { - if (node != null) { - return "NodeHandle[transient:" + node + "]"; - } else { - return "NodeHandle[" + key + "]"; - } - } -} diff --git a/src/helma/objectmodel/db/NodeManager.java b/src/helma/objectmodel/db/NodeManager.java deleted file mode 100644 index 1ba86361..00000000 --- a/src/helma/objectmodel/db/NodeManager.java +++ /dev/null @@ -1,1954 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.framework.core.Application; -import helma.objectmodel.*; -import helma.util.CacheMap; -import java.math.BigDecimal; -import java.io.*; -import java.sql.*; -import java.util.*; - -/** - * The NodeManager is responsible for fetching Nodes from the internal or - * external data sources, caching them in a least-recently-used Hashtable, - * and writing changes back to the databases. - */ -public final class NodeManager { - - protected Application app; - private CacheMap cache; - private Replicator replicator; - protected IDatabase db; - protected IDGenerator idgen; - private long idBaseValue = 1L; - private boolean logSql; - protected boolean logReplication; - - // a wrapper that catches some Exceptions while accessing this NM - public final WrappedNodeManager safe; - - /** - * Create a new NodeManager for Application app. An embedded database will be - * created in dbHome if one doesn't already exist. - */ - public NodeManager(Application app, String dbHome, Properties props) - throws DatabaseException { - this.app = app; - - int cacheSize = Integer.parseInt(props.getProperty("cachesize", "1000")); - - // Make actual cache size bigger, since we use it only up to the threshold - // cache = new CacheMap ((int) Math.ceil (cacheSize/0.75f), 0.75f); - cache = new CacheMap(cacheSize, 0.75f); - cache.setLogger(app.getLogger("event")); - app.logEvent("Setting up node cache (" + cacheSize + ")"); - - safe = new WrappedNodeManager(this); - - // nullNode = new Node (); - logSql = "true".equalsIgnoreCase(props.getProperty("logsql")); - logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication")); - - String replicationUrl = props.getProperty("replicationUrl"); - - if (replicationUrl != null) { - if (logReplication) { - app.logEvent("Setting up replication listener at " + replicationUrl); - } - - replicator = new Replicator(this); - replicator.addUrl(replicationUrl); - } else { - replicator = null; - } - - // get the initial id generator value - String idb = props.getProperty("idBaseValue"); - - if (idb != null) { - try { - idBaseValue = Long.parseLong(idb); - idBaseValue = Math.max(1L, idBaseValue); // 0 and 1 are reserved for root nodes - } catch (NumberFormatException ignore) { - } - } - - db = new XmlDatabase(dbHome, null, this); - initDb(); - } - - /** - * app.properties file has been updated. Reread some settings. - */ - public void updateProperties(Properties props) { - int cacheSize = Integer.parseInt(props.getProperty("cachesize", "1000")); - - cache.setCapacity(cacheSize); - logSql = "true".equalsIgnoreCase(props.getProperty("logsql")); - logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication")); - } - - /** - * Method used to create the root node and id-generator, if they don't exist already. - */ - public void initDb() throws DatabaseException { - ITransaction txn = null; - - try { - txn = db.beginTransaction(); - - try { - idgen = db.getIDGenerator(txn); - - if (idgen.getValue() < idBaseValue) { - idgen.setValue(idBaseValue); - db.saveIDGenerator(txn, idgen); - } - } catch (ObjectNotFoundException notfound) { - // will start with idBaseValue+1 - idgen = new IDGenerator(idBaseValue); - db.saveIDGenerator(txn, idgen); - } - - // check if we need to set the id generator to a base value - Node node = null; - - try { - node = (Node) db.getNode(txn, "0"); - node.nmgr = safe; - } catch (ObjectNotFoundException notfound) { - node = new Node("root", "0", "root", safe); - node.setDbMapping(app.getDbMapping("root")); - db.saveNode(txn, node.getID(), node); - registerNode(node); // register node with nodemanager cache - } - - try { - node = (Node) db.getNode(txn, "1"); - node.nmgr = safe; - } catch (ObjectNotFoundException notfound) { - node = new Node("users", "1", null, safe); - node.setDbMapping(app.getDbMapping("__userroot__")); - db.saveNode(txn, node.getID(), node); - registerNode(node); // register node with nodemanager cache - } - - db.commitTransaction(txn); - } catch (Exception x) { - System.err.println(">> " + x); - x.printStackTrace(); - - try { - db.abortTransaction(txn); - } catch (Exception ignore) { - } - - throw (new DatabaseException("Error initializing db")); - } - } - - /** - * Shut down this node manager. This is called when the application using this - * node manager is stopped. - */ - public void shutdown() throws DatabaseException { - db.shutdown(); - - if (cache != null) { - synchronized (cache) { - cache.clear(); - cache = null; - } - } - } - - /** - * Delete a node from the database. - */ - public void deleteNode(Node node) throws Exception { - if (node != null) { - synchronized (this) { - Transactor tx = (Transactor) Thread.currentThread(); - - node.setState(Node.INVALID); - deleteNode(db, tx.txn, node); - } - } - } - - /** - * Get a node by key. This is called from a node that already holds - * a reference to another node via a NodeHandle/Key. - */ - public Node getNode(Key key) throws Exception { - Transactor tx = (Transactor) Thread.currentThread(); - - // tx.timer.beginEvent ("getNode "+kstr); - // it would be a good idea to reuse key objects one day. - // Key key = new Key (dbmap, kstr); - // See if Transactor has already come across this node - Node node = tx.getVisitedNode(key); - - if ((node != null) && (node.getState() != Node.INVALID)) { - // tx.timer.endEvent ("getNode "+kstr); - return node; - } - - // try to get the node from the shared cache - node = (Node) cache.get(key); - - if ((node == null) || (node.getState() == Node.INVALID)) { - // The requested node isn't in the shared cache. Synchronize with key to make sure only one - // version is fetched from the database. - if (key instanceof SyntheticKey) { - Node parent = getNode(key.getParentKey()); - Relation rel = parent.dbmap.getPropertyRelation(key.getID()); - - if ((rel == null) || (rel.groupby != null)) { - node = parent.getGroupbySubnode(key.getID(), true); - } else if (rel != null) { - node = getNode(parent, key.getID(), rel); - } else { - node = null; - } - } else { - node = getNodeByKey(tx.txn, (DbKey) key); - } - - if (node != null) { - synchronized (cache) { - Node oldnode = (Node) cache.put(node.getKey(), node); - - if ((oldnode != null) && !oldnode.isNullNode() && - (oldnode.getState() != Node.INVALID)) { - cache.put(node.getKey(), oldnode); - node = oldnode; - } - } - // synchronized - } - } - - if (node != null) { - tx.visitCleanNode(key, node); - } - - // tx.timer.endEvent ("getNode "+kstr); - return node; - } - - /** - * Get a node by relation, using the home node, the relation and a key to apply. - * In contrast to getNode (Key key), this is usually called when we don't yet know - * whether such a node exists. - */ - public Node getNode(Node home, String kstr, Relation rel) - throws Exception { - if (kstr == null) { - return null; - } - - Transactor tx = (Transactor) Thread.currentThread(); - - Key key = null; - - // check what kind of object we're looking for and make an apropriate key - if (rel.isComplexReference()) { - // a key for a complex reference - key = new MultiKey(rel.otherType, rel.getKeyParts(home)); - // } else if (rel.virtual || (rel.groupby != null) || !rel.usesPrimaryKey()) { - } else if (rel.createOnDemand()) { - // a key for a virtually defined object that's never actually stored in the db - // or a key for an object that represents subobjects grouped by some property, - // generated on the fly - key = new SyntheticKey(home.getKey(), kstr); - } else { - // if a key for a node from within the DB - // FIXME: This should never apply, since for every relation-based loading - // Synthetic Keys are used. Right? - key = new DbKey(rel.otherType, kstr); - } - - // See if Transactor has already come across this node - Node node = tx.getVisitedNode(key); - - if ((node != null) && (node.getState() != Node.INVALID)) { - // we used to refresh the node in the main cache here to avoid the primary key entry being - // flushed from cache before the secondary one (risking duplicate nodes in cache) but - // we don't need to since we fetched the node from the threadlocal transactor cache and - // didn't refresh it in the main cache. - return node; - } - - // try to get the node from the shared cache - node = (Node) cache.get(key); - - // check if we can use the cached node without further checks. - // we need further checks for subnodes fetched by name if the subnodes were changed. - if ((node != null) && (node.getState() != Node.INVALID)) { - // check if node is null node (cached null) - if (node.isNullNode()) { - if ((node.created < rel.otherType.getLastDataChange()) || - (node.created < rel.ownType.getLastTypeChange())) { - node = null; // cached null not valid anymore - } - } else if (!rel.virtual) { - // apply different consistency checks for groupby nodes and database nodes: - // for group nodes, check if they're contained - if (rel.groupby != null) { - if (home.contains(node) < 0) { - node = null; - } - - // for database nodes, check if constraints are fulfilled - } else if (!rel.usesPrimaryKey()) { - if (!rel.checkConstraints(home, node)) { - node = null; - } - } - } - } - - if ((node == null) || (node.getState() == Node.INVALID)) { - // The requested node isn't in the shared cache. Synchronize with key to make sure only one - // version is fetched from the database. - node = getNodeByRelation(tx.txn, home, kstr, rel); - - if (node != null) { - Key primKey = node.getKey(); - boolean keyIsPrimary = primKey.equals(key); - - synchronized (cache) { - // check if node is already in cache with primary key - Node oldnode = (Node) cache.put(primKey, node); - - // no need to check for oldnode != node because we fetched a new node from db - if ((oldnode != null) && !oldnode.isNullNode() && - (oldnode.getState() != Node.INVALID)) { - // reset create time of old node, otherwise Relation.checkConstraints - // will reject it under certain circumstances. - oldnode.created = oldnode.lastmodified; - cache.put(primKey, oldnode); - - if (!keyIsPrimary) { - cache.put(key, oldnode); - } - - node = oldnode; - } else if (!keyIsPrimary) { - // cache node with secondary key - cache.put(key, node); - } - } - // synchronized - } else { - // node fetched from db is null, cache result using nullNode - synchronized (cache) { - cache.put(key, new Node()); - - // we ignore the case that onother thread has created the node in the meantime - return null; - } - } - } else if (node.isNullNode()) { - // the nullNode caches a null value, i.e. an object that doesn't exist - return null; - } else { - // update primary key in cache to keep it from being flushed, see above - if (!rel.usesPrimaryKey()) { - synchronized (cache) { - Node oldnode = (Node) cache.put(node.getKey(), node); - - if ((oldnode != node) && (oldnode != null) && - (oldnode.getState() != Node.INVALID)) { - cache.put(node.getKey(), oldnode); - cache.put(key, oldnode); - node = oldnode; - } - } - } - } - - if (node != null) { - tx.visitCleanNode(key, node); - } - - // tx.timer.endEvent ("getNode "+kstr); - return node; - } - - /** - * Register a node in the node cache. - */ - public void registerNode(Node node) { - cache.put(node.getKey(), node); - } - - - /** - * Register a node in the node cache using the key argument. - */ - protected void registerNode(Node node, Key key) { - cache.put(key, node); - } - - /** - * Remove a node from the node cache. If at a later time it is accessed again, - * it will be refetched from the database. - */ - public void evictNode(Node node) { - node.setState(INode.INVALID); - cache.remove(node.getKey()); - } - - /** - * Remove a node from the node cache. If at a later time it is accessed again, - * it will be refetched from the database. - */ - public void evictNodeByKey(Key key) { - Node n = (Node) cache.remove(key); - - if (n != null) { - n.setState(INode.INVALID); - - if (!(key instanceof DbKey)) { - cache.remove(n.getKey()); - } - } - } - - /** - * Used when a key stops being valid for a node. The cached node itself - * remains valid, if it is present in the cache by other keys. - */ - public void evictKey(Key key) { - cache.remove(key); - } - - //////////////////////////////////////////////////////////////////////// - // methods to do the actual db work - //////////////////////////////////////////////////////////////////////// - - /** - * Insert a new node in the embedded database or a relational database table, - * depending on its db mapping. - */ - public void insertNode(IDatabase db, ITransaction txn, Node node) - throws IOException, SQLException, ClassNotFoundException { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("insertNode "+node); - DbMapping dbm = node.getDbMapping(); - - if ((dbm == null) || !dbm.isRelational()) { - db.saveNode(txn, node.getID(), node); - } else { - insertRelationalNode(node, dbm, dbm.getConnection()); - dbm.notifyDataChange(); - } - - // tx.timer.endEvent ("insertNode "+node); - } - - /** - * Insert a node into a different (relational) database than its default one. - */ - public void exportNode(Node node, DbSource dbs) - throws IOException, SQLException, ClassNotFoundException { - if (node == null) { - throw new IllegalArgumentException("Node can't be null in exportNode"); - } - - DbMapping dbm = node.getDbMapping(); - - if (dbs == null) { - throw new IllegalArgumentException("DbSource can't be null in exportNode"); - } else if ((dbm == null) || !dbm.isRelational()) { - throw new SQLException("Can't export into non-relational database"); - } else { - insertRelationalNode(node, dbm, dbs.getConnection()); - } - } - - /** - * Insert a node into a relational database. - */ - protected void insertRelationalNode(Node node, DbMapping dbm, Connection con) - throws ClassNotFoundException, SQLException { - - if (con == null) { - throw new NullPointerException("Error inserting relational node: Connection is null"); - } - - // app.logEvent ("inserting relational node: "+node.getID ()); - DbColumn[] columns = dbm.getColumns(); - - StringBuffer b1 = dbm.getInsert(); - StringBuffer b2 = new StringBuffer(" ) VALUES ( ?"); - - String nameField = dbm.getNameField(); - String prototypeField = dbm.getPrototypeField(); - - for (int i = 0; i < columns.length; i++) { - Relation rel = columns[i].getRelation(); - String name = columns[i].getName(); - - if (((rel != null) && (rel.isPrimitive() || rel.isReference())) || - name.equals(nameField) || name.equals(prototypeField)) { - b1.append(", " + columns[i].getName()); - b2.append(", ?"); - } - } - - b1.append(b2.toString()); - b1.append(" )"); - - // Connection con = dbm.getConnection(); - PreparedStatement stmt = con.prepareStatement(b1.toString()); - - if (logSql) { - app.logEvent("### insertNode: " + b1.toString()); - } - - try { - int stmtNumber = 1; - - // first column of insert statement is always the primary key - stmt.setString(stmtNumber, node.getID()); - - Hashtable propMap = node.getPropMap(); - - for (int i = 0; i < columns.length; i++) { - Relation rel = columns[i].getRelation(); - Property p = null; - - if (rel != null && propMap != null && (rel.isPrimitive() || rel.isReference())) { - p = (Property) propMap.get(rel.getPropName()); - } - - String name = columns[i].getName(); - - if (!((rel != null) && (rel.isPrimitive() || rel.isReference())) && - !name.equals(nameField) && !name.equals(prototypeField)) { - continue; - } - - stmtNumber++; - - if (p != null) { - if (p.getValue() == null) { - stmt.setNull(stmtNumber, columns[i].getType()); - } else { - switch (columns[i].getType()) { - case Types.BIT: - case Types.TINYINT: - case Types.BIGINT: - case Types.SMALLINT: - case Types.INTEGER: - stmt.setLong(stmtNumber, p.getIntegerValue()); - - break; - - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: - case Types.NUMERIC: - case Types.DECIMAL: - stmt.setDouble(stmtNumber, p.getFloatValue()); - - break; - - case Types.VARBINARY: - case Types.BINARY: - case Types.BLOB: - stmt.setString(stmtNumber, p.getStringValue()); - - break; - - case Types.LONGVARBINARY: - case Types.LONGVARCHAR: - - try { - stmt.setString(stmtNumber, p.getStringValue()); - } catch (SQLException x) { - String str = p.getStringValue(); - Reader r = new StringReader(str); - - stmt.setCharacterStream(stmtNumber, r, - str.length()); - } - - break; - - case Types.CHAR: - case Types.VARCHAR: - case Types.OTHER: - stmt.setString(stmtNumber, p.getStringValue()); - - break; - - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: - stmt.setTimestamp(stmtNumber, p.getTimestampValue()); - - break; - - case Types.NULL: - stmt.setNull(stmtNumber, 0); - - break; - - default: - stmt.setString(stmtNumber, p.getStringValue()); - - break; - } - } - } else { - if (name.equals(nameField)) { - stmt.setString(stmtNumber, node.getName()); - } else if (name.equals(prototypeField)) { - stmt.setString(stmtNumber, node.getPrototype()); - } else { - stmt.setNull(stmtNumber, columns[i].getType()); - } - } - } - - stmt.executeUpdate(); - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) {} - } - } - - } - - /** - * Updates a modified node in the embedded db or an external relational database, depending - * on its database mapping. - */ - public void updateNode(IDatabase db, ITransaction txn, Node node) - throws IOException, SQLException, ClassNotFoundException { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("updateNode "+node); - DbMapping dbm = node.getDbMapping(); - boolean markMappingAsUpdated = false; - - if ((dbm == null) || !dbm.isRelational()) { - db.saveNode(txn, node.getID(), node); - } else { - Hashtable propMap = node.getPropMap(); - Property[] props = new Property[propMap.size()]; - - propMap.values().toArray(props); - - // make sure table meta info is loaded by dbmapping - dbm.getColumns(); - - StringBuffer b = dbm.getUpdate(); - - boolean comma = false; - - for (int i = 0; i < props.length; i++) { - // skip clean properties - if ((props[i] == null) || !props[i].dirty) { - // null out clean property so we don't consider it later - props[i] = null; - - continue; - } - - Relation rel = dbm.propertyToRelation(props[i].getName()); - - // skip readonly, virtual and collection relations - if ((rel == null) || rel.readonly || rel.virtual || - ((rel.reftype != Relation.REFERENCE) && - (rel.reftype != Relation.PRIMITIVE))) { - // null out property so we don't consider it later - props[i] = null; - - continue; - } - - if (comma) { - b.append(", "); - } else { - comma = true; - } - - b.append(rel.getDbField()); - b.append(" = ?"); - } - - // if no columns were updated, return - if (!comma) { - return; - } - - b.append(" WHERE "); - b.append(dbm.getIDField()); - b.append(" = "); - - if (dbm.needsQuotes(dbm.getIDField())) { - b.append("'"); - b.append(escape(node.getID())); - b.append("'"); - } else { - b.append(node.getID()); - } - - Connection con = dbm.getConnection(); - PreparedStatement stmt = con.prepareStatement(b.toString()); - - if (logSql) { - app.logEvent("### updateNode: " + b.toString()); - } - - int stmtNumber = 0; - - try { - for (int i = 0; i < props.length; i++) { - Property p = props[i]; - - if (p == null) { - continue; - } - - Relation rel = dbm.propertyToRelation(p.getName()); - - stmtNumber++; - - if (p.getValue() == null) { - stmt.setNull(stmtNumber, rel.getColumnType()); - } else { - switch (rel.getColumnType()) { - case Types.BIT: - case Types.TINYINT: - case Types.BIGINT: - case Types.SMALLINT: - case Types.INTEGER: - stmt.setLong(stmtNumber, p.getIntegerValue()); - - break; - - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: - case Types.NUMERIC: - case Types.DECIMAL: - stmt.setDouble(stmtNumber, p.getFloatValue()); - - break; - - case Types.VARBINARY: - case Types.BINARY: - case Types.BLOB: - stmt.setString(stmtNumber, p.getStringValue()); - - break; - - case Types.LONGVARBINARY: - case Types.LONGVARCHAR: - - try { - stmt.setString(stmtNumber, p.getStringValue()); - } catch (SQLException x) { - String str = p.getStringValue(); - Reader r = new StringReader(str); - - stmt.setCharacterStream(stmtNumber, r, str.length()); - } - - break; - - case Types.CHAR: - case Types.VARCHAR: - case Types.OTHER: - stmt.setString(stmtNumber, p.getStringValue()); - - break; - - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: - stmt.setTimestamp(stmtNumber, p.getTimestampValue()); - - break; - - case Types.NULL: - stmt.setNull(stmtNumber, 0); - - break; - - default: - stmt.setString(stmtNumber, p.getStringValue()); - - break; - } - } - - p.dirty = false; - - if (!rel.isPrivate()) { - markMappingAsUpdated = true; - } - } - - stmt.executeUpdate(); - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - if (markMappingAsUpdated) { - dbm.notifyDataChange(); - } - } - - // update may cause changes in the node's parent subnode array - if (node.isAnonymous()) { - Node parent = node.getCachedParent(); - - if (parent != null) { - parent.lastSubnodeChange = System.currentTimeMillis(); - } - } - - // tx.timer.endEvent ("updateNode "+node); - } - - /** - * Performs the actual deletion of a node from either the embedded or an external SQL database. - */ - public void deleteNode(IDatabase db, ITransaction txn, Node node) - throws Exception { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("deleteNode "+node); - DbMapping dbm = node.getDbMapping(); - - if ((dbm == null) || !dbm.isRelational()) { - db.deleteNode(txn, node.getID()); - } else { - Statement st = null; - - try { - Connection con = dbm.getConnection(); - String str = new StringBuffer("DELETE FROM ").append(dbm.getTableName()) - .append(" WHERE ") - .append(dbm.getIDField()) - .append(" = ") - .append(node.getID()) - .toString(); - - st = con.createStatement(); - st.executeUpdate(str); - - if (logSql) { - app.logEvent("### deleteNode: " + str); - } - } finally { - if (st != null) { - try { - st.close(); - } catch (Exception ignore) { - } - } - } - - dbm.notifyDataChange(); - } - - // node may still be cached via non-primary keys. mark as invalid - node.setState(Node.INVALID); - - // tx.timer.endEvent ("deleteNode "+node); - } - - /** - * Generates an ID for the table by finding out the maximum current value - */ - public synchronized String generateMaxID(DbMapping map) - throws Exception { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("generateID "+map); - String retval = null; - Statement stmt = null; - - try { - Connection con = map.getConnection(); - String q = new StringBuffer("SELECT MAX(").append(map.getIDField()) - .append(") FROM ") - .append(map.getTableName()) - .toString(); - - stmt = con.createStatement(); - - ResultSet rs = stmt.executeQuery(q); - - // check for empty table - if (!rs.next()) { - long currMax = map.getNewID(0); - - retval = Long.toString(currMax); - } else { - long currMax = rs.getLong(1); - - currMax = map.getNewID(currMax); - retval = Long.toString(currMax); - } - } finally { - // tx.timer.endEvent ("generateID "+map); - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - return retval; - } - - /** - * Generate a new ID from an Oracle sequence. - */ - public String generateID(DbMapping map) throws Exception { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("generateID "+map); - Statement stmt = null; - String retval = null; - - try { - Connection con = map.getConnection(); - String q = new StringBuffer("SELECT ").append(map.getIDgen()) - .append(".nextval FROM dual").toString(); - - stmt = con.createStatement(); - - ResultSet rs = stmt.executeQuery(q); - - if (!rs.next()) { - throw new SQLException("Error creating ID from Sequence: empty recordset"); - } - - retval = rs.getString(1); - } finally { - // tx.timer.endEvent ("generateID "+map); - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - return retval; - } - - /** - * Loades subnodes via subnode relation. Only the ID index is loaded, the nodes are - * loaded later on demand. - */ - public List getNodeIDs(Node home, Relation rel) throws Exception { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("getNodeIDs "+home); - - if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { - // this should never be called for embedded nodes - throw new RuntimeException("NodeMgr.getNodeIDs called for non-relational node " + - home); - } else { - List retval = new ArrayList(); - - // if we do a groupby query (creating an intermediate layer of groupby nodes), - // retrieve the value of that field instead of the primary key - String idfield = (rel.groupby == null) ? rel.otherType.getIDField() - : rel.groupby; - Connection con = rel.otherType.getConnection(); - String table = rel.otherType.getTableName(); - - Statement stmt = null; - - try { - String q = null; - - if (home.getSubnodeRelation() != null) { - // subnode relation was explicitly set - q = new StringBuffer("SELECT ").append(table).append('.') - .append(idfield).append(" FROM ") - .append(table).append(" ") - .append(home.getSubnodeRelation()) - .toString(); - } else { - // let relation object build the query - q = new StringBuffer("SELECT ").append(idfield).append(" FROM ") - .append(table) - .append(rel.buildQuery(home, - home.getNonVirtualParent(), - null, - " WHERE ", true)) - .toString(); - } - - if (logSql) { - app.logEvent("### getNodeIDs: " + q); - } - - stmt = con.createStatement(); - - if (rel.maxSize > 0) { - stmt.setMaxRows(rel.maxSize); - } - - ResultSet result = stmt.executeQuery(q); - - // problem: how do we derive a SyntheticKey from a not-yet-persistent Node? - Key k = (rel.groupby != null) ? home.getKey() : null; - - while (result.next()) { - String kstr = result.getString(1); - - // jump over null values - this can happen especially when the selected - // column is a group-by column. - if (kstr == null) { - continue; - } - - // make the proper key for the object, either a generic DB key or a groupby key - Key key = (rel.groupby == null) - ? (Key) new DbKey(rel.otherType, kstr) - : (Key) new SyntheticKey(k, kstr); - - retval.add(new NodeHandle(key)); - - // if these are groupby nodes, evict nullNode keys - if (rel.groupby != null) { - Node n = (Node) cache.get(key); - - if ((n != null) && n.isNullNode()) { - evictKey(key); - } - } - } - } finally { - // tx.timer.endEvent ("getNodeIDs "+home); - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - return retval; - } - } - - /** - * Loades subnodes via subnode relation. This is similar to getNodeIDs, but it - * actually loades all nodes in one go, which is better for small node collections. - * This method is used when xxx.loadmode=aggressive is specified. - */ - public List getNodes(Node home, Relation rel) throws Exception { - // This does not apply for groupby nodes - use getNodeIDs instead - if (rel.groupby != null) { - return getNodeIDs(home, rel); - } - - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("getNodes "+home); - if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { - // this should never be called for embedded nodes - throw new RuntimeException("NodeMgr.countNodes called for non-relational node " + - home); - } else { - List retval = new ArrayList(); - DbMapping dbm = rel.otherType; - - Connection con = dbm.getConnection(); - Statement stmt = con.createStatement(); - DbColumn[] columns = dbm.getColumns(); - Relation[] joins = dbm.getJoins(); - StringBuffer q = dbm.getSelect(); - - try { - if (home.getSubnodeRelation() != null) { - q.append(home.getSubnodeRelation()); - } else { - // let relation object build the query - q.append(rel.buildQuery(home, home.getNonVirtualParent(), null, - " WHERE ", true)); - } - - if (logSql) { - app.logEvent("### getNodes: " + q.toString()); - } - - if (rel.maxSize > 0) { - stmt.setMaxRows(rel.maxSize); - } - - ResultSet rs = stmt.executeQuery(q.toString()); - - while (rs.next()) { - // create new Nodes. - Node node = createNode(rel.otherType, rs, columns, 0); - if (node == null) { - continue; - } - Key primKey = node.getKey(); - - retval.add(new NodeHandle(primKey)); - - // do we need to synchronize on primKey here? - synchronized (cache) { - Node oldnode = (Node) cache.put(primKey, node); - - if ((oldnode != null) && (oldnode.getState() != INode.INVALID)) { - cache.put(primKey, oldnode); - } - } - - fetchJoinedNodes(rs, joins, columns.length); - } - - } finally { - // tx.timer.endEvent ("getNodes "+home); - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - return retval; - } - } - - /** - * - */ - public void prefetchNodes(Node home, Relation rel, Key[] keys) - throws Exception { - DbMapping dbm = rel.otherType; - - if ((dbm == null) || !dbm.isRelational()) { - // this does nothing for objects in the embedded database - return; - } else { - int missing = cache.containsKeys(keys); - - if (missing > 0) { - Connection con = dbm.getConnection(); - Statement stmt = con.createStatement(); - DbColumn[] columns = dbm.getColumns(); - Relation[] joins = dbm.getJoins(); - StringBuffer q = dbm.getSelect(); - - try { - String idfield = (rel.groupby != null) ? rel.groupby : dbm.getIDField(); - boolean needsQuotes = dbm.needsQuotes(idfield); - - q.append("WHERE "); - q.append(dbm.getTableName()); - q.append("."); - q.append(idfield); - q.append(" IN ("); - - boolean first = true; - - for (int i = 0; i < keys.length; i++) { - if (keys[i] != null) { - if (!first) { - q.append(','); - } else { - first = false; - } - - if (needsQuotes) { - q.append("'"); - q.append(escape(keys[i].getID())); - q.append("'"); - } else { - q.append(keys[i].getID()); - } - } - } - - q.append(") "); - - if (rel.groupby != null) { - q.append(rel.renderConstraints(home, home.getNonVirtualParent())); - - if (rel.order != null) { - q.append(" ORDER BY "); - q.append(rel.order); - } - } - - if (logSql) { - app.logEvent("### prefetchNodes: " + q.toString()); - } - - ResultSet rs = stmt.executeQuery(q.toString()); - - ; - - String groupbyProp = null; - HashMap groupbySubnodes = null; - - if (rel.groupby != null) { - groupbyProp = dbm.columnNameToProperty(rel.groupby); - groupbySubnodes = new HashMap(); - } - - String accessProp = null; - - if ((rel.accessName != null) && !rel.usesPrimaryKey()) { - accessProp = dbm.columnNameToProperty(rel.accessName); - } - - while (rs.next()) { - // create new Nodes. - Node node = createNode(dbm, rs, columns, 0); - if (node == null) { - continue; - } - Key primKey = node.getKey(); - - // for grouped nodes, collect subnode lists for the intermediary - // group nodes. - String groupName = null; - - if (groupbyProp != null) { - groupName = node.getString(groupbyProp); - - List sn = (List) groupbySubnodes.get(groupName); - - if (sn == null) { - sn = new ExternalizableVector(); - groupbySubnodes.put(groupName, sn); - } - - sn.add(new NodeHandle(primKey)); - } - - // if relation doesn't use primary key as accessName, get accessName value - String accessName = null; - - if (accessProp != null) { - accessName = node.getString(accessProp); - } - - // register new nodes with the cache. If an up-to-date copy - // existed in the cache, use that. - synchronized (cache) { - Node oldnode = (Node) cache.put(primKey, node); - - if ((oldnode != null) && - (oldnode.getState() != INode.INVALID)) { - // found an ok version in the cache, use it. - cache.put(primKey, oldnode); - } else if (accessName != null) { - // put the node into cache with its secondary key - if (groupName != null) { - cache.put(new SyntheticKey(new SyntheticKey(home.getKey(), - groupName), - accessName), node); - } else { - cache.put(new SyntheticKey(home.getKey(), accessName), - node); - } - } - } - - fetchJoinedNodes(rs, joins, columns.length); - } - - // If these are grouped nodes, build the intermediary group nodes - // with the subnod lists we created - if (groupbyProp != null) { - for (Iterator i = groupbySubnodes.keySet().iterator(); - i.hasNext();) { - String groupname = (String) i.next(); - - if (groupname == null) { - continue; - } - - Node groupnode = home.getGroupbySubnode(groupname, true); - - cache.put(groupnode.getKey(), groupnode); - groupnode.setSubnodes((List) groupbySubnodes.get(groupname)); - groupnode.lastSubnodeFetch = System.currentTimeMillis(); - } - } - } catch (Exception x) { - System.err.println ("ERROR IN PREFETCHNODES: "+x); - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - } - } - } - - /** - * Count the nodes contained in the child collection of the home node - * which is defined by Relation rel. - */ - public int countNodes(Node home, Relation rel) throws Exception { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("countNodes "+home); - if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { - // this should never be called for embedded nodes - throw new RuntimeException("NodeMgr.countNodes called for non-relational node " + - home); - } else { - int retval = 0; - Connection con = rel.otherType.getConnection(); - String table = rel.otherType.getTableName(); - - Statement stmt = null; - - try { - String q = null; - - if (home.getSubnodeRelation() != null) { - // use the manually set subnoderelation of the home node - q = new StringBuffer("SELECT count(*) FROM ").append(table).append(" ") - .append(home.getSubnodeRelation()) - .toString(); - } else { - // let relation object build the query - q = new StringBuffer("SELECT count(*) FROM ").append(table) - .append(rel.buildQuery(home, - home.getNonVirtualParent(), - null, - " WHERE ", - false)) - .toString(); - } - - if (logSql) { - app.logEvent("### countNodes: " + q); - } - - stmt = con.createStatement(); - - ResultSet rs = stmt.executeQuery(q); - - if (!rs.next()) { - retval = 0; - } else { - retval = rs.getInt(1); - } - } finally { - // tx.timer.endEvent ("countNodes "+home); - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - return (rel.maxSize > 0) ? Math.min(rel.maxSize, retval) : retval; - } - } - - /** - * Similar to getNodeIDs, but returns a Vector that return's the nodes property names instead of IDs - */ - public Vector getPropertyNames(Node home, Relation rel) - throws Exception { - // Transactor tx = (Transactor) Thread.currentThread (); - // tx.timer.beginEvent ("getNodeIDs "+home); - if ((rel == null) || (rel.otherType == null) || !rel.otherType.isRelational()) { - // this should never be called for embedded nodes - throw new RuntimeException("NodeMgr.getPropertyNames called for non-relational node " + - home); - } else { - Vector retval = new Vector(); - - // if we do a groupby query (creating an intermediate layer of groupby nodes), - // retrieve the value of that field instead of the primary key - String namefield = rel.accessName; - Connection con = rel.otherType.getConnection(); - String table = rel.otherType.getTableName(); - - Statement stmt = null; - - try { - StringBuffer q = new StringBuffer("SELECT ").append(namefield).append(" FROM ") - .append(table); - - if (home.getSubnodeRelation() != null) { - q.append(" ").append(home.getSubnodeRelation()); - } else { - // let relation object build the query - q.append(rel.buildQuery(home, home.getNonVirtualParent(), null, - " WHERE ", true)); - } - - stmt = con.createStatement(); - - if (logSql) { - app.logEvent("### getPropertyNames: " + q); - } - - ResultSet rs = stmt.executeQuery(q.toString()); - - while (rs.next()) { - String n = rs.getString(1); - - if (n != null) { - retval.addElement(n); - } - } - } finally { - // tx.timer.endEvent ("getNodeIDs "+home); - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - - return retval; - } - } - - /////////////////////////////////////////////////////////////////////////////////////// - // private getNode methods - /////////////////////////////////////////////////////////////////////////////////////// - private Node getNodeByKey(ITransaction txn, DbKey key) - throws Exception { - // Note: Key must be a DbKey, otherwise will not work for relational objects - Node node = null; - DbMapping dbm = app.getDbMapping(key.getStorageName()); - String kstr = key.getID(); - - if ((dbm == null) || !dbm.isRelational()) { - node = (Node) db.getNode(txn, kstr); - node.nmgr = safe; - - if ((node != null) && (dbm != null)) { - node.setDbMapping(dbm); - } - } else { - String idfield = dbm.getIDField(); - - Statement stmt = null; - - try { - Connection con = dbm.getConnection(); - - stmt = con.createStatement(); - - DbColumn[] columns = dbm.getColumns(); - Relation[] joins = dbm.getJoins(); - StringBuffer q = dbm.getSelect(); - - q.append("WHERE "); - q.append(dbm.getTableName()); - q.append("."); - q.append(idfield); - q.append(" = "); - - if (dbm.needsQuotes(idfield)) { - q.append("'"); - q.append(escape(kstr)); - q.append("'"); - } else { - q.append(kstr); - } - - if (logSql) { - app.logEvent("### getNodeByKey: " + q.toString()); - } - - ResultSet rs = stmt.executeQuery(q.toString()); - - if (!rs.next()) { - return null; - } - - node = createNode(dbm, rs, columns, 0); - - fetchJoinedNodes(rs, joins, columns.length); - - if (rs.next()) { - throw new RuntimeException("More than one value returned by query."); - } - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - } - - return node; - } - - private Node getNodeByRelation(ITransaction txn, Node home, String kstr, Relation rel) - throws Exception { - Node node = null; - - if ((rel != null) && rel.virtual) { - if (rel.needsPersistence()) { - node = (Node) home.createNode(kstr); - } else { - node = new Node(home, kstr, safe, rel.prototype); - } - - // set prototype and dbmapping on the newly created virtual/collection node - node.setPrototype(rel.prototype); - node.setDbMapping(rel.getVirtualMapping()); - } else if ((rel != null) && (rel.groupby != null)) { - node = home.getGroupbySubnode(kstr, false); - - if ((node == null) && - ((rel.otherType == null) || !rel.otherType.isRelational())) { - node = (Node) db.getNode(txn, kstr); - node.nmgr = safe; - } - - return node; - } else if ((rel == null) || (rel.otherType == null) || - !rel.otherType.isRelational()) { - node = (Node) db.getNode(txn, kstr); - node.nmgr = safe; - node.setDbMapping(rel.otherType); - - return node; - } else { - Statement stmt = null; - - try { - DbMapping dbm = rel.otherType; - - Connection con = dbm.getConnection(); - DbColumn[] columns = dbm.getColumns(); - Relation[] joins = dbm.getJoins(); - StringBuffer q = dbm.getSelect(); - - if (home.getSubnodeRelation() != null && !rel.isComplexReference()) { - // combine our key with the constraints in the manually set subnode relation - q.append("WHERE "); - q.append(dbm.getTableName()); - q.append("."); - q.append(rel.accessName); - q.append(" = '"); - q.append(escape(kstr)); - q.append("'"); - q.append(" AND ("); - q.append(home.getSubnodeRelation().trim().substring(5)); - q.append(")"); - } else { - q.append(rel.buildQuery(home, home.getNonVirtualParent(), kstr, - "WHERE ", false)); - } - - if (logSql) { - app.logEvent("### getNodeByRelation: " + q.toString()); - } - - stmt = con.createStatement(); - - ResultSet rs = stmt.executeQuery(q.toString()); - - if (!rs.next()) { - return null; - } - - node = createNode(rel.otherType, rs, columns, 0); - - fetchJoinedNodes(rs, joins, columns.length); - - if (rs.next()) { - throw new RuntimeException("More than one value returned by query."); - } - - // Check if node is already cached with primary Key. - if (!rel.usesPrimaryKey()) { - Key pk = node.getKey(); - Node existing = (Node) cache.get(pk); - - if ((existing != null) && (existing.getState() != Node.INVALID)) { - node = existing; - } - } - - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (Exception ignore) { - } - } - } - } - - return node; - } - - /** - * Create a new Node from a ResultSet. - */ - public Node createNode(DbMapping dbm, ResultSet rs, DbColumn[] columns, int offset) - throws SQLException, IOException { - Hashtable propMap = new Hashtable(); - String id = null; - String name = null; - String protoName = dbm.getTypeName(); - DbMapping dbmap = dbm; - - Node node = new Node(); - - for (int i = 0; i < columns.length; i++) { - - // set prototype? - if (columns[i].isPrototypeField()) { - protoName = rs.getString(i+1+offset); - - if (protoName != null) { - dbmap = getDbMapping(protoName); - - if (dbmap == null) { - // invalid prototype name! - System.err.println("Warning: Invalid prototype name: " + protoName + - " - using default"); - dbmap = dbm; - } - } - } - - // set id? - if (columns[i].isIdField()) { - id = rs.getString(i+1+offset); - // if id == null, the object doesn't actually exist - return null - if (id == null) { - return null; - } - } - - // set name? - if (columns[i].isNameField()) { - name = rs.getString(i+1+offset); - } - - Relation rel = columns[i].getRelation(); - - if ((rel == null) || - ((rel.reftype != Relation.PRIMITIVE) && - (rel.reftype != Relation.REFERENCE))) { - continue; - } - - Property newprop = new Property(rel.propName, node); - - switch (columns[i].getType()) { - case Types.BIT: - newprop.setBooleanValue(rs.getBoolean(i+1+offset)); - - break; - - case Types.TINYINT: - case Types.BIGINT: - case Types.SMALLINT: - case Types.INTEGER: - newprop.setIntegerValue(rs.getLong(i+1+offset)); - - break; - - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: - newprop.setFloatValue(rs.getDouble(i+1+offset)); - - break; - - case Types.DECIMAL: - case Types.NUMERIC: - - BigDecimal num = rs.getBigDecimal(i+1+offset); - - if (num == null) { - break; - } - - if (num.scale() > 0) { - newprop.setFloatValue(num.doubleValue()); - } else { - newprop.setIntegerValue(num.longValue()); - } - - break; - - case Types.VARBINARY: - case Types.BINARY: - newprop.setStringValue(rs.getString(i+1+offset)); - - break; - - case Types.LONGVARBINARY: - case Types.LONGVARCHAR: - - try { - newprop.setStringValue(rs.getString(i+1+offset)); - } catch (SQLException x) { - Reader in = rs.getCharacterStream(i+1+offset); - char[] buffer = new char[2048]; - int read = 0; - int r = 0; - - while ((r = in.read(buffer, read, buffer.length - read)) > -1) { - read += r; - - if (read == buffer.length) { - // grow input buffer - char[] newBuffer = new char[buffer.length * 2]; - - System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); - buffer = newBuffer; - } - } - - newprop.setStringValue(new String(buffer, 0, read)); - } - - break; - - case Types.CHAR: - case Types.VARCHAR: - case Types.OTHER: - newprop.setStringValue(rs.getString(i+1+offset)); - - break; - - case Types.DATE: - newprop.setDateValue(rs.getDate(i+1+offset)); - - break; - - case Types.TIME: - newprop.setDateValue(rs.getTime(i+1+offset)); - - break; - - case Types.TIMESTAMP: - newprop.setDateValue(rs.getTimestamp(i+1+offset)); - - break; - - case Types.NULL: - newprop.setStringValue(null); - - break; - - // continue; - default: - newprop.setStringValue(rs.getString(i+1+offset)); - - break; - } - - if (rs.wasNull()) { - newprop.setStringValue(null); - } - - propMap.put(rel.propName.toLowerCase(), newprop); - - // if the property is a pointer to another node, change the property type to NODE - if ((rel.reftype == Relation.REFERENCE) && rel.usesPrimaryKey()) { - // FIXME: References to anything other than the primary key are not supported - newprop.convertToNodeReference(rel.otherType); - } - - // mark property as clean, since it's fresh from the db - newprop.dirty = false; - } - - if (id == null) { - return null; - } - - node.init(dbmap, id, name, protoName, propMap, safe); - - return node; - } - - /** - * Fetch nodes that are fetched additionally to another node via join. - */ - private void fetchJoinedNodes(ResultSet rs, Relation[] joins, int offset) - throws ClassNotFoundException, SQLException, IOException { - int resultSetOffset = offset; - // create joined objects - for (int i = 0; i < joins.length; i++) { - DbMapping jdbm = joins[i].otherType; - Node node = createNode(jdbm, rs, jdbm.getColumns(), resultSetOffset); - if (node != null) { - Key primKey = node.getKey(); - // register new nodes with the cache. If an up-to-date copy - // existed in the cache, use that. - synchronized (cache) { - Node oldnode = (Node) cache.put(primKey, node); - - if ((oldnode != null) && - (oldnode.getState() != INode.INVALID)) { - // found an ok version in the cache, use it. - cache.put(primKey, oldnode); - } - } - } - resultSetOffset += jdbm.getColumns().length; - } - } - - - /** - * Get a DbMapping for a given prototype name. This is just a proxy - * method to the app's getDbMapping() method. - */ - public DbMapping getDbMapping(String protoname) { - return app.getDbMapping(protoname); - } - - // a utility method to escape single quotes - private String escape(String str) { - if (str == null) { - return null; - } - - if (str.indexOf("'") < 0) { - return str; - } - - int l = str.length(); - StringBuffer sbuf = new StringBuffer(l + 10); - - for (int i = 0; i < l; i++) { - char c = str.charAt(i); - - if (c == '\'') { - sbuf.append('\''); - } - - sbuf.append(c); - } - - return sbuf.toString(); - } - - /** - * Get an array of the the keys currently held in the object cache - */ - public Object[] getCacheEntries() { - return cache.getEntryArray(); - } - - /** - * Get the number of elements in the object cache - */ - public int countCacheEntries() { - return cache.size(); - } - - /** - * Clear the object cache, causing all objects to be recreated. - */ - public void clearCache() { - synchronized (cache) { - cache.clear(); - } - } - - /** - * Get a replicator for this node cache. A replicator is used to transfer updates - * in this node manager to other node managers in remote servers via RMI. - */ - protected Replicator getReplicator() { - return replicator; - } - - /** - * Receive notification from a remote app that objects in its cache have been - * modified. - */ - public void replicateCache(Vector add, Vector delete) { - if (logReplication) { - app.logEvent("Received cache replication event: " + add.size() + " added, " + - delete.size() + " deleted"); - } - - synchronized (cache) { - for (Enumeration en = add.elements(); en.hasMoreElements();) { - Node n = (Node) en.nextElement(); - DbMapping dbm = app.getDbMapping(n.getPrototype()); - - if (dbm != null) { - dbm.notifyDataChange(); - } - - n.lastParentSet = -1; - n.setDbMapping(dbm); - n.nmgr = safe; - cache.put(n.getKey(), n); - } - - for (Enumeration en = delete.elements(); en.hasMoreElements();) { - // NOTE: it would be more efficient to transfer just the keys - // of nodes that are to be deleted. - Node n = (Node) en.nextElement(); - DbMapping dbm = app.getDbMapping(n.getPrototype()); - - if (dbm != null) { - dbm.notifyDataChange(); - } - - n.setDbMapping(dbm); - n.nmgr = safe; - - Node oldNode = (Node) cache.get(n.getKey()); - - if (oldNode != null) { - evictNode(oldNode); - } - } - } - } -} diff --git a/src/helma/objectmodel/db/ParentInfo.java b/src/helma/objectmodel/db/ParentInfo.java deleted file mode 100644 index b572a74e..00000000 --- a/src/helma/objectmodel/db/ParentInfo.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - - -/** - * This class describes a parent relation between releational nodes. - */ -public class ParentInfo { - public final String propname; - public final String virtualname; - public final boolean named; - public final boolean isroot; - - /** - * Creates a new ParentInfo object. - * - * @param desc ... - */ - public ParentInfo(String desc) { - int n = desc.indexOf("[named]"); - - named = n > -1; - - String d = named ? desc.substring(0, n) : desc; - - int dot = d.indexOf("."); - - if (dot > -1) { - propname = d.substring(0, dot).trim(); - virtualname = d.substring(dot + 1).trim(); - } else { - propname = d.trim(); - virtualname = null; - } - - isroot = "root".equals(propname); - - // System.err.println ("created "+this); - } - - /** - * - * - * @return ... - */ - public String toString() { - return "ParentInfo[" + propname + "," + virtualname + "," + named + "]"; - } -} diff --git a/src/helma/objectmodel/db/Property.java b/src/helma/objectmodel/db/Property.java deleted file mode 100644 index 8e949122..00000000 --- a/src/helma/objectmodel/db/Property.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.objectmodel.*; -import helma.util.*; -import java.io.*; -import java.sql.Timestamp; -import java.text.*; -import java.util.*; - -/** - * A property implementation for Nodes stored inside a database. Basically - * the same as for transient nodes, with a few hooks added. - */ -public final class Property implements IProperty, Serializable, Cloneable { - static final long serialVersionUID = -1022221688349192379L; - private String propname; - private Node node; - private Object value; - private int type; - transient boolean dirty; - - /** - * Creates a new Property object. - * - * @param node ... - */ - public Property(Node node) { - this.node = node; - dirty = true; - } - - /** - * Creates a new Property object. - * - * @param propname ... - * @param node ... - */ - public Property(String propname, Node node) { - this.propname = propname; - this.node = node; - dirty = true; - } - - /** - * Creates a new Property object. - * - * @param propname ... - * @param node ... - * @param valueNode ... - */ - public Property(String propname, Node node, Node valueNode) { - this(propname, node); - type = NODE; - value = (valueNode == null) ? null : valueNode.getHandle(); - dirty = true; - } - - private void readObject(ObjectInputStream in) throws IOException { - try { - propname = in.readUTF(); - node = (Node) in.readObject(); - type = in.readInt(); - - switch (type) { - case STRING: - value = in.readObject(); - - break; - - case BOOLEAN: - value = in.readBoolean() ? Boolean.TRUE : Boolean.FALSE; - - break; - - case INTEGER: - value = new Long(in.readLong()); - - break; - - case DATE: - value = new Date(in.readLong()); - - break; - - case FLOAT: - value = new Double(in.readDouble()); - - break; - - case NODE: - value = (NodeHandle) in.readObject(); - - break; - - case JAVAOBJECT: - value = in.readObject(); - - break; - } - } catch (ClassNotFoundException x) { - throw new IOException(x.toString()); - } - } - - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeUTF(propname); - out.writeObject(node); - out.writeInt(type); - - switch (type) { - case STRING: - out.writeObject(value); - - break; - - case BOOLEAN: - out.writeBoolean(((Boolean) value).booleanValue()); - - break; - - case INTEGER: - out.writeLong(((Long) value).longValue()); - - break; - - case DATE: - out.writeLong(((Date) value).getTime()); - - break; - - case FLOAT: - out.writeDouble(((Double) value).doubleValue()); - - break; - - case NODE: - out.writeObject(value); - - break; - - case JAVAOBJECT: - - if ((value != null) && !(value instanceof Serializable)) { - out.writeObject(null); - } else { - out.writeObject(value); - } - - break; - } - } - - /** - * - * - * @return ... - */ - public String getName() { - return propname; - } - - /** - * - * - * @return the property's value in its native class - */ - public Object getValue() { - return value; - } - - /** - * - * - * @return the property's type as defined in helma.objectmodel.IProperty.java - */ - public int getType() { - return type; - } - - /** - * Directly set the value of this property. - */ - protected void setValue(Object value, int type) { - if (type == NODE) { - unregisterNode(); - } - this.value = value; - this.type = type; - dirty = true; - } - - /** - * - * - * @param str ... - */ - public void setStringValue(String str) { - if (type == NODE) { - unregisterNode(); - } - - type = STRING; - value = str; - dirty = true; - } - - /** - * - * - * @param l ... - */ - public void setIntegerValue(long l) { - if (type == NODE) { - unregisterNode(); - } - - type = INTEGER; - value = new Long(l); - dirty = true; - } - - /** - * - * - * @param d ... - */ - public void setFloatValue(double d) { - if (type == NODE) { - unregisterNode(); - } - - type = FLOAT; - value = new Double(d); - dirty = true; - } - - /** - * - * - * @param date ... - */ - public void setDateValue(Date date) { - if (type == NODE) { - unregisterNode(); - } - - type = DATE; - value = date; - dirty = true; - } - - /** - * - * - * @param bool ... - */ - public void setBooleanValue(boolean bool) { - if (type == NODE) { - unregisterNode(); - } - - type = BOOLEAN; - value = bool ? Boolean.TRUE : Boolean.FALSE; - dirty = true; - } - - /** - * - * - * @param node ... - */ - public void setNodeValue(Node node) { - // value.checkWriteLock (); - if (type == NODE) { - unregisterNode(); - } - - // registerNode (value); - type = NODE; - - value = (node == null) ? null : node.getHandle(); - dirty = true; - } - - /** - * - * - * @param handle ... - */ - public void setNodeHandle(NodeHandle handle) { - if (type == NODE) { - unregisterNode(); - } - - // registerNode (value); - type = NODE; - value = handle; - dirty = true; - } - - /** - * - * - * @return ... - */ - public NodeHandle getNodeHandle() { - if (type == NODE) { - return (NodeHandle) value; - } - - return null; - } - - /** - * - * - * @param dbm ... - */ - public void convertToNodeReference(DbMapping dbm) { - if ((value != null) && !(value instanceof NodeHandle)) { - value = new NodeHandle(new DbKey(dbm, value.toString())); - } - - type = NODE; - } - - /** - * - * - * @param obj ... - */ - public void setJavaObjectValue(Object obj) { - if (type == NODE) { - unregisterNode(); - } - - type = JAVAOBJECT; - value = obj; - } - - /** - * tell a the value node that it is no longer used as a property. - * If this was the "main" property for the node, also remove all other references. - */ - protected void unregisterNode() { - if ((value == null) || !(value instanceof NodeHandle)) { - return; - } - - NodeHandle nhandle = (NodeHandle) value; - Node nvalue = nhandle.getNode(node.nmgr); - - DbMapping nvmap = null; - Relation nvrel = null; - - if (node.dbmap != null) { - nvmap = node.dbmap.getPropertyMapping(propname); - nvrel = node.dbmap.getPropertyRelation(propname); - } - - if (nvalue == null) { - return; - } - - nvalue.checkWriteLock(); - - // check if the property node is also a subnode - // BUG: this doesn't work because properties for subnode/properties are never stored and therefore - // never reused. - if ((nvrel != null) && nvrel.hasAccessName()) { - node.removeNode(nvalue); - } - - // only need to call unregisterPropLink if the value node is not stored in a relational db - // also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode - // based on that for relational nodes. - if ((nvmap == null) || !nvmap.isRelational()) { - if (!nvalue.isAnonymous() && propname.equals(nvalue.getName()) && - (this.node == nvalue.getParent())) { - // this is the "main" property of a named node, so handle this as a cascading delete. - nvalue.deepRemoveNode(); - } - } - } - - /** - * - * - * @return ... - */ - public String getStringValue() { - if (value == null) { - return null; - } - - switch (type) { - case STRING: - case BOOLEAN: - case INTEGER: - case FLOAT: - case JAVAOBJECT: - return value.toString(); - - case DATE: - - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); - - return format.format((Date) value); - - case NODE: - return ((NodeHandle) value).getID(); - } - - return ""; - } - - /** - * - * - * @return ... - */ - public String toString() { - return getStringValue(); - } - - /** - * - * - * @return ... - */ - public long getIntegerValue() { - if (type == INTEGER) { - return ((Long) value).longValue(); - } - - if (type == FLOAT) { - return ((Double) value).longValue(); - } - - if (type == BOOLEAN) { - return ((Boolean) value).booleanValue() ? 1 : 0; - } - - try { - return Long.parseLong(getStringValue()); - } catch (Exception x) { - return 0; - } - } - - /** - * - * - * @return ... - */ - public double getFloatValue() { - if (type == FLOAT) { - return ((Double) value).doubleValue(); - } - - if (type == INTEGER) { - return ((Long) value).doubleValue(); - } - - try { - return Double.parseDouble(getStringValue()); - } catch (Exception x) { - return 0.0; - } - } - - /** - * - * - * @return ... - */ - public Date getDateValue() { - if (type == DATE) { - return (Date) value; - } - - return null; - } - - /** - * - * - * @return ... - */ - public Timestamp getTimestampValue() { - if ((type == DATE) && (value != null)) { - return new Timestamp(((Date) value).getTime()); - } - - return null; - } - - /** - * - * - * @return ... - */ - public boolean getBooleanValue() { - if (type == BOOLEAN) { - return ((Boolean) value).booleanValue(); - } - - if (type == INTEGER) { - return !(0 == getIntegerValue()); - } - - return false; - } - - /** - * - * - * @return ... - */ - public INode getNodeValue() { - if ((type == NODE) && (value != null)) { - NodeHandle nhandle = (NodeHandle) value; - - return nhandle.getNode(node.nmgr); - } - - return null; - } - - /** - * - * - * @return ... - */ - public Object getJavaObjectValue() { - if (type == JAVAOBJECT) { - return value; - } - - return null; - } -} diff --git a/src/helma/objectmodel/db/Relation.java b/src/helma/objectmodel/db/Relation.java deleted file mode 100644 index b6e6c274..00000000 --- a/src/helma/objectmodel/db/Relation.java +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.framework.core.Application; -import helma.objectmodel.*; -import java.sql.SQLException; -import java.util.Properties; -import java.util.Vector; -import java.util.Map; -import java.util.HashMap; - -/** - * This describes how a property of a persistent Object is stored in a - * relational database table. This can be either a scalar property (string, date, number etc.) - * or a reference to one or more other objects. - */ -public final class Relation { - // these constants define different type of property-to-db-mappings - // there is an error in the description of this relation - public final static int INVALID = -1; - - // a mapping of a non-object, scalar type - public final static int PRIMITIVE = 0; - - // a 1-to-1 relation, i.e. a field in the table is a foreign key to another object - public final static int REFERENCE = 1; - - // a 1-to-many relation, a field in another table points to objects of this type - public final static int COLLECTION = 2; - - // a 1-to-1 reference with multiple or otherwise not-trivial constraints - // this is managed differently than REFERENCE, hence the separate type. - public final static int COMPLEX_REFERENCE = 3; - - // direct mapping is a very powerful feature: objects of some types can be directly accessed - // by one of their properties/db fields. - // public final static int DIRECT = 3; - // the DbMapping of the type we come from - DbMapping ownType; - - // the DbMapping of the prototype we link to, unless this is a "primitive" (non-object) relation - DbMapping otherType; - - // the column type, as defined in java.sql.Types - int columnType; - - // if this relation defines a virtual node, we need to provide a DbMapping for these virtual nodes - DbMapping virtualMapping; - String propName; - String columnName; - int reftype; - Constraint[] constraints; - boolean virtual; - boolean readonly; - boolean aggressiveLoading; - boolean aggressiveCaching; - boolean isPrivate = false; - boolean referencesPrimaryKey = false; - String accessName; // db column used to access objects through this relation - String order; - String groupbyOrder; - String groupby; - String prototype; - String groupbyPrototype; - String filter; - int maxSize = 0; - - /** - * This constructor makes a copy of an existing relation. Not all fields are copied, just those - * which are needed in groupby- and virtual nodes defined by this relation. - */ - public Relation(Relation rel) { - this.ownType = rel.ownType; - this.otherType = rel.otherType; - this.propName = rel.propName; - this.columnName = rel.columnName; - this.reftype = rel.reftype; - this.constraints = rel.constraints; - this.accessName = rel.accessName; - this.maxSize = rel.maxSize; - } - - /** - * Reads a relation entry from a line in a properties file. - */ - public Relation(String desc, String propName, DbMapping ownType, Properties props) { - this.ownType = ownType; - this.propName = propName; - otherType = null; - } - - //////////////////////////////////////////////////////////////////////////////////////////// - // parse methods for new file format - //////////////////////////////////////////////////////////////////////////////////////////// - public void update(String desc, Properties props) { - Application app = ownType.getApplication(); - - if ((desc == null) || "".equals(desc.trim())) { - if (propName != null) { - reftype = PRIMITIVE; - columnName = propName; - } else { - reftype = INVALID; - columnName = propName; - } - } else { - desc = desc.trim(); - - int open = desc.indexOf("("); - int close = desc.indexOf(")"); - - if ((open > -1) && (close > open)) { - String ref = desc.substring(0, open).trim(); - String proto = desc.substring(open + 1, close).trim(); - - if ("collection".equalsIgnoreCase(ref)) { - virtual = !"_children".equalsIgnoreCase(propName); - reftype = COLLECTION; - } else if ("mountpoint".equalsIgnoreCase(ref)) { - virtual = true; - reftype = COLLECTION; - prototype = proto; - } else if ("object".equalsIgnoreCase(ref)) { - virtual = false; - if (reftype != COMPLEX_REFERENCE) { - reftype = REFERENCE; - } - } else { - throw new RuntimeException("Invalid property Mapping: " + desc); - } - - otherType = app.getDbMapping(proto); - - if (otherType == null) { - throw new RuntimeException("DbMapping for " + proto + - " not found from " + ownType.getTypeName()); - } - - // make sure the type we're referring to is up to date! - if (otherType != null && otherType.needsUpdate()) { - otherType.update(); - } - - } else { - virtual = false; - columnName = desc; - reftype = PRIMITIVE; - } - } - - readonly = "true".equalsIgnoreCase(props.getProperty(propName + ".readonly")); - - isPrivate = "true".equalsIgnoreCase(props.getProperty(propName + ".private")); - - // the following options only apply to object and collection relations - if ((reftype != PRIMITIVE) && (reftype != INVALID)) { - Vector newConstraints = new Vector(); - - parseOptions(newConstraints, props); - - constraints = new Constraint[newConstraints.size()]; - newConstraints.copyInto(constraints); - - - if (reftype == REFERENCE || reftype == COMPLEX_REFERENCE) { - if (constraints.length == 0) { - referencesPrimaryKey = true; - } else { - boolean rprim = false; - for (int i=0; i 0 && !usesPrimaryKey()) { - reftype = COMPLEX_REFERENCE; - } else { - reftype = REFERENCE; - } - } - - if (reftype == COLLECTION) { - referencesPrimaryKey = (accessName == null) || - accessName.equalsIgnoreCase(otherType.getIDField()); - } - - // if DbMapping for virtual nodes has already been created, - // update its subnode relation. - // FIXME: needs to be synchronized? - if (virtualMapping != null) { - virtualMapping.lastTypeChange = ownType.lastTypeChange; - virtualMapping.subRelation = getVirtualSubnodeRelation(); - virtualMapping.propRelation = getVirtualPropertyRelation(); - } - } else { - referencesPrimaryKey = false; - } - } - - protected void parseOptions(Vector cnst, Properties props) { - String loading = props.getProperty(propName + ".loadmode"); - - aggressiveLoading = (loading != null) && - "aggressive".equalsIgnoreCase(loading.trim()); - - String caching = props.getProperty(propName + ".cachemode"); - - aggressiveCaching = (caching != null) && - "aggressive".equalsIgnoreCase(caching.trim()); - - // get order property - order = props.getProperty(propName + ".order"); - - if ((order != null) && (order.trim().length() == 0)) { - order = null; - } - - // get additional filter property - filter = props.getProperty(propName + ".filter"); - - if (filter != null) { - if (filter.trim().length() == 0) { - filter = null; - } else { - // parenthesise filter - filter = "("+filter+")"; - } - } - - // get max size of collection - String max = props.getProperty(propName + ".maxSize"); - - if (max != null) { - try { - maxSize = Integer.parseInt(max); - } catch (NumberFormatException nfe) { - maxSize = 0; - } - } else { - maxSize = 0; - } - - // get group by property - groupby = props.getProperty(propName + ".group"); - - if ((groupby != null) && (groupby.trim().length() == 0)) { - groupby = null; - } - - if (groupby != null) { - groupbyOrder = props.getProperty(propName + ".group.order"); - - if ((groupbyOrder != null) && (groupbyOrder.trim().length() == 0)) { - groupbyOrder = null; - } - - groupbyPrototype = props.getProperty(propName + ".group.prototype"); - - if ((groupbyPrototype != null) && (groupbyPrototype.trim().length() == 0)) { - groupbyPrototype = null; - } - - // aggressive loading and caching is not supported for groupby-nodes - // aggressiveLoading = aggressiveCaching = false; - } - - // check if subnode condition should be applied for property relations - accessName = props.getProperty(propName + ".accessname"); - - // parse contstraints - String local = props.getProperty(propName + ".local"); - String foreign = props.getProperty(propName + ".foreign"); - - if ((local != null) && (foreign != null)) { - cnst.addElement(new Constraint(local, foreign, false)); - columnName = local; - } - - // parse additional contstraints from *.1 to *.9 - for (int i=1; i<10; i++) { - local = props.getProperty(propName + ".local."+i); - foreign = props.getProperty(propName + ".foreign."+i); - - if ((local != null) && (foreign != null)) { - cnst.addElement(new Constraint(local, foreign, false)); - } - } - } - - /////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Does this relation describe a virtual (collection) node? - */ - public boolean isVirtual() { - return virtual; - } - - /** - * Tell if this relation represents a primitive (scalar) value mapping. - */ - public boolean isPrimitive() { - return reftype == PRIMITIVE; - } - - /** - * Returns true if this Relation describes an object reference property - */ - public boolean isReference() { - return reftype == REFERENCE; - } - - /** - * Returns true if this Relation describes a collection object property - */ - public boolean isCollection() { - return reftype == COLLECTION; - } - - /** - * Returns true if this Relation describes a complex object reference property - */ - public boolean isComplexReference() { - return reftype == COMPLEX_REFERENCE; - } - - /** - * Tell wether the property described by this relation is to be handled as private, i.e. - * a change on it should not result in any changed object/collection relations. - */ - public boolean isPrivate() { - return isPrivate; - } - - /** - * Check whether aggressive loading is set for this relation - */ - public boolean loadAggressively() { - return aggressiveLoading; - } - - /** - * Returns the number of constraints for this relation. - */ - public int countConstraints() { - if (constraints == null) - return 0; - return constraints.length; - } - - /** - * Returns true if the object represented by this Relation has to be - * created on demand at runtime by the NodeManager. This is true for: - * - * - collection (aka virtual) nodes - * - nodes accessed via accessname - * - group nodes - * - complex reference nodes - */ - public boolean createOnDemand() { - return virtual || - (otherType.isRelational() && accessName != null) || - (groupby != null) || isComplexReference(); - } - - /** - * Returns true if the object represented by this Relation has to be - * persisted in the internal db in order to be functional. This is true if - * the subnodes contained in this collection are stored in the embedded - * database. In this case, the collection itself must also be an ordinary - * object stored in the db, since a virtual collection would lose its - * its content after restarts. - */ - public boolean needsPersistence() { - if (!virtual) { - return false; - } - - if (prototype == null) { - return !otherType.isRelational(); - } - - DbMapping sub = otherType.getSubnodeMapping(); - - return (sub != null) && !sub.isRelational(); - } - - /** - * Return the prototype to be used for object reached by this relation - */ - public String getPrototype() { - return prototype; - } - - /** - * Return the name of the local property this relation is defined for - */ - public String getPropName() { - return propName; - } - - /** - * - * - * @param ct ... - */ - public void setColumnType(int ct) { - columnType = ct; - } - - /** - * - * - * @return ... - */ - public int getColumnType() { - return columnType; - } - - /** - * Get the group for a collection relation, if defined. - * - * @return the name of the column used to group child objects, if any. - */ - public String getGroup() { - return groupby; - } - - /** - * Add a constraint to the current list of constraints - */ - protected void addConstraint(Constraint c) { - if (constraints == null) { - constraints = new Constraint[1]; - constraints[0] = c; - } else { - Constraint[] nc = new Constraint[constraints.length + 1]; - - System.arraycopy(constraints, 0, nc, 0, constraints.length); - nc[nc.length - 1] = c; - constraints = nc; - } - } - - /** - * - * - * @return true if the foreign key used for this relation is the - * other object's primary key. - */ - public boolean usesPrimaryKey() { - return referencesPrimaryKey; - } - - /** - * - * - * @return ... - */ - public boolean hasAccessName() { - return accessName != null; - } - - /** - * - * - * @return ... - */ - public String getAccessName() { - return accessName; - } - - /** - * - * - * @return ... - */ - public Relation getSubnodeRelation() { - // return subnoderelation; - return null; - } - - /** - * Return the local field name for updates. - */ - public String getDbField() { - return columnName; - } - - /** - * get a DbMapping to use for virtual aka collection nodes. - */ - public DbMapping getVirtualMapping() { - // return null unless this relation describes a virtual/collection node. - if (!virtual) { - return null; - } - - // if the collection node is prototyped, return the app's DbMapping - // for that prototype - if (prototype != null) { - return otherType; - } - - // create a synthetic DbMapping that describes how to fetch the - // collection's child objects. - if (virtualMapping == null) { - virtualMapping = new DbMapping(ownType.app); - virtualMapping.subRelation = getVirtualSubnodeRelation(); - virtualMapping.propRelation = getVirtualPropertyRelation(); - } - - return virtualMapping; - } - - /** - * Return a Relation that defines the subnodes of a virtual node. - */ - Relation getVirtualSubnodeRelation() { - if (!virtual) { - throw new RuntimeException("getVirtualSubnodeRelation called on non-virtual relation"); - } - - Relation vr = new Relation(this); - - vr.groupby = groupby; - vr.groupbyOrder = groupbyOrder; - vr.groupbyPrototype = groupbyPrototype; - vr.order = order; - vr.filter = filter; - vr.maxSize = maxSize; - vr.constraints = constraints; - vr.aggressiveLoading = aggressiveLoading; - vr.aggressiveCaching = aggressiveCaching; - - return vr; - } - - /** - * Return a Relation that defines the properties of a virtual node. - */ - Relation getVirtualPropertyRelation() { - if (!virtual) { - throw new RuntimeException("getVirtualPropertyRelation called on non-virtual relation"); - } - - Relation vr = new Relation(this); - - vr.groupby = groupby; - vr.groupbyOrder = groupbyOrder; - vr.groupbyPrototype = groupbyPrototype; - vr.order = order; - vr.filter = filter; - vr.maxSize = maxSize; - vr.constraints = constraints; - - return vr; - } - - /** - * Return a Relation that defines the subnodes of a group-by node. - */ - Relation getGroupbySubnodeRelation() { - if (groupby == null) { - throw new RuntimeException("getGroupbySubnodeRelation called on non-group-by relation"); - } - - Relation vr = new Relation(this); - - vr.order = order; - vr.prototype = groupbyPrototype; - vr.filter = filter; - vr.constraints = constraints; - vr.addConstraint(new Constraint(null, groupby, true)); - vr.aggressiveLoading = aggressiveLoading; - vr.aggressiveCaching = aggressiveCaching; - - return vr; - } - - /** - * Return a Relation that defines the properties of a group-by node. - */ - Relation getGroupbyPropertyRelation() { - if (groupby == null) { - throw new RuntimeException("getGroupbyPropertyRelation called on non-group-by relation"); - } - - Relation vr = new Relation(this); - - vr.order = order; - vr.prototype = groupbyPrototype; - vr.filter = filter; - vr.constraints = constraints; - vr.addConstraint(new Constraint(null, groupby, true)); - - return vr; - } - - /** - * Build the second half of an SQL select statement according to this relation - * and a local object. - */ - public String buildQuery(INode home, INode nonvirtual, String kstr, String pre, - boolean useOrder) throws SQLException { - StringBuffer q = new StringBuffer(); - String prefix = pre; - - if (kstr != null && !isComplexReference()) { - q.append(prefix); - - String accessColumn = (accessName == null) ? otherType.getIDField() : accessName; - - q.append(otherType.getTableName()); - q.append("."); - q.append(accessColumn); - q.append(" = "); - - // check if column is string type and value needs to be quoted - if (otherType.needsQuotes(accessColumn)) { - q.append("'"); - q.append(escape(kstr)); - q.append("'"); - } else { - q.append(escape(kstr)); - } - - prefix = " AND "; - } - - for (int i = 0; i < constraints.length; i++) { - q.append(prefix); - constraints[i].addToQuery(q, home, nonvirtual); - prefix = " AND "; - } - - if (filter != null) { - q.append(prefix); - q.append(filter); - } - - if (groupby != null) { - q.append(" GROUP BY " + groupby); - - if (useOrder && (groupbyOrder != null)) { - q.append(" ORDER BY " + groupbyOrder); - } - } else if (useOrder && (order != null)) { - q.append(" ORDER BY " + order); - } - - return q.toString(); - } - - /** - * - * - * @param home ... - * @param nonvirtual ... - * - * @return ... - * - * @throws SQLException ... - */ - public String renderConstraints(INode home, INode nonvirtual) - throws SQLException { - StringBuffer q = new StringBuffer(); - String prefix = " AND "; - - for (int i = 0; i < constraints.length; i++) { - q.append(prefix); - constraints[i].addToQuery(q, home, nonvirtual); - } - - if (filter != null) { - q.append(prefix); - q.append(filter); - } - - return q.toString(); - } - - public void renderJoinConstraints(StringBuffer select) { - for (int i = 0; i < constraints.length; i++) { - select.append(ownType.getTableName()); - select.append("."); - select.append(constraints[i].localName); - select.append(" = _HLM_"); - select.append(propName); - select.append("."); - select.append(constraints[i].foreignName); - if (i == constraints.length-1) { - select.append(" "); - } else { - select.append(" AND "); - } - } - - } - - /** - * Get the order section to use for this relation - */ - public String getOrder() { - if (groupby != null) { - return groupbyOrder; - } else { - return order; - } - } - - /** - * Tell wether the property described by this relation is to be handled - * as readonly/write protected. - */ - public boolean isReadonly() { - return readonly; - } - - /** - * Check if the child node fullfills the constraints defined by this relation. - */ - public boolean checkConstraints(Node parent, Node child) { - // problem: if a filter property is defined for this relation, - // i.e. a piece of static SQL-where clause, we'd have to evaluate it - // in order to check the constraints. Because of this, if a filter - // is defined, we return false as soon as the modified-time is greater - // than the create-time of the child, i.e. if the child node has been - // modified since it was first fetched from the db. - if ((filter != null) && (child.lastModified() > child.created())) { - return false; - } - - for (int i = 0; i < constraints.length; i++) { - String propname = constraints[i].foreignProperty(); - - if (propname != null) { - INode home = constraints[i].isGroupby ? parent - : parent.getNonVirtualParent(); - String value = null; - - if (constraints[i].localKeyIsPrimary(home.getDbMapping())) { - value = home.getID(); - } else if (ownType.isRelational()) { - value = home.getString(constraints[i].localProperty()); - } else { - value = home.getString(constraints[i].localName); - } - - if ((value != null) && !value.equals(child.getString(propname))) { - return false; - } - } - } - - return true; - } - - /** - * Make sure that the child node fullfills the constraints defined by this relation by setting the - * appropriate properties - */ - public void setConstraints(Node parent, Node child) { - Node home = parent.getNonVirtualParent(); - for (int i = 0; i < constraints.length; i++) { - // don't set groupby constraints since we don't know if the - // parent node is the base node or a group node - if (constraints[i].isGroupby) { - continue; - } - - // check if we update the local or the other object, depending on - // whether the primary key of either side is used. - - if (constraints[i].foreignKeyIsPrimary()) { - String localProp = constraints[i].localProperty(); - if (localProp == null) { - System.err.println ("Error: column "+constraints[i].localName+ - " must be mapped in order to be used as constraint in "+ - Relation.this); - } else { - home.setString(localProp, child.getID()); - } - continue; - } - - Relation crel = otherType.columnNameToRelation(constraints[i].foreignName); - if (crel != null) { - // INode home = constraints[i].isGroupby ? parent : nonVirtual; - - if (constraints[i].localKeyIsPrimary(home.getDbMapping())) { - // only set node if property in child object is defined as reference. - if (crel.reftype == REFERENCE) { - INode currentValue = child.getNode(crel.propName); - - // we set the backwards reference iff the reference is currently unset, if - // is set to a transient object, or if the new target is not transient. This - // prevents us from overwriting a persistent refererence with a transient one, - // which would most probably not be what we want. - if ((currentValue == null) || - ((currentValue != home) && - ((currentValue.getState() == Node.TRANSIENT) || - (home.getState() != Node.TRANSIENT)))) { - child.setNode(crel.propName, home); - } - } else if (crel.reftype == PRIMITIVE) { - child.setString(crel.propName, home.getID()); - } - } else if (crel.reftype == PRIMITIVE) { - Property prop = null; - - if (ownType.isRelational()) { - prop = home.getProperty(constraints[i].localProperty()); - } else { - prop = home.getProperty(constraints[i].localName); - } - - if (prop != null) { - child.set(crel.propName, prop.getValue(), prop.getType()); - } - } - } - } - } - - /** - * Unset the constraints that link two objects together. - */ - public void unsetConstraints(Node parent, INode child) { - Node home = parent.getNonVirtualParent(); - for (int i = 0; i < constraints.length; i++) { - // don't set groupby constraints since we don't know if the - // parent node is the base node or a group node - if (constraints[i].isGroupby) { - continue; - } - - // check if we update the local or the other object, depending on - // whether the primary key of either side is used. - - if (constraints[i].foreignKeyIsPrimary()) { - String localProp = constraints[i].localProperty(); - if (localProp != null) { - home.setString(localProp, null); - } - continue; - } - - Relation crel = otherType.columnNameToRelation(constraints[i].foreignName); - if (crel != null) { - // INode home = constraints[i].isGroupby ? parent : nonVirtual; - - if (constraints[i].localKeyIsPrimary(home.getDbMapping())) { - // only set node if property in child object is defined as reference. - if (crel.reftype == REFERENCE) { - INode currentValue = child.getNode(crel.propName); - - if ((currentValue == home)) { - child.setString(crel.propName, null); - } - } else if (crel.reftype == PRIMITIVE) { - child.setString(crel.propName, null); - } - } else if (crel.reftype == PRIMITIVE) { - Property prop = null; - - if (ownType.isRelational()) { - prop = home.getProperty(constraints[i].localProperty()); - } else { - prop = home.getProperty(constraints[i].localName); - } - - if (prop != null) { - child.setString(crel.propName, null); - } - } - } - } - } - - /** - * Returns a map containing the key/value pairs for a specific Node - */ - public Map getKeyParts(INode home) { - Map map = new HashMap(); - for (int i=0; i " + target + c; - } - - /** - * The Constraint class represents a part of the where clause in the query used to - * establish a relation between database mapped objects. - */ - class Constraint { - String localName; - String foreignName; - boolean isGroupby; - - Constraint(String local, String foreign, boolean groupby) { - localName = local; - foreignName = foreign; - isGroupby = groupby; - } - - public void addToQuery(StringBuffer q, INode home, INode nonvirtual) - throws SQLException { - String local = null; - INode ref = isGroupby ? home : nonvirtual; - - if ((localName == null) || - localName.equalsIgnoreCase(ref.getDbMapping().getIDField())) { - local = ref.getID(); - } else { - String homeprop = ownType.columnNameToProperty(localName); - - local = ref.getString(homeprop); - } - - q.append(otherType.getTableName()); - q.append("."); - q.append(foreignName); - q.append(" = "); - - if (otherType.needsQuotes(foreignName)) { - q.append("'"); - q.append(escape(local)); - q.append("'"); - } else { - q.append(escape(local)); - } - } - - public boolean foreignKeyIsPrimary() { - return (foreignName == null) || - foreignName.equalsIgnoreCase(otherType.getIDField()); - } - - public boolean localKeyIsPrimary(DbMapping homeMapping) { - return (homeMapping == null) || (localName == null) || - localName.equalsIgnoreCase(homeMapping.getIDField()); - } - - public String foreignProperty() { - return otherType.columnNameToProperty(foreignName); - } - - public String localProperty() { - return ownType.columnNameToProperty(localName); - } - - public String toString() { - return localName + "=" + otherType.getTypeName() + "." + foreignName; - } - } -} diff --git a/src/helma/objectmodel/db/Replicator.java b/src/helma/objectmodel/db/Replicator.java deleted file mode 100644 index a4286ed2..00000000 --- a/src/helma/objectmodel/db/Replicator.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.rmi.*; -import java.util.*; - -/** - * This class replicates the updates of transactions to other applications via RMI - */ -public class Replicator implements Runnable { - Vector urls; - Vector add; - Vector delete; - Vector currentAdd; - Vector currentDelete; - Thread runner; - NodeManager nmgr; - - /** - * Creates a new Replicator object. - * - * @param nmgr ... - */ - public Replicator(NodeManager nmgr) { - urls = new Vector(); - add = new Vector(); - delete = new Vector(); - this.nmgr = nmgr; - runner = new Thread(this); - runner.start(); - } - - /** - * - * - * @param url ... - */ - public void addUrl(String url) { - urls.addElement(url); - - if (nmgr.logReplication) { - nmgr.app.logEvent("Adding replication listener: " + url); - } - } - - /** - * - */ - public void run() { - while (Thread.currentThread() == runner) { - if (prepareReplication()) { - for (int i = 0; i < urls.size(); i++) { - try { - String url = (String) urls.elementAt(i); - IReplicationListener listener = (IReplicationListener) Naming.lookup(url); - - if (listener == null) { - throw new NullPointerException("Replication listener not bound for URL "+url); - } - - listener.replicateCache(currentAdd, currentDelete); - - if (nmgr.logReplication) { - nmgr.app.logEvent("Sent cache replication event: " + - currentAdd.size() + " added, " + currentDelete.size() + - " deleted"); - } - } catch (Exception x) { - nmgr.app.logEvent("Error sending cache replication event: " + x); - if (nmgr.app.debug()) { - x.printStackTrace(); - } - } - } - } - - try { - if (runner != null) { - Thread.sleep(1000L); - } - } catch (InterruptedException ir) { - runner = null; - } - } - } - - /** - * - * - * @param n ... - */ - public synchronized void addNewNode(Node n) { - add.addElement(n); - } - - /** - * - * - * @param n ... - */ - public synchronized void addModifiedNode(Node n) { - add.addElement(n); - } - - /** - * - * - * @param n ... - */ - public synchronized void addDeletedNode(Node n) { - delete.addElement(n); - } - - private synchronized boolean prepareReplication() { - if ((add.size() == 0) && (delete.size() == 0)) { - return false; - } - - currentAdd = add; - currentDelete = delete; - add = new Vector(); - delete = new Vector(); - - return true; - } -} diff --git a/src/helma/objectmodel/db/Server.java b/src/helma/objectmodel/db/Server.java deleted file mode 100644 index 4b5111ae..00000000 --- a/src/helma/objectmodel/db/Server.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.io.IOException; - -/** - * Helma server main class. This moved to the helma.main package but a - * simple redirector is kept here for backwards compatibility. - */ -public class Server { - /** - * Just invoke the main method in the new Server class. - */ - public static void main(String[] args) throws IOException { - System.err.println("The Helma main class is now in helma.main.Server. Please update your start script accordingly."); - helma.main.Server.main(args); - } -} diff --git a/src/helma/objectmodel/db/SyntheticKey.java b/src/helma/objectmodel/db/SyntheticKey.java deleted file mode 100644 index 7704e6dd..00000000 --- a/src/helma/objectmodel/db/SyntheticKey.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import java.io.Serializable; - -/** - * This is the internal key for an object that is not - or not directly - fetched from a db, - * but derived from another object. This is useful for all kinds of object accessed via a - * symbolic name from another object, like objects mounted via a property name column, - * virtual nodes and groupby nodes. - */ -public final class SyntheticKey implements Key, Serializable { - - // the parent key - private final Key parentKey; - - // the name relative to the parent key - private final String name; - - // lazily initialized hashcode - private transient int hashcode = 0; - - static final long serialVersionUID = -693454133259421857L; - - /** - * make a key for a persistent Object, describing its datasource and id. - */ - public SyntheticKey(Key key, String name) { - this.parentKey = key; - this.name = name; - } - - /** - * - * - * @param what ... - * - * @return ... - */ - public boolean equals(Object what) { - if (what == this) { - return true; - } - - if (!(what instanceof SyntheticKey)) { - return false; - } - - SyntheticKey k = (SyntheticKey) what; - - return parentKey.equals(k.parentKey) && - ((name == k.name) || name.equals(k.name)); - } - - /** - * - * - * @return ... - */ - public int hashCode() { - if (hashcode == 0) { - hashcode = 17 + (37 * name.hashCode()) + (37 * parentKey.hashCode()); - } - - return hashcode; - } - - /** - * - * - * @return ... - */ - public Key getParentKey() { - return parentKey; - } - - /** - * - * - * @return ... - */ - public String getID() { - return name; - } - - /** - * - * - * @return ... - */ - public String getStorageName() { - return null; - } - - /** - * - * - * @return ... - */ - public String toString() { - return parentKey + "/" + name; - } -} diff --git a/src/helma/objectmodel/db/Transactor.java b/src/helma/objectmodel/db/Transactor.java deleted file mode 100644 index 8a9fa06a..00000000 --- a/src/helma/objectmodel/db/Transactor.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.framework.TimeoutException; -import helma.objectmodel.*; -import helma.util.Timer; -import java.io.*; -import java.sql.*; -import java.util.*; - -/** - * A subclass of thread that keeps track of changed nodes and triggers - * changes in the database when a transaction is commited. - */ -public class Transactor extends Thread { - NodeManager nmgr; - - // List of nodes to be updated - private HashMap nodes; - private ArrayList nodesArray; - - // List of visited clean nodes - private HashMap cleannodes; - - // Is a transaction in progress? - private volatile boolean active; - private volatile boolean killed; - - // Transaction for the embedded database - protected ITransaction txn; - - // Transactions for SQL data sources - protected HashMap sqlCon; - public Timer timer; - - // when did the current transaction start? - private long tstart; - - // a name to log the transaction. For HTTP transactions this is the rerquest path - private String tname; - - /** - * Creates a new Transactor object. - * - * @param runnable ... - * @param group ... - * @param nmgr ... - */ - public Transactor(Runnable runnable, ThreadGroup group, NodeManager nmgr) { - super(group, runnable, group.getName()); - this.nmgr = nmgr; - nodes = new HashMap(); - nodesArray = new ArrayList(); - cleannodes = new HashMap(); - sqlCon = new HashMap(); - active = false; - killed = false; - timer = new Timer(); - } - - /** - * - * - * @param node ... - */ - public void visitNode(Node node) { - if (node != null) { - Key key = node.getKey(); - - if (!nodes.containsKey(key)) { - nodes.put(key, node); - nodesArray.add(node); - } - } - } - - /** - * - * - * @param node ... - */ - public void dropNode(Node node) { - if (node != null) { - Key key = node.getKey(); - - nodes.remove(key); - nodesArray.remove(node); - } - } - - /** - * - * - * @param node ... - */ - public void visitCleanNode(Node node) { - if (node != null) { - Key key = node.getKey(); - - if (!cleannodes.containsKey(key)) { - cleannodes.put(key, node); - } - } - } - - /** - * - * - * @param key ... - * @param node ... - */ - public void visitCleanNode(Key key, Node node) { - if (node != null) { - if (!cleannodes.containsKey(key)) { - cleannodes.put(key, node); - } - } - } - - /** - * - * - * @param key ... - * - * @return ... - */ - public Node getVisitedNode(Object key) { - return (key == null) ? null : (Node) cleannodes.get(key); - } - - /** - * - * - * @return ... - */ - public boolean isActive() { - return active; - } - - /** - * - * - * @param src ... - * @param con ... - */ - public void registerConnection(DbSource src, Connection con) { - sqlCon.put(src, con); - } - - /** - * - * - * @param src ... - * - * @return ... - */ - public Connection getConnection(DbSource src) { - return (Connection) sqlCon.get(src); - } - - /** - * - * - * @param tnm ... - * - * @throws Exception ... - * @throws DatabaseException ... - */ - public synchronized void begin(String tnm) throws Exception { - if (killed) { - throw new DatabaseException("Transaction started on killed thread"); - } - - if (active) { - abort(); - } - - nodes.clear(); - nodesArray.clear(); - cleannodes.clear(); - txn = nmgr.db.beginTransaction(); - active = true; - tstart = System.currentTimeMillis(); - tname = tnm; - } - - /** - * - * - * @throws Exception ... - */ - public synchronized void commit() throws Exception { - if (killed) { - abort(); - - return; - } - - int ins = 0; - int upd = 0; - int dlt = 0; - int l = nodesArray.size(); - - Replicator replicator = nmgr.getReplicator(); - - for (int i = 0; i < l; i++) { - Node node = (Node) nodesArray.get(i); - - // update nodes in db - int nstate = node.getState(); - - if (nstate == Node.NEW) { - nmgr.registerNode(node); // register node with nodemanager cache - nmgr.insertNode(nmgr.db, txn, node); - node.setState(Node.CLEAN); - - if (replicator != null) { - replicator.addNewNode(node); - } - - ins++; - nmgr.app.logEvent("inserted: Node " + node.getPrototype() + "/" + - node.getID()); - } else if (nstate == Node.MODIFIED) { - nmgr.updateNode(nmgr.db, txn, node); - node.setState(Node.CLEAN); - - if (replicator != null) { - replicator.addModifiedNode(node); - } - - upd++; - nmgr.app.logEvent("updated: Node " + node.getPrototype() + "/" + - node.getID()); - } else if (nstate == Node.DELETED) { - // nmgr.app.logEvent ("deleted: "+node.getFullName ()+" ("+node.getName ()+")"); - nmgr.deleteNode(nmgr.db, txn, node); - nmgr.evictNode(node); - - if (replicator != null) { - replicator.addDeletedNode(node); - } - - dlt++; - } else { - // nmgr.app.logEvent ("noop: "+node.getFullName ()); - } - - node.clearWriteLock(); - } - - nodes.clear(); - nodesArray.clear(); - cleannodes.clear(); - - if (nmgr.idgen.dirty) { - nmgr.db.saveIDGenerator(txn, nmgr.idgen); - nmgr.idgen.dirty = false; - } - - if (active) { - active = false; - nmgr.db.commitTransaction(txn); - txn = null; - } - - nmgr.app.logAccess(tname + " " + l + " marked, " + ins + " inserted, " + upd + - " updated, " + dlt + " deleted in " + - (System.currentTimeMillis() - tstart) + " millis"); - } - - /** - * - * - * @throws Exception ... - */ - public synchronized void abort() throws Exception { - int l = nodesArray.size(); - - for (int i = 0; i < l; i++) { - Node node = (Node) nodesArray.get(i); - - // Declare node as invalid, so it won't be used by other threads that want to - // write on it and remove it from cache - nmgr.evictNode(node); - node.clearWriteLock(); - } - - nodes.clear(); - nodesArray.clear(); - cleannodes.clear(); - - // close any JDBC connections associated with this transactor thread - closeConnections(); - - if (active) { - active = false; - - if (txn != null) { - nmgr.db.abortTransaction(txn); - txn = null; - } - - nmgr.app.logAccess(tname + " aborted after " + - (System.currentTimeMillis() - tstart) + " millis"); - } - } - - /** - * - */ - public synchronized void kill() { - killed = true; - - // The thread is told to stop by setting the thread flag in the EcmaScript - // evaluator, so we can hope that it stops without doing anything else. - try { - join(500); - } catch (InterruptedException ir) { - } - - // Interrupt the thread if it has not noticed the flag (e.g. because it is busy - // reading from a network socket). - if (isAlive()) { - interrupt(); - - try { - join(1000); - } catch (InterruptedException ir) { - } - } - } - - /** - * - */ - public void closeConnections() { - // nmgr.app.logEvent("Cleaning up Transactor thread"); - if (sqlCon != null) { - for (Iterator i = sqlCon.values().iterator(); i.hasNext();) { - try { - Connection con = (Connection) i.next(); - - con.close(); - nmgr.app.logEvent("Closing DB connection: " + con); - } catch (Exception ignore) { - } - } - - sqlCon.clear(); - } - } - - /** - * - * - * @return ... - */ - public String toString() { - return "Transactor[" + tname + "]"; - } -} diff --git a/src/helma/objectmodel/db/WrappedNodeManager.java b/src/helma/objectmodel/db/WrappedNodeManager.java deleted file mode 100644 index 4c57eb6a..00000000 --- a/src/helma/objectmodel/db/WrappedNodeManager.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.objectmodel.*; -import java.util.List; -import java.util.Vector; - -/** - * A wrapper around NodeManager that catches most Exceptions, or rethrows them as RuntimeExceptions. - * The idea behind this is that we don't care a lot about Exception classes, since Hop programming is done - * in JavaScript which doesn't know about them (except for the exception message). - */ -public final class WrappedNodeManager { - NodeManager nmgr; - - /** - * Creates a new WrappedNodeManager object. - * - * @param nmgr ... - */ - public WrappedNodeManager(NodeManager nmgr) { - this.nmgr = nmgr; - } - - /** - * - * - * @param id ... - * @param dbmap ... - * - * @return ... - */ - public Node getNode(String id, DbMapping dbmap) { - return getNode(new DbKey(dbmap, id)); - } - - /** - * - * - * @param key ... - * - * @return ... - */ - public Node getNode(Key key) { - try { - return nmgr.getNode(key); - } catch (ObjectNotFoundException x) { - return null; - } catch (Exception x) { - nmgr.app.logEvent("Error retrieving Node via DbMapping: " + x); - - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error retrieving Node: " + x); - } - } - - /** - * - * - * @param home ... - * @param id ... - * @param rel ... - * - * @return ... - */ - public Node getNode(Node home, String id, Relation rel) { - try { - return nmgr.getNode(home, id, rel); - } catch (ObjectNotFoundException x) { - return null; - } catch (Exception x) { - nmgr.app.logEvent("Error retrieving Node \"" + id + "\" from " + home + ": " + - x); - - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error retrieving Node: " + x); - } - } - - /** - * - * - * @param home ... - * @param rel ... - * - * @return ... - */ - public List getNodes(Node home, Relation rel) { - try { - return nmgr.getNodes(home, rel); - } catch (Exception x) { - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error retrieving Nodes: " + x); - } - } - - /** - * - * - * @param home ... - * @param rel ... - * - * @return ... - */ - public List getNodeIDs(Node home, Relation rel) { - try { - return nmgr.getNodeIDs(home, rel); - } catch (Exception x) { - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error retrieving NodeIDs: " + x); - } - } - - /** - * - * - * @param home ... - * @param rel ... - * - * @return ... - */ - public int countNodes(Node home, Relation rel) { - try { - return nmgr.countNodes(home, rel); - } catch (Exception x) { - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error counting Node: " + x); - } - } - - /** - * - * - * @param node ... - */ - public void deleteNode(Node node) { - try { - nmgr.deleteNode(node); - } catch (Exception x) { - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error deleting Node: " + x); - } - } - - /** - * - * - * @param home ... - * @param rel ... - * - * @return ... - */ - public Vector getPropertyNames(Node home, Relation rel) { - try { - return nmgr.getPropertyNames(home, rel); - } catch (Exception x) { - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException("Error retrieving property names: " + x); - } - } - - /** - * - * - * @param node ... - */ - public void registerNode(Node node) { - nmgr.registerNode(node); - } - - /** - * - * - * @param node ... - */ - public void evictNode(Node node) { - nmgr.evictNode(node); - } - - /** - * - * - * @param key ... - */ - public void evictNodeByKey(Key key) { - nmgr.evictNodeByKey(key); - } - - /** - * - * - * @param key ... - */ - public void evictKey(Key key) { - nmgr.evictKey(key); - } - - /** - * - * - * @return ... - */ - public String generateID() { - return nmgr.idgen.newID(); - } - - /** - * - * - * @param map ... - * - * @return ... - */ - public String generateID(DbMapping map) { - try { - // check if we use internal id generator - if ((map == null) || !map.isRelational() || - "[hop]".equalsIgnoreCase(map.getIDgen())) { - return nmgr.idgen.newID(); - } - // or if we query max key value - else if ((map.getIDgen() == null) || - "[max]".equalsIgnoreCase(map.getIDgen())) { - return nmgr.generateMaxID(map); - } else { - return nmgr.generateID(map); - } - - // otherwise, we use an oracle sequence - } catch (Exception x) { - if (nmgr.app.debug()) { - x.printStackTrace(); - } - - throw new RuntimeException(x.toString()); - } - } - - /** - * - * - * @return ... - */ - public Object[] getCacheEntries() { - return nmgr.getCacheEntries(); - } - - /** - * - * - * @param msg ... - */ - public void logEvent(String msg) { - nmgr.app.logEvent(msg); - } - - /** - * - * - * @param name ... - * - * @return ... - */ - public DbMapping getDbMapping(String name) { - return nmgr.app.getDbMapping(name); - } -} diff --git a/src/helma/objectmodel/db/XmlDatabase.java b/src/helma/objectmodel/db/XmlDatabase.java deleted file mode 100644 index c4a6ddc5..00000000 --- a/src/helma/objectmodel/db/XmlDatabase.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.db; - -import helma.objectmodel.*; -import helma.objectmodel.dom.*; -import java.io.*; -import javax.xml.parsers.ParserConfigurationException; -import org.xml.sax.SAXException; - -/** - * A simple XML-database - */ -public final class XmlDatabase implements IDatabase { - private String dbHome; - private File dbBaseDir; - private NodeManager nmgr; - private IDGenerator idgen; - - // character encoding to use when writing files. - // use standard encoding by default. - private String encoding = null; - - /** - * Creates a new XmlDatabase object. - * - * @param dbHome ... - * @param dbFilename ... - * @param nmgr ... - * - * @throws DatabaseException ... - * @throws RuntimeException ... - */ - public XmlDatabase(String dbHome, String dbFilename, NodeManager nmgr) - throws DatabaseException { - this.dbHome = dbHome; - this.nmgr = nmgr; - dbBaseDir = new File(dbHome); - - if (!dbBaseDir.exists() && !dbBaseDir.mkdirs()) { - throw new RuntimeException("Couldn't create DB-directory"); - } - - this.encoding = nmgr.app.getCharset(); - } - - /** - * - */ - public void shutdown() { - } - - /** - * - * - * @return ... - * - * @throws DatabaseException ... - */ - public ITransaction beginTransaction() throws DatabaseException { - return null; - } - - /** - * - * - * @param txn ... - * - * @throws DatabaseException ... - */ - public void commitTransaction(ITransaction txn) throws DatabaseException { - } - - /** - * - * - * @param txn ... - * - * @throws DatabaseException ... - */ - public void abortTransaction(ITransaction txn) throws DatabaseException { - } - - /** - * - * - * @return ... - * - * @throws ObjectNotFoundException ... - */ - public String nextID() throws ObjectNotFoundException { - if (idgen == null) { - getIDGenerator(null); - } - - return idgen.newID(); - } - - /** - * - * - * @param txn ... - * - * @return ... - * - * @throws ObjectNotFoundException ... - */ - public IDGenerator getIDGenerator(ITransaction txn) - throws ObjectNotFoundException { - File file = new File(dbBaseDir, "idgen.xml"); - - this.idgen = IDGenParser.getIDGenerator(file); - - return idgen; - } - - /** - * - * - * @param txn ... - * @param idgen ... - * - * @throws Exception ... - */ - public void saveIDGenerator(ITransaction txn, IDGenerator idgen) - throws IOException { - File file = new File(dbBaseDir, "idgen.xml"); - - IDGenParser.saveIDGenerator(idgen, file); - this.idgen = idgen; - } - - /** - * - * - * @param txn ... - * @param kstr ... - * - * @return ... - * - * @throws Exception ... - * @throws ObjectNotFoundException ... - */ - public INode getNode(ITransaction txn, String kstr) - throws IOException, ObjectNotFoundException, - ParserConfigurationException, SAXException { - File f = new File(dbBaseDir, kstr + ".xml"); - - if (!f.exists()) { - throw new ObjectNotFoundException("Object not found for key " + kstr + "."); - } - - try { - XmlDatabaseReader reader = new XmlDatabaseReader(nmgr); - Node node = reader.read(f); - - return node; - } catch (RuntimeException x) { - nmgr.app.logEvent("error reading node from XmlDatbase: " + x.toString()); - throw new ObjectNotFoundException(x.toString()); - } - } - - /** - * - * - * @param txn ... - * @param kstr ... - * @param node ... - * - * @throws Exception ... - */ - public void saveNode(ITransaction txn, String kstr, INode node) - throws IOException { - XmlWriter writer = null; - File file = new File(dbBaseDir, kstr + ".xml"); - - if (encoding != null) { - writer = new XmlWriter(file, encoding); - } else { - writer = new XmlWriter(file); - } - - writer.setMaxLevels(1); - - writer.write((Node) node); - - writer.close(); - } - - /** - * - * - * @param txn ... - * @param kstr ... - * - * @throws Exception ... - */ - public void deleteNode(ITransaction txn, String kstr) - throws IOException { - File f = new File(dbBaseDir, kstr + ".xml"); - - f.delete(); - } - - /** - * - * - * @param enc ... - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * - * - * @return ... - */ - public String getEncoding() { - return encoding; - } -} diff --git a/src/helma/objectmodel/dom/IDGenParser.java b/src/helma/objectmodel/dom/IDGenParser.java deleted file mode 100644 index f6cfd3f8..00000000 --- a/src/helma/objectmodel/dom/IDGenParser.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - -import helma.objectmodel.ObjectNotFoundException; -import helma.objectmodel.db.IDGenerator; -import org.w3c.dom.*; -import java.io.*; -import java.util.Date; - -/** - * - */ -public class IDGenParser { - /** - * - * - * @param file ... - * - * @return ... - * - * @throws ObjectNotFoundException ... - */ - public static IDGenerator getIDGenerator(File file) - throws ObjectNotFoundException { - if (!file.exists()) { - throw new ObjectNotFoundException("IDGenerator not found in idgen.xml"); - } - - try { - Document document = XmlUtil.parse(new FileInputStream(file)); - org.w3c.dom.Element tmp = (Element) document.getDocumentElement() - .getElementsByTagName("counter") - .item(0); - - return new IDGenerator(Long.parseLong(XmlUtil.getTextContent(tmp))); - } catch (Exception e) { - throw new ObjectNotFoundException(e.toString()); - } - } - - /** - * - * - * @param idgen ... - * @param file ... - * - * @return ... - * - * @throws Exception ... - */ - public static IDGenerator saveIDGenerator(IDGenerator idgen, File file) - throws IOException { - OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file)); - - out.write("\n"); - out.write("\n"); - out.write("\n"); - out.write("\n"); - out.write(" " + idgen.getValue() + "\n"); - out.write("\n"); - out.close(); - - return idgen; - } -} diff --git a/src/helma/objectmodel/dom/XmlConstants.java b/src/helma/objectmodel/dom/XmlConstants.java deleted file mode 100644 index 7c87064c..00000000 --- a/src/helma/objectmodel/dom/XmlConstants.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - -/** - * - */ -public interface XmlConstants { - public final String NAMESPACE = "http://www.helma.org/docs/guide/features/database"; - public final String DATEFORMAT = "dd.MM.yyyy HH:mm:ss z"; -} diff --git a/src/helma/objectmodel/dom/XmlConverter.java b/src/helma/objectmodel/dom/XmlConverter.java deleted file mode 100644 index 95e1bed6..00000000 --- a/src/helma/objectmodel/dom/XmlConverter.java +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - -import helma.objectmodel.*; -import helma.util.SystemProperties; -import org.w3c.dom.*; -import org.xml.sax.InputSource; -import java.io.*; -import java.net.*; -import java.util.*; -import javax.xml.parsers.*; - -/** - * - */ -public class XmlConverter implements XmlConstants { - private boolean DEBUG = false; - private boolean sparse = false; - private Properties props; - private char defaultSeparator = '_'; - private int offset = 0; - - /** - * Creates a new XmlConverter object. - */ - public XmlConverter() { - props = new SystemProperties(); - } - - /** - * Creates a new XmlConverter object. - * - * @param propFile ... - */ - public XmlConverter(String propFile) { - props = new SystemProperties(propFile); - extractProperties(props); - } - - /** - * Creates a new XmlConverter object. - * - * @param propFile ... - */ - public XmlConverter(File propFile) { - this(propFile.getAbsolutePath()); - } - - /** - * Creates a new XmlConverter object. - * - * @param props ... - */ - public XmlConverter(Properties props) { - this.props = props; - extractProperties(props); - } - - /** - * - * - * @param desc ... - * - * @return ... - */ - public INode convert(String desc) { - return convert(desc, new TransientNode()); - } - - /** - * - * - * @param desc ... - * @param helmaNode ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public INode convert(String desc, INode helmaNode) - throws RuntimeException { - try { - return convert(new URL(desc), helmaNode); - } catch (MalformedURLException notanurl) { - try { - return convert(new File(desc), helmaNode); - } catch (FileNotFoundException notfound) { - throw new RuntimeException("couldn't read xml: " + desc); - } - } catch (IOException ioerror) { - throw new RuntimeException("couldn't read xml: " + desc); - } - } - - /** - * - * - * @param file ... - * @param helmaNode ... - * - * @return ... - * - * @throws RuntimeException ... - * @throws FileNotFoundException ... - */ - public INode convert(File file, INode helmaNode) - throws RuntimeException, FileNotFoundException { - return convert(new FileInputStream(file), helmaNode); - } - - /** - * - * - * @param url ... - * @param helmaNode ... - * - * @return ... - * - * @throws RuntimeException ... - * @throws IOException ... - * @throws MalformedURLException ... - */ - public INode convert(URL url, INode helmaNode) - throws RuntimeException, IOException, MalformedURLException { - return convert(url.openConnection().getInputStream(), helmaNode); - } - - /** - * - * - * @param in ... - * @param helmaNode ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public INode convert(InputStream in, INode helmaNode) - throws RuntimeException { - Document document = XmlUtil.parse(in); - - if ((document != null) && (document.getDocumentElement() != null)) { - return convert(document.getDocumentElement(), helmaNode, new HashMap()); - } else { - return helmaNode; - } - } - - /** - * - * - * @param xml ... - * @param helmaNode ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public INode convertFromString(String xml, INode helmaNode) - throws RuntimeException { - Document document = XmlUtil.parse(new InputSource(new StringReader(xml))); - - if ((document != null) && (document.getDocumentElement() != null)) { - return convert(document.getDocumentElement(), helmaNode, new HashMap()); - } else { - return helmaNode; - } - } - - /** - * - * - * @param element ... - * @param helmaNode ... - * @param nodeCache ... - * - * @return ... - */ - public INode convert(Element element, INode helmaNode, Map nodeCache) { - offset++; - - // previousNode is used to cache previous nodes with the same prototype - // so we can reset it in the nodeCache after we've run - Object previousNode = null; - - if (DEBUG) { - debug("reading " + element.getNodeName()); - } - - String prototype = props.getProperty(element.getNodeName() + "._prototype"); - - if ((prototype == null) && !sparse) { - prototype = "HopObject"; - } - - // if we have a prototype (either explicit or implicit "hopobject"), - // set it on the Helma node and store it in the node cache. - if (prototype != null) { - helmaNode.setName(element.getNodeName()); - helmaNode.setPrototype(prototype); - previousNode = nodeCache.put(prototype, helmaNode); - } - - // check attributes of the current element - attributes(element, helmaNode, nodeCache); - - // check child nodes of the current element - if (element.hasChildNodes()) { - children(element, helmaNode, nodeCache); - } - - // if it exists, restore the previous node we've replaced in the node cache. - if (previousNode != null) { - nodeCache.put(prototype, previousNode); - } - - offset--; - - return helmaNode; - } - - /** - * parse xml children and create hopobject-children - */ - private INode children(Element element, helma.objectmodel.INode helmaNode, - Map nodeCache) { - NodeList list = element.getChildNodes(); - int len = list.getLength(); - boolean nodeIsInitialized = !nodeCache.isEmpty(); - StringBuffer textcontent = new StringBuffer(); - String domKey; - String helmaKey; - - for (int i = 0; i < len; i++) { - // loop through the list of children - org.w3c.dom.Node childNode = list.item(i); - - // if the current node hasn't been initialized yet, try if it can - // be initialized and converted from one of the child elements. - if (!nodeIsInitialized) { - if (childNode.getNodeType() == Node.ELEMENT_NODE) { - convert((Element) childNode, helmaNode, nodeCache); - - if (helmaNode.getPrototype() != null) { - return helmaNode; - } - } - - continue; - } - - // if it's text content of this element -> append to StringBuffer - if ((childNode.getNodeType() == Node.TEXT_NODE) || - (childNode.getNodeType() == Node.CDATA_SECTION_NODE)) { - textcontent.append(childNode.getNodeValue().trim()); - - continue; - } - - // it's some kind of element (property or child) - if (childNode.getNodeType() == Node.ELEMENT_NODE) { - Element childElement = (Element) childNode; - - // get the basic key we have to look for in the properties-table - domKey = element.getNodeName() + "." + childElement.getNodeName(); - - // is there a childtext-2-property mapping? - if ((props != null) && props.containsKey(domKey + "._text")) { - helmaKey = props.getProperty(domKey + "._text"); - - if (helmaKey.equals("")) { - // if property is set but without value, read elementname for this mapping - helmaKey = childElement.getNodeName().replace(':', - defaultSeparator); - } - - if (DEBUG) { - debug("childtext-2-property mapping, helmaKey " + helmaKey + - " for domKey " + domKey); - } - - // check if helmaKey contains an explicit prototype name in which to - // set the property. - int dot = helmaKey.indexOf("."); - - if (dot > -1) { - String prototype = helmaKey.substring(0, dot); - INode node = (INode) nodeCache.get(prototype); - - helmaKey = helmaKey.substring(dot + 1); - - if ((node != null) && (node.getString(helmaKey) == null)) { - node.setString(helmaKey, XmlUtil.getTextContent(childNode)); - } - } else if (helmaNode.getString(helmaKey) == null) { - helmaNode.setString(helmaKey, XmlUtil.getTextContent(childNode)); - - if (DEBUG) { - debug("childtext-2-property mapping, setting " + helmaKey + - " as string"); - } - } - - continue; - } - - // is there a simple child-2-property mapping? - // (lets the user define to use only one element and make this a property - // and simply ignore other elements of the same name) - if ((props != null) && props.containsKey(domKey + "._property")) { - helmaKey = props.getProperty(domKey + "._property"); - - // if property is set but without value, read elementname for this mapping: - if (helmaKey.equals("")) { - helmaKey = childElement.getNodeName().replace(':', - defaultSeparator); - } - - if (DEBUG) { - debug("child-2-property mapping, helmaKey " + helmaKey + - " for domKey " + domKey); - } - - // get the node on which to opererate, depending on the helmaKey - // value from the properties file. - INode node = helmaNode; - int dot = helmaKey.indexOf("."); - - if (dot > -1) { - String prototype = helmaKey.substring(0, dot); - - if (!prototype.equalsIgnoreCase(node.getPrototype())) { - node = (INode) nodeCache.get(prototype); - } - - helmaKey = helmaKey.substring(dot + 1); - } - - if (node == null) { - continue; - } - - if (node.getNode(helmaKey) == null) { - convert(childElement, node.createNode(helmaKey), nodeCache); - - if (DEBUG) { - debug("read " + childElement.toString() + - node.getNode(helmaKey).toString()); - } - } - - continue; - } - - // map it to one of the children-lists - helma.objectmodel.INode newHelmaNode = null; - String childrenMapping = props.getProperty(element.getNodeName() + - "._children"); - - // do we need a mapping directly among _children of helmaNode? - // can either be through property elname._children=_all or elname._children=childname - if ((childrenMapping != null) && - (childrenMapping.equals("_all") || - childrenMapping.equals(childElement.getNodeName()))) { - newHelmaNode = convert(childElement, helmaNode.createNode(null), - nodeCache); - } - - // in which virtual subnode collection should objects of this type be stored? - helmaKey = props.getProperty(domKey); - - if ((helmaKey == null) && !sparse) { - helmaKey = childElement.getNodeName().replace(':', defaultSeparator); - } - - if (helmaKey == null) { - // we don't map this child element itself since we do - // sparse parsing, but there may be something of interest - // in the child's attributes and child elements. - attributes(childElement, helmaNode, nodeCache); - children(childElement, helmaNode, nodeCache); - - continue; - } - - // get the node on which to opererate, depending on the helmaKey - // value from the properties file. - INode node = helmaNode; - int dot = helmaKey.indexOf("."); - - if (dot > -1) { - String prototype = helmaKey.substring(0, dot); - - if (!prototype.equalsIgnoreCase(node.getPrototype())) { - node = (INode) nodeCache.get(prototype); - } - - helmaKey = helmaKey.substring(dot + 1); - } - - if (node == null) { - continue; - } - - // try to get the virtual node - INode worknode = null; - - if ("_children".equals(helmaKey)) { - worknode = node; - } else { - worknode = node.getNode(helmaKey); - - if (worknode == null) { - // if virtual node doesn't exist, create it - worknode = helmaNode.createNode(helmaKey); - } - } - - if (DEBUG) { - debug("mounting child " + childElement.getNodeName() + - " at worknode " + worknode.toString()); - } - - // now mount it, possibly re-using the helmaNode that's been created before - if (newHelmaNode != null) { - worknode.addNode(newHelmaNode); - } else { - convert(childElement, worknode.createNode(null), nodeCache); - } - } - - // forget about other types (comments etc) - continue; - } - - // if there's some text content for this element, map it: - if ((textcontent.length() > 0) && !sparse) { - helmaKey = props.getProperty(element.getNodeName() + "._text"); - - if (helmaKey == null) { - helmaKey = "text"; - } - - if (DEBUG) { - debug("setting text " + textcontent + " to property " + helmaKey + - " of object " + helmaNode); - } - - helmaNode.setString(helmaKey, textcontent.toString().trim()); - } - - return helmaNode; - } - - /** - * set element's attributes as properties of helmaNode - */ - private INode attributes(Element element, INode helmaNode, Map nodeCache) { - NamedNodeMap nnm = element.getAttributes(); - int len = nnm.getLength(); - - for (int i = 0; i < len; i++) { - org.w3c.dom.Node attr = nnm.item(i); - String helmaKey = props.getProperty(element.getNodeName() + "._attribute." + - attr.getNodeName()); - - // unless we only map explicit attributes, use attribute name as property name - // in case no property name was defined. - if ((helmaKey == null) && !sparse) { - helmaKey = attr.getNodeName().replace(':', defaultSeparator); - } - - if (helmaKey != null) { - // check if the mapping contains the prototype to which - // the property should be applied - int dot = helmaKey.indexOf("."); - - if (dot > -1) { - String prototype = helmaKey.substring(0, dot); - INode node = (INode) nodeCache.get(prototype); - - if (node != null) { - node.setString(helmaKey.substring(dot + 1), attr.getNodeValue()); - } - } else if (helmaNode.getPrototype() != null) { - helmaNode.setString(helmaKey, attr.getNodeValue()); - } - } - } - - return helmaNode; - } - - /** - * utility function - */ - private void extractProperties(Properties props) { - if (props.containsKey("separator")) { - defaultSeparator = props.getProperty("separator").charAt(0); - } - - sparse = "sparse".equalsIgnoreCase(props.getProperty("_mode")); - } - - /** for testing */ - void debug(Object msg) { - for (int i = 0; i < offset; i++) { - System.out.print(" "); - } - - System.out.println(msg.toString()); - } - - /** - * - * - * @param args ... - */ - public static void main(String[] args) { - } -} diff --git a/src/helma/objectmodel/dom/XmlDatabaseReader.java b/src/helma/objectmodel/dom/XmlDatabaseReader.java deleted file mode 100644 index 650b9a9f..00000000 --- a/src/helma/objectmodel/dom/XmlDatabaseReader.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - -import helma.objectmodel.INode; -import helma.objectmodel.db.DbKey; -import helma.objectmodel.db.DbMapping; -import helma.objectmodel.db.ExternalizableVector; -import helma.objectmodel.db.Node; -import helma.objectmodel.db.NodeHandle; -import helma.objectmodel.db.NodeManager; -import helma.objectmodel.db.Property; -import org.xml.sax.*; -import org.xml.sax.helpers.DefaultHandler; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; - -// import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import javax.xml.parsers.*; - -/** - * - */ -public final class XmlDatabaseReader extends DefaultHandler implements XmlConstants { - static SAXParserFactory factory = SAXParserFactory.newInstance(); - private NodeManager nmgr = null; - private Node currentNode; - private String elementType = null; - private String elementName = null; - private StringBuffer charBuffer = null; - Hashtable propMap = null; - List subnodes = null; - - /** - * Creates a new XmlDatabaseReader object. - * - * @param nmgr ... - */ - public XmlDatabaseReader(NodeManager nmgr) { - this.nmgr = nmgr; - } - - /** - * read an InputSource with xml-content. - */ - public Node read(File file) - throws ParserConfigurationException, SAXException, IOException { - if (nmgr == null) { - throw new RuntimeException("can't create a new Node without a NodeManager"); - } - - SAXParser parser = factory.newSAXParser(); - - currentNode = null; - - parser.parse(file, this); - - return currentNode; - } - - /** - * - * - * @param namespaceURI ... - * @param localName ... - * @param qName ... - * @param atts ... - */ - public void startElement(String namespaceURI, String localName, String qName, - Attributes atts) { - // System.err.println ("XML-READ: startElement "+namespaceURI+", "+localName+", "+qName+", "+atts.getValue("id")); - // discard the first element called xmlroot - if ("xmlroot".equals(qName) && (currentNode == null)) { - return; - } - - // if currentNode is null, this must be the hopobject node - if ("hopobject".equals(qName) && (currentNode == null)) { - String id = atts.getValue("id"); - String name = atts.getValue("name"); - String prototype = atts.getValue("prototype"); - - if ("".equals(prototype)) { - prototype = "hopobject"; - } - - try { - long created = Long.parseLong(atts.getValue("created")); - long lastmodified = Long.parseLong(atts.getValue("lastModified")); - - currentNode = new Node(name, id, prototype, nmgr.safe, created, - lastmodified); - } catch (NumberFormatException e) { - currentNode = new Node(name, id, prototype, nmgr.safe); - } - - return; - } - - // find out what kind of element this is by looking at - // the number and names of attributes. - String idref = atts.getValue("idref"); - - if (idref != null) { - // a hopobject reference. - NodeHandle handle = makeNodeHandle(atts); - - if ("hop:child".equals(qName)) { - if (subnodes == null) { - subnodes = new ExternalizableVector(); - currentNode.setSubnodes(subnodes); - } - - subnodes.add(handle); - } else if ("hop:parent".equals(qName)) { - currentNode.setParentHandle(handle); - } else { - // property name may be encoded as "propertyname" attribute, - // otherwise it is the element name - String propName = atts.getValue("propertyname"); - - if (propName == null) { - propName = qName; - } - - Property prop = new Property(propName, currentNode); - - prop.setNodeHandle(handle); - - if (propMap == null) { - propMap = new Hashtable(); - currentNode.setPropMap(propMap); - } - - propMap.put(propName.toLowerCase(), prop); - } - } else { - // a primitive property - elementType = atts.getValue("type"); - - if (elementType == null) { - elementType = "string"; - } - - // property name may be encoded as "propertyname" attribute, - // otherwise it is the element name - elementName = atts.getValue("propertyname"); - - if (elementName == null) { - elementName = qName; - } - - if (charBuffer == null) { - charBuffer = new StringBuffer(); - } else { - charBuffer.setLength(0); - } - } - } - - /** - * - * - * @param ch ... - * @param start ... - * @param length ... - * - * @throws SAXException ... - */ - public void characters(char[] ch, int start, int length) - throws SAXException { - // append chars to char buffer - if (elementType != null) { - charBuffer.append(ch, start, length); - } - } - - /** - * - * - * @param namespaceURI ... - * @param localName ... - * @param qName ... - * - * @throws SAXException ... - */ - public void endElement(String namespaceURI, String localName, String qName) - throws SAXException { - if (elementType != null) { - Property prop = new Property(elementName, currentNode); - String charValue = charBuffer.toString(); - - charBuffer.setLength(0); - - if ("boolean".equals(elementType)) { - if ("true".equals(charValue)) { - prop.setBooleanValue(true); - } else { - prop.setBooleanValue(false); - } - } else if ("date".equals(elementType)) { - SimpleDateFormat format = new SimpleDateFormat(DATEFORMAT); - - try { - Date date = format.parse(charValue); - - prop.setDateValue(date); - } catch (ParseException e) { - prop.setStringValue(charValue); - } - } else if ("float".equals(elementType)) { - prop.setFloatValue((new Double(charValue)).doubleValue()); - } else if ("integer".equals(elementType)) { - prop.setIntegerValue((new Long(charValue)).longValue()); - } else { - prop.setStringValue(charValue); - } - - if (propMap == null) { - propMap = new Hashtable(); - currentNode.setPropMap(propMap); - } - - propMap.put(elementName.toLowerCase(), prop); - elementName = null; - elementType = null; - charValue = null; - } - } - - // create a node handle from a node reference DOM element - private NodeHandle makeNodeHandle(Attributes atts) { - String idref = atts.getValue("idref"); - String protoref = atts.getValue("prototyperef"); - DbMapping dbmap = null; - - if (protoref != null) { - dbmap = nmgr.getDbMapping(protoref); - } - - return new NodeHandle(new DbKey(dbmap, idref)); - } -} diff --git a/src/helma/objectmodel/dom/XmlReader.java b/src/helma/objectmodel/dom/XmlReader.java deleted file mode 100644 index 10ffbb73..00000000 --- a/src/helma/objectmodel/dom/XmlReader.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - -import helma.objectmodel.INode; -import org.xml.sax.*; -import org.xml.sax.helpers.DefaultHandler; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Stack; -import javax.xml.parsers.*; - -/** - * - */ -public final class XmlReader extends DefaultHandler implements XmlConstants { - static SAXParserFactory factory = SAXParserFactory.newInstance(); - private INode rootNode; - private INode currentNode; - private Stack nodeStack; - private HashMap convertedNodes; - private String elementType = null; - private String elementName = null; - private StringBuffer charBuffer = null; - boolean parsingHopObject; - - /** - * Creates a new XmlReader object. - */ - public XmlReader() { - } - - /** - * main entry to read an xml-file. - */ - public INode read(File file, INode helmaNode) - throws ParserConfigurationException, SAXException, IOException { - try { - return read(new FileInputStream(file), helmaNode); - } catch (FileNotFoundException notfound) { - System.err.println("couldn't find xml-file: " + file.getAbsolutePath()); - - return helmaNode; - } - } - - /** - * read an InputStream with xml-content. - */ - public INode read(InputStream in, INode helmaNode) - throws ParserConfigurationException, SAXException, IOException { - return read(new InputSource(in), helmaNode); - } - - /** - * read an character reader with xml-content. - */ - public INode read(Reader in, INode helmaNode) - throws ParserConfigurationException, SAXException, IOException { - return read(new InputSource(in), helmaNode); - } - - /** - * read an InputSource with xml-content. - */ - public INode read(InputSource in, INode helmaNode) - throws ParserConfigurationException, SAXException, IOException { - if (helmaNode == null) { - throw new RuntimeException("Can't create a new Node without a root Node"); - } - - SAXParser parser = factory.newSAXParser(); - - rootNode = helmaNode; - currentNode = null; - convertedNodes = new HashMap(); - nodeStack = new Stack(); - parsingHopObject = true; - - parser.parse(in, this); - - return rootNode; - } - - /** - * - * - * @param namespaceURI ... - * @param localName ... - * @param qName ... - * @param atts ... - * - * @throws SAXException ... - */ - public void startElement(String namespaceURI, String localName, String qName, - Attributes atts) throws SAXException { - // System.err.println ("XML-READ: startElement "+namespaceURI+", "+localName+", "+qName+", "+atts.getValue("id")); - // discard the first element called xmlroot - if ("xmlroot".equals(qName) && (currentNode == null)) { - return; - } - - // if currentNode is null, this must be the hopobject node - String id = atts.getValue("id"); - - if (id != null) { - // check if there is a current node. - if (currentNode == null) { - // If currentNode is null, this is the root node we're parsing. - currentNode = rootNode; - } else if ("hop:child".equals(qName)) { - // it's an anonymous child node - nodeStack.push(currentNode); - currentNode = currentNode.createNode(null); - } else { - // it's a named node property - nodeStack.push(currentNode); - - // property name may be encoded as "propertyname" attribute, - // otherwise it is the element name - String propName = atts.getValue("propertyname"); - - if (propName == null) { - propName = qName; - } - - currentNode = currentNode.createNode(propName); - } - - // set the prototype on the current node and - // add it to the map of parsed nodes. - String prototype = atts.getValue("prototype"); - - if (!"".equals(prototype) && !"hopobject".equals(prototype)) { - currentNode.setPrototype(prototype); - } - - String key = id + "-" + prototype; - - convertedNodes.put(key, currentNode); - - return; - } - - // check if we have a currentNode to set properties on, - // otherwise throw exception. - if (currentNode == null) { - throw new SAXException("Invalid XML: No valid root HopObject found"); - } - - // check if we are inside a HopObject - otherwise throw an exception - if (!parsingHopObject) { - throw new SAXException("Invalid XML: Found nested non-HobObject elements"); - } - - // if we got so far, the element is not a hopobject. Set flag to prevent - // the hopobject stack to be popped when the element - // is closed. - parsingHopObject = false; - - // Is it a reference to an already parsed node? - String idref = atts.getValue("idref"); - - if (idref != null) { - // a reference to a node that should have been parsed - // and lying in our cache of parsed nodes. - String prototyperef = atts.getValue("prototyperef"); - String key = idref + "-" + prototyperef; - INode n = (INode) convertedNodes.get(key); - - if (n != null) { - if ("hop:child".equals(qName)) { - // add an already parsed node as child to current node - currentNode.addNode(n); - } else { - // set an already parsed node as node property to current node - // property name may be encoded as "propertyname" attribute, - // otherwise it is the element name - String propName = atts.getValue("propertyname"); - - if (propName == null) { - propName = qName; - } - - currentNode.setNode(propName, n); - } - } - } else { - // It's a primitive property. Remember the property name and type - // so we can properly parse/interpret the character data when we - // get it later on. - elementType = atts.getValue("type"); - - if (elementType == null) { - elementType = "string"; - } - - // property name may be encoded as "propertyname" attribute, - // otherwise it is the element name - elementName = atts.getValue("propertyname"); - - if (elementName == null) { - elementName = qName; - } - - if (charBuffer == null) { - charBuffer = new StringBuffer(); - } else { - charBuffer.setLength(0); - } - } - } - - /** - * - * - * @param ch ... - * @param start ... - * @param length ... - * - * @throws SAXException ... - */ - public void characters(char[] ch, int start, int length) - throws SAXException { - // System.err.println ("CHARACTERS: "+new String (ch, start, length)); - // append chars to char buffer - if (elementType != null) { - charBuffer.append(ch, start, length); - } - } - - /** - * - * - * @param namespaceURI ... - * @param localName ... - * @param qName ... - * - * @throws SAXException ... - */ - public void endElement(String namespaceURI, String localName, String qName) - throws SAXException { - if (elementType != null) { - String charValue = charBuffer.toString(); - - charBuffer.setLength(0); - - if ("boolean".equals(elementType)) { - if ("true".equals(charValue)) { - currentNode.setBoolean(elementName, true); - } else { - currentNode.setBoolean(elementName, false); - } - } else if ("date".equals(elementType)) { - SimpleDateFormat format = new SimpleDateFormat(DATEFORMAT); - - try { - Date date = format.parse(charValue); - - currentNode.setDate(elementName, date); - } catch (ParseException e) { - currentNode.setString(elementName, charValue); - } - } else if ("float".equals(elementType)) { - currentNode.setFloat(elementName, (new Double(charValue)).doubleValue()); - } else if ("integer".equals(elementType)) { - currentNode.setInteger(elementName, (new Long(charValue)).longValue()); - } else { - currentNode.setString(elementName, charValue); - } - - elementName = null; - elementType = null; - charValue = null; - } - - if (parsingHopObject && !nodeStack.isEmpty()) { - currentNode = (INode) nodeStack.pop(); - } else { - parsingHopObject = true; // the next element end tag closes a hopobject again - } - } -} diff --git a/src/helma/objectmodel/dom/XmlUtil.java b/src/helma/objectmodel/dom/XmlUtil.java deleted file mode 100644 index 78c50b39..00000000 --- a/src/helma/objectmodel/dom/XmlUtil.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - -import helma.objectmodel.INode; -import helma.objectmodel.TransientNode; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import java.io.IOException; -import java.io.InputStream; -import java.util.WeakHashMap; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -/** - * - */ -public class XmlUtil { - private static final DocumentBuilderFactory domBuilderFactory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); - private static final WeakHashMap domBuilders = new WeakHashMap(); - - private static synchronized DocumentBuilder getDocumentBuilder() { - DocumentBuilder domBuilder = (DocumentBuilder) domBuilders.get(Thread.currentThread()); - - if (domBuilder != null) { - return domBuilder; - } else { - try { - domBuilder = domBuilderFactory.newDocumentBuilder(); - domBuilders.put(Thread.currentThread(), domBuilder); - - return domBuilder; - } catch (ParserConfigurationException e) { - throw new RuntimeException("Cannot build parser: " + e.toString()); - } - } - } - - /** - * - * - * @return ... - */ - public static Document newDocument() { - DocumentBuilder d = getDocumentBuilder(); - - return d.newDocument(); - } - - /** - * - * - * @param in ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public static Document parse(InputStream in) throws RuntimeException { - DocumentBuilder d = getDocumentBuilder(); - - try { - Document doc = d.parse(in); - - doc.normalize(); - - return doc; - } catch (SAXException e) { - throw new RuntimeException("Bad xml-code: " + e.toString()); - } catch (IOException f) { - throw new RuntimeException("Could not read Xml: " + f.toString()); - } - } - - /** - * - * - * @param in ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public static Document parse(InputSource in) throws RuntimeException { - DocumentBuilder d = getDocumentBuilder(); - - try { - Document doc = d.parse(in); - - doc.normalize(); - - return doc; - } catch (SAXException e) { - throw new RuntimeException("Bad xml-code: " + e.toString()); - } catch (IOException f) { - throw new RuntimeException("Could not read Xml: " + f.toString()); - } - } - - /** - * get first "real" element (ie not the document-rootelement, but the next one - */ - public static Element getFirstElement(Document document) { - Element workelement = null; - - if (document.getDocumentElement() != null) { - org.w3c.dom.Node tmp = document.getDocumentElement().getFirstChild(); - - while (tmp != null) { - tmp = tmp.getNextSibling(); - - if (tmp.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { - workelement = (Element) tmp; - - break; - } - } - } - - return workelement; - } - - /** - * return the text content of an element - */ - public static String getTextContent(org.w3c.dom.Node element) { - StringBuffer childtext = new StringBuffer(); - NodeList childlist = element.getChildNodes(); - int ct = childlist.getLength(); - - for (int j = 0; j < ct; j++) { - org.w3c.dom.Node childNode = childlist.item(j); - - if ((childNode.getNodeType() == Node.TEXT_NODE) || - (childNode.getNodeType() == Node.CDATA_SECTION_NODE)) { - childtext.append(childNode.getNodeValue().trim()); - } - } - - return childtext.toString(); - } -} diff --git a/src/helma/objectmodel/dom/XmlWriter.java b/src/helma/objectmodel/dom/XmlWriter.java deleted file mode 100644 index 2c796f7e..00000000 --- a/src/helma/objectmodel/dom/XmlWriter.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.objectmodel.dom; - - -// import java.util.Set; -import helma.objectmodel.*; -import helma.objectmodel.INode; -import helma.objectmodel.IProperty; -import helma.objectmodel.TransientNode; -import helma.objectmodel.db.DbMapping; -import helma.objectmodel.db.Node; -import helma.util.HtmlEncoder; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -/** - * - */ -public class XmlWriter extends OutputStreamWriter implements XmlConstants { - private final static String LINESEPARATOR = System.getProperty("line.separator"); - private static int fileid; - private Vector convertedNodes; - private int maxLevels = 3; - private String indent = " "; - private StringBuffer prefix = new StringBuffer(); - private SimpleDateFormat format = new SimpleDateFormat(DATEFORMAT); - private boolean dbmode = true; - - // Only add encoding to XML declaration if it was explicitly set, not when we're using - // the platform's standard encoding. - private String explicitEncoding; - - /** - * empty constructor, will use System.out as outputstream. - */ - public XmlWriter() { - super(System.out); - } - - /** - * Creates a new XmlWriter object. - * - * @param out ... - */ - public XmlWriter(OutputStream out) { - super(out); - } - - /** - * Creates a new XmlWriter object. - * - * @param out ... - * @param enc ... - * - * @throws UnsupportedEncodingException ... - */ - public XmlWriter(OutputStream out, String enc) throws UnsupportedEncodingException { - super(out, enc); - explicitEncoding = enc; - } - - /** - * Creates a new XmlWriter object. - * - * @param desc ... - * - * @throws FileNotFoundException ... - */ - public XmlWriter(String desc) throws FileNotFoundException { - super(new FileOutputStream(desc)); - } - - /** - * Creates a new XmlWriter object. - * - * @param desc ... - * @param enc ... - * - * @throws FileNotFoundException ... - * @throws UnsupportedEncodingException ... - */ - public XmlWriter(String desc, String enc) - throws FileNotFoundException, UnsupportedEncodingException { - super(new FileOutputStream(desc), enc); - explicitEncoding = enc; - } - - /** - * Creates a new XmlWriter object. - * - * @param file ... - * - * @throws FileNotFoundException ... - */ - public XmlWriter(File file) throws FileNotFoundException { - super(new FileOutputStream(file)); - } - - /** - * Creates a new XmlWriter object. - * - * @param file ... - * @param enc ... - * - * @throws FileNotFoundException ... - * @throws UnsupportedEncodingException ... - */ - public XmlWriter(File file, String enc) - throws FileNotFoundException, UnsupportedEncodingException { - super(new FileOutputStream(file), enc); - explicitEncoding = enc; - } - - // Set of prototypes at which to stop writing. - // private Set stopTypes = null; - - /** - * create ids that can be used for temporary files. - */ - public static int generateID() { - return fileid++; - } - - /** - * by default writing only descends 50 levels into the node tree to prevent - * infite loops. number can be changed here. - */ - public void setMaxLevels(int levels) { - maxLevels = levels; - } - - /** - * - * - * @param dbmode ... - */ - public void setDatabaseMode(boolean dbmode) { - this.dbmode = dbmode; - } - - /** - * Set a group of prototypes at which to stop XML serialization. - */ - - /* public void setStopTypes (Set set) { - this.stopTypes = set; - } */ - - /** - * set the number of space chars - */ - public void setIndent(int ct) { - StringBuffer tmp = new StringBuffer(); - - for (int i = 0; i < ct; i++) { - tmp.append(" "); - } - - indent = tmp.toString(); - } - - /** - * starting point for printing a node tree. - * creates document header too and initializes - * the cache of already converted nodes. - */ - public boolean write(INode node) throws IOException { - convertedNodes = new Vector(); - - if (explicitEncoding == null) { - writeln(""); - } else { - writeln(""); - } - - // writeln (""); - // writeln ("" ); - write(""); - write(node, null, null, 0); - writeln(""); - convertedNodes = null; - - return true; - } - - /** - * write a hopobject and print all its properties and children. - * references are made here if a node already has been fully printed - * or if this is the last level that's going to be dumped - */ - public void write(INode node, String elementName, String propName, int level) - throws IOException { - if (node == null) { - return; - } - - // if (stopTypes != null && stopTypes.contains (node.getPrototype())) - // return; - int previousLength = prefix.length(); - - prefix.append(indent); - - if (++level > maxLevels) { - writeReferenceTag(node, elementName, propName); - prefix.setLength(previousLength); - - return; - } - - if (convertedNodes.contains(node)) { - writeReferenceTag(node, elementName, propName); - } else { - convertedNodes.addElement(node); - writeTagOpen(node, elementName, propName); - - INode parent = node.getParent(); - - if (parent != null) { - writeReferenceTag(parent, "hop:parent", null); - } - - writeProperties(node, level); - writeChildren(node, level); - writeTagClose(elementName); - } - - prefix.setLength(previousLength); - } - - /** - * loop through properties and print them with their property-name - * as elementname - */ - private void writeProperties(INode node, int level) - throws IOException { - Enumeration e = null; - - if ((dbmode == true) && node instanceof helma.objectmodel.db.Node) { - // a newly constructed db.Node doesn't have a propMap, - // but returns an enumeration of all it's db-mapped properties - Hashtable props = ((Node) node).getPropMap(); - - if (props == null) { - return; - } - - e = props.keys(); - } else { - e = node.properties(); - } - - while (e.hasMoreElements()) { - String key = (String) e.nextElement(); - IProperty prop = node.get(key); - - if (prop != null) { - boolean validName = isValidElementName(key); - String elementName; - String propName; - - if (validName) { - elementName = key; - propName = null; - } else { - elementName = "property"; - propName = key; - } - - int type = prop.getType(); - - if (type == IProperty.NODE) { - write(prop.getNodeValue(), elementName, propName, level); - } else { - writeProperty(prop, elementName, propName); - } - } - } - } - - /* public void writeNullProperty (String key) throws IOException { - write (prefix.toString()); - write (indent); - write ("<"); - write (key); - write (" type=\"null\"/>"); - write (LINESEPARATOR); - } */ - - /** - * write a single property, set attribute type according to type, - * apply xml-encoding. - */ - public void writeProperty(IProperty property, String elementName, String propName) - throws IOException { - int propType = property.getType(); - - // we can't encode java objects in XML - if (propType == IProperty.JAVAOBJECT) { - return; - } - - write(prefix.toString()); - write(indent); - write("<"); - write(elementName); - - if (propName != null) { - write(" propertyname=\""); - write(HtmlEncoder.encodeXml(propName)); - write("\""); - } - - switch (propType) { - case IProperty.BOOLEAN: - write(" type=\"boolean\">"); - write(property.getStringValue()); - - break; - - case IProperty.FLOAT: - write(" type=\"float\">"); - write(property.getStringValue()); - - break; - - case IProperty.INTEGER: - write(" type=\"integer\">"); - write(property.getStringValue()); - - break; - - case IProperty.DATE: - write(" type=\"date\">"); - write(format.format(property.getDateValue())); - - break; - - case IProperty.STRING: - write(">"); - - String str = HtmlEncoder.encodeXml(property.getStringValue()); - - if (str != null) { - write(str); - } - } - - write(""); - write(LINESEPARATOR); - } - - /** - * loop through the children-array and print them as - */ - private void writeChildren(INode node, int level) throws IOException { - if ((dbmode == true) && node instanceof helma.objectmodel.db.Node) { - Node dbNode = (Node) node; - DbMapping smap = (dbNode.getDbMapping() == null) ? null - : dbNode.getDbMapping() - .getSubnodeMapping(); - - if ((smap != null) && smap.isRelational()) { - return; - } - } - - Enumeration e = node.getSubnodes(); - - while (e.hasMoreElements()) { - INode nextNode = (INode) e.nextElement(); - - write(nextNode, "hop:child", null, level); - } - } - - /** - * write an opening tag for a node. Include id and prototype, use a - * name if parameter is non-empty. - */ - public void writeTagOpen(INode node, String name, String propName) - throws IOException { - write(prefix.toString()); - write("<"); - write((name == null) ? "hopobject" : name); - write(" id=\""); - write(getNodeIdentifier(node)); - - if (propName != null) { - write("\" propertyname=\""); - write(HtmlEncoder.encodeXml(propName)); - } - - write("\" name=\""); - write(HtmlEncoder.encodeXml(node.getName())); - write("\" prototype=\""); - write(getNodePrototype(node)); - write("\" created=\""); - write(Long.toString(node.created())); - write("\" lastModified=\""); - write(Long.toString(node.lastModified())); - - //FIXME: do we need anonymous-property? - write("\">"); - write(LINESEPARATOR); - } - - /** - * write a closing tag for a node - * e.g. - */ - public void writeTagClose(String name) throws IOException { - write(prefix.toString()); - write(""); - write(LINESEPARATOR); - } - - /** - * write a tag holding a reference to an element that has - * been written out before. - * e.g. - */ - public void writeReferenceTag(INode node, String name, String propName) - throws IOException { - write(prefix.toString()); - write("<"); - write((name == null) ? "hopobject" : name); - write(" idref=\""); - write(getNodeIdentifier(node)); - - if (propName != null) { - write("\" propertyname=\""); - write(HtmlEncoder.encodeXml(propName)); - } - - write("\" prototyperef=\""); - write(getNodePrototype(node)); - write("\"/>"); - write(LINESEPARATOR); - } - - /** - * retrieve prototype-string of a node, defaults to "hopobject" - */ - private String getNodePrototype(INode node) { - if ((node.getPrototype() == null) || "".equals(node.getPrototype())) { - return "hopobject"; - } else { - return node.getPrototype(); - } - } - - /** - * TransientNode produces a different ID each time we call the getID()-method - * this is a workaround and uses hashCode if INode stands for a TransientNode. - */ - private String getNodeIdentifier(INode node) { - try { - TransientNode tmp = (TransientNode) node; - - return Integer.toString(tmp.hashCode()); - } catch (ClassCastException e) { - return node.getID(); - } - } - - /** - * - * - * @param str ... - * - * @throws IOException ... - */ - public void writeln(String str) throws IOException { - write(str); - write(LINESEPARATOR); - } - - /** - * Check if a string is usable as XML element name. If not, the name - * will be appended as attribute to the XML element. We are - * conservative here, preferring to return false rather too often than - * not enough. - */ - private boolean isValidElementName(String str) { - char c = str.charAt(0); - - if (!Character.isLetter(c)) { - return false; - } - - int l = str.length(); - - for (int i = 1; i < l; i++) { - c = str.charAt(i); - - if (!Character.isLetterOrDigit(c) && (c != '-') && (c != '_')) { - return false; - } - } - - return true; - } -} diff --git a/src/helma/scripting/ActionFile.java b/src/helma/scripting/ActionFile.java deleted file mode 100644 index bb1e6957..00000000 --- a/src/helma/scripting/ActionFile.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting; - -import helma.framework.*; -import helma.framework.core.*; -import helma.util.Updatable; -import java.io.*; -import java.util.Iterator; -import java.util.Vector; - -/** - * An ActionFile is a file containing function code that is exposed as a URI - * of objects of this class/type. It is - * usually represented by a file with extension .hac (hop action file) - * that contains the raw body of the function. - */ -public class ActionFile implements Updatable { - String name; - String sourceName; - Prototype prototype; - Application app; - File file; - String content; - long lastmod; - - /** - * Creates a new ActionFile object. - * - * @param file ... - * @param name ... - * @param proto ... - */ - public ActionFile(File file, String name, Prototype proto) { - this.prototype = proto; - this.app = proto.getApplication(); - this.name = name; - this.sourceName = file.getParentFile().getName() + "/" + file.getName(); - this.file = file; - this.lastmod = file.lastModified(); - this.content = null; - } - - /** - * Creates a new ActionFile object. - * - * @param content ... - * @param name ... - * @param sourceName ... - * @param proto ... - */ - public ActionFile(String content, String name, String sourceName, Prototype proto) { - this.prototype = proto; - this.app = proto.getApplication(); - this.name = name; - this.sourceName = sourceName; - this.file = null; - this.content = content; - } - - /** - * Tell the type manager whether we need an update. this is the case when - * the file has been modified or deleted. - */ - public boolean needsUpdate() { - return lastmod != file.lastModified(); - } - - /** - * - */ - public void update() { - if (!file.exists()) { - // remove functions declared by this from all object prototypes - remove(); - } else { - lastmod = file.lastModified(); - } - } - - /** - * - */ - public void remove() { - prototype.removeActionFile(this); - } - - /** - * - * - * @return ... - */ - public File getFile() { - return file; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @return ... - */ - public String getSourceName() { - return sourceName; - } - - /** - * - * - * @return ... - * - * @throws FileNotFoundException ... - */ - public Reader getReader() throws FileNotFoundException { - if (content != null) { - return new StringReader(content); - } else if (file.length() == 0) { - return new StringReader(";"); - } else { - return new FileReader(file); - } - } - - /** - * - * - * @return ... - */ - public String getContent() { - if (content != null) { - return content; - } else { - try { - FileReader reader = new FileReader(file); - char[] cbuf = new char[(int) file.length()]; - - reader.read(cbuf); - reader.close(); - - return new String(cbuf); - } catch (Exception filex) { - app.logEvent("Error reading " + this + ": " + filex); - - return null; - } - } - } - - /** - * - * - * @return ... - */ - public String getFunctionName() { - return name + "_action"; - } - - /** - * - * - * @return ... - */ - public Prototype getPrototype() { - return prototype; - } - - /** - * - * - * @return ... - */ - public Application getApplication() { - return app; - } - - /** - * - * - * @return ... - */ - public String toString() { - return "ActionFile[" + sourceName + "]"; - } -} diff --git a/src/helma/scripting/FunctionFile.java b/src/helma/scripting/FunctionFile.java deleted file mode 100644 index 5c271414..00000000 --- a/src/helma/scripting/FunctionFile.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting; - -import helma.framework.*; -import helma.framework.core.*; -import helma.util.Updatable; -import java.io.*; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; - -/** - * This represents a File containing script functions for a given class/prototype. - */ -public class FunctionFile implements Updatable { - Prototype prototype; - Application app; - File file; - String sourceName; - String content; - long lastmod; - - /** - * Creates a new FunctionFile object. - * - * @param file ... - * @param proto ... - */ - public FunctionFile(File file, Prototype proto) { - this.prototype = proto; - this.app = proto.getApplication(); - this.sourceName = file.getParentFile().getName() + "/" + file.getName(); - this.file = file; - update(); - } - - /** - * Create a function file without a file, passing the code directly. This is used for - * files contained in zipped applications. The whole update mechanism is bypassed - * by immediately parsing the code. - */ - public FunctionFile(String body, String sourceName, Prototype proto) { - this.prototype = proto; - this.app = proto.getApplication(); - this.sourceName = sourceName; - this.file = null; - this.content = body; - } - - /** - * Tell the type manager whether we need an update. this is the case when - * the file has been modified or deleted. - */ - public boolean needsUpdate() { - return (file != null) && (lastmod != file.lastModified()); - } - - /** - * - */ - public void update() { - if (file != null) { - if (!file.exists()) { - remove(); - } else { - lastmod = file.lastModified(); - } - } - } - - /** - * - * - * @return ... - */ - public File getFile() { - return file; - } - - /** - * - * - * @return ... - */ - public String getContent() { - return content; - } - - /** - * - * - * @return ... - */ - public String getSourceName() { - return sourceName; - } - - /** - * - */ - public void remove() { - prototype.removeFunctionFile(this); - } - - /** - * - * - * @return ... - */ - public String toString() { - return sourceName; - } -} diff --git a/src/helma/scripting/ScriptingEngine.java b/src/helma/scripting/ScriptingEngine.java deleted file mode 100644 index d9320a57..00000000 --- a/src/helma/scripting/ScriptingEngine.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting; - -import helma.framework.IPathElement; -import helma.framework.core.Application; -import helma.framework.core.Prototype; -import helma.framework.core.RequestEvaluator; -import java.io.File; -import java.util.*; - -/** - * This is the interface that must be implemented to make a scripting environment - * usable by the Helma application server. - * - * Implementations of this interface must have a public zero-argument constructor - * to be usable by the Helma framework. - */ -public interface ScriptingEngine { - /** - * Init the scripting engine with an application and a request evaluator - */ - public void init(Application app, RequestEvaluator reval); - - /** - * This method is called before an execution context for a request - * evaluation is entered to let the Engine know it should update - * its prototype information - */ - public void updatePrototypes(); - - /** - * This method is called when an execution context for a request - * evaluation is entered. The globals parameter contains the global values - * to be applied during this execution context. - */ - public void enterContext(HashMap globals) throws ScriptingException; - - /** - * This method is called to let the scripting engine know that the current - * execution context has terminated. - */ - public void exitContext(); - - /** - * Invoke a function on some object, using the given arguments and global vars. - * XML-RPC calls require special input and output parameter conversion. - */ - public Object invoke(Object thisObject, String functionName, Object[] args, - boolean xmlrpc) throws ScriptingException; - - /** - * Let the evaluator know that the current evaluation has been aborted. - */ - public void abort(); - - /** - * Get a property on an object - */ - public Object get(Object thisObject, String key); - - /** - * Return true if a function by that name is defined for that object. - */ - public boolean hasFunction(Object thisObject, String functionName); - - /** - * Get an IPathElement that offers introspection services into the application. - * If this method returns null, no introspection is available for this kind of engine. - * In order to be compatible with the standard Helma management application, this - * class should be compatible with helma.doc.DocApplication. - */ - public IPathElement getIntrospector(); -} diff --git a/src/helma/scripting/ScriptingException.java b/src/helma/scripting/ScriptingException.java deleted file mode 100644 index 0e9f6f28..00000000 --- a/src/helma/scripting/ScriptingException.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting; - -import java.io.PrintStream; -import java.io.PrintWriter; - -/** - * The base class for exceptions thrown by Helma scripting package - */ -public class ScriptingException extends Exception { - Exception wrapped; - - /** - * Construct a ScriptingException given an error message - */ - public ScriptingException(String msg) { - super(msg); - wrapped = null; - } - - /** - * Construct a ScriptingException given an error message - */ - public ScriptingException(Exception w) { - wrapped = w; - } - - /** - * - * - * @return ... - */ - public String toString() { - if (wrapped == null) { - return super.toString(); - } else { - return wrapped.toString(); - } - } - - /** - * - * - * @return ... - */ - public String getMessage() { - if (wrapped == null) { - return super.getMessage(); - } else { - return wrapped.getMessage(); - } - } - - /** - * - */ - public void printStackTrace() { - if (wrapped == null) { - super.printStackTrace(); - } else { - wrapped.printStackTrace(); - } - } - - /** - * - * - * @param stream ... - */ - public void printStackTrace(PrintStream stream) { - if (wrapped == null) { - super.printStackTrace(stream); - } else { - wrapped.printStackTrace(stream); - } - } - - /** - * - * - * @param writer ... - */ - public void printStackTrace(PrintWriter writer) { - if (wrapped == null) { - super.printStackTrace(writer); - } else { - wrapped.printStackTrace(writer); - } - } -} diff --git a/src/helma/scripting/Template.java b/src/helma/scripting/Template.java deleted file mode 100644 index 72aa5044..00000000 --- a/src/helma/scripting/Template.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting; - -import helma.framework.*; -import helma.framework.core.*; -import java.io.*; -import java.util.Iterator; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * This represents a Helma template, i.e. a file with the extension .hsp - * (Helma server page) that contains both parts that are to be evaluated - * as EcmaScript and parts that are to be delivered to the client as-is. - * Internally, templates are regular functions. - * Helma templates are callable via URL, but this is just a leftover from the - * days when there were no .hac (action) files. The recommended way - * now is to have a .hac file with all the logic which in turn calls one or more - * template files to do the formatting. - */ -public class Template extends ActionFile { - /** - * Creates a new Template object. - * - * @param file ... - * @param name ... - * @param proto ... - */ - public Template(File file, String name, Prototype proto) { - super(file, name, proto); - } - - /** - * Creates a new Template object. - * - * @param content ... - * @param name ... - * @param sourceName ... - * @param proto ... - */ - public Template(String content, String name, String sourceName, Prototype proto) { - super(content, name, sourceName, proto); - } - - /** - * - * - * @return ... - */ - public String getFunctionName() { - return name; - } - - /** - * - * - * @return ... - */ - public Reader getReader() { - return new StringReader(getContent()); - } - - /** - * - * - * @return ... - */ - public String getContent() { - Vector partBuffer = new Vector(); - String cstring = super.getContent(); - char[] cnt = cstring.toCharArray(); - int l = cnt.length; - - if (l == 0) { - return ""; - } - - // if last charackter is whitespace, swallow it. this is necessary for some inner templates to look ok. - if (Character.isWhitespace(cnt[l - 1])) { - l -= 1; - } - - int lastIdx = 0; - - for (int i = 0; i < (l - 1); i++) { - if ((cnt[i] == '<') && (cnt[i + 1] == '%')) { - int j = i + 2; - - while ((j < (l - 1)) && ((cnt[j] != '%') || (cnt[j + 1] != '>'))) { - j++; - } - - if (j > (i + 2)) { - if ((i - lastIdx) > 0) { - partBuffer.addElement(new Part(this, - new String(cnt, lastIdx, - i - lastIdx), true)); - } - - String script = new String(cnt, i + 2, (j - i) - 2); - - partBuffer.addElement(new Part(this, script, false)); - lastIdx = j + 2; - } - - i = j + 1; - } - } - - if (lastIdx < l) { - partBuffer.addElement(new Part(this, new String(cnt, lastIdx, l - lastIdx), - true)); - } - - StringBuffer templateBody = new StringBuffer(); - int nparts = partBuffer.size(); - - for (int k = 0; k < nparts; k++) { - Part nextPart = (Part) partBuffer.elementAt(k); - - if (nextPart.isStatic || nextPart.content.trim().startsWith("=")) { - // check for <%= ... %> statements - if (!nextPart.isStatic) { - nextPart.content = nextPart.content.trim().substring(1).trim(); - - // cut trailing ";" - while (nextPart.content.endsWith(";")) - nextPart.content = nextPart.content.substring(0, - nextPart.content.length() - - 1); - } - - StringTokenizer st = new StringTokenizer(nextPart.content, "\r\n", true); - String nextLine = st.hasMoreTokens() ? st.nextToken() : null; - - // count newLines we "swallow", see explanation below - int newLineCount = 0; - - templateBody.append("res.write ("); - - if (nextPart.isStatic) { - templateBody.append("\""); - } - - while (nextLine != null) { - if ("\n".equals(nextLine)) { - // append a CRLF - newLineCount++; - templateBody.append("\\r\\n"); - } else if (!"\r".equals(nextLine)) { - try { - StringReader lineReader = new StringReader(nextLine); - int c = lineReader.read(); - - while (c > -1) { - if (nextPart.isStatic && - (((char) c == '"') || ((char) c == '\\'))) { - templateBody.append('\\'); - } - - templateBody.append((char) c); - c = lineReader.read(); - } - } catch (IOException srx) { - } - } - - nextLine = st.hasMoreTokens() ? st.nextToken() : null; - } - - if (nextPart.isStatic) { - templateBody.append("\""); - } - - templateBody.append("); "); - - // append the number of lines we have "swallowed" into - // one write statement, so error messages will *approximately* - // give correct line numbers. - for (int i = 0; i < newLineCount; i++) { - templateBody.append("\r\n"); - } - } else { - templateBody.append(nextPart.content); - - if (!nextPart.content.trim().endsWith(";")) { - templateBody.append(";"); - } - } - } - - // templateBody.append ("\r\nreturn null;\r\n"); - return templateBody.toString(); - } - - /** - * - */ - public void remove() { - prototype.removeTemplate(this); - } - - class Part { - String content; - Template parent; - boolean isPart; - boolean isStatic; - - public Part(Template parent, String content, boolean isStatic) { - isPart = false; - this.parent = parent; - this.content = content; - this.isStatic = isStatic; - } - - public String getName() { - return isStatic ? null : content; - } - - public String toString() { - return "Template.Part [" + content + "," + isStatic + "]"; - } - } -} diff --git a/src/helma/scripting/rhino/GlobalObject.java b/src/helma/scripting/rhino/GlobalObject.java deleted file mode 100644 index 6787e4c9..00000000 --- a/src/helma/scripting/rhino/GlobalObject.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino; - -import helma.scripting.rhino.extensions.*; -import helma.framework.*; -import helma.framework.core.*; -import helma.objectmodel.*; -import helma.objectmodel.db.*; -import helma.util.HtmlEncoder; -import helma.util.MimePart; -import helma.util.XmlUtils; -import org.mozilla.javascript.*; - -import java.util.HashMap; -import java.util.Map; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.text.*; -import java.io.*; - -/** - * - */ -public class GlobalObject extends ScriptableObject { - Application app; - RhinoCore core; - - /** - * Creates a new GlobalObject object. - * - * @param core ... - * @param app ... - */ - public GlobalObject(RhinoCore core, Application app) { - this.core = core; - this.app = app; - } - - /** - * Initializes the global object. This is only done for the shared - * global objects not the per-thread ones. - * - * @throws PropertyException ... - */ - public void init() throws PropertyException { - String[] globalFuncs = { - "renderSkin", "renderSkinAsString", "getProperty", - "authenticate", "createSkin", "format", "encode", - "encodeXml", "encodeForm", "stripTags", - "getXmlDocument", "getHtmlDocument", - "getDBConnection", "getURL", "write", "writeln" - }; - - defineFunctionProperties(globalFuncs, GlobalObject.class, 0); - put("app", this, Context.toObject(new ApplicationBean(app), this)); - put("Xml", this, Context.toObject(new XmlObject(core), this)); - } - - /** - * - * - * @return ... - */ - public String getClassName() { - return "GlobalObject"; - } - - /** - * - * - * @param skin ... - * @param param ... - * - * @return ... - */ - public boolean renderSkin(Object skinobj, Object paramobj) { - Context cx = Context.getCurrentContext(); - RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval"); - RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine"); - Skin skin; - - if (skinobj instanceof Skin) { - skin = (Skin) skinobj; - } else { - skin = engine.getSkin("global", skinobj.toString()); - } - - Map param = RhinoCore.getSkinParam(paramobj); - - if (skin != null) { - skin.render(reval, null, param); - } - - return true; - } - - /** - * - * - * @param skin ... - * @param param ... - * - * @return ... - */ - public String renderSkinAsString(Object skinobj, Object paramobj) { - Context cx = Context.getCurrentContext(); - RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval"); - RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine"); - Skin skin; - - if (skinobj instanceof Skin) { - skin = (Skin) skinobj; - } else { - skin = engine.getSkin("global", skinobj.toString()); - } - - Map param = RhinoCore.getSkinParam(paramobj); - - if (skin != null) { - reval.res.pushStringBuffer(); - skin.render(reval, null, param); - - return reval.res.popStringBuffer(); - } - - return ""; - } - - /** - * - * - * @param propname ... - * @param defvalue ... - * - * @return ... - */ - public String getProperty(String propname, Object defvalue) { - if (defvalue == Undefined.instance) { - return app.getProperty(propname); - } else { - return app.getProperty(propname, toString(defvalue)); - } - } - - /** - * - * - * @param user ... - * @param pwd ... - * - * @return ... - */ - public boolean authenticate(String user, String pwd) { - return app.authenticate(user, pwd); - } - - /** - * Create a Skin object from a string - * - * @param str the source string to parse - * - * @return a parsed skin object - */ - public Object createSkin(String str) { - return new Skin(str, app); - } - - /** - * Get a Helma DB connection specified in db.properties - * - * @param str the db source name - * - * @return a DatabaseObject for the specified DbConnection - */ - public Object getDBConnection(String dbsource) throws Exception { - if (dbsource == null) - throw new RuntimeException ("Wrong number of arguments in getDBConnection(dbsource)"); - DbSource dbsrc = app.getDbSource (dbsource.toLowerCase ()); - if (dbsrc == null) - throw new RuntimeException ("DbSource "+dbsource+" does not exist"); - DatabaseObject db = new DatabaseObject (dbsrc, 0); - return Context.toObject(db, this); - } - - /** - * Retrieve a Document from the specified URL. - * - * @param location the URL to retrieve - * @param opt either a LastModified date or an ETag string for conditional GETs - * - * @return a wrapped MIME object - */ - public Object getURL(String location, Object opt) { - if (location == null) { - return null; - } - - try { - URL url = new URL(location); - URLConnection con = url.openConnection(); - - // do we have if-modified-since or etag headers to set? - if (opt != null && opt != Undefined.instance) { - if (opt instanceof Scriptable) { - Scriptable scr = (Scriptable) opt; - if ("Date".equals(scr.getClassName())) { - Date date = new Date((long) ScriptRuntime.toNumber(scr)); - - con.setIfModifiedSince(date.getTime()); - - SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", - Locale.UK); - - format.setTimeZone(TimeZone.getTimeZone("GMT")); - con.setRequestProperty("If-Modified-Since", format.format(date)); - }else { - con.setRequestProperty("If-None-Match", scr.toString()); - } - } else { - con.setRequestProperty("If-None-Match", opt.toString()); - } - } - - String httpUserAgent = app.getProperty("httpUserAgent"); - - if (httpUserAgent != null) { - con.setRequestProperty("User-Agent", httpUserAgent); - } - - con.setAllowUserInteraction(false); - - String filename = url.getFile(); - String contentType = con.getContentType(); - long lastmod = con.getLastModified(); - String etag = con.getHeaderField("ETag"); - int length = con.getContentLength(); - int resCode = 0; - - if (con instanceof HttpURLConnection) { - resCode = ((HttpURLConnection) con).getResponseCode(); - } - - ByteArrayOutputStream body = new ByteArrayOutputStream(); - - if ((length != 0) && (resCode != 304)) { - InputStream in = new BufferedInputStream(con.getInputStream()); - byte[] b = new byte[1024]; - int read; - - while ((read = in.read(b)) > -1) - body.write(b, 0, read); - - in.close(); - } - - MimePart mime = new MimePart(filename, body.toByteArray(), contentType); - - if (lastmod > 0) { - mime.lastModified = new Date(lastmod); - } - - mime.eTag = etag; - - return Context.toObject(mime, this); - } catch (Exception xcept) { - System.err.println ("Error in getURL(): "+xcept); - } - - return null; - } - - /** - * Try to parse an object to a XML DOM tree. The argument must be - * either a URL, a piece of XML, an InputStream or a Reader. - */ - public Object getXmlDocument(Object src) { - try { - Object p = src; - if (p instanceof Wrapper) { - p = ((Wrapper) p).unwrap(); - } - Object doc = XmlUtils.parseXml(p); - - return Context.toObject(doc, this); - } catch (Exception noluck) { - app.logEvent("Error creating XML document: " + noluck); - } - - return null; - } - - /** - * Try to parse an object to a XML DOM tree. The argument must be - * either a URL, a piece of XML, an InputStream or a Reader. - */ - public Object getHtmlDocument(Object src) { - try { - Object p = src; - if (p instanceof Wrapper) { - p = ((Wrapper) p).unwrap(); - } - Object doc = helma.util.XmlUtils.parseHtml(p); - - return Context.toObject(doc, this); - } catch (Exception noluck) { - app.logEvent("Error creating HTML document: " + noluck); - } - - return null; - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public String encode(Object obj) { - return HtmlEncoder.encodeAll(toString(obj)); - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public String encodeXml(Object obj) { - return HtmlEncoder.encodeXml(toString(obj)); - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public String encodeForm(Object obj) { - return HtmlEncoder.encodeFormValue(toString(obj)); - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public String format(Object obj) { - return HtmlEncoder.encode(toString(obj)); - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public void write(String str) { - System.out.print(str); - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public void writeln(String str) { - System.out.println(str); - } - - - /** - * - * - * @param str ... - * - * @return ... - */ - public String stripTags(String str) { - if (str == null) { - return null; - } - - char[] c = str.toCharArray(); - boolean inTag = false; - int i; - int j = 0; - - for (i = 0; i < c.length; i++) { - if (c[i] == '<') { - inTag = true; - } - - if (!inTag) { - if (i > j) { - c[j] = c[i]; - } - - j++; - } - - if (c[i] == '>') { - inTag = false; - } - } - - if (i > j) { - return new String(c, 0, j); - } - - return str; - } - - private static String toString(Object obj) { - if (obj == null || obj == Undefined.instance) { - // Note: we might return "" here in order - // to handle null/undefined as empty string - return null; - } - return Context.toString(obj); - } -} diff --git a/src/helma/scripting/rhino/HopObject.java b/src/helma/scripting/rhino/HopObject.java deleted file mode 100644 index 32a09f70..00000000 --- a/src/helma/scripting/rhino/HopObject.java +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino; - -import helma.scripting.ScriptingException; -import helma.framework.*; -import helma.framework.core.*; -import helma.objectmodel.*; -import helma.objectmodel.db.*; -import org.mozilla.javascript.*; - -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -/** - * - */ -public class HopObject extends ScriptableObject implements Wrapper { - static Method hopObjCtor; - - static { - Method[] methods = HopObject.class.getMethods(); - - for (int i = 0; i < methods.length; i++) { - if ("jsConstructor".equals(methods[i].getName())) { - hopObjCtor = methods[i]; - - break; - } - } - } - - String className; - INode node; - RhinoCore core; - - /** - * Creates a new HopObject object. - */ - public HopObject() { - className = "HopObject"; - } - - /** - * Creates a new HopObject prototype. - * - * @param cname ... - */ - protected HopObject(String cname) { - className = cname; - } - - - /** - * This method is used as HopObject constructor from JavaScript. - */ - public static Object jsConstructor(Context cx, Object[] args, - Function ctorObj, boolean inNewExpr) - throws JavaScriptException, ScriptingException { - RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine"); - RhinoCore c = engine.core; - String prototype = ((FunctionObject) ctorObj).getFunctionName(); - - // if this is a java object prototype, create a new java object - // of the given class instead of a HopObject. - if (c.app.isJavaPrototype(prototype)) { - String classname = c.app.getJavaClassForPrototype(prototype); - try { - Class clazz = Class.forName(classname); - Constructor[] cnst = clazz.getConstructors(); - // brute force loop through constructors - - // alas, this isn't very pretty. - for (int i=0; i= 0 && index < path.size(); - } - - /** - * Returns a list of array indices 0..length-1. - */ - public Object[] getIds() { - Object[] ids = new Object[path.size()]; - - for (int i=0; i 0) { - Prototype p = app.typemgr.getPrototype(info.protoName); - - if (p != null) { - // System.err.println ("UPDATING PROTO: "+p); - app.typemgr.updatePrototype(p); - - if (p.getLastUpdate() > info.lastUpdate) { - evaluatePrototype(p, info); - } - } - } - } - - lastUpdate = System.currentTimeMillis(); - } - - /** - * Get a raw prototype, i.e. in potentially unfinished state - * without checking if it needs to be updated. - */ - private ScriptableObject getRawPrototype(String protoName) { - if (protoName == null) { - return null; - } - - TypeInfo info = (TypeInfo) prototypes.get(protoName); - - return (info == null) ? null : info.objectPrototype; - } - - /** - * Get the object prototype for a prototype name and initialize/update it - * if necessary. The policy here is to update the prototype only if it - * hasn't been updated before, otherwise we assume it already was updated - * by updatePrototypes(), which is called for each request. - */ - public Scriptable getPrototype(String protoName) { - if (protoName == null) { - return null; - } - - TypeInfo info = (TypeInfo) prototypes.get(protoName); - - if ((info != null) && (info.lastUpdate == 0)) { - Prototype p = app.typemgr.getPrototype(protoName); - - if (p != null) { - app.typemgr.updatePrototype(p); - - if (p.getLastUpdate() > info.lastUpdate) { - evaluatePrototype(p, info); - } - - // set info.lastUpdate to 1 if it is 0 so we know we - // have initialized this prototype already, even if - // it is empty (i.e. doesn't contain any scripts/skins/actions) - if (info.lastUpdate == 0) { - info.lastUpdate = 1; - } - } - } - - return (info == null) ? null : info.objectPrototype; - } - - /** - * Register an object prototype for a prototype name. - */ - private void putPrototype(String protoName, ScriptableObject op) { - if ((protoName != null) && (op != null)) { - prototypes.put(protoName, new TypeInfo(op, protoName)); - } - } - - /** - * Check if an object has a function property (public method if it - * is a java object) with that name. - */ - public boolean hasFunction(String protoname, String fname) { - // System.err.println ("HAS_FUNC: "+fname); - try { - Scriptable op = getPrototype(protoname); - - // if this is an untyped object return false - if (op == null) { - return false; - } - - Object func = ScriptableObject.getProperty(op, fname); - - if ((func != null) && func instanceof Function) { - return true; - } - } catch (Exception esx) { - // System.err.println ("Error in hasFunction: "+esx); - return false; - } - - return false; - } - - /** - * Convert an input argument from Java to the scripting runtime - * representation. - */ - public Object processXmlRpcArgument (Object what) throws Exception { - if (what == null) - return null; - if (what instanceof Vector) { - Vector v = (Vector) what; - Object[] a = v.toArray(); - for (int i=0; i 0) && - (n.getDbMapping() == null)) { - n.setDbMapping(app.getDbMapping(protoname)); - } - - op = getPrototype(protoname); - - // no prototype found for this node? - if (op == null) { - op = getPrototype("hopobject"); - protoname = "hopobject"; - } - - esn = new HopObject(protoname); - esn.init(this, n); - esn.setPrototype(op); - - wrappercache.put(n, esn); - - // app.logEvent ("Wrapper for "+n+" created"); - } catch (Exception x) { - System.err.println("Error creating node wrapper: " + x); - throw new RuntimeException(x.toString()); - } - } - - return esn; - } - - ///////////////////////////////////////////// - // skin related methods - ///////////////////////////////////////////// - - protected static Object[] unwrapSkinpath(Object[] skinpath) { - if (skinpath != null) { - for (int i=0; i 0 && args[0] != Undefined.instance) { - df = new SimpleDateFormat(args[0].toString()); - } else { - df = new SimpleDateFormat(); - } - return df.format(date); - } - } - - class NumberFormat extends BaseFunction { - public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { - DecimalFormat df = null; - if (args.length > 0 && args[0] != Undefined.instance) { - df = new DecimalFormat(args[0].toString()); - } else { - df = new DecimalFormat("#,##0.00"); - } - return df.format(ScriptRuntime.toNumber(thisObj)).toString(); - } - } - -} - diff --git a/src/helma/scripting/rhino/RhinoEngine.java b/src/helma/scripting/rhino/RhinoEngine.java deleted file mode 100644 index afe2982b..00000000 --- a/src/helma/scripting/rhino/RhinoEngine.java +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino; - -import helma.doc.DocApplication; -import helma.extensions.ConfigurationException; -import helma.extensions.HelmaExtension; -import helma.framework.*; -import helma.framework.core.*; -import helma.main.Server; -import helma.objectmodel.*; -import helma.objectmodel.db.DbMapping; -import helma.objectmodel.db.Relation; -import helma.scripting.*; -import helma.scripting.rhino.debug.Tracer; -import helma.util.CacheMap; -import helma.util.Updatable; -import org.mozilla.javascript.*; - -import java.io.*; -import java.util.*; - -/** - * This is the implementation of ScriptingEnvironment for the Mozilla Rhino EcmaScript interpreter. - */ -public class RhinoEngine implements ScriptingEngine { - // map for Application to RhinoCore binding - static Map coreMap; - - // the application we're running in - public Application app; - - // The Rhino context - Context context; - - // the global object - Scriptable global; - - // the request evaluator instance owning this fesi evaluator - RequestEvaluator reval; - RhinoCore core; - - // remember global variables from last invokation to be able to - // do lazy cleanup - Map lastGlobals = null; - - // the global vars set by extensions - HashMap extensionGlobals; - - // the thread currently running this engine - Thread thread; - - // the introspector that provides documentation for this application - DocApplication doc = null; - - /** - * Zero argument constructor. - */ - public RhinoEngine() { - } - - /** - * Init the scripting engine with an application and a request evaluator - */ - public void init(Application app, RequestEvaluator reval) { - this.app = app; - this.reval = reval; - core = getRhinoCore(app); - context = Context.enter(); - context.setCompileFunctionsWithDynamicScope(true); - - try { - global = new GlobalObject(core, app); // context.newObject(core.global); - global.setPrototype(core.global); - global.setParentScope(null); - - // context.putThreadLocal ("reval", reval); - // context.putThreadLocal ("engine", this); - extensionGlobals = new HashMap(); - - Vector extVec = Server.getServer().getExtensions(); - - for (int i = 0; i < extVec.size(); i++) { - HelmaExtension ext = (HelmaExtension) extVec.get(i); - - try { - HashMap tmpGlobals = ext.initScripting(app, this); - - if (tmpGlobals != null) { - extensionGlobals.putAll(tmpGlobals); - } - } catch (ConfigurationException e) { - app.logEvent("Couldn't initialize extension " + ext.getName() + ": " + - e.getMessage()); - } - } - - // context.removeThreadLocal ("reval"); - // context.removeThreadLocal ("engine"); - } catch (Exception e) { - System.err.println("Cannot initialize interpreter"); - System.err.println("Error: " + e); - e.printStackTrace(); - throw new RuntimeException(e.getMessage()); - } finally { - Context.exit (); - } - } - - static synchronized RhinoCore getRhinoCore(Application app) { - RhinoCore core = null; - - if (coreMap == null) { - coreMap = new WeakHashMap(); - } else { - core = (RhinoCore) coreMap.get(app); - } - - if (core == null) { - core = new RhinoCore(app); - coreMap.put(app, core); - } - - return core; - } - - /** - * This method is called before an execution context is entered to let the - * engine know it should update its prototype information. - */ - public void updatePrototypes() { - context = Context.enter(); - context.setCompileFunctionsWithDynamicScope(true); - context.setWrapFactory(core.wrapper); - - boolean trace = "true".equals(app.getProperty("rhino.trace")); - - if (trace) { - context.setDebugger(new Tracer(getResponse()), null); - } - - int optLevel = 0; - - try { - optLevel = Integer.parseInt(app.getProperty("rhino.optlevel")); - } catch (Exception ignore) { - } - - context.setOptimizationLevel(optLevel); - core.updatePrototypes(); - context.putThreadLocal("reval", reval); - context.putThreadLocal("engine", this); - } - - /** - * This method is called when an execution context for a request - * evaluation is entered. The globals parameter contains the global values - * to be applied during this execution context. - */ - public void enterContext(HashMap globals) throws ScriptingException { - // set the thread filed in the FESI evaluator - // evaluator.thread = Thread.currentThread (); - // set globals on the global object - // context = Context.enter (context); - globals.putAll(extensionGlobals); - thread = Thread.currentThread(); - - if ((globals != null) && (globals != lastGlobals)) { - // loop through global vars and set them - for (Iterator i = globals.keySet().iterator(); i.hasNext();) { - String k = (String) i.next(); - Object v = globals.get(k); - Scriptable scriptable = null; - - try { - // create a special wrapper for the path object. - // other objects are wrapped in the default way. - if (v instanceof RequestPath) { - scriptable = new PathWrapper((RequestPath) v, core); - scriptable.setPrototype(core.pathProto); - } else { - scriptable = Context.toObject(v, global); - } - - global.put(k, global, scriptable); - } catch (Exception x) { - app.logEvent("Error setting global variable " + k + ": " + x); - } - } - } - - // remember the globals set on this evaluator - lastGlobals = globals; - } - - /** - * This method is called to let the scripting engine know that the current - * execution context has terminated. - */ - public void exitContext() { - context.removeThreadLocal("reval"); - context.removeThreadLocal("engine"); - Context.exit(); - thread = null; - - // loop through previous globals and unset them, if necessary. - if (lastGlobals != null) { - for (Iterator i=lastGlobals.keySet().iterator(); i.hasNext(); ) { - String g = (String) i.next (); - try { - global.delete (g); - } catch (Exception x) { - System.err.println ("Error resetting global property: "+g); - } - } - lastGlobals = null; - } - } - - /** - * Invoke a function on some object, using the given arguments and global vars. - */ - public Object invoke(Object thisObject, String functionName, Object[] args, - boolean xmlrpc) throws ScriptingException { - Scriptable eso = null; - - if (thisObject == null) { - eso = global; - } else { - eso = Context.toObject(thisObject, global); - } - try { - for (int i = 0; i < args.length; i++) { - // XML-RPC requires special argument conversion - if (xmlrpc) { - args[i] = core.processXmlRpcArgument (args[i]); - } else if (args[i] != null) { - args[i] = Context.toObject(args[i], global); - } - } - - Object f = ScriptableObject.getProperty(eso, functionName.replace('.', '_')); - - if ((f == ScriptableObject.NOT_FOUND) || !(f instanceof Function)) { - return null; - } - - Object retval = ((Function) f).call(context, global, eso, args); - - if (xmlrpc) { - return core.processXmlRpcResponse (retval); - } else if ((retval == null) || (retval == Undefined.instance)) { - return null; - } else if (retval instanceof Wrapper) { - return ((Wrapper) retval).unwrap(); - } else { - return retval; - } - } catch (RedirectException redirect) { - throw redirect; - } catch (TimeoutException timeout) { - throw timeout; - } catch (ConcurrencyException concur) { - throw concur; - } catch (Exception x) { - // check if this is a redirect exception, which has been converted by fesi - // into an EcmaScript exception, which is why we can't explicitly catch it - if (reval.res.getRedirect() != null) { - throw new RedirectException(reval.res.getRedirect()); - } - - // do the same for not-modified responses - if (reval.res.getNotModified()) { - throw new RedirectException(null); - } - - // has the request timed out? If so, throw TimeoutException - if (thread != Thread.currentThread()) - throw new TimeoutException (); - // create and throw a ScriptingException with the right message - String msg; - if (x instanceof JavaScriptException) { - msg = ((JavaScriptException) x).getValue().toString(); - } else { - msg = x.toString(); - } - - if (app.debug()) { - System.err.println("Error in Script: " + msg); - x.printStackTrace(); - } - - throw new ScriptingException(msg); - } - } - - /** - * Let the evaluator know that the current evaluation has been - * aborted. - */ - public void abort() { - // current request has been aborted. - Thread t = thread; - if (t != null && t.isAlive()) { - t.interrupt(); - try { - Thread.sleep(5000); - if (t.isAlive()) { - // thread is still running, gotta stop it. - t.stop(); - } - } catch (InterruptedException i) { - } - } - } - - /** - * Check if an object has a function property (public method if it - * is a java object) with that name. - */ - public boolean hasFunction(Object obj, String fname) { - // System.err.println ("HAS_FUNC: "+obj+"."+fname); - return core.hasFunction(app.getPrototypeName(obj), fname.replace('.', '_')); - } - - /** - * Check if an object has a defined property (public field if it - * is a java object) with that name. - */ - public Object get(Object obj, String propname) { - // System.err.println ("GET: "+propname); - if ((obj == null) || (propname == null)) { - return null; - } - - String prototypeName = app.getPrototypeName(obj); - - if ("user".equalsIgnoreCase(prototypeName) && - "password".equalsIgnoreCase(propname)) { - return "[macro access to password property not allowed]"; - } - - // if this is a HopObject, check if the property is defined - // in the type.properties db-mapping. - if (obj instanceof INode) { - DbMapping dbm = app.getDbMapping(prototypeName); - - if (dbm != null) { - Relation rel = dbm.propertyToRelation(propname); - - if ((rel == null) || !rel.isPrimitive()) { - return "[property \"" + propname + "\" is not defined for " + - prototypeName + "]"; - } - } - } - - Scriptable so = Context.toObject(obj, global); - - try { - Object prop = so.get(propname, so); - - if ((prop == null) || (prop == Undefined.instance)) { - return null; - } else if (prop instanceof Wrapper) { - return ((Wrapper) prop).unwrap(); - } else if (prop == Undefined.instance || prop == ScriptableObject.NOT_FOUND) { - return null; - } else { - return prop; - } - } catch (Exception esx) { - // System.err.println ("Error in getProperty: "+esx); - return null; - } - } - - /** - * Get an introspector to this engine. - */ - public IPathElement getIntrospector() { - if (doc == null) { - doc = new DocApplication(app.getName(), app.getAppDir().toString()); - doc.readApplication(); - } - return doc; - } - - /** - * Return the application we're running in - */ - public Application getApplication() { - return app; - } - - /** - * Return the RequestEvaluator owning and driving this FESI evaluator. - */ - public RequestEvaluator getRequestEvaluator() { - return reval; - } - - /** - * Return the Response object of the current evaluation context. - * Proxy method to RequestEvaluator. - */ - public ResponseTrans getResponse() { - return reval.res; - } - - /** - * Return the Request object of the current evaluation context. - * Proxy method to RequestEvaluator. - */ - public RequestTrans getRequest() { - return reval.req; - } - - /** - * Return the RhinoCore object for the application this engine belongs to. - * - * @return this engine's RhinoCore instance - */ - public RhinoCore getCore() { - return core; - } - - /** - * Get a skin for the given prototype and skin name. This method considers the - * skinpath set in the current response object and does per-response skin - * caching. - */ - public Skin getSkin(String protoName, String skinName) { - SkinKey key = new SkinKey(protoName, skinName); - - Skin skin = reval.res.getCachedSkin(key); - - if (skin == null) { - // retrieve res.skinpath, an array of objects that tell us where to look for skins - // (strings for directory names and INodes for internal, db-stored skinsets) - Object[] skinpath = reval.res.getSkinpath(); - RhinoCore.unwrapSkinpath(skinpath); - skin = app.getSkin(protoName, skinName, skinpath); - reval.res.cacheSkin(key, skin); - } - return skin; - } - -} diff --git a/src/helma/scripting/rhino/SkinKey.java b/src/helma/scripting/rhino/SkinKey.java deleted file mode 100644 index ceed5f0e..00000000 --- a/src/helma/scripting/rhino/SkinKey.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino; - -import java.io.Serializable; - -/** - * A helper class to serve as Map key for two strings - */ -final class SkinKey { - - private final String type; - - private final String id; - - // lazily initialized hashcode - private transient int hashcode = 0; - - /** - * make a key for a persistent Object, describing its datasource and id. - */ - public SkinKey(String type, String id) { - this.type = type == null ? "" : type; - this.id = id; - } - - /** - * - * - * @param what the other key to be compared with this one - * - * @return true if both keys are identical - */ - public boolean equals(Object what) { - - if (!(what instanceof SkinKey)) { - return false; - } - - SkinKey k = (SkinKey) what; - - return (type.equals(k.type)) && (id.equals(k.id)); - } - - /** - * - * - * @return this key's hash code - */ - public int hashCode() { - if (hashcode == 0) { - hashcode = (17 + (37 * type.hashCode()) + - (+37 * id.hashCode())); - } - - return hashcode; - } - -} diff --git a/src/helma/scripting/rhino/debug/Tracer.java b/src/helma/scripting/rhino/debug/Tracer.java deleted file mode 100644 index 00afface..00000000 --- a/src/helma/scripting/rhino/debug/Tracer.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino.debug; - - -import org.mozilla.javascript.*; -import org.mozilla.javascript.debug.*; -import helma.framework.ResponseTrans; - -public class Tracer implements Debugger { - - ResponseTrans res; - - /** - * Create a tracer that writes to this response object - */ - public Tracer(ResponseTrans res) { - this.res = res; - } - - - /** - * Implementws handleCompilationDone in interface org.mozilla.javascript.debug.Debugger - */ - public void handleCompilationDone(Context cx, DebuggableScript script, String source) { - // res.debug("CompilationDone: "+toString(script)); - } - - /** - * Implementws getFrame in interface org.mozilla.javascript.debug.Debugger - */ - public DebugFrame getFrame(Context cx, DebuggableScript script) { - // res.debug("getFrame: "+toString(script)); - if (script.isFunction()) { - return new TracerFrame(script); - } - return null; - } - - static String toString(DebuggableScript script) { - if (script.isFunction()) { - return script.getSourceName()+": "+script.getFunctionName(); - } else { - return script.getSourceName(); - } - } - -class TracerFrame implements DebugFrame { - - DebuggableScript script; - - TracerFrame(DebuggableScript script) { - this.script = script; - } - - /** - * Called when execution is ready to start bytecode interpretation - * for entered a particular function or script. - */ - public void onEnter(Context cx, Scriptable activation, - Scriptable thisObj, Object[] args) { - StringBuffer b = new StringBuffer("Trace: "); - b.append(Tracer.toString(script)); - b.append("("); - for (int i=0; i0 && idx <=colNames.size()) { - return (String) colNames.elementAt(idx-1); // to base 0 - } else { - lastError = new SQLException("Column index (base 1) " + idx + - " out of range, max: " +colNames.size()); - return null; - } - } - - - public int getColumnDatatypeNumber(int idx) { - if (resultSet == null) { - lastError = new SQLException("Attempt to access a released result set"); - return -1; - } - if (idx>0 && idx <=colNames.size()) { - try { - return resultSetMetaData.getColumnType(idx); - } catch (SQLException e) { - lastError = e; - return -1; - } - } else { - lastError = new SQLException("Column index (base 1) " + idx + - " out of range, max: " +colNames.size()); - return -1; - } - } - - - public String getColumnDatatypeName(int idx) { - if (resultSet == null) { - lastError = new SQLException("Attempt to access a released result set"); - return null; - } - if (idx>0 && idx <=colNames.size()) { - try { - return resultSetMetaData.getColumnTypeName(idx); - } catch (SQLException e) { - lastError = e; - return null; - } - } else { - lastError = new SQLException("Column index (base 1) " + idx + - " out of range, max: " +colNames.size()); - return null; - } - } - - - public Object getColumnItem(String propertyName) { - if (resultSet == null) { - lastError = new SQLException("Attempt to access a released result set"); - return null; - } - if (!firstRowSeen) { - lastError = new SQLException("Attempt to access data before the first row is read"); - return null; - } - try { - int index = -1; // indicates not a valid index value - try { - char c = propertyName.charAt(0); - if ('0' <= c && c <= '9') { - index = Integer.parseInt(propertyName); - } - } catch (NumberFormatException e) { - } catch (StringIndexOutOfBoundsException e) { // for charAt - } - if (index>=0) { - return getProperty(index); - } - Object value = resultSet.getObject(propertyName); - // IServer.getLogger().log("&& @VALUE : " + value); - lastError = null; - return value; - } catch (SQLException e) { - //System.err.println("##Cannot get property '" + propertyName + "' " + e); - //e.printStackTrace(); - lastError = e; - } - return null; - } - - public Object getProperty(String propertyName, int hash) { - //System.err.println(" &&& Getting property '" + propertyName + "'"); - - // Length property is firsy checked - - // First return system or or prototype properties - if (propertyName.equals("length")) { - return new Integer(colNames.size()); - } else { - if (resultSet == null) { - lastError = new SQLException("Attempt to access a released result set"); - return null; - } - if (!firstRowSeen) { - lastError = new SQLException("Attempt to access data before the first row is read"); - return null; - } - try { - int index = -1; // indicates not a valid index value - try { - char c = propertyName.charAt(0); - if ('0' <= c && c <= '9') { - index = Integer.parseInt(propertyName); - } - } catch (NumberFormatException e) { - } catch (StringIndexOutOfBoundsException e) { // for charAt - } - if (index>=0) { - return getProperty(index); - } - Object value = resultSet.getObject(propertyName); - // IServer.getLogger().log("&& @VALUE : " + value); - lastError = null; - return value; - } catch (SQLException e) { - // System.err.println("##Cannot get property '" + propertyName + "' " + e); - // e.printStackTrace(); - lastError = e; - } - } - return null; - } - - public Object getProperty(int index) { - if (!firstRowSeen) { - lastError = new SQLException("Attempt to access data before the first row is read"); - return null; - } - if (resultSet == null) { - lastError = new SQLException("Attempt to access a released result set"); - return null; - } - - try { - Object value = resultSet.getObject(index); - lastError = null; - return value; - } catch (SQLException e) { - // System.err.println("##Cannot get property: " + e); - // e.printStackTrace(); - lastError = e; - } - return null; - } - - /* - * Returns an enumerator for the key elements of this object. - * - * @return the enumerator - may have 0 length of coulmn names where not found - */ - public Enumeration getProperties() { - if (resultSet == null) { - return (new Vector()).elements(); - } - return colNames.elements(); - } - - - public String[] getSpecialPropertyNames() { - String [] ns = {"length"}; - return ns; - } - - - public boolean next() { - boolean status = false; - if (lastRowSeen) { - lastError = new SQLException("Attempt to access a next row after last row has been returned"); - return false; - } - if (resultSet == null) { - lastError = new SQLException("Attempt to access a released result set"); - return false; - } - try { - status = resultSet.next(); - lastError = null; - } catch (SQLException e) { - // System.err.println("##Cannot do next:" + e); - // e.printStackTrace(); - lastError = e; - } - if (status) firstRowSeen = true; - else lastRowSeen = true; - return status; - } - - public String toString() { - return "[RowSet: '"+sql+"'" + - (resultSet==null ? " - released]" : - (lastRowSeen ? " - at end]" : - (firstRowSeen ? "]" : " - at start]"))); - } - -} diff --git a/src/helma/scripting/rhino/extensions/FileObject.java b/src/helma/scripting/rhino/extensions/FileObject.java deleted file mode 100644 index fe324e9a..00000000 --- a/src/helma/scripting/rhino/extensions/FileObject.java +++ /dev/null @@ -1,509 +0,0 @@ -// FileIO.java -// FESI Copyright (c) Jean-Marc Lugrin, 1999 -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package helma.scripting.rhino.extensions; - - -import java.io.BufferedReader; -import java.io.File; -import java.io.Reader; -import java.io.Writer; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.PrintWriter; -import java.io.EOFException; -import java.io.IOException; -import java.util.Date; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.FunctionObject; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; -import org.mozilla.javascript.PropertyException; -import org.mozilla.javascript.Undefined; -import java.lang.reflect.Member; -import java.lang.reflect.Method; - -/** - * An EcmaScript FileIO 'File' object - */ -public class FileObject extends ScriptableObject { - File file = null; - Object readerWriter = null; - boolean atEOF = false; - String lastLine = null; - Throwable lastError = null; - - protected FileObject() { - } - - protected FileObject(String fileName) { - file = new File(fileName); - } - - protected FileObject(String pathName, String fileName) { - file = new File(pathName, fileName); - } - - public static FileObject fileObjCtor(Context cx, Object[] args, - Function ctorObj, boolean inNewExpr) { - if (args.length == 0 || args[0] == Undefined.instance) { - throw new IllegalArgumentException("File constructor called without argument"); - } - if (args.length < 2 || args[1] == Undefined.instance) { - return new FileObject(args[0].toString()); - } - return new FileObject(args[0].toString(), args[1].toString()); - } - - public static void init(Scriptable scope) { - Method[] methods = FileObject.class.getDeclaredMethods(); - ScriptableObject proto = new FileObject(); - proto.setPrototype(getObjectPrototype(scope)); - Member ctorMember = null; - for (int i=0; i"; - return file.toString(); - } - - public String toDetailString() { - return "ES:[Object: builtin " + this.getClass().getName() + ":" + - ((file == null) ? "null" : file.toString()) + "]"; - } - - protected void setError(Throwable e) { - lastError = e; - } - - public boolean exists() { - if (file == null) return false; - return file.exists(); - } - - public boolean open() { - if (readerWriter != null) { - setError(new IllegalStateException("File already open")); - return false; - } - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return false; - } - - // We assume that the BufferedReader and PrintWriter creation - // cannot fail except if the FileReader/FileWriter fails. - // Otherwise we have an open file until the reader/writer - // get garbage collected. - try{ - if (file.exists()) { - readerWriter = new BufferedReader(new FileReader(file)); - } else { - readerWriter = new PrintWriter(new FileWriter(file)); - } - return true; - } catch (IOException e) { - setError(e); - return false; - } - } - - public boolean isOpened() { - return (readerWriter != null); - } - - public boolean close() { - if (readerWriter == null) - return false; - try { - if (readerWriter instanceof Reader) { - ((Reader) readerWriter).close(); - } else { - ((Writer) readerWriter).close(); - } - readerWriter = null; - return true; - } catch (IOException e) { - setError(e); - readerWriter = null; - return false; - } - } - - public boolean write(Object what) { - if (readerWriter == null) { - setError(new IllegalStateException("File not opened")); - return false; - } - if (! (readerWriter instanceof PrintWriter)) { - setError(new IllegalStateException("File not opened for writing")); - return false; - } - PrintWriter writer = (PrintWriter) readerWriter; - if (what != null) { - writer.print(what.toString()); - } - // writer.println(); - return true; - } - - public boolean writeln(Object what) { - if (readerWriter == null) { - setError(new IllegalStateException("File not opened")); - return false; - } - if (! (readerWriter instanceof PrintWriter)) { - setError(new IllegalStateException("File not opened for writing")); - return false; - } - PrintWriter writer = (PrintWriter) readerWriter; - if (what != null) { - writer.print(what.toString()); - } - writer.println(); - return true; - } - - public String readln() { - if (readerWriter == null) { - setError(new IllegalStateException("File not opened")); - return null; - } - if (! (readerWriter instanceof BufferedReader)) { - setError(new IllegalStateException("File not opened for reading")); - return null; - } - if (atEOF) { - setError(new EOFException()); - return null; - } - if (lastLine!=null) { - String line = lastLine; - lastLine = null; - return line; - } - BufferedReader reader = (BufferedReader) readerWriter; - // Here lastLine is null, return a new line - try { - String line = reader.readLine(); - if (line == null) { - atEOF = true; - setError(new EOFException()); - } - return line; - } catch (IOException e) { - setError(e); - return null; - } - } - - public boolean eof() { - if (readerWriter == null) { - setError(new IllegalStateException("File not opened")); - return true; - } - if (! (readerWriter instanceof BufferedReader)) { - setError(new IllegalStateException("File not opened for read")); - return true; - } - if (atEOF) return true; - if (lastLine!=null) return false; - BufferedReader reader = (BufferedReader) readerWriter; - try { - lastLine = reader.readLine(); - if (lastLine == null) atEOF = true; - return atEOF; - } catch (IOException e) { - setError(e); - return true; - } - } - - public boolean isFile() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return false; - } - return file.isFile(); - } - - public boolean isDirectory() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return false; - } - return file.isDirectory(); - } - - public boolean flush() { - if (readerWriter == null) { - setError(new IllegalStateException("File not opened")); - return false; - } - if (readerWriter instanceof Writer) { - try { - ((Writer) readerWriter).flush(); - } catch (IOException e) { - setError(e); - return false; - } - } else { - setError(new IllegalStateException("File not opened for write")); - return false; // not supported by reader - } - return true; - } - - - public long getLength() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return -1; - } - return file.length(); - } - - public long lastModified() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return 0L; - } - return file.lastModified(); - } - - public String error() { - if (lastError == null) { - return ""; - } else { - String exceptionName = lastError.getClass().getName(); - int l = exceptionName.lastIndexOf("."); - if (l>0) exceptionName = exceptionName.substring(l+1); - return exceptionName +": " + lastError.getMessage(); - } - } - - public void clearError() { - lastError = null; - } - - public boolean remove() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return false; - } - if (readerWriter != null) { - setError(new IllegalStateException("An openened file cannot be removed")); - return false; - } - return file.delete(); - } - - public boolean renameTo(FileObject toFile) { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized source File object")); - return false; - } - if (toFile.file == null) { - setError(new IllegalArgumentException("Uninitialized target File object")); - return false; - } - if (readerWriter != null) { - setError(new IllegalStateException("An openened file cannot be renamed")); - return false; - } - if (toFile.readerWriter!=null) { - setError(new IllegalStateException("You cannot rename to an openened file")); - return false; - } - return file.renameTo(toFile.file); - } - - public boolean canRead() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return false; - } - return file.canRead(); - } - - public boolean canWrite() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return false; - } - return file.canWrite(); - } - - public String getParent() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return ""; - } - String parent = file.getParent(); - return (parent==null ? "" : parent); - } - - public String getName() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return ""; - } - String name = file.getName(); - return (name==null ? "" : name); - } - - public String getPath() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return ""; - } - String path = file.getPath(); - return (path==null ? "" : path); - } - - public String getAbsolutePath() { - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return ""; - } - String absolutPath = file.getAbsolutePath(); - return (absolutPath==null ? "" : absolutPath); - } - - public boolean isAbsolute() { - if (file == null) return false; - return file.isAbsolute(); - } - - public boolean mkdir() { - if (file == null) return false; - if(readerWriter != null) return false; - return file.mkdirs(); // Using multi directory version - } - - public String [] list() { - if (file == null) return null; - if(readerWriter != null) return null; - if (!file.isDirectory()) return null; - return file.list(); - } - - - public String readAll() { - // Open the file for readAll - if (readerWriter != null) { - setError(new IllegalStateException("File already open")); - return null; - } - if (file == null) { - setError(new IllegalArgumentException("Uninitialized File object")); - return null; - } - try{ - if (file.exists()) { - readerWriter = new BufferedReader(new FileReader(file)); - } else { - setError(new IllegalStateException("File does not exist")); - return null; - } - if(!file.isFile()) { - setError(new IllegalStateException("File is not a regular file")); - return null; - } - - // read content line by line to setup properl eol - StringBuffer buffer = new StringBuffer((int) (file.length()*1.10)); - BufferedReader reader = (BufferedReader) readerWriter; - while (true) { - String line = reader.readLine(); - if (line == null) { - break; - } - buffer.append(line); - buffer.append("\n"); // EcmaScript EOL - } - - - // Close the file - ((Reader) readerWriter).close(); - readerWriter = null; - return buffer.toString(); - } catch (IOException e) { - readerWriter = null; - setError(e); - return null; - } - } - -} //class FileObject - diff --git a/src/helma/scripting/rhino/extensions/FtpObject.java b/src/helma/scripting/rhino/extensions/FtpObject.java deleted file mode 100644 index 218f3800..00000000 --- a/src/helma/scripting/rhino/extensions/FtpObject.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino.extensions; - -import com.oroinc.net.ftp.*; -import java.io.*; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.FunctionObject; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; -import org.mozilla.javascript.PropertyException; -import org.mozilla.javascript.Undefined; -import java.lang.reflect.Member; -import java.lang.reflect.Method; - - -/** - * A FTP-client object that allows to do some FTP from HOP applications. - * FTP support is far from complete but can easily be extended if more - * functionality is needed. - * This uses the NetComponent classes from savarese.org (ex oroinc.com). - */ -public class FtpObject extends ScriptableObject { - private FTPClient ftpclient; - private String server; - private Exception lastError = null; - private File localDir = null; - - /** - * Create a new FTP Client - * - * @param prototype The prototype object for the FTP object - * @param evaluator The current evaluator - */ - FtpObject(String srvstr) { - this.server = srvstr; - } - - FtpObject() { - } - - /** - * - * - * @return ... - */ - public String getClassName() { - return "FtpClient"; - } - - /** - * - * - * @return ... - */ - public String toString() { - return "[FtpClient]"; - } - - /** - * - * - * @return ... - */ - public String toDetailString() { - return "ES:[Object: builtin " + this.getClass().getName() + ":" + - this.toString() + "]"; - } - - Exception getLastError() { - if (lastError == null) { - return null; - } else { - return lastError; - } - } - - /** - * Login to the FTP server - * - * @param arguments The argument list - * @return true if successful, false otherwise - */ - public boolean login(String username, String password) { - if (server == null) { - return false; - } - - try { - ftpclient = new FTPClient(); - ftpclient.connect(server); - - boolean b = ftpclient.login(username, password); - - return b; - } catch (Exception x) { - return false; - } catch (NoClassDefFoundError x) { - return false; - } - } - - public boolean cd(String path) { - if (ftpclient == null) { - return false; - } - - try { - ftpclient.changeWorkingDirectory(path); - - return true; - } catch (Exception wrong) { - } - - return false; - } - - public boolean mkdir(String dir) { - if (ftpclient == null) { - return false; - } - - try { - return ftpclient.makeDirectory(dir); - } catch (Exception wrong) { - } - - return false; - } - - public boolean lcd(String dir) { - try { - localDir = new File(dir); - - if (!localDir.exists()) { - localDir.mkdirs(); - } - - return true; - } catch (Exception wrong) { - } - - return false; - } - - public boolean putFile(String localFile, String remoteFile) { - if (ftpclient == null) { - return false; - } - - try { - File f = (localDir == null) ? new File(localFile) : new File(localDir, localFile); - InputStream fin = new BufferedInputStream(new FileInputStream(f)); - - ftpclient.storeFile(remoteFile, fin); - fin.close(); - - return true; - } catch (Exception wrong) { - } - - return false; - } - - public boolean putString(Object obj, String remoteFile) { - if (ftpclient == null || obj == null) { - return false; - } - - try { - byte[] bytes = null; - - // check if this already is a byte array - if (obj instanceof byte[]) { - bytes = (byte[]) obj; - } - - if (bytes == null) { - bytes = obj.toString().getBytes(); - } - - ByteArrayInputStream bin = new ByteArrayInputStream(bytes); - - ftpclient.storeFile(remoteFile, bin); - - return true; - } catch (Exception wrong) { - } - - return false; - } - - public boolean getFile(String remoteFile, String localFile) { - if (ftpclient == null) { - return false; - } - - try { - File f = (localDir == null) ? new File(localFile) : new File(localDir, localFile); - OutputStream out = new BufferedOutputStream(new FileOutputStream(f)); - - ftpclient.retrieveFile(remoteFile, out); - out.close(); - - return true; - } catch (Exception wrong) { - } - - return false; - } - - public Object getString(String remoteFile) { - if (ftpclient == null) { - return null; - } - - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - - ftpclient.retrieveFile(remoteFile, bout); - - return bout.toString(); - } catch (Exception wrong) { - } - - return null; - } - - /** - * Disconnect from FTP server - * - * @param arguments The argument list - * @return true if successful, false otherwise - */ - public boolean logout() { - if (ftpclient != null) { - try { - ftpclient.logout(); - } catch (IOException ignore) { - } - - try { - ftpclient.disconnect(); - } catch (IOException ignore) { - } - } - - return true; - } - - public boolean binary() { - if (ftpclient != null) { - try { - ftpclient.setFileType(FTP.BINARY_FILE_TYPE); - - return true; - } catch (IOException ignore) { - } - } - - return false; - } - - public boolean ascii() { - if (ftpclient != null) { - try { - ftpclient.setFileType(FTP.ASCII_FILE_TYPE); - - return true; - } catch (IOException ignore) { - } - } - - return false; - } - - - - public static FtpObject ftpObjCtor(Context cx, Object[] args, - Function ctorObj, boolean inNewExpr) { - if (args.length != 1 || args[0] == Undefined.instance) { - throw new IllegalArgumentException("Ftp constructor called without argument"); - } - return new FtpObject(args[0].toString()); - } - - public static void init(Scriptable scope) { - Method[] methods = FtpObject.class.getDeclaredMethods(); - ScriptableObject proto = new FtpObject(); - proto.setPrototype(getObjectPrototype(scope)); - Member ctorMember = null; - for (int i=0; i 1 && arguments[1] instanceof ESNumber) - // writer.setMaxLevels(arguments[1].toInt32()); - writer.setDatabaseMode(false); - - writer.write(node); - - writer.flush(); - - return out.toString("UTF-8"); - } - - /** - * - * - * @param file ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public Object read(String file) throws RuntimeException { - return read(file, null); - } - - /** - * - * - * @param file ... - * @param hopObject ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public Object read(String file, INode node) throws RuntimeException { - if (file == null) { - throw new RuntimeException("Missing arguments in Xml.read()"); - } - - if (node == null) { - // make sure we have a node, even if 2nd arg doesn't exist or is not a node - node = new Node((String) null, (String) null, - core.getApplication().getWrappedNodeManager()); - } - - try { - XmlReader reader = new XmlReader(); - INode result = reader.read(new File(file), node); - - return core.getNodeWrapper(result); - } catch (NoClassDefFoundError e) { - throw new RuntimeException("Can't load XML parser:" + e); - } catch (Exception f) { - throw new RuntimeException(f.toString()); - } - } - - /** - * - * - * @param str ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public Object readFromString(String str) throws RuntimeException { - return readFromString(str, null); - } - - /** - * - * - * @param str ... - * @param hopObject ... - * - * @return ... - * - * @throws RuntimeException ... - */ - public Object readFromString(String str, INode node) - throws RuntimeException { - if (str == null) { - throw new RuntimeException("Missing arguments in Xml.read()"); - } - - if (node == null) { - // make sure we have a node, even if 2nd arg doesn't exist or is not a node - node = new Node((String) null, (String) null, - core.getApplication().getWrappedNodeManager()); - } - - try { - XmlReader reader = new XmlReader(); - INode result = reader.read(new StringReader(str), node); - - return core.getNodeWrapper(result); - } catch (NoClassDefFoundError e) { - throw new RuntimeException("Can't load XML parser:" + e); - } catch (Exception f) { - throw new RuntimeException(f.toString()); - } - } - -} diff --git a/src/helma/scripting/rhino/extensions/XmlRpcObject.java b/src/helma/scripting/rhino/extensions/XmlRpcObject.java deleted file mode 100644 index 08d1dacc..00000000 --- a/src/helma/scripting/rhino/extensions/XmlRpcObject.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino.extensions; - -import helma.scripting.rhino.*; -import org.mozilla.javascript.*; -import org.apache.xmlrpc.*; -import java.io.*; -import java.net.*; -import java.util.*; -import java.lang.reflect.Member; -import java.lang.reflect.Method; - -/** - * An extension to transparently call and serve XML-RPC from Rhino. - * The extension adds constructors for XML-RPC clients and servers to the Global Object. - * - * All argument conversion is done automatically. Currently the following argument and return - * types are supported: - *
    - *
  • plain objects (with all properties returned by ESObject.getProperties ()) - *
  • arrays - *
  • strings - *
  • date objects - *
  • booleans - *
  • integer and float numbers (long values are not supported!) - *
- * - */ -public class XmlRpcObject extends BaseFunction { - - String url = null; - String method = null; - - XmlRpcObject(String url) { - this.url = url; - this.method = null; - } - - XmlRpcObject(String url, String method) { - this.url = url; - this.method = method; - } - - /** - * This method is used as HopObject constructor from JavaScript. - */ - public static Object xmlrpcObjectConstructor(Context cx, Object[] args, - Function ctorObj, boolean inNewExpr) { - if (args.length == 0 || args.length > 2) { - throw new IllegalArgumentException("Wrong number of arguments in constructor for XML-RPC client"); - } - if (args.length == 1) { - String url = args[0].toString(); - return new XmlRpcObject(url); - } else { - String url = args[0].toString(); - String method = args[1].toString(); - return new XmlRpcObject(url, method); - } - - } - - /** - * Called by the evaluator after the extension is loaded. - */ - public static void init(Scriptable scope) { - Method[] methods = XmlRpcObject.class.getDeclaredMethods(); - Member ctorMember = null; - for (int i=0; i 0)) { - reqtrans.set(key, values[0]); // set to single string value - - if (values.length > 1) { - reqtrans.set(key + "_array", values); // set string array - } - } - } - - // check for MIME file uploads - String contentType = request.getContentType(); - - if ((contentType != null) && - (contentType.indexOf("multipart/form-data") == 0)) { - // File Upload - try { - FileUpload upload = getUpload(request); - - if (upload != null) { - Hashtable parts = upload.getParts(); - - for (Enumeration e = parts.keys(); e.hasMoreElements();) { - String nextKey = (String) e.nextElement(); - Object nextPart = parts.get(nextKey); - - reqtrans.set(nextKey, nextPart); - } - } - } catch (Exception upx) { - sendError(response, HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, - "Sorry, upload size exceeds limit of " + uploadLimit + - "kB."); - - return; - } - } - - // read cookies - Cookie[] reqCookies = request.getCookies(); - - if (reqCookies != null) { - for (int i = 0; i < reqCookies.length; i++) - try { - // get Cookies - String nextKey = reqCookies[i].getName(); - String nextPart = reqCookies[i].getValue(); - - if ("HopSession".equals(nextKey)) { - reqtrans.session = nextPart; - } else { - reqtrans.set(nextKey, nextPart); - } - } catch (Exception badCookie) { - } - } - - // do standard HTTP variables - String host = request.getHeader("Host"); - - if (host != null) { - host = host.toLowerCase(); - reqtrans.set("http_host", host); - } - - String referer = request.getHeader("Referer"); - - if (referer != null) { - reqtrans.set("http_referer", referer); - } - - try { - long ifModifiedSince = request.getDateHeader("If-Modified-Since"); - - if (ifModifiedSince > -1) { - reqtrans.setIfModifiedSince(ifModifiedSince); - } - } catch (IllegalArgumentException ignore) { - } - - String ifNoneMatch = request.getHeader("If-None-Match"); - - if (ifNoneMatch != null) { - reqtrans.setETags(ifNoneMatch); - } - - String remotehost = request.getRemoteAddr(); - - if (remotehost != null) { - reqtrans.set("http_remotehost", remotehost); - } - - // get the cookie domain to use for this response, if any. - String resCookieDomain = cookieDomain; - - if (resCookieDomain != null) { - // check if cookieDomain is valid for this response. - // (note: cookieDomain is guaranteed to be lower case) - if ((host != null) && (host.toLowerCase().indexOf(cookieDomain) == -1)) { - resCookieDomain = null; - } - } - - // check if session cookie is present and valid, creating it if not. - checkSessionCookie(request, response, reqtrans, resCookieDomain); - - String browser = request.getHeader("User-Agent"); - - if (browser != null) { - reqtrans.set("http_browser", browser); - } - - String authorization = request.getHeader("authorization"); - - if (authorization != null) { - reqtrans.set("authorization", authorization); - } - - // response.setHeader ("Server", "Helma/"+helma.main.Server.version); - reqtrans.path = getPathInfo(request); - - ResponseTrans restrans = execute(reqtrans); - - // set cookies - if (restrans.countCookies() > 0) { - CookieTrans[] resCookies = restrans.getCookies(); - - for (int i = 0; i < resCookies.length; i++) - try { - Cookie c = resCookies[i].getCookie("/", resCookieDomain); - - response.addCookie(c); - } catch (Exception ignore) { - } - } - - // write response - writeResponse(request, response, restrans); - } catch (Exception x) { - try { - if (debug) { - sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Error in request handler:" + x); - x.printStackTrace(); - } else { - sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "The server encountered an error while processing your request. " + - "Please check back later."); - } - - log("Exception in execute: " + x); - } catch (IOException io_e) { - log("Exception in sendError: " + io_e); - } - } - } - - void writeResponse(HttpServletRequest req, HttpServletResponse res, - ResponseTrans hopres) { - if (hopres.getETag() != null) { - res.setHeader("ETag", hopres.getETag()); - } - - if (hopres.getRedirect() != null) { - sendRedirect(req, res, hopres.getRedirect()); - } else if (hopres.getNotModified()) { - res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - } else { - if (!hopres.cache || !caching) { - // Disable caching of response. - // for HTTP 1.0 - res.setDateHeader("Expires", System.currentTimeMillis() - 10000); - res.setHeader("Pragma", "no-cache"); - - // for HTTP 1.1 - res.setHeader("Cache-Control", - "no-cache, no-store, must-revalidate, max-age=0"); - } - - if (hopres.realm != null) { - res.setHeader("WWW-Authenticate", "Basic realm=\"" + hopres.realm + "\""); - } - - if (hopres.status > 0) { - res.setStatus(hopres.status); - } - - // set last-modified header to now - long modified = hopres.getLastModified(); - - if (modified > -1) { - res.setDateHeader("Last-Modified", System.currentTimeMillis()); - } - - // if we don't know which charset to use for parsing HTTP params, - // take the one from the response. This usually works because - // browsers send parrameters in the same encoding as the page - // containing the form has. Problem is we can do this only per servlet, - // not per session or even per page, which would produce too much overhead - if (defaultEncoding == null) { - defaultEncoding = hopres.charset; - } - - res.setContentLength(hopres.getContentLength()); - res.setContentType(hopres.getContentType()); - - try { - OutputStream out = res.getOutputStream(); - - out.write(hopres.getContent()); - out.flush(); - } catch (Exception io_e) { - log("Exception in writeResponse: " + io_e); - } - } - } - - void sendError(HttpServletResponse response, int code, String message) - throws IOException { - response.reset(); - response.setStatus(code); - response.setContentType("text/html"); - - Writer writer = response.getWriter(); - - writer.write(message); - writer.flush(); - } - - void sendRedirect(HttpServletRequest req, HttpServletResponse res, String url) { - String location = url; - - if (url.indexOf("://") == -1) { - // need to transform a relative URL into an absolute one - String scheme = req.getScheme(); - StringBuffer loc = new StringBuffer(scheme); - - loc.append("://"); - loc.append(req.getServerName()); - - int p = req.getServerPort(); - - // check if we need to include server port - if ((p > 0) && - (("http".equals(scheme) && (p != 80)) || - ("https".equals(scheme) && (p != 443)))) { - loc.append(":"); - loc.append(p); - } - - if (!url.startsWith("/")) { - String requri = req.getRequestURI(); - int lastSlash = requri.lastIndexOf("/"); - - if (lastSlash == (requri.length() - 1)) { - loc.append(requri); - } else if (lastSlash > -1) { - loc.append(requri.substring(0, lastSlash + 1)); - } else { - loc.append("/"); - } - } - - loc.append(url); - location = loc.toString(); - } - - // send status code 303 for HTTP 1.1, 302 otherwise - if (isOneDotOne(req.getProtocol())) { - res.setStatus(HttpServletResponse.SC_SEE_OTHER); - } else { - res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - } - - res.setContentType("text/html"); - res.setHeader("Location", location); - } - - FileUpload getUpload(HttpServletRequest request) throws Exception { - int contentLength = request.getContentLength(); - BufferedInputStream in = new BufferedInputStream(request.getInputStream()); - - if (contentLength > (uploadLimit * 1024)) { - throw new RuntimeException("Upload exceeds limit of " + uploadLimit + " kb."); - } - - String contentType = request.getContentType(); - FileUpload upload = new FileUpload(uploadLimit); - - upload.load(in, contentType, contentLength); - - return upload; - } - - Object getUploadPart(FileUpload upload, String name) { - return upload.getParts().get(name); - } - - /** - * Check if the session cookie is set and valid for this request. - * If not, create a new one. - */ - private void checkSessionCookie(HttpServletRequest request, HttpServletResponse response, - RequestTrans reqtrans, String resCookieDomain) { - // check if we need to create a session id. also handle the - // case that the session id doesn't match the remote host address - StringBuffer b = new StringBuffer(); - addIPAddress(b, request.getRemoteAddr()); - addIPAddress(b, request.getHeader("X-Forwarded-For")); - addIPAddress(b, request.getHeader("Client-ip")); - if ((reqtrans.session == null) || !reqtrans.session.startsWith(b.toString())) { - b.append (Long.toString(Math.round(Math.random() * Long.MAX_VALUE) - - System.currentTimeMillis(), 36)); - - reqtrans.session = b.toString(); - Cookie c = new Cookie("HopSession", reqtrans.session); - - c.setPath("/"); - - if (resCookieDomain != null) { - c.setDomain(resCookieDomain); - } - - response.addCookie(c); - } - } - - /** - * Adds an the 3 most significant bytes of an IP address to the - * session cookie id. - */ - private void addIPAddress(StringBuffer b, String addr) { - if (addr != null) { - int cut = addr.lastIndexOf("."); - if (cut == -1) { - cut = addr.lastIndexOf(":"); - } - if (cut > -1) { - b.append(addr.substring(0, cut+1)); - } - } - } - - - /** - * Put name value pair in map. - * - * @param b the character value byte - * - * Put name and value pair in map. When name already exist, add value - * to array of values. - */ - private static void putMapEntry(Map map, String name, String value) { - String[] newValues = null; - String[] oldValues = (String[]) map.get(name); - - if (oldValues == null) { - newValues = new String[1]; - newValues[0] = value; - } else { - newValues = new String[oldValues.length + 1]; - System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); - newValues[oldValues.length] = value; - } - - map.put(name, newValues); - } - - protected Map parseParameters(HttpServletRequest request) { - String encoding = request.getCharacterEncoding(); - - if (encoding == null) { - // no encoding from request, use standard one - encoding = defaultEncoding; - } - - if (encoding == null) { - encoding = "ISO-8859-1"; - } - - HashMap parameters = new HashMap(); - - // Parse any query string parameters from the request - String queryString = request.getQueryString(); - if (queryString != null) { - try { - parseParameters(parameters, queryString.getBytes(), encoding); - } catch (Exception e) { - System.err.println("Error parsing query string: "+e); - } - } - - // Parse any posted parameters in the input stream - if ("POST".equals(request.getMethod()) && - "application/x-www-form-urlencoded".equals(request.getContentType())) { - try { - int max = request.getContentLength(); - int len = 0; - byte[] buf = new byte[max]; - ServletInputStream is = request.getInputStream(); - - while (len < max) { - int next = is.read(buf, len, max - len); - - if (next < 0) { - break; - } - - len += next; - } - - // is.close(); - parseParameters(parameters, buf, encoding); - } catch (IllegalArgumentException e) { - } catch (IOException e) { - } - } - - return parameters; - } - - /** - * Append request parameters from the specified String to the specified - * Map. It is presumed that the specified Map is not accessed from any - * other thread, so no synchronization is performed. - *

- * IMPLEMENTATION NOTE: URL decoding is performed - * individually on the parsed name and value elements, rather than on - * the entire query string ahead of time, to properly deal with the case - * where the name or value includes an encoded "=" or "&" character - * that would otherwise be interpreted as a delimiter. - * - * NOTE: byte array data is modified by this method. Caller beware. - * - * @param map Map that accumulates the resulting parameters - * @param data Input string containing request parameters - * @param encoding Encoding to use for converting hex - * - * @exception UnsupportedEncodingException if the data is malformed - */ - public static void parseParameters(Map map, byte[] data, String encoding) - throws UnsupportedEncodingException { - if ((data != null) && (data.length > 0)) { - int ix = 0; - int ox = 0; - String key = null; - String value = null; - - while (ix < data.length) { - byte c = data[ix++]; - - switch ((char) c) { - case '&': - value = new String(data, 0, ox, encoding); - - if (key != null) { - putMapEntry(map, key, value); - key = null; - } - - ox = 0; - - break; - - case '=': - key = new String(data, 0, ox, encoding); - ox = 0; - - break; - - case '+': - data[ox++] = (byte) ' '; - - break; - - case '%': - data[ox++] = (byte) ((convertHexDigit(data[ix++]) << 4) + - convertHexDigit(data[ix++])); - - break; - - default: - data[ox++] = c; - } - } - - //The last value does not end in '&'. So save it now. - if (key != null) { - value = new String(data, 0, ox, encoding); - putMapEntry(map, key, value); - } - } - } - - /** - * Convert a byte character value to hexidecimal digit value. - * - * @param b the character value byte - */ - private static byte convertHexDigit(byte b) { - if ((b >= '0') && (b <= '9')) { - return (byte) (b - '0'); - } - - if ((b >= 'a') && (b <= 'f')) { - return (byte) (b - 'a' + 10); - } - - if ((b >= 'A') && (b <= 'F')) { - return (byte) (b - 'A' + 10); - } - - return 0; - } - - boolean isOneDotOne(String protocol) { - if (protocol == null) { - return false; - } - - if (protocol.endsWith("1.1")) { - return true; - } - - return false; - } - - String getPathInfo(HttpServletRequest req) { - StringTokenizer t = new StringTokenizer(req.getContextPath(), "/"); - int prefixTokens = t.countTokens(); - - t = new StringTokenizer(req.getServletPath(), "/"); - prefixTokens += t.countTokens(); - - t = new StringTokenizer(req.getRequestURI(), "/"); - - int uriTokens = t.countTokens(); - StringBuffer pathbuffer = new StringBuffer(); - - for (int i = 0; i < uriTokens; i++) { - String token = t.nextToken(); - - if (i < prefixTokens) { - continue; - } - - if (i > prefixTokens) { - pathbuffer.append("/"); - } - - if ((token.indexOf("+") == -1) && (token.indexOf("%") == -1)) { - pathbuffer.append(token); - } else { - pathbuffer.append(URLDecoder.decode(token)); - } - } - - return pathbuffer.toString(); - } - - /** - * - * - * @return ... - */ - public String getServletInfo() { - return new String("Helma Servlet Client"); - } -} diff --git a/src/helma/servlet/EmbeddedServletClient.java b/src/helma/servlet/EmbeddedServletClient.java deleted file mode 100644 index 7d9f16d4..00000000 --- a/src/helma/servlet/EmbeddedServletClient.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.servlet; - -import helma.framework.*; -import helma.framework.core.Application; -import helma.main.*; -import helma.util.*; -import java.io.*; -import java.util.*; -import javax.servlet.*; - -/** - * Servlet client that runs a Helma application for the embedded - * web server - */ -public final class EmbeddedServletClient extends AbstractServletClient { - private Application app = null; - private String appName; - - /** - * Creates a new EmbeddedServletClient object. - */ - public EmbeddedServletClient() { - super(); - } - - /** - * - * - * @param init ... - * - * @throws ServletException ... - */ - public void init(ServletConfig init) throws ServletException { - super.init(init); - appName = init.getInitParameter("application"); - - if (appName == null) { - throw new ServletException("Application name not set in init parameters"); - } - } - - ResponseTrans execute(RequestTrans req) throws Exception { - if (app == null) { - app = Server.getServer().getApplication(appName); - } - - return app.execute(req); - } -} diff --git a/src/helma/servlet/MultiServletClient.java b/src/helma/servlet/MultiServletClient.java deleted file mode 100644 index 29a98f0a..00000000 --- a/src/helma/servlet/MultiServletClient.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.servlet; - -import helma.framework.*; -import java.io.*; -import java.rmi.Naming; -import java.rmi.RemoteException; -import java.util.Hashtable; -import javax.servlet.*; -import javax.servlet.http.*; - -/** - * This is the HOP servlet adapter. This class communicates with any - * Hop application on a given Hop server, extracting the application name - * from the request path. - */ -public class MultiServletClient extends AbstractServletClient { - private Hashtable apps; - - /** - * - * - * @param init ... - * - * @throws ServletException ... - */ - public void init(ServletConfig init) throws ServletException { - super.init(init); - apps = new Hashtable(); - host = init.getInitParameter("host"); - - if (host == null) { - host = "localhost"; - } - - String portstr = init.getInitParameter("port"); - - port = (portstr == null) ? 5055 : Integer.parseInt(portstr); - hopUrl = "//" + host + ":" + port + "/"; - } - - /** - * - */ - public void destroy() { - if (apps != null) { - apps.clear(); - apps = null; - } - } - - ResponseTrans execute(RequestTrans req) throws Exception { - // the app-id is the first element in the request path - // so we have to first get than and than rewrite req.path. - int slash = req.path.indexOf("/"); - String appId = null; - - if (slash == -1) { - // no slash found, path equals app-id - appId = req.path; - req.path = ""; - } else { - // cut path into app id and rewritten path - appId = req.path.substring(0, slash); - req.path = req.path.substring(slash + 1); - } - - IRemoteApp app = getApp(appId); - - try { - return app.execute(req); - } catch (Exception x) { - invalidateApp(appId); - app = getApp(appId); - - return app.execute(req); - } - } - - IRemoteApp getApp(String appId) throws Exception { - IRemoteApp app = (IRemoteApp) apps.get(appId); - - if (app != null) { - return app; - } - - app = (IRemoteApp) Naming.lookup(hopUrl + appId); - apps.put(appId, app); - - return app; - } - - void invalidateApp(String appId) { - apps.remove(appId); - } -} diff --git a/src/helma/servlet/ServletClient.java b/src/helma/servlet/ServletClient.java deleted file mode 100644 index 45bab3fd..00000000 --- a/src/helma/servlet/ServletClient.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.servlet; - -import helma.framework.*; -import java.io.*; -import java.rmi.Naming; -import java.rmi.RemoteException; -import java.util.*; -import javax.servlet.*; - -/** - * This is the standard Helma servlet adapter. This class represents a servlet - * that is dedicated to one Helma application over RMI. - */ -public class ServletClient extends AbstractServletClient { - private IRemoteApp app = null; - private String appName = null; - - /** - * - * - * @param init ... - * - * @throws ServletException ... - */ - public void init(ServletConfig init) throws ServletException { - super.init(init); - appName = init.getInitParameter("application"); - host = init.getInitParameter("host"); - - if (host == null) { - host = "localhost"; - } - - String portstr = init.getInitParameter("port"); - - port = (portstr == null) ? 5055 : Integer.parseInt(portstr); - hopUrl = "//" + host + ":" + port + "/"; - - if (appName == null) { - throw new ServletException("Application name not specified for helma.servlet.ServletClient"); - } - } - - /** - * - */ - public void destroy() { - if (app != null) { - app = null; - } - } - - ResponseTrans execute(RequestTrans req) throws Exception { - if (app == null) { - initApp(); - } - - try { - return app.execute(req); - } catch (Exception x) { - initApp(); - - return app.execute(req); - } - } - - synchronized void initApp() throws Exception { - app = (IRemoteApp) Naming.lookup(hopUrl + appName); - } -} diff --git a/src/helma/servlet/StandaloneServletClient.java b/src/helma/servlet/StandaloneServletClient.java deleted file mode 100644 index 53b1c869..00000000 --- a/src/helma/servlet/StandaloneServletClient.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.servlet; - -import helma.framework.*; -import helma.framework.core.Application; -import helma.util.*; -import java.io.*; -import java.util.*; -import javax.servlet.*; - -/** - * Standalone servlet client that runs a Helma application all by itself - * in embedded mode without relying on a central instance of helma.main.Server - * to start and manage the application. - * - * StandaloneServletClient takes the following init parameters: - *

    - *
  • application - the application name
  • - *
  • appdir - the path of the application home directory
  • - *
  • dbdir - the path of the embedded XML data store
  • - *
- */ -public final class StandaloneServletClient extends AbstractServletClient { - private Application app = null; - private String appName; - private String appDir; - private String dbDir; - - /** - * - * - * @param init ... - * - * @throws ServletException ... - */ - public void init(ServletConfig init) throws ServletException { - super.init(init); - - appName = init.getInitParameter("application"); - - if ((appName == null) || (appName.trim().length() == 0)) { - throw new ServletException("application parameter not specified"); - } - - appDir = init.getInitParameter("appdir"); - - if ((appDir == null) || (appDir.trim().length() == 0)) { - throw new ServletException("appdir parameter not specified"); - } - - dbDir = init.getInitParameter("dbdir"); - - if ((dbDir == null) || (dbDir.trim().length() == 0)) { - throw new ServletException("dbdir parameter not specified"); - } - } - - ResponseTrans execute(RequestTrans req) throws Exception { - if (app == null) { - createApp(); - } - - return app.execute(req); - } - - /** - * Create the application. Since we are synchronized only here, we - * do another check if the app already exists and immediately return if it does. - */ - synchronized void createApp() { - if (app != null) { - return; - } - - try { - File appHome = new File(appDir); - File dbHome = new File(dbDir); - - app = new Application(appName, appHome, dbHome); - app.init(); - app.start(); - } catch (Exception x) { - log("Error starting Application " + appName + ": " + x); - x.printStackTrace(); - } - } - - /** - * The servlet is being destroyed. Close and release the application if - * it does exist. - */ - public void destroy() { - if (app != null) { - try { - app.stop(); - } catch (Exception x) { - log("Error shutting down app " + app.getName() + ": "); - x.printStackTrace(); - } - } - - app = null; - } -} diff --git a/src/helma/util/Base64.java b/src/helma/util/Base64.java deleted file mode 100644 index 641a9746..00000000 --- a/src/helma/util/Base64.java +++ /dev/null @@ -1,286 +0,0 @@ -//////////////////////license & copyright header///////////////////////// -// // -// Base64 - encode/decode data using the Base64 encoding scheme // -// // -// Copyright (c) 1998 by Kevin Kelley // -// // -// This library is free software; you can redistribute it and/or // -// modify it under the terms of the GNU Lesser General Public // -// License as published by the Free Software Foundation; either // -// version 2.1 of the License, or (at your option) any later version. // -// // -// This library is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU Lesser General Public License for more details. // -// // -// You should have received a copy of the GNU Lesser General Public // -// License along with this library; if not, write to the Free Software // -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // -// 02111-1307, USA, or contact the author: // -// // -// Kevin Kelley - 30718 Rd. 28, La Junta, CO, // -// 81050 USA. // -// // -////////////////////end license & copyright header/////////////////////// - -package helma.util; - -import java.io.*; // needed only for main() method. - - -/** -* Provides encoding of raw bytes to base64-encoded characters, and -* decoding of base64 characters to raw bytes. -* -* @author Kevin Kelley (kelley@ruralnet.net) -* @version 1.3 -* @date 06 August 1998 -* @modified 14 February 2000 -* @modified 22 September 2000 -*/ -public class Base64 { - -/** -* returns an array of base64-encoded characters to represent the -* passed data array. -* -* @param data the array of bytes to encode -* @return base64-coded character array. -*/ -static public char[] encode(byte[] data) -{ - char[] out = new char[((data.length + 2) / 3) * 4]; - - // - // 3 bytes encode to 4 chars. Output is always an even - // multiple of 4 characters. - // - for (int i=0, index=0; i>= 6; - out[index+2] = alphabet[(trip? (val & 0x3F): 64)]; - val >>= 6; - out[index+1] = alphabet[val & 0x3F]; - val >>= 6; - out[index+0] = alphabet[val & 0x3F]; - } - return out; -} - - /** - * Decodes a BASE-64 encoded stream to recover the original - * data. White space before and after will be trimmed away, - * but no other manipulation of the input will be performed. - * - * As of version 1.2 this method will properly handle input - * containing junk characters (newlines and the like) rather - * than throwing an error. It does this by pre-parsing the - * input and generating from that a count of VALID input - * characters. - **/ -static public byte[] decode(char[] data) -{ - // as our input could contain non-BASE64 data (newlines, - // whitespace of any sort, whatever) we must first adjust - // our count of USABLE data so that... - // (a) we don't misallocate the output array, and - // (b) think that we miscalculated our data length - // just because of extraneous throw-away junk - - int tempLen = data.length; - for( int ix=0; ix 255) || codes[ data[ix] ] < 0 ) - --tempLen; // ignore non-valid chars and padding - } - // calculate required length: - // -- 3 bytes for every 4 valid base64 chars - // -- plus 2 bytes if there are 3 extra base64 chars, - // or plus 1 byte if there are 2 extra. - - int len = (tempLen / 4) * 3; - if ((tempLen % 4) == 3) len += 2; - if ((tempLen % 4) == 2) len += 1; - - byte[] out = new byte[len]; - - - - int shift = 0; // # of excess bits stored in accum - int accum = 0; // excess bits - int index = 0; - - // we now go through the entire array (NOT using the 'tempLen' value) - for (int ix=0; ix255)? -1: codes[ data[ix] ]; - - if ( value >= 0 ) // skip over non-code - { - accum <<= 6; // bits shift up by 6 each time thru - shift += 6; // loop, with new bits being put in - accum |= value; // at the bottom. - if ( shift >= 8 ) // whenever there are 8 or more shifted in, - { - shift -= 8; // write them out (from the top, leaving any - out[index++] = // excess at the bottom for next iteration. - (byte) ((accum >> shift) & 0xff); - } - } - // we will also have skipped processing a padding null byte ('=') here; - // these are used ONLY for padding to an even length and do not legally - // occur as encoded data. for this reason we can ignore the fact that - // no index++ operation occurs in that special case: the out[] array is - // initialized to all-zero bytes to start with and that works to our - // advantage in this combination. - } - - // if there is STILL something wrong we just have to throw up now! - if( index != out.length) - { - throw new Error("Miscalculated data length (wrote " + index + " instead of " + out.length + ")"); - } - - return out; -} - - -// -// code characters for values 0..63 -// -static private char[] alphabet = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" - .toCharArray(); - -// -// lookup table for converting base64 characters to value in range 0..63 -// -static private byte[] codes = new byte[256]; -static { - for (int i=0; i<256; i++) codes[i] = -1; - for (int i = 'A'; i <= 'Z'; i++) codes[i] = (byte)( i - 'A'); - for (int i = 'a'; i <= 'z'; i++) codes[i] = (byte)(26 + i - 'a'); - for (int i = '0'; i <= '9'; i++) codes[i] = (byte)(52 + i - '0'); - codes['+'] = 62; - codes['/'] = 63; -} - - - - -/////////////////////////////////////////////////// -// remainder (main method and helper functions) is -// for testing purposes only, feel free to clip it. -/////////////////////////////////////////////////// - -public static void main(String[] args) -{ - boolean decode = false; - - if (args.length == 0) { - System.out.println("usage: java Base64 [-d[ecode]] filename"); - System.exit(0); - } - for (int i=0; i 0) baos.write(buf, 0, count); - } - is.close(); - } - catch (Exception e) { e.printStackTrace(); } - - return baos.toByteArray(); -} - -private static char[] readChars(File file) -{ - CharArrayWriter caw = new CharArrayWriter(); - try - { - Reader fr = new FileReader(file); - Reader in = new BufferedReader(fr); - int count = 0; - char[] buf = new char[16384]; - while ((count=in.read(buf)) != -1) { - if (count > 0) caw.write(buf, 0, count); - } - in.close(); - } - catch (Exception e) { e.printStackTrace(); } - - return caw.toCharArray(); -} - -private static void writeBytes(File file, byte[] data) { - try { - OutputStream fos = new FileOutputStream(file); - OutputStream os = new BufferedOutputStream(fos); - os.write(data); - os.close(); - } - catch (Exception e) { e.printStackTrace(); } -} - -private static void writeChars(File file, char[] data) { - try { - Writer fos = new FileWriter(file); - Writer os = new BufferedWriter(fos); - os.write(data); - os.close(); - } - catch (Exception e) { e.printStackTrace(); } -} -/////////////////////////////////////////////////// -// end of test code. -/////////////////////////////////////////////////// - -} diff --git a/src/helma/util/CacheMap.java b/src/helma/util/CacheMap.java deleted file mode 100644 index 7816f9fe..00000000 --- a/src/helma/util/CacheMap.java +++ /dev/null @@ -1,284 +0,0 @@ -// LruHashtable - a Hashtable that expires least-recently-used objects -// -// 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. -// 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/ - -// Moved to helma.util to use java.util.HashMap instead of java.util.Hashtable -package helma.util; - -import java.util.HashMap; - -/// A Hashtable that expires least-recently-used objects. -//

-// Use just like java.util.Hashtable, except that the initial-capacity -// parameter is required. Instead of growing bigger than that size, -// it will throw out objects that haven't been looked at in a while. -//

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

-// @see java.util.Hashtable - -public class CacheMap { - - // Load factor. - private float loadFactor; - - // When count exceeds this threshold, expires the old table. - private int threshold; - - // Capacity of each bucket. - private int eachCapacity; - - // The tables. - private HashMap oldTable; - private HashMap newTable; - - // the logger to output messages to - private Logger logger = null; - - /// Constructs a new, empty hashtable with the specified initial - // capacity and the specified load factor. - // Unlike a plain Hashtable, an LruHashtable will never grow or - // shrink from this initial capacity. - // @param initialCapacity the initial number of buckets - // @param loadFactor a number between 0.0 and 1.0, it defines - // the threshold for expiring old entries - // @exception IllegalArgumentException If the initial capacity - // is less than or equal to zero. - // @exception IllegalArgumentException If the load factor is - // less than or equal to zero. - public CacheMap (int initialCapacity, float loadFactor) { - // We have to call a superclass constructor, but we're not actually - // going to use it at all. The only reason we want to extend Hashtable - // is for type conformance. So, make a parent hash table of minimum - // size and then ignore it. - if ( initialCapacity <= 0 || loadFactor <= 0.0 ) - throw new IllegalArgumentException(); - this.loadFactor = loadFactor; - // table rotation threshold: we allow each table to gain - // initialCapacity/2 entries. - threshold = initialCapacity / 2; - // We deliberately choose the initial capacity of tables large - // enough that it can hold threshold entries without being rehashed, - // in other words, make sure our threshold for table rotation is lower - // than that of the underlying HashMap for table rehashing. - eachCapacity = (int) (threshold / loadFactor) + 2; - // create tables - oldTable = new HashMap (); - newTable = new HashMap (eachCapacity, loadFactor); - } - - /// Constructs a new, empty hashtable with the specified initial - // capacity. - // Unlike a plain Hashtable, an LruHashtable will never grow or - // shrink from this initial capacity. - // @param initialCapacity the initial number of buckets - public CacheMap (int initialCapacity) { - this (initialCapacity, 0.75F); - } - - /// Returns the number of elements contained in the hashtable. - public int size() { - return newTable.size() + oldTable.size(); - } - - /// Returns true if the hashtable contains no elements. - public boolean isEmpty() { - return size() == 0; - } - - - /// Set the capacity of the CacheMap - public void setCapacity(int capacity) { - // table rotation threshold: we allow each table to gain - // initialCapacity/2 entries. - int newThreshold = capacity / 2; - if (newThreshold != threshold) { - if (logger != null) - logger.log ("Setting cache capacity to "+capacity); - updateThreshold (newThreshold); - } - } - - private synchronized void updateThreshold (int newThreshold) { - threshold = newThreshold; - eachCapacity = (int) (threshold / loadFactor) + 2; - // if newtable is larger than threshold, rotate. - if (newTable.size() > threshold) { - oldTable = newTable; - newTable = new HashMap (eachCapacity, loadFactor); - } - } - - /// Returns true if the specified object is an element of the hashtable. - // This operation is more expensive than the containsKey() method. - // @param value the value that we are looking for - // @exception NullPointerException If the value being searched - // for is equal to null. - // @see LruHashtable#containsKey - public synchronized boolean containsValue (Object value) { - if (newTable.containsValue (value)) - return true; - if (oldTable.containsValue (value)) { - // We would like to move the object from the old table to the - // new table. However, we need keys to re-add the objects, and - // there's no good way to find all the keys for the given object. - // We'd have to enumerate through all the keys and check each - // one. Yuck. For now we just punt. Anyway, contains() is - // probably not a commonly-used operation. - return true; - } - return false; - } - - /// Returns true if the collection contains an element for the key. - // @param key the key that we are looking for - // @see LruHashtable#contains - public synchronized boolean containsKey (Object key) { - if (newTable.containsKey(key)) - return true; - if (oldTable.containsKey (key)) { - // Move object from old table to new table. - Object value = oldTable.get (key); - newTable.put (key, value); - oldTable.remove (key); - return true; - } - return false; - } - - /// Returns the number of keys in object array keys that - // were not found in the Map. - // Those keys that are contained in the Map are nulled out in the array. - // @param keys an array of key objects we are looking for - // @see LruHashtable#contains - public synchronized int containsKeys (Object[] keys) { - int notfound = 0; - for (int i=0; i= threshold) { - // Rotate the tables. - if (logger != null) - logger.log ("Rotating Cache tables at "+newTable.size()+ - "/"+oldTable.size()+" (new/old)"); - oldTable = newTable; - newTable = new HashMap (eachCapacity, loadFactor); - } - return oldValue; - } - - /// 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) { - Object oldValue = newTable.remove (key); - if (oldValue == null) - oldValue = oldTable.remove (key); - return oldValue; - } - - /// Clears the hash table so that it has no more elements in it. - public synchronized void clear() { - newTable.clear (); - oldTable.clear (); - } - - /// Set the logger to use for debug and profiling output - public void setLogger (Logger log) { - this.logger = log; - } - - public synchronized Object[] getEntryArray () { - Object[] k1 = newTable.keySet().toArray(); - Object[] k2 = oldTable.keySet().toArray(); - Object[] k = new Object[k1.length+k2.length]; - System.arraycopy (k1, 0, k, 0, k1.length); - System.arraycopy (k2, 0, k, k1.length, k2.length); - return k; - } - - public String toString () { - return newTable.toString () + oldTable.toString () + hashCode (); - } - -} - - diff --git a/src/helma/util/CronJob.java b/src/helma/util/CronJob.java deleted file mode 100644 index 87b83f98..00000000 --- a/src/helma/util/CronJob.java +++ /dev/null @@ -1,735 +0,0 @@ -package helma.util; - -/** - * Modifications by Stefan Pollach, 2002-08, 2003-03 - * First, to compile without protomatter-library (we're only interested in the - * parsing functions for helma), second to encapsulate a function call and not - * a PASEvent - */ - -/** - * The Protomatter Software License, Version 1.0 - * derived from The Apache Software License, Version 1.1 - * - * Copyright (c) 1998-2002 Nate Sammons. 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. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed for the - * Protomatter Software Project - * (http://protomatter.sourceforge.net/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Protomatter" and "Protomatter Software Project" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact support@protomatter.com. - * - * 5. Products derived from this software may not be called "Protomatter", - * nor may "Protomatter" appear in their name, without prior written - * permission of the Protomatter Software Project - * (support@protomatter.com). - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 PROTOMATTER SOFTWARE PROJECT OR - * ITS 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. - */ - -import java.util.*; - - -/** - * A cron entry, derived from Protomatter's CronEntry class. - * This class encapsulates a function call, a timeout value - * and a specification for when the given event should be - * delivered to the given topics. The specification of when - * the event should be delivered is based on the UNIX cron - * facility. - */ - - -public class CronJob { - - private static HashSet all = new HashSet (2); - private static String ALL_VALUE = "*"; - static { - all.add (ALL_VALUE); - } - - private HashSet year; - private HashSet month; - private HashSet day; - private HashSet weekday; - private HashSet hour; - private HashSet minute; - - private String name = null; - private String function = null; - private long timeout = 600000; - - /** A method for parsing properties. It looks through the properties - * file for entries that look like this: - * - *

-     *  cron.name1.function = functionname
-     *
-     *  cron.name1.year     = year-list
-     *  cron.name1.month    = month-list
-     *  cron.name1.day      = day-list
-     *  cron.name1.weekday  = weekday-list
-     *  cron.name1.hour     = hour-list
-     *  cron.name1.minute   = minute-list
-     *
-     *  cron.name1.timeout  = timeout-value
-     *  
-     *  

- * - * And delivers corresponding CronJob objects in a collection. - * The specified lists from above are:

- * - *

    - *
    year-list
    - **
    - ** This is a comma (,) separated list of individual - * years or of year ranges. Examples: "1999,2000" or - * "1999-2004,2005-2143,2650" - *

    - * - *

    month-list
    - *
    - * This is a comma (,) separated list of month - * names. Example: "january,march,may" - *

    - * - *

    day-list
    - *
    - * This is a comma (,) separated list of individual - * day-of-month numbers or of day-of-month ranges. - * Examples: "1,15" or "1-5,7,10-24" - *

    - * - *

    weekday-list
    - *
    - * This is a comma (,) separated list of weekday names - * names. Example: "monday,tuesday" - *

    - * - *

    hour-list
    - *
    - * This is a comma (,) separated list of individual - * hours-of-day (24-hour time) or of hour-of-day ranges. - * Examples: "12,15" or "8-17,19,20-22" - *

    - * - *

    minute-list
    - *
    - * This is a comma (,) separated list of individual - * minutes (during an hour) or of minute ranges. - * Examples: "0,15,30,45" or "0-5,8-14,23,28-32" - *

    - * - *

- * - * The value of each of those lists can also be an asterisk (*), - * which tells the cron system to disregard the given list when - * determining if a cron entry applies to a specific time -- for instance - * setting the year-list to * would cause the system to - * not take the current year into consideration. If a given list is - * not specified at all, it's the same as specifying it and giving it - * a value of *.

- */ - - - public static CronJob newJob (String functionName, String year, String month, - String day, String weekday, String hour, String minute) { - CronJob job = new CronJob (functionName); - job.setFunction (functionName); - if (year != null) - job.parseYear (year); - if (month != null) - job.parseMonth (month); - if (day != null) - job.parseDay (day); - if (weekday != null) - job.parseWeekDay (weekday); - if (hour != null) - job.parseHour (hour); - if (minute != null) - job.parseMinute (minute); - return job; - } - - - public static List parse(Properties props) { - Hashtable jobs = new Hashtable (); - Enumeration e = props.keys (); - while (e.hasMoreElements ()) { - String key = (String) e.nextElement (); - if (!key.startsWith ("cron.")) - continue; - try { - StringTokenizer st = new StringTokenizer (key.trim(), "."); - st.nextElement (); - String jobName = st.nextToken (); - String jobSpec = st.nextToken (); - if (jobSpec==null || jobSpec.equals("")) // might happen with cron.testname. = XXX - continue; - CronJob job = (CronJob) jobs.get (jobName); - if (job==null) { - job = new CronJob (jobName); - jobs.put (jobName, job); - } - String value = props.getProperty (key); - if (jobSpec.equalsIgnoreCase("function")) { - job.setFunction(value); - } else if (jobSpec.equalsIgnoreCase("year")) { - job.parseYear (value); - } else if (jobSpec.equalsIgnoreCase("month")) { - job.parseMonth (value); - } else if (jobSpec.equalsIgnoreCase("day")) { - job.parseDay (value); - } else if (jobSpec.equalsIgnoreCase("weekday")) { - job.parseWeekDay (value); - } else if (jobSpec.equalsIgnoreCase("hour")) { - job.parseHour (value); - } else if (jobSpec.equalsIgnoreCase("minute")) { - job.parseMinute (value); - } else if (jobSpec.equalsIgnoreCase("timeout")) { - job.parseTimeout (value); - } - } catch (NoSuchElementException nsee) { - } - } - List jobVec = new ArrayList (jobs.values ()); - return sort (jobVec); - } - - public static List sort (List list) { - Collections.sort (list, new Comparator() { - public int compare (Object o1, Object o2) { - CronJob cron1 = (CronJob) o1; - CronJob cron2 = (CronJob) o2; - if (cron1.getTimeout () > cron2.getTimeout ()) - return 1; - else if (cron1.getTimeout () < cron2.getTimeout ()) - return -1; - else - return 0; - } - public boolean equals (Object o1, Object o2) { - if (o1!=null) { - return o1.equals (o2); - } else { - return false; - } - } - - }); - return list; - } - - - public void parseYear (String value) { - if (value.equals("*")) { - setAllYears(true); - } else { - StringTokenizer st = new StringTokenizer(value.trim(), ","); - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (s.indexOf("-") != -1) { - int start = Integer.parseInt(s.substring(0, s.indexOf("-"))); - int finish = Integer.parseInt(s.substring(s.indexOf("-") +1)); - for (int i=start; i<=finish; i++) { - addYear(i); - } - } else { - int y = Integer.parseInt(s); - addYear(y); - } - } - } - } - - public void parseMonth (String value) { - if (value.equals("*")) { - setAllMonths(true); - } else { - StringTokenizer st = new StringTokenizer(value.trim(), ","); - while (st.hasMoreTokens()) { - String m = st.nextToken(); - if (m.equalsIgnoreCase("january")) - addMonth(Calendar.JANUARY); - if (m.equalsIgnoreCase("february")) - addMonth(Calendar.FEBRUARY); - if (m.equalsIgnoreCase("march")) - addMonth(Calendar.MARCH); - if (m.equalsIgnoreCase("april")) - addMonth(Calendar.APRIL); - if (m.equalsIgnoreCase("may")) - addMonth(Calendar.MAY); - if (m.equalsIgnoreCase("june")) - addMonth(Calendar.JUNE); - if (m.equalsIgnoreCase("july")) - addMonth(Calendar.JULY); - if (m.equalsIgnoreCase("august")) - addMonth(Calendar.AUGUST); - if (m.equalsIgnoreCase("september")) - addMonth(Calendar.SEPTEMBER); - if (m.equalsIgnoreCase("october")) - addMonth(Calendar.OCTOBER); - if (m.equalsIgnoreCase("november")) - addMonth(Calendar.NOVEMBER); - if (m.equalsIgnoreCase("december")) - addMonth(Calendar.DECEMBER); - } - } - } - - public void parseDay (String day) { - if (day.equals("*")) { - setAllDays(true); - } else { - StringTokenizer st = new StringTokenizer(day.trim(), ","); - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (s.indexOf("-") != -1) { - int start = Integer.parseInt(s.substring(0, s.indexOf("-"))); - int finish = Integer.parseInt(s.substring(s.indexOf("-") +1)); - for (int i=start; i<=finish; i++) { - addDay(i); - } - } else { - int d = Integer.parseInt(s); - addDay(d); - } - } - } - } - - - public void parseWeekDay (String weekday) { - if (weekday.equals("*")) { - setAllWeekdays(true); - } else { - StringTokenizer st = new StringTokenizer(weekday.trim(), ","); - while (st.hasMoreTokens()) { - String d = st.nextToken(); - if (d.equalsIgnoreCase("monday")) - addWeekday(Calendar.MONDAY); - if (d.equalsIgnoreCase("tuesday")) - addWeekday(Calendar.TUESDAY); - if (d.equalsIgnoreCase("wednesday")) - addWeekday(Calendar.WEDNESDAY); - if (d.equalsIgnoreCase("thursday")) - addWeekday(Calendar.THURSDAY); - if (d.equalsIgnoreCase("friday")) - addWeekday(Calendar.FRIDAY); - if (d.equalsIgnoreCase("saturday")) - addWeekday(Calendar.SATURDAY); - if (d.equalsIgnoreCase("sunday")) - addWeekday(Calendar.SUNDAY); - } - } - } - - - public void parseHour (String hour) { - if (hour.equals("*")) { - setAllHours(true); - } else { - StringTokenizer st = new StringTokenizer(hour.trim (), ","); - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (s.indexOf("-") != -1) { - int start = Integer.parseInt(s.substring(0, s.indexOf("-"))); - int finish = Integer.parseInt(s.substring(s.indexOf("-") +1)); - for (int i=start; i<=finish; i++) { - addHour(i); - } - } else { - int h = Integer.parseInt(s); - addHour(h); - } - } - } - } - - - public void parseMinute (String minute) { - if (minute.equals("*")) { - setAllMinutes(true); - } else { - StringTokenizer st = new StringTokenizer(minute.trim (), ","); - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (s.indexOf("-") != -1) { - int start = Integer.parseInt(s.substring(0, s.indexOf("-"))); - int finish = Integer.parseInt(s.substring(s.indexOf("-") +1)); - for (int i=start; i<=finish; i++) { - addMinute(i); - } - } else { - int m = Integer.parseInt(s); - addMinute(m); - } - } - } - } - - public void parseTimeout (String timeout) { - long timeoutValue = 1000 * Long.valueOf(timeout).longValue (); - setTimeout (timeoutValue); - } - - public static long nextFullMinute () { - long now = System.currentTimeMillis(); - long millisAfterMinute = (now % 60000); - return (now + 60000 - millisAfterMinute); - } - - public static long millisToNextFullMinute () { - long now = System.currentTimeMillis(); - long millisAfterMinute = (now % 60000); - return (60000 - millisAfterMinute); - } - - /** - * Create an empty CronJob. - */ - public CronJob (String name) { - this.name = name; - year = new HashSet (all); - month = new HashSet (all); - day = new HashSet (all); - weekday = new HashSet (all); - hour = new HashSet (all); - minute = new HashSet (all); - } - - /** - * Determines if this CronJob applies to the given date. - * Seconds and milliseconds in the date are ignored. - */ - public boolean appliesToDate(Date date) - { - GregorianCalendar cal = new GregorianCalendar(); - cal.setTime(date); - - // try and short-circuit as fast as possible. - Integer theYear = new Integer(cal.get(Calendar.YEAR)); - if (!year.contains(ALL_VALUE) && !year.contains(theYear)) - return false; - - Integer theMonth = new Integer(cal.get(Calendar.MONTH)); - if (!month.contains(ALL_VALUE) && !month.contains(theMonth)) - return false; - - Integer theDay = new Integer(cal.get(Calendar.DAY_OF_MONTH)); - if (!day.contains(ALL_VALUE) && !day.contains(theDay)) - return false; - - Integer theWeekDay = new Integer(cal.get(Calendar.DAY_OF_WEEK)); - if (!weekday.contains(ALL_VALUE) && !weekday.contains(theWeekDay)) - return false; - - Integer theHour = new Integer(cal.get(Calendar.HOUR_OF_DAY)); - if (!hour.contains(ALL_VALUE) && !hour.contains(theHour)) - return false; - - Integer theMinute = new Integer(cal.get(Calendar.MINUTE)); - if (!minute.contains(ALL_VALUE) && !minute.contains(theMinute)) - return false; - - return true; - } - - - /** - * Add a year to the list of years this entry applies to. - */ - public void addYear(int year) - { - this.year.remove(ALL_VALUE); - this.year.add(new Integer(year)); - } - - /** - * Remove a year from the list of years this entry applies to. - */ - public void removeYear(int year) - { - this.year.remove(new Integer(year)); - } - - /** - * Should the current year be taken into consideration when - * deciding if this entry is applicable? - * If this is set to false (the default) then the values set with - * the addYear() and removeYear() are taken - * into consideration. If this is set to true then the current - * year is not taken into consideration. - */ - public void setAllYears(boolean set) - { - if (set) - this.year.add(ALL_VALUE); - else - this.year.remove(ALL_VALUE); - } - - - /** - * Add a month to the list of years this entry applies to. - * Month numbers are taken from the constants on the - * java.util.Calendar class. - */ - public void addMonth(int month) - { - this.month.remove(ALL_VALUE); - this.month.add(new Integer(month)); - } - - /** - * Remove a month from the list of years this entry applies to. - * Month numbers are taken from the constants on the - * java.util.Calendar class. - */ - public void removeMonth(int month) - { - this.month.remove(new Integer(month)); - } - - /** - * Should the current month be taken into consideration when - * deciding if this entry is applicable? - * If this is set to false (the default) then the values set with - * the addMonth() and removeMonth() are taken - * into consideration. If this is set to true then the current - * month is not taken into consideration. - */ - public void setAllMonths(boolean set) - { - if (set) - this.month.add(ALL_VALUE); - else - this.month.remove(ALL_VALUE); - } - - - /** - * Add a day of the month to the list of years this entry applies to. - */ - public void addDay(int day) - { - this.day.remove(ALL_VALUE); - this.day.add(new Integer(day)); - } - - /** - * Remove a day of the month from the list of years this entry applies to. - */ - public void removeDay(int day) - { - this.day.remove(new Integer(day)); - } - - /** - * Should the current day of the month be taken into consideration when - * deciding if this entry is applicable? - * If this is set to false (the default) then the values set with - * the addDay() and removeDay() are taken - * into consideration. If this is set to true then the current - * year is not taken into consideration. - */ - public void setAllDays(boolean set) - { - if (set) - this.day.add(ALL_VALUE); - else - this.day.remove(ALL_VALUE); - } - - - /** - * Add a weekday to the list of years this entry applies to. - * Weekday numbers are taken from the constants on the - * java.util.Calendar class. - */ - public void addWeekday(int weekday) - { - this.weekday.remove(ALL_VALUE); - this.weekday.add(new Integer(weekday)); - } - - /** - * Remove a weekday from the list of years this entry applies to. - * Weekday numbers are taken from the constants on the - * java.util.Calendar class. - */ - public void removeWeekday(int weekday) - { - this.weekday.remove(new Integer(weekday)); - } - - /** - * Should the current weekday be taken into consideration when - * deciding if this entry is applicable? - * If this is set to false (the default) then the values set with - * the addWeekday() and removeWeekday() are taken - * into consideration. If this is set to true then the current - * weekday is not taken into consideration. - */ - public void setAllWeekdays(boolean set) - { - if (set) - this.weekday.add(ALL_VALUE); - else - this.weekday.remove(ALL_VALUE); - } - - - /** - * Add an hour to the list of years this entry applies to. - */ - public void addHour(int hour) - { - this.hour.remove(ALL_VALUE); - this.hour.add(new Integer(hour)); - } - - /** - * Remove an hour from the list of years this entry applies to. - */ - public void removeHour(int hour) - { - this.hour.remove(new Integer(hour)); - } - - /** - * Should the current hour be taken into consideration when - * deciding if this entry is applicable? - * If this is set to false (the default) then the values set with - * the addHour() and removeHour() are taken - * into consideration. If this is set to true then the current - * hour is not taken into consideration. - */ - public void setAllHours(boolean set) - { - if (set) - this.hour.add(ALL_VALUE); - else - this.hour.remove(ALL_VALUE); - } - - - /** - * Add a minute to the list of years this entry applies to. - */ - public void addMinute(int minute) - { - this.minute.remove(ALL_VALUE); - this.minute.add(new Integer(minute)); - } - - /** - * Remove a minute from the list of years this entry applies to. - */ - public void removeMinute(int minute) - { - this.minute.remove(new Integer(minute)); - } - - /** - * Should the current minute be taken into consideration when - * deciding if this entry is applicable? - * If this is set to false (the default) then the values set with - * the addMinute() and removeMinute() are taken - * into consideration. If this is set to true then the current - * minute is not taken into consideration. - */ - public void setAllMinutes(boolean set) - { - if (set) - this.minute.add(ALL_VALUE); - else - this.minute.remove(ALL_VALUE); - } - - /** - * Set this entry's name - */ - public void setName(String name) - { - this.name = name; - } - - /** - * Get this entry's name - */ - public String getName() - { - return this.name; - } - - /** - * Set this entry's function - */ - public void setFunction(String function) - { - this.function = function; - } - - /** - * Get this entry's function - */ - public String getFunction() - { - return this.function; - } - - - /** - * Set this entry's timeout - */ - public void setTimeout(long timeout) - { - this.timeout = timeout; - } - - - /** - * Get this entry's timeout - */ - public long getTimeout() - { - return this.timeout; - } - - public String toString () - { - return "[CronJob " + name + "]"; - } - -} diff --git a/src/helma/util/Crypt.java b/src/helma/util/Crypt.java deleted file mode 100644 index f2f7952a..00000000 --- a/src/helma/util/Crypt.java +++ /dev/null @@ -1,629 +0,0 @@ -/**************************************************************************** - * jcrypt.java - * - * Java-based implementation of the unix crypt command - * - * Based upon C source code written by Eric Young, eay@psych.uq.oz.au - * - ****************************************************************************/ - -package helma.util; - - -public class Crypt { - - private static final int ITERATIONS = 16; - - private static final int con_salt[] = - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, - 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, - 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, - 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, - 0x23, 0x24, 0x25, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, - 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, - 0x3D, 0x3E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - private static final boolean shifts2[] = - { - false, false, true, true, true, true, true, true, - false, true, true, true, true, true, true, false - }; - - private static final int skb[][] = - { - { - /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ - 0x00000000, 0x00000010, 0x20000000, 0x20000010, - 0x00010000, 0x00010010, 0x20010000, 0x20010010, - 0x00000800, 0x00000810, 0x20000800, 0x20000810, - 0x00010800, 0x00010810, 0x20010800, 0x20010810, - 0x00000020, 0x00000030, 0x20000020, 0x20000030, - 0x00010020, 0x00010030, 0x20010020, 0x20010030, - 0x00000820, 0x00000830, 0x20000820, 0x20000830, - 0x00010820, 0x00010830, 0x20010820, 0x20010830, - 0x00080000, 0x00080010, 0x20080000, 0x20080010, - 0x00090000, 0x00090010, 0x20090000, 0x20090010, - 0x00080800, 0x00080810, 0x20080800, 0x20080810, - 0x00090800, 0x00090810, 0x20090800, 0x20090810, - 0x00080020, 0x00080030, 0x20080020, 0x20080030, - 0x00090020, 0x00090030, 0x20090020, 0x20090030, - 0x00080820, 0x00080830, 0x20080820, 0x20080830, - 0x00090820, 0x00090830, 0x20090820, 0x20090830, - }, - { - /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ - 0x00000000, 0x02000000, 0x00002000, 0x02002000, - 0x00200000, 0x02200000, 0x00202000, 0x02202000, - 0x00000004, 0x02000004, 0x00002004, 0x02002004, - 0x00200004, 0x02200004, 0x00202004, 0x02202004, - 0x00000400, 0x02000400, 0x00002400, 0x02002400, - 0x00200400, 0x02200400, 0x00202400, 0x02202400, - 0x00000404, 0x02000404, 0x00002404, 0x02002404, - 0x00200404, 0x02200404, 0x00202404, 0x02202404, - 0x10000000, 0x12000000, 0x10002000, 0x12002000, - 0x10200000, 0x12200000, 0x10202000, 0x12202000, - 0x10000004, 0x12000004, 0x10002004, 0x12002004, - 0x10200004, 0x12200004, 0x10202004, 0x12202004, - 0x10000400, 0x12000400, 0x10002400, 0x12002400, - 0x10200400, 0x12200400, 0x10202400, 0x12202400, - 0x10000404, 0x12000404, 0x10002404, 0x12002404, - 0x10200404, 0x12200404, 0x10202404, 0x12202404, - }, - { - /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ - 0x00000000, 0x00000001, 0x00040000, 0x00040001, - 0x01000000, 0x01000001, 0x01040000, 0x01040001, - 0x00000002, 0x00000003, 0x00040002, 0x00040003, - 0x01000002, 0x01000003, 0x01040002, 0x01040003, - 0x00000200, 0x00000201, 0x00040200, 0x00040201, - 0x01000200, 0x01000201, 0x01040200, 0x01040201, - 0x00000202, 0x00000203, 0x00040202, 0x00040203, - 0x01000202, 0x01000203, 0x01040202, 0x01040203, - 0x08000000, 0x08000001, 0x08040000, 0x08040001, - 0x09000000, 0x09000001, 0x09040000, 0x09040001, - 0x08000002, 0x08000003, 0x08040002, 0x08040003, - 0x09000002, 0x09000003, 0x09040002, 0x09040003, - 0x08000200, 0x08000201, 0x08040200, 0x08040201, - 0x09000200, 0x09000201, 0x09040200, 0x09040201, - 0x08000202, 0x08000203, 0x08040202, 0x08040203, - 0x09000202, 0x09000203, 0x09040202, 0x09040203, - }, - { - /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ - 0x00000000, 0x00100000, 0x00000100, 0x00100100, - 0x00000008, 0x00100008, 0x00000108, 0x00100108, - 0x00001000, 0x00101000, 0x00001100, 0x00101100, - 0x00001008, 0x00101008, 0x00001108, 0x00101108, - 0x04000000, 0x04100000, 0x04000100, 0x04100100, - 0x04000008, 0x04100008, 0x04000108, 0x04100108, - 0x04001000, 0x04101000, 0x04001100, 0x04101100, - 0x04001008, 0x04101008, 0x04001108, 0x04101108, - 0x00020000, 0x00120000, 0x00020100, 0x00120100, - 0x00020008, 0x00120008, 0x00020108, 0x00120108, - 0x00021000, 0x00121000, 0x00021100, 0x00121100, - 0x00021008, 0x00121008, 0x00021108, 0x00121108, - 0x04020000, 0x04120000, 0x04020100, 0x04120100, - 0x04020008, 0x04120008, 0x04020108, 0x04120108, - 0x04021000, 0x04121000, 0x04021100, 0x04121100, - 0x04021008, 0x04121008, 0x04021108, 0x04121108, - }, - { - /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ - 0x00000000, 0x10000000, 0x00010000, 0x10010000, - 0x00000004, 0x10000004, 0x00010004, 0x10010004, - 0x20000000, 0x30000000, 0x20010000, 0x30010000, - 0x20000004, 0x30000004, 0x20010004, 0x30010004, - 0x00100000, 0x10100000, 0x00110000, 0x10110000, - 0x00100004, 0x10100004, 0x00110004, 0x10110004, - 0x20100000, 0x30100000, 0x20110000, 0x30110000, - 0x20100004, 0x30100004, 0x20110004, 0x30110004, - 0x00001000, 0x10001000, 0x00011000, 0x10011000, - 0x00001004, 0x10001004, 0x00011004, 0x10011004, - 0x20001000, 0x30001000, 0x20011000, 0x30011000, - 0x20001004, 0x30001004, 0x20011004, 0x30011004, - 0x00101000, 0x10101000, 0x00111000, 0x10111000, - 0x00101004, 0x10101004, 0x00111004, 0x10111004, - 0x20101000, 0x30101000, 0x20111000, 0x30111000, - 0x20101004, 0x30101004, 0x20111004, 0x30111004, - }, - { - /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ - 0x00000000, 0x08000000, 0x00000008, 0x08000008, - 0x00000400, 0x08000400, 0x00000408, 0x08000408, - 0x00020000, 0x08020000, 0x00020008, 0x08020008, - 0x00020400, 0x08020400, 0x00020408, 0x08020408, - 0x00000001, 0x08000001, 0x00000009, 0x08000009, - 0x00000401, 0x08000401, 0x00000409, 0x08000409, - 0x00020001, 0x08020001, 0x00020009, 0x08020009, - 0x00020401, 0x08020401, 0x00020409, 0x08020409, - 0x02000000, 0x0A000000, 0x02000008, 0x0A000008, - 0x02000400, 0x0A000400, 0x02000408, 0x0A000408, - 0x02020000, 0x0A020000, 0x02020008, 0x0A020008, - 0x02020400, 0x0A020400, 0x02020408, 0x0A020408, - 0x02000001, 0x0A000001, 0x02000009, 0x0A000009, - 0x02000401, 0x0A000401, 0x02000409, 0x0A000409, - 0x02020001, 0x0A020001, 0x02020009, 0x0A020009, - 0x02020401, 0x0A020401, 0x02020409, 0x0A020409, - }, - { - /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ - 0x00000000, 0x00000100, 0x00080000, 0x00080100, - 0x01000000, 0x01000100, 0x01080000, 0x01080100, - 0x00000010, 0x00000110, 0x00080010, 0x00080110, - 0x01000010, 0x01000110, 0x01080010, 0x01080110, - 0x00200000, 0x00200100, 0x00280000, 0x00280100, - 0x01200000, 0x01200100, 0x01280000, 0x01280100, - 0x00200010, 0x00200110, 0x00280010, 0x00280110, - 0x01200010, 0x01200110, 0x01280010, 0x01280110, - 0x00000200, 0x00000300, 0x00080200, 0x00080300, - 0x01000200, 0x01000300, 0x01080200, 0x01080300, - 0x00000210, 0x00000310, 0x00080210, 0x00080310, - 0x01000210, 0x01000310, 0x01080210, 0x01080310, - 0x00200200, 0x00200300, 0x00280200, 0x00280300, - 0x01200200, 0x01200300, 0x01280200, 0x01280300, - 0x00200210, 0x00200310, 0x00280210, 0x00280310, - 0x01200210, 0x01200310, 0x01280210, 0x01280310, - }, - { - /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ - 0x00000000, 0x04000000, 0x00040000, 0x04040000, - 0x00000002, 0x04000002, 0x00040002, 0x04040002, - 0x00002000, 0x04002000, 0x00042000, 0x04042000, - 0x00002002, 0x04002002, 0x00042002, 0x04042002, - 0x00000020, 0x04000020, 0x00040020, 0x04040020, - 0x00000022, 0x04000022, 0x00040022, 0x04040022, - 0x00002020, 0x04002020, 0x00042020, 0x04042020, - 0x00002022, 0x04002022, 0x00042022, 0x04042022, - 0x00000800, 0x04000800, 0x00040800, 0x04040800, - 0x00000802, 0x04000802, 0x00040802, 0x04040802, - 0x00002800, 0x04002800, 0x00042800, 0x04042800, - 0x00002802, 0x04002802, 0x00042802, 0x04042802, - 0x00000820, 0x04000820, 0x00040820, 0x04040820, - 0x00000822, 0x04000822, 0x00040822, 0x04040822, - 0x00002820, 0x04002820, 0x00042820, 0x04042820, - 0x00002822, 0x04002822, 0x00042822, 0x04042822, - }, - }; - - private static final int SPtrans[][] = - { - { - /* nibble 0 */ - 0x00820200, 0x00020000, 0x80800000, 0x80820200, - 0x00800000, 0x80020200, 0x80020000, 0x80800000, - 0x80020200, 0x00820200, 0x00820000, 0x80000200, - 0x80800200, 0x00800000, 0x00000000, 0x80020000, - 0x00020000, 0x80000000, 0x00800200, 0x00020200, - 0x80820200, 0x00820000, 0x80000200, 0x00800200, - 0x80000000, 0x00000200, 0x00020200, 0x80820000, - 0x00000200, 0x80800200, 0x80820000, 0x00000000, - 0x00000000, 0x80820200, 0x00800200, 0x80020000, - 0x00820200, 0x00020000, 0x80000200, 0x00800200, - 0x80820000, 0x00000200, 0x00020200, 0x80800000, - 0x80020200, 0x80000000, 0x80800000, 0x00820000, - 0x80820200, 0x00020200, 0x00820000, 0x80800200, - 0x00800000, 0x80000200, 0x80020000, 0x00000000, - 0x00020000, 0x00800000, 0x80800200, 0x00820200, - 0x80000000, 0x80820000, 0x00000200, 0x80020200, - }, - { - /* nibble 1 */ - 0x10042004, 0x00000000, 0x00042000, 0x10040000, - 0x10000004, 0x00002004, 0x10002000, 0x00042000, - 0x00002000, 0x10040004, 0x00000004, 0x10002000, - 0x00040004, 0x10042000, 0x10040000, 0x00000004, - 0x00040000, 0x10002004, 0x10040004, 0x00002000, - 0x00042004, 0x10000000, 0x00000000, 0x00040004, - 0x10002004, 0x00042004, 0x10042000, 0x10000004, - 0x10000000, 0x00040000, 0x00002004, 0x10042004, - 0x00040004, 0x10042000, 0x10002000, 0x00042004, - 0x10042004, 0x00040004, 0x10000004, 0x00000000, - 0x10000000, 0x00002004, 0x00040000, 0x10040004, - 0x00002000, 0x10000000, 0x00042004, 0x10002004, - 0x10042000, 0x00002000, 0x00000000, 0x10000004, - 0x00000004, 0x10042004, 0x00042000, 0x10040000, - 0x10040004, 0x00040000, 0x00002004, 0x10002000, - 0x10002004, 0x00000004, 0x10040000, 0x00042000, - }, - { - /* nibble 2 */ - 0x41000000, 0x01010040, 0x00000040, 0x41000040, - 0x40010000, 0x01000000, 0x41000040, 0x00010040, - 0x01000040, 0x00010000, 0x01010000, 0x40000000, - 0x41010040, 0x40000040, 0x40000000, 0x41010000, - 0x00000000, 0x40010000, 0x01010040, 0x00000040, - 0x40000040, 0x41010040, 0x00010000, 0x41000000, - 0x41010000, 0x01000040, 0x40010040, 0x01010000, - 0x00010040, 0x00000000, 0x01000000, 0x40010040, - 0x01010040, 0x00000040, 0x40000000, 0x00010000, - 0x40000040, 0x40010000, 0x01010000, 0x41000040, - 0x00000000, 0x01010040, 0x00010040, 0x41010000, - 0x40010000, 0x01000000, 0x41010040, 0x40000000, - 0x40010040, 0x41000000, 0x01000000, 0x41010040, - 0x00010000, 0x01000040, 0x41000040, 0x00010040, - 0x01000040, 0x00000000, 0x41010000, 0x40000040, - 0x41000000, 0x40010040, 0x00000040, 0x01010000, - }, - { - /* nibble 3 */ - 0x00100402, 0x04000400, 0x00000002, 0x04100402, - 0x00000000, 0x04100000, 0x04000402, 0x00100002, - 0x04100400, 0x04000002, 0x04000000, 0x00000402, - 0x04000002, 0x00100402, 0x00100000, 0x04000000, - 0x04100002, 0x00100400, 0x00000400, 0x00000002, - 0x00100400, 0x04000402, 0x04100000, 0x00000400, - 0x00000402, 0x00000000, 0x00100002, 0x04100400, - 0x04000400, 0x04100002, 0x04100402, 0x00100000, - 0x04100002, 0x00000402, 0x00100000, 0x04000002, - 0x00100400, 0x04000400, 0x00000002, 0x04100000, - 0x04000402, 0x00000000, 0x00000400, 0x00100002, - 0x00000000, 0x04100002, 0x04100400, 0x00000400, - 0x04000000, 0x04100402, 0x00100402, 0x00100000, - 0x04100402, 0x00000002, 0x04000400, 0x00100402, - 0x00100002, 0x00100400, 0x04100000, 0x04000402, - 0x00000402, 0x04000000, 0x04000002, 0x04100400, - }, - { - /* nibble 4 */ - 0x02000000, 0x00004000, 0x00000100, 0x02004108, - 0x02004008, 0x02000100, 0x00004108, 0x02004000, - 0x00004000, 0x00000008, 0x02000008, 0x00004100, - 0x02000108, 0x02004008, 0x02004100, 0x00000000, - 0x00004100, 0x02000000, 0x00004008, 0x00000108, - 0x02000100, 0x00004108, 0x00000000, 0x02000008, - 0x00000008, 0x02000108, 0x02004108, 0x00004008, - 0x02004000, 0x00000100, 0x00000108, 0x02004100, - 0x02004100, 0x02000108, 0x00004008, 0x02004000, - 0x00004000, 0x00000008, 0x02000008, 0x02000100, - 0x02000000, 0x00004100, 0x02004108, 0x00000000, - 0x00004108, 0x02000000, 0x00000100, 0x00004008, - 0x02000108, 0x00000100, 0x00000000, 0x02004108, - 0x02004008, 0x02004100, 0x00000108, 0x00004000, - 0x00004100, 0x02004008, 0x02000100, 0x00000108, - 0x00000008, 0x00004108, 0x02004000, 0x02000008, - }, - { - /* nibble 5 */ - 0x20000010, 0x00080010, 0x00000000, 0x20080800, - 0x00080010, 0x00000800, 0x20000810, 0x00080000, - 0x00000810, 0x20080810, 0x00080800, 0x20000000, - 0x20000800, 0x20000010, 0x20080000, 0x00080810, - 0x00080000, 0x20000810, 0x20080010, 0x00000000, - 0x00000800, 0x00000010, 0x20080800, 0x20080010, - 0x20080810, 0x20080000, 0x20000000, 0x00000810, - 0x00000010, 0x00080800, 0x00080810, 0x20000800, - 0x00000810, 0x20000000, 0x20000800, 0x00080810, - 0x20080800, 0x00080010, 0x00000000, 0x20000800, - 0x20000000, 0x00000800, 0x20080010, 0x00080000, - 0x00080010, 0x20080810, 0x00080800, 0x00000010, - 0x20080810, 0x00080800, 0x00080000, 0x20000810, - 0x20000010, 0x20080000, 0x00080810, 0x00000000, - 0x00000800, 0x20000010, 0x20000810, 0x20080800, - 0x20080000, 0x00000810, 0x00000010, 0x20080010, - }, - { - /* nibble 6 */ - 0x00001000, 0x00000080, 0x00400080, 0x00400001, - 0x00401081, 0x00001001, 0x00001080, 0x00000000, - 0x00400000, 0x00400081, 0x00000081, 0x00401000, - 0x00000001, 0x00401080, 0x00401000, 0x00000081, - 0x00400081, 0x00001000, 0x00001001, 0x00401081, - 0x00000000, 0x00400080, 0x00400001, 0x00001080, - 0x00401001, 0x00001081, 0x00401080, 0x00000001, - 0x00001081, 0x00401001, 0x00000080, 0x00400000, - 0x00001081, 0x00401000, 0x00401001, 0x00000081, - 0x00001000, 0x00000080, 0x00400000, 0x00401001, - 0x00400081, 0x00001081, 0x00001080, 0x00000000, - 0x00000080, 0x00400001, 0x00000001, 0x00400080, - 0x00000000, 0x00400081, 0x00400080, 0x00001080, - 0x00000081, 0x00001000, 0x00401081, 0x00400000, - 0x00401080, 0x00000001, 0x00001001, 0x00401081, - 0x00400001, 0x00401080, 0x00401000, 0x00001001, - }, - { - /* nibble 7 */ - 0x08200020, 0x08208000, 0x00008020, 0x00000000, - 0x08008000, 0x00200020, 0x08200000, 0x08208020, - 0x00000020, 0x08000000, 0x00208000, 0x00008020, - 0x00208020, 0x08008020, 0x08000020, 0x08200000, - 0x00008000, 0x00208020, 0x00200020, 0x08008000, - 0x08208020, 0x08000020, 0x00000000, 0x00208000, - 0x08000000, 0x00200000, 0x08008020, 0x08200020, - 0x00200000, 0x00008000, 0x08208000, 0x00000020, - 0x00200000, 0x00008000, 0x08000020, 0x08208020, - 0x00008020, 0x08000000, 0x00000000, 0x00208000, - 0x08200020, 0x08008020, 0x08008000, 0x00200020, - 0x08208000, 0x00000020, 0x00200020, 0x08008000, - 0x08208020, 0x00200000, 0x08200000, 0x08000020, - 0x00208000, 0x00008020, 0x08008020, 0x08200000, - 0x00000020, 0x08208000, 0x00208020, 0x00000000, - 0x08000000, 0x08200020, 0x00008000, 0x00208020 - } - }; - - private static final int cov_2char[] = - { - 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, - 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, - 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, - 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A - }; - - private static final int byteToUnsigned(byte b) - { - int value = (int)b; - - return(value >= 0 ? value : value + 256); - } - - private static int fourBytesToInt(byte b[], int offset) - { - int value; - - value = byteToUnsigned(b[offset++]); - value |= (byteToUnsigned(b[offset++]) << 8); - value |= (byteToUnsigned(b[offset++]) << 16); - value |= (byteToUnsigned(b[offset++]) << 24); - - return(value); - } - - private static final void intToFourBytes(int iValue, byte b[], int offset) - { - b[offset++] = (byte)((iValue) & 0xff); - b[offset++] = (byte)((iValue >>> 8 ) & 0xff); - b[offset++] = (byte)((iValue >>> 16) & 0xff); - b[offset++] = (byte)((iValue >>> 24) & 0xff); - } - - private static final void PERM_OP(int a, int b, int n, int m, int results[]) - { - int t; - - t = ((a >>> n) ^ b) & m; - a ^= t << n; - b ^= t; - - results[0] = a; - results[1] = b; - } - - private static final int HPERM_OP(int a, int n, int m) - { - int t; - - t = ((a << (16 - n)) ^ a) & m; - a = a ^ t ^ (t >>> (16 - n)); - - return(a); - } - - private static int [] des_set_key(byte key[]) - { - int schedule[] = new int[ITERATIONS * 2]; - - int c = fourBytesToInt(key, 0); - int d = fourBytesToInt(key, 4); - - int results[] = new int[2]; - - PERM_OP(d, c, 4, 0x0f0f0f0f, results); - d = results[0]; c = results[1]; - - c = HPERM_OP(c, -2, 0xcccc0000); - d = HPERM_OP(d, -2, 0xcccc0000); - - PERM_OP(d, c, 1, 0x55555555, results); - d = results[0]; c = results[1]; - - PERM_OP(c, d, 8, 0x00ff00ff, results); - c = results[0]; d = results[1]; - - PERM_OP(d, c, 1, 0x55555555, results); - d = results[0]; c = results[1]; - - d = (((d & 0x000000ff) << 16) | (d & 0x0000ff00) | - ((d & 0x00ff0000) >>> 16) | ((c & 0xf0000000) >>> 4)); - c &= 0x0fffffff; - - int s, t; - int j = 0; - - for(int i = 0; i < ITERATIONS; i ++) - { - if(shifts2[i]) - { - c = (c >>> 2) | (c << 26); - d = (d >>> 2) | (d << 26); - } - else - { - c = (c >>> 1) | (c << 27); - d = (d >>> 1) | (d << 27); - } - - c &= 0x0fffffff; - d &= 0x0fffffff; - - s = skb[0][ (c ) & 0x3f ]| - skb[1][((c >>> 6) & 0x03) | ((c >>> 7) & 0x3c)]| - skb[2][((c >>> 13) & 0x0f) | ((c >>> 14) & 0x30)]| - skb[3][((c >>> 20) & 0x01) | ((c >>> 21) & 0x06) | - ((c >>> 22) & 0x38)]; - - t = skb[4][ (d ) & 0x3f ]| - skb[5][((d >>> 7) & 0x03) | ((d >>> 8) & 0x3c)]| - skb[6][ (d >>>15) & 0x3f ]| - skb[7][((d >>>21) & 0x0f) | ((d >>> 22) & 0x30)]; - - schedule[j++] = ((t << 16) | (s & 0x0000ffff)) & 0xffffffff; - s = ((s >>> 16) | (t & 0xffff0000)); - - s = (s << 4) | (s >>> 28); - schedule[j++] = s & 0xffffffff; - } - return(schedule); - } - - private static final int D_ENCRYPT - ( - int L, int R, int S, int E0, int E1, int s[] - ) - { - int t, u, v; - - v = R ^ (R >>> 16); - u = v & E0; - v = v & E1; - u = (u ^ (u << 16)) ^ R ^ s[S]; - t = (v ^ (v << 16)) ^ R ^ s[S + 1]; - t = (t >>> 4) | (t << 28); - - L ^= SPtrans[1][(t ) & 0x3f] | - SPtrans[3][(t >>> 8) & 0x3f] | - SPtrans[5][(t >>> 16) & 0x3f] | - SPtrans[7][(t >>> 24) & 0x3f] | - SPtrans[0][(u ) & 0x3f] | - SPtrans[2][(u >>> 8) & 0x3f] | - SPtrans[4][(u >>> 16) & 0x3f] | - SPtrans[6][(u >>> 24) & 0x3f]; - - return(L); - } - - private static final int [] body(int schedule[], int Eswap0, int Eswap1) - { - int left = 0; - int right = 0; - int t = 0; - - for(int j = 0; j < 25; j ++) - { - for(int i = 0; i < ITERATIONS * 2; i += 4) - { - left = D_ENCRYPT(left, right, i, Eswap0, Eswap1, schedule); - right = D_ENCRYPT(right, left, i + 2, Eswap0, Eswap1, schedule); - } - t = left; - left = right; - right = t; - } - - t = right; - - right = (left >>> 1) | (left << 31); - left = (t >>> 1) | (t << 31); - - left &= 0xffffffff; - right &= 0xffffffff; - - int results[] = new int[2]; - - PERM_OP(right, left, 1, 0x55555555, results); - right = results[0]; left = results[1]; - - PERM_OP(left, right, 8, 0x00ff00ff, results); - left = results[0]; right = results[1]; - - PERM_OP(right, left, 2, 0x33333333, results); - right = results[0]; left = results[1]; - - PERM_OP(left, right, 16, 0x0000ffff, results); - left = results[0]; right = results[1]; - - PERM_OP(right, left, 4, 0x0f0f0f0f, results); - right = results[0]; left = results[1]; - - int out[] = new int[2]; - - out[0] = left; out[1] = right; - - return(out); - } - - public static final String crypt(String salt, String original) - { - while(salt.length() < 2) - salt += "A"; - - StringBuffer buffer = new StringBuffer(" "); - - char charZero = salt.charAt(0); - char charOne = salt.charAt(1); - - buffer.setCharAt(0, charZero); - buffer.setCharAt(1, charOne); - - int Eswap0 = con_salt[(int)charZero]; - int Eswap1 = con_salt[(int)charOne] << 4; - - byte key[] = new byte[8]; - - for(int i = 0; i < key.length; i ++) - key[i] = (byte)0; - - for(int i = 0; i < key.length && i < original.length(); i ++) - { - int iChar = (int)original.charAt(i); - - key[i] = (byte)(iChar << 1); - } - - int schedule[] = des_set_key(key); - int out[] = body(schedule, Eswap0, Eswap1); - - byte b[] = new byte[9]; - - intToFourBytes(out[0], b, 0); - intToFourBytes(out[1], b, 4); - b[8] = 0; - - for(int i = 2, y = 0, u = 0x80; i < 13; i ++) - { - for(int j = 0, c = 0; j < 6; j ++) - { - c <<= 1; - - if(((int)b[y] & u) != 0) - c |= 1; - - u >>>= 1; - - if(u == 0) - { - y++; - u = 0x80; - } - buffer.setCharAt(i, (char)cov_2char[c]); - } - } - return(buffer.toString()); - } - - public static void main(String args[]) - { - if(args.length >= 2) - { - System.out.println - ( - "[" + args[0] + "] [" + args[1] + "] => [" + - Crypt.crypt(args[0], args[1]) + "]" - ); - } - } -} diff --git a/src/helma/util/CryptFile.java b/src/helma/util/CryptFile.java deleted file mode 100644 index bc44c679..00000000 --- a/src/helma/util/CryptFile.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.*; -import java.util.*; - -/** - * This file authenticates against a passwd file - */ -public class CryptFile { - private Properties users; - private CryptFile parentFile; - private File file; - private long lastRead = 0; - - /** - * Creates a new CryptFile object. - * - * @param file ... - * @param parentFile ... - */ - public CryptFile(File file, CryptFile parentFile) { - this.file = file; - this.parentFile = parentFile; - users = new Properties(); - } - - /** - * - * - * @param username ... - * @param pw ... - * - * @return ... - */ - public boolean authenticate(String username, String pw) { - if (file.exists() && (file.lastModified() > lastRead)) { - readFile(); - } else if (!file.exists() && (users.size() > 0)) { - users.clear(); - } - - String realpw = users.getProperty(username); - - if (realpw != null) { - try { - // check if password matches - // first we try with unix crypt algorithm - String cryptpw = Crypt.crypt(realpw, pw); - - if (realpw.equals(cryptpw)) { - return true; - } - - // then try MD5 - if (realpw.equals(MD5Encoder.encode(pw))) { - return true; - } - } catch (Exception x) { - return false; - } - } else { - if (parentFile != null) { - return parentFile.authenticate(username, pw); - } - } - - return false; - } - - private synchronized void readFile() { - BufferedReader reader = null; - - users = new Properties(); - - try { - reader = new BufferedReader(new FileReader(file)); - - String line = reader.readLine(); - - while (line != null) { - StringTokenizer st = new StringTokenizer(line, ":"); - - if (st.countTokens() > 1) { - users.put(st.nextToken(), st.nextToken()); - } - - line = reader.readLine(); - } - } catch (Exception ignore) { - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception x) { - } - } - - lastRead = System.currentTimeMillis(); - } - } - - /** - * - * - * @param args ... - */ - public static void main(String[] args) { - CryptFile cf = new CryptFile(new File("passwd"), null); - - System.err.println(cf.authenticate("hns", "asdf")); - } -} diff --git a/src/helma/util/Diff.java b/src/helma/util/Diff.java deleted file mode 100644 index aa4d5f0d..00000000 --- a/src/helma/util/Diff.java +++ /dev/null @@ -1,863 +0,0 @@ -/* $Log$ -/* Revision 1.1 2002/10/31 08:39:34 hannes -/* Added GNU Diff class from http://www.bmsi.com/java/#diff -/* - * Revision 1.3 2000/03/03 21:58:03 stuart - * move discard_confusing_lines and shift_boundaries to class file_data - * - * Revision 1.2 2000/03/02 16:37:38 stuart - * Add GPL and copyright - * - */ -package helma.util; - -import java.util.Hashtable; - -/** A class to compare vectors of objects. The result of comparison - is a list of change objects which form an - edit script. The objects compared are traditionally lines - of text from two files. Comparison options such as "ignore - whitespace" are implemented by modifying the equals - and hashcode methods for the objects compared. -

- The basic algorithm is described in:
- "An O(ND) Difference Algorithm and its Variations", Eugene Myers, - Algorithmica Vol. 1 No. 2, 1986, p 251. -

- This class outputs different results from GNU diff 1.15 on some - inputs. Our results are actually better (smaller change list, smaller - total size of changes), but it would be nice to know why. Perhaps - there is a memory overwrite bug in GNU diff 1.15. - - @author Stuart D. Gathman, translated from GNU diff 1.15 - Copyright (C) 2000 Business Management Systems, Inc. -

- This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -

- This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -

- You should have received a copy of the - GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -public class Diff { - - /** Prepare to find differences between two arrays. Each element of - the arrays is translated to an "equivalence number" based on - the result of equals. The original Object arrays - are no longer needed for computing the differences. They will - be needed again later to print the results of the comparison as - an edit script, if desired. - */ - public Diff(Object[] a,Object[] b) { - Hashtable h = new Hashtable(a.length + b.length); - filevec[0] = new file_data(a,h); - filevec[1] = new file_data(b,h); - } - - /** 1 more than the maximum equivalence value used for this or its - sibling file. */ - private int equiv_max = 1; - - /** When set to true, the comparison uses a heuristic to speed it up. - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - public boolean heuristic = false; - - /** When set to true, the algorithm returns a guarranteed minimal - set of changes. This makes things slower, sometimes much slower. */ - public boolean no_discards = false; - - private int[] xvec, yvec; /* Vectors being compared. */ - private int[] fdiag; /* Vector, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the forward - search of the edit matrix. */ - private int[] bdiag; /* Vector, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the backward - search of the edit matrix. */ - private int fdiagoff, bdiagoff; - private final file_data[] filevec = new file_data[2]; - private int cost; - - /** Find the midpoint of the shortest edit script for a specified - portion of the two files. - - We scan from the beginnings of the files, and simultaneously from the ends, - doing a breadth-first search through the space of edit-sequence. - When the two searches meet, we have found the midpoint of the shortest - edit sequence. - - The value returned is the number of the diagonal on which the midpoint lies. - The diagonal number equals the number of inserted lines minus the number - of deleted lines (counting only lines before the midpoint). - The edit cost is stored into COST; this is the total number of - lines inserted or deleted (counting only lines before the midpoint). - - This function assumes that the first lines of the specified portions - of the two files do not match, and likewise that the last lines do not - match. The caller must trim matching lines from the beginning and end - of the portions it is going to specify. - - Note that if we return the "wrong" diagonal value, or if - the value of bdiag at that diagonal is "wrong", - the worst this can do is cause suboptimal diff output. - It cannot cause incorrect diff output. */ - - private int diag (int xoff, int xlim, int yoff, int ylim) { - final int[] fd = fdiag; // Give the compiler a chance. - final int[] bd = bdiag; // Additional help for the compiler. - final int[] xv = xvec; // Still more help for the compiler. - final int[] yv = yvec; // And more and more . . . - final int dmin = xoff - ylim; // Minimum valid diagonal. - final int dmax = xlim - yoff; // Maximum valid diagonal. - final int fmid = xoff - yoff; // Center diagonal of top-down search. - final int bmid = xlim - ylim; // Center diagonal of bottom-up search. - int fmin = fmid, fmax = fmid; // Limits of top-down search. - int bmin = bmid, bmax = bmid; // Limits of bottom-up search. - /* True if southeast corner is on an odd - diagonal with respect to the northwest. */ - final boolean odd = (fmid - bmid & 1) != 0; - - fd[fdiagoff + fmid] = xoff; - bd[bdiagoff + bmid] = xlim; - - for (int c = 1;; ++c) - { - int d; /* Active diagonal. */ - boolean big_snake = false; - - /* Extend the top-down search by an edit step in each diagonal. */ - if (fmin > dmin) - fd[fdiagoff + --fmin - 1] = -1; - else - ++fmin; - if (fmax < dmax) - fd[fdiagoff + ++fmax + 1] = -1; - else - --fmax; - for (d = fmax; d >= fmin; d -= 2) - { - int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1]; - - if (tlo >= thi) - x = tlo + 1; - else - x = thi; - oldx = x; - y = x - d; - while (x < xlim && y < ylim && xv[x] == yv[y]) { - ++x; ++y; - } - if (x - oldx > 20) - big_snake = true; - fd[fdiagoff + d] = x; - if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c - 1; - return d; - } - } - - /* Similar extend the bottom-up search. */ - if (bmin > dmin) - bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE; - else - ++bmin; - if (bmax < dmax) - bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE; - else - --bmax; - for (d = bmax; d >= bmin; d -= 2) - { - int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1]; - - if (tlo < thi) - x = tlo; - else - x = thi - 1; - oldx = x; - y = x - d; - while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) { - --x; --y; - } - if (oldx - x > 20) - big_snake = true; - bd[bdiagoff + d] = x; - if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c; - return d; - } - } - - /* Heuristic: check occasionally for a diagonal that has made - lots of progress compared with the edit distance. - If we have any such, find the one that has made the most - progress and return it as if it had succeeded. - - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - - if (c > 200 && big_snake && heuristic) - { - int best = 0; - int bestpos = -1; - - for (d = fmax; d >= fmin; d -= 2) - { - int dd = d - fmid; - if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if (fd[fdiagoff + d] * 2 - dd > best - && fd[fdiagoff + d] - xoff > 20 - && fd[fdiagoff + d] - d - yoff > 20) - { - int k; - int x = fd[fdiagoff + d]; - - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - for (k = 1; k <= 20; k++) - if (xvec[x - k] != yvec[x - d - k]) - break; - - if (k == 21) - { - best = fd[fdiagoff + d] * 2 - dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - - best = 0; - for (d = bmax; d >= bmin; d -= 2) - { - int dd = d - bmid; - if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if ((xlim - bd[bdiagoff + d]) * 2 + dd > best - && xlim - bd[bdiagoff + d] > 20 - && ylim - (bd[bdiagoff + d] - d) > 20) - { - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - int k; - int x = bd[bdiagoff + d]; - - for (k = 0; k < 20; k++) - if (xvec[x + k] != yvec[x - d + k]) - break; - if (k == 20) - { - best = (xlim - bd[bdiagoff + d]) * 2 + dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - } - } - } - - /** Compare in detail contiguous subsequences of the two files - which are known, as a whole, to match each other. - - The results are recorded in the vectors filevec[N].changed_flag, by - storing a 1 in the element for each line that is an insertion or deletion. - - The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. - - Note that XLIM, YLIM are exclusive bounds. - All line numbers are origin-0 and discarded lines are not counted. */ - - private void compareseq (int xoff, int xlim, int yoff, int ylim) { - /* Slide down the bottom initial diagonal. */ - while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) { - ++xoff; ++yoff; - } - /* Slide up the top initial diagonal. */ - while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) { - --xlim; --ylim; - } - - /* Handle simple cases. */ - if (xoff == xlim) - while (yoff < ylim) - filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true; - else if (yoff == ylim) - while (xoff < xlim) - filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true; - else - { - /* Find a point of correspondence in the middle of the files. */ - - int d = diag (xoff, xlim, yoff, ylim); - int c = cost; - //int f = fdiag[fdiagoff + d]; - int b = bdiag[bdiagoff + d]; - - if (c == 1) - { - /* This should be impossible, because it implies that - one of the two subsequences is empty, - and that case was handled above without calling `diag'. - Let's verify that this is true. */ - throw new IllegalArgumentException("Empty subsequence"); - } - else - { - /* Use that point to split this problem into two subproblems. */ - compareseq (xoff, b, yoff, b - d); - /* This used to use f instead of b, - but that is incorrect! - It is not necessarily the case that diagonal d - has a snake from b to f. */ - compareseq (b, xlim, b - d, ylim); - } - } - } - - /** Discard lines from one file that have no matches in the other file. - */ - - private void discard_confusing_lines() { - filevec[0].discard_confusing_lines(filevec[1]); - filevec[1].discard_confusing_lines(filevec[0]); - } - - private boolean inhibit = false; - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - */ - - private void shift_boundaries() { - if (inhibit) - return; - filevec[0].shift_boundaries(filevec[1]); - filevec[1].shift_boundaries(filevec[0]); - } - - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in reverse order. */ - - private change build_reverse_script() { - change script = null; - final boolean[] changed0 = filevec[0].changed_flag; - final boolean[] changed1 = filevec[1].changed_flag; - final int len0 = filevec[0].buffered_lines; - final int len1 = filevec[1].buffered_lines; - - /* Note that changedN[len0] does exist, and contains 0. */ - - int i0 = 0, i1 = 0; - - while (i0 < len0 || i1 < len1) - { - if (changed0[1+i0] || changed1[1+i1]) - { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[1+i0]) ++i0; - while (changed1[1+i1]) ++i1; - - /* Record this change. */ - script = new change(line0, line1, i0 - line0, i1 - line1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0++; i1++; - } - - return script; - } - - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in forward order. */ - - private change build_script() { - change script = null; - final boolean[] changed0 = filevec[0].changed_flag; - final boolean[] changed1 = filevec[1].changed_flag; - final int len0 = filevec[0].buffered_lines; - final int len1 = filevec[1].buffered_lines; - int i0 = len0, i1 = len1; - - /* Note that changedN[-1] does exist, and contains 0. */ - - while (i0 >= 0 || i1 >= 0) - { - if (changed0[i0] || changed1[i1]) - { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[i0]) --i0; - while (changed1[i1]) --i1; - - /* Record this change. */ - script = new change(i0, i1, line0 - i0, line1 - i1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0--; i1--; - } - - return script; - } - - /** - * Convenience method to get a diff on the two files. - */ - public change diff() { - return diff_2 (false); - } - - /* Report the differences of two files. DEPTH is the current directory - depth. */ - public change diff_2(final boolean reverse) { - - /* Some lines are obviously insertions or deletions - because they don't match anything. Detect them now, - and avoid even thinking about them in the main comparison algorithm. */ - - discard_confusing_lines (); - - /* Now do the main comparison algorithm, considering just the - undiscarded lines. */ - - xvec = filevec[0].undiscarded; - yvec = filevec[1].undiscarded; - - int diags = - filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3; - fdiag = new int[diags]; - fdiagoff = filevec[1].nondiscarded_lines + 1; - bdiag = new int[diags]; - bdiagoff = filevec[1].nondiscarded_lines + 1; - - compareseq (0, filevec[0].nondiscarded_lines, - 0, filevec[1].nondiscarded_lines); - fdiag = null; - bdiag = null; - - /* Modify the results slightly to make them prettier - in cases where that can validly be done. */ - - shift_boundaries (); - - /* Get the results of comparison in the form of a chain - of `struct change's -- an edit script. */ - - if (reverse) - return build_reverse_script(); - else - return build_script(); - } - - /** The result of comparison is an "edit script": a chain of change objects. - Each change represents one place where some lines are deleted - and some are inserted. - - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - - public static class change { - /** Previous or next edit command. */ - public change link; - /** # lines of file 1 changed here. */ - public final int inserted; - /** # lines of file 0 changed here. */ - public final int deleted; - /** Line number of 1st deleted line. */ - public final int line0; - /** Line number of 1st inserted line. */ - public final int line1; - - /** Cons an additional entry onto the front of an edit script OLD. - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - change(int line0, int line1, int deleted, int inserted, change old) { - this.line0 = line0; - this.line1 = line1; - this.inserted = inserted; - this.deleted = deleted; - this.link = old; - //System.err.println(line0+","+line1+","+inserted+","+deleted); - } - } - - /** Data on one input file being compared. - */ - - class file_data { - - /** Allocate changed array for the results of comparison. */ - void clear() { - /* Allocate a flag for each line of each file, saying whether that line - is an insertion or deletion. - Allocate an extra element, always zero, at each end of each vector. - */ - changed_flag = new boolean[buffered_lines + 2]; - } - - /** Return equiv_count[I] as the number of lines in this file - that fall in equivalence class I. - @return the array of equivalence class counts. - */ - int[] equivCount() { - int[] equiv_count = new int[equiv_max]; - for (int i = 0; i < buffered_lines; ++i) - ++equiv_count[equivs[i]]; - return equiv_count; - } - - /** Discard lines that have no matches in another file. - - A line which is discarded will not be considered by the actual - comparison algorithm; it will be as if that line were not in the file. - The file's `realindexes' table maps virtual line numbers - (which don't count the discarded lines) into real line numbers; - this is how the actual comparison algorithm produces results - that are comprehensible when the discarded lines are counted. -

- When we discard a line, we also mark it as a deletion or insertion - so that it will be printed in the output. - @param f the other file - */ - void discard_confusing_lines(file_data f) { - clear(); - /* Set up table of which lines are going to be discarded. */ - final byte[] discarded = discardable(f.equivCount()); - - /* Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - filterDiscards(discarded); - - /* Actually discard the lines. */ - discard(discarded); - } - - /** Mark to be discarded each line that matches no line of another file. - If a line matches many lines, mark it as provisionally discardable. - @see equivCount() - @param counts The count of each equivalence number for the other file. - @return 0=nondiscardable, 1=discardable or 2=provisionally discardable - for each line - */ - - private byte[] discardable(final int[] counts) { - final int end = buffered_lines; - final byte[] discards = new byte[end]; - final int[] equivs = this.equivs; - int many = 5; - int tem = end / 64; - - /* Multiply MANY by approximate square root of number of lines. - That is the threshold for provisionally discardable lines. */ - while ((tem = tem >> 2) > 0) - many *= 2; - - for (int i = 0; i < end; i++) - { - int nmatch; - if (equivs[i] == 0) - continue; - nmatch = counts[equivs[i]]; - if (nmatch == 0) - discards[i] = 1; - else if (nmatch > many) - discards[i] = 2; - } - return discards; - } - - /** Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - - private void filterDiscards(final byte[] discards) { - final int end = buffered_lines; - - for (int i = 0; i < end; i++) - { - /* Cancel provisional discards not in middle of run of discards. */ - if (discards[i] == 2) - discards[i] = 0; - else if (discards[i] != 0) - { - /* We have found a nonprovisional discard. */ - int j; - int length; - int provisional = 0; - - /* Find end of this run of discardable lines. - Count how many are provisionally discardable. */ - for (j = i; j < end; j++) - { - if (discards[j] == 0) - break; - if (discards[j] == 2) - ++provisional; - } - - /* Cancel provisional discards at end, and shrink the run. */ - while (j > i && discards[j - 1] == 2) { - discards[--j] = 0; --provisional; - } - - /* Now we have the length of a run of discardable lines - whose first and last are not provisional. */ - length = j - i; - - /* If 1/4 of the lines in the run are provisional, - cancel discarding of all provisional lines in the run. */ - if (provisional * 4 > length) - { - while (j > i) - if (discards[--j] == 2) - discards[j] = 0; - } - else - { - int consec; - int minimum = 1; - int tem = length / 4; - - /* MINIMUM is approximate square root of LENGTH/4. - A subrun of two or more provisionals can stand - when LENGTH is at least 16. - A subrun of 4 or more can stand when LENGTH >= 64. */ - while ((tem = tem >> 2) > 0) - minimum *= 2; - minimum++; - - /* Cancel any subrun of MINIMUM or more provisionals - within the larger run. */ - for (j = 0, consec = 0; j < length; j++) - if (discards[i + j] != 2) - consec = 0; - else if (minimum == ++consec) - /* Back up to start of subrun, to cancel it all. */ - j -= consec; - else if (minimum < consec) - discards[i + j] = 0; - - /* Scan from beginning of run - until we find 3 or more nonprovisionals in a row - or until the first nonprovisional at least 8 lines in. - Until that point, cancel any provisionals. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i + j] == 1) - break; - if (discards[i + j] == 2) { - consec = 0; discards[i + j] = 0; - } - else if (discards[i + j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - - /* I advances to the last line of the run. */ - i += length - 1; - - /* Same thing, from end. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i - j] == 1) - break; - if (discards[i - j] == 2) { - consec = 0; discards[i - j] = 0; - } - else if (discards[i - j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - } - } - } - } - - /** Actually discard the lines. - @param discards flags lines to be discarded - */ - private void discard(final byte[] discards) { - final int end = buffered_lines; - int j = 0; - for (int i = 0; i < end; ++i) - if (no_discards || discards[i] == 0) - { - undiscarded[j] = equivs[i]; - realindexes[j++] = i; - } - else - changed_flag[1+i] = true; - nondiscarded_lines = j; - } - - file_data(Object[] data,Hashtable h) { - buffered_lines = data.length; - - equivs = new int[buffered_lines]; - undiscarded = new int[buffered_lines]; - realindexes = new int[buffered_lines]; - - for (int i = 0; i < data.length; ++i) { - Integer ir = (Integer)h.get(data[i]); - if (ir == null) - h.put(data[i],new Integer(equivs[i] = equiv_max++)); - else - equivs[i] = ir.intValue(); - } - } - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - - We do something when a run of changed lines include a blank - line at one end and have an excluded blank line at the other. - We are free to choose which blank line is included. - `compareseq' always chooses the one at the beginning, - but usually it is cleaner to consider the following blank line - to be the "change". The only exception is if the preceding blank line - would join this change to other changes. - @param f the file being compared against - */ - - void shift_boundaries(file_data f) { - final boolean[] changed = changed_flag; - final boolean[] other_changed = f.changed_flag; - int i = 0; - int j = 0; - int i_end = buffered_lines; - int preceding = -1; - int other_preceding = -1; - - for (;;) - { - int start, end, other_start; - - /* Scan forwards to find beginning of another run of changes. - Also keep track of the corresponding point in the other file. */ - - while (i < i_end && !changed[1+i]) - { - while (other_changed[1+j++]) - /* Non-corresponding lines in the other file - will count as the preceding batch of changes. */ - other_preceding = j; - i++; - } - - if (i == i_end) - break; - - start = i; - other_start = j; - - for (;;) - { - /* Now find the end of this run of changes. */ - - while (i < i_end && changed[1+i]) i++; - end = i; - - /* If the first changed line matches the following unchanged one, - and this run does not follow right after a previous run, - and there are no lines deleted from the other file here, - then classify the first changed line as unchanged - and the following line as changed in its place. */ - - /* You might ask, how could this run follow right after another? - Only because the previous run was shifted here. */ - - if (end != i_end - && equivs[start] == equivs[end] - && !other_changed[1+j] - && end != i_end - && !((preceding >= 0 && start == preceding) - || (other_preceding >= 0 - && other_start == other_preceding))) - { - changed[1+end++] = true; - changed[1+start++] = false; - ++i; - /* Since one line-that-matches is now before this run - instead of after, we must advance in the other file - to keep in synch. */ - ++j; - } - else - break; - } - - preceding = i; - other_preceding = j; - } - } - - /** Number of elements (lines) in this file. */ - final int buffered_lines; - - /** Vector, indexed by line number, containing an equivalence code for - each line. It is this vector that is actually compared with that - of another file to generate differences. */ - private final int[] equivs; - - /** Vector, like the previous one except that - the elements for discarded lines have been squeezed out. */ - final int[] undiscarded; - - /** Vector mapping virtual line numbers (not counting discarded lines) - to real ones (counting those lines). Both are origin-0. */ - final int[] realindexes; - - /** Total number of nondiscarded lines. */ - int nondiscarded_lines; - - /** Array, indexed by real origin-1 line number, - containing true for a line that is an insertion or a deletion. - The results of comparison are stored here. */ - boolean[] changed_flag; - - } -} diff --git a/src/helma/util/EmptyEnumeration.java b/src/helma/util/EmptyEnumeration.java deleted file mode 100644 index 36765c1e..00000000 --- a/src/helma/util/EmptyEnumeration.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.util.Enumeration; - -/** - * Utility class for empty enum - */ -public class EmptyEnumeration implements Enumeration { - /** - * - * - * @return ... - */ - public boolean hasMoreElements() { - return false; - } - - /** - * - * - * @return ... - */ - public Object nextElement() { - return null; - } -} diff --git a/src/helma/util/FileUpload.java b/src/helma/util/FileUpload.java deleted file mode 100644 index 1b8b80a3..00000000 --- a/src/helma/util/FileUpload.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import helma.util.mime.*; -import java.io.*; -import java.util.*; - -/** - * Utility class for MIME file uploads via HTTP POST. - */ -public class FileUpload { - public Hashtable parts; - int maxKbytes; - - /** - * Creates a new FileUpload object. - */ - public FileUpload() { - maxKbytes = 1024; - } - - /** - * Creates a new FileUpload object. - * - * @param max ... - */ - public FileUpload(int max) { - maxKbytes = max; - } - - /** - * - * - * @return ... - */ - public Hashtable getParts() { - return parts; - } - - /** - * - * - * @param is ... - * @param contentType ... - * @param contentLength ... - * - * @throws Exception ... - * @throws MimeParserException ... - * @throws IOException ... - */ - public void load(InputStream is, String contentType, int contentLength) - throws Exception { - parts = new Hashtable(); - - String boundary = getSubHeader(contentType, "boundary"); - - if (boundary == null) { - throw new MimeParserException("Error parsing MIME input stream."); - } - - if ((maxKbytes > -1) && (contentLength > (maxKbytes * 1024))) { - throw new IOException("Size of upload exceeds limit of " + maxKbytes + - " kB."); - } - - byte[] b = new byte[contentLength]; - MultipartInputStream in = new MultipartInputStream(new BufferedInputStream(is), - boundary.getBytes()); - - while (in.nextInputStream()) { - MimeParser parser = new MimeParser(in, new MimeHeadersFactory()); - MimeHeaders headers = (MimeHeaders) parser.parse(); - - InputStream bodystream = parser.getInputStream(); - int read; - int count = 0; - - while ((read = bodystream.read(b, count, 4096)) > -1) { - count += read; - - if (count == b.length) { - byte[] newb = new byte[count + 4096]; - - System.arraycopy(b, 0, newb, 0, count); - b = newb; - } - } - - byte[] newb = new byte[count]; - - System.arraycopy(b, 0, newb, 0, count); - - String type = headers.getValue("Content-Type"); - String disposition = headers.getValue("Content-Disposition"); - String name = getSubHeader(disposition, "name"); - String filename = getSubHeader(disposition, "filename"); - - if (filename != null) { - int sep = filename.lastIndexOf("\\"); - - if (sep > -1) { - filename = filename.substring(sep + 1); - } - - sep = filename.lastIndexOf("/"); - - if (sep > -1) { - filename = filename.substring(sep + 1); - } - } - - if (filename != null) { - MimePart part = new MimePart(filename, newb, type); - - parts.put(name, part); - } else { - parts.put(name, new String(newb)); - } - } - } - - private String getSubHeader(String header, String subHeaderName) { - if (header == null) { - return null; - } - - String retval = null; - StringTokenizer headerTokenizer = new StringTokenizer(header, ";"); - - while (headerTokenizer.hasMoreTokens()) { - String token = headerTokenizer.nextToken().trim(); - int i = token.indexOf("="); - - if (i > 0) { - String hname = token.substring(0, i).trim(); - - if (hname.equalsIgnoreCase(subHeaderName)) { - retval = token.substring(i + 1).replace('"', ' ').trim(); - } - } - } - - return retval; - } -} diff --git a/src/helma/util/HtmlEncoder.java b/src/helma/util/HtmlEncoder.java deleted file mode 100644 index 6f4f69f6..00000000 --- a/src/helma/util/HtmlEncoder.java +++ /dev/null @@ -1,971 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.awt.*; -import java.awt.image.*; -import java.io.*; -import java.text.*; -import java.util.*; - -/** - * This is a utility class to encode special characters and do formatting - * for HTML output. - */ -public final class HtmlEncoder { - - // transformation table for characters 128 to 255. These actually fall into two - // groups, put together for efficiency: "Windows" chacacters 128-159 such as - // "smart quotes", which are encoded to valid Unicode entities, and - // valid ISO-8859 caracters 160-255, which are encoded to the symbolic HTML - // entity. Everything >= 256 is encoded to a numeric entity. - // - // for mor on HTML entities see http://www.pemberley.com/janeinfo/latin1.html and - // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT - // - static final String[] transform = { - "€", // 128 - "", // empty string means character is undefined in unicode - "‚", - "ƒ", - "„", - "…", - "†", - "‡", - "ˆ", - "‰", - "Š", - "‹", - "Œ", - "", - "Ž", - "", - "", - "‘", - "’", - "“", - "”", - "•", - "–", - "—", - "˜", - "™", - "š", - "›", - "œ", - "", - "ž", - "Ÿ", // 159 - " ", // 160 - "¡", - "¢", - "£", - "¤", - "¥", - "¦", - "§", - "¨", - "©", - "ª", - "«", - "¬", - "­", - "®", - "¯", - "°", - "±", - "²", - "³", - "´", - "µ", - "¶", - "·", - "¸", - "¹", - "º", - "»", - "¼", - "½", - "¾", - "¿", - "À", - "Á", - "Â", - "Ã", - "Ä", - "Å", - "Æ", - "Ç", - "È", - "É", - "Ê", - "Ë", - "Ì", - "Í", - "Î", - "Ï", - "Ð", - "Ñ", - "Ò", - "Ó", - "Ô", - "Õ", - "Ö", - "×", - "Ø", - "Ù", - "Ú", - "Û", - "Ü", - "Ý", - "Þ", - "ß", - "à", - "á", - "â", - "ã", - "ä", - "å", - "æ", - "ç", - "è", - "é", - "ê", - "ë", - "ì", - "í", - "î", - "ï", - "ð", - "ñ", - "ò", - "ó", - "ô", - "õ", - "ö", - "÷", - "ø", - "ù", - "ú", - "û", - "ü", - "ý", - "þ", - "ÿ" // 255 - }; - - static final HashSet allTags = new HashSet(); - - static { - allTags.add("a"); - allTags.add("abbr"); - allTags.add("acronym"); - allTags.add("address"); - allTags.add("applet"); - allTags.add("area"); - allTags.add("b"); - allTags.add("base"); - allTags.add("basefont"); - allTags.add("bdo"); - allTags.add("bgsound"); - allTags.add("big"); - allTags.add("blink"); - allTags.add("blockquote"); - allTags.add("bq"); - allTags.add("body"); - allTags.add("br"); - allTags.add("button"); - allTags.add("caption"); - allTags.add("center"); - allTags.add("cite"); - allTags.add("code"); - allTags.add("col"); - allTags.add("colgroup"); - allTags.add("del"); - allTags.add("dfn"); - allTags.add("dir"); - allTags.add("div"); - allTags.add("dl"); - allTags.add("dt"); - allTags.add("dd"); - allTags.add("em"); - allTags.add("embed"); - allTags.add("fieldset"); - allTags.add("font"); - allTags.add("form"); - allTags.add("frame"); - allTags.add("frameset"); - allTags.add("h1"); - allTags.add("h2"); - allTags.add("h3"); - allTags.add("h4"); - allTags.add("h5"); - allTags.add("h6"); - allTags.add("head"); - allTags.add("html"); - allTags.add("hr"); - allTags.add("i"); - allTags.add("iframe"); - allTags.add("img"); - allTags.add("input"); - allTags.add("ins"); - allTags.add("isindex"); - allTags.add("kbd"); - allTags.add("label"); - allTags.add("legend"); - allTags.add("li"); - allTags.add("link"); - allTags.add("listing"); - allTags.add("map"); - allTags.add("marquee"); - allTags.add("menu"); - allTags.add("meta"); - allTags.add("nobr"); - allTags.add("noframes"); - allTags.add("noscript"); - allTags.add("object"); - allTags.add("ol"); - allTags.add("option"); - allTags.add("optgroup"); - allTags.add("p"); - allTags.add("param"); - allTags.add("plaintext"); - allTags.add("pre"); - allTags.add("q"); - allTags.add("s"); - allTags.add("samp"); - allTags.add("script"); - allTags.add("select"); - allTags.add("small"); - allTags.add("span"); - allTags.add("strike"); - allTags.add("strong"); - allTags.add("style"); - allTags.add("sub"); - allTags.add("sup"); - allTags.add("table"); - allTags.add("tbody"); - allTags.add("td"); - allTags.add("textarea"); - allTags.add("tfoot"); - allTags.add("th"); - allTags.add("thead"); - allTags.add("title"); - allTags.add("tr"); - allTags.add("tt"); - allTags.add("u"); - allTags.add("ul"); - allTags.add("var"); - allTags.add("wbr"); - allTags.add("xmp"); - } - - // HTML block tags need to suppress automatic newline to
- // conversion around them to look good. However, they differ - // in how many newlines around them should ignored. These sets - // help to treat each tag right in newline conversion. - static final HashSet swallowAll = new HashSet(); - static final HashSet swallowTwo = new HashSet(); - static final HashSet swallowOne = new HashSet(); - - static { - // actual block level elements - swallowOne.add("address"); - swallowTwo.add("blockquote"); - swallowTwo.add("center"); - swallowOne.add("dir"); - swallowOne.add("div"); - swallowTwo.add("dl"); - swallowTwo.add("fieldset"); - swallowTwo.add("form"); - swallowTwo.add("h1"); - swallowTwo.add("h2"); - swallowTwo.add("h3"); - swallowTwo.add("h4"); - swallowTwo.add("h5"); - swallowTwo.add("h6"); - swallowTwo.add("hr"); - swallowTwo.add("isindex"); - swallowAll.add("menu"); - swallowAll.add("noframes"); - swallowAll.add("noscript"); - swallowTwo.add("ol"); - swallowTwo.add("p"); - swallowTwo.add("pre"); - swallowOne.add("table"); - swallowTwo.add("ul"); - - /// to be treated as block level elements - swallowTwo.add("br"); - swallowTwo.add("dd"); - swallowTwo.add("dt"); - swallowTwo.add("frameset"); - swallowTwo.add("li"); - swallowAll.add("tbody"); - swallowTwo.add("td"); - swallowAll.add("tfoot"); - swallowOne.add("th"); - swallowAll.add("thead"); - swallowAll.add("tr"); - } - - // set of tags that are always empty - static final HashSet emptyTags = new HashSet(); - - static { - emptyTags.add("area"); - emptyTags.add("base"); - emptyTags.add("basefont"); - emptyTags.add("br"); - emptyTags.add("col"); - emptyTags.add("frame"); - emptyTags.add("hr"); - emptyTags.add("img"); - emptyTags.add("input"); - emptyTags.add("isindex"); - emptyTags.add("link"); - emptyTags.add("meta"); - emptyTags.add("param"); - } - - final static byte TAG_NAME = 0; - final static byte TAG_SPACE = 1; - final static byte TAG_ATT_NAME = 2; - final static byte TAG_ATT_VAL = 3; - - - /** - * Do "smart" encodging on a string. This means that valid HTML entities and tags, - * Helma macros and HTML comments are passed through unescaped, while - * other occurrences of '<', '>' and '&' are encoded to HTML entities. - */ - public final static String encode(String str) { - if (str == null) { - return null; - } - - int l = str.length(); - - if (l == 0) { - return ""; - } - - // try to make stringbuffer large enough from the start - StringBuffer ret = new StringBuffer(Math.round(l * 1.4f)); - - encode(str, ret, null); - - return ret.toString(); - } - - /** - * Do "smart" encodging on a string. This means that valid HTML entities and tags, - * Helma macros and HTML comments are passed through unescaped, while - * other occurrences of '<', '>' and '&' are encoded to HTML entities. - */ - public final static void encode(String str, StringBuffer ret) { - encode(str, ret, null); - } - - /** - * Do "smart" encodging on a string. This means that valid HTML entities and tags, - * Helma macros and HTML comments are passed through unescaped, while - * other occurrences of '<', '>' and '&' are encoded to HTML entities. - */ - public final static void encode(String str, StringBuffer ret, Set allowedTags) { - if (str == null) { - return; - } - - int l = str.length(); - - Stack openTags = new Stack(); - - // are we currently within a < and a > that consitute some kind of tag? - // we use tag balancing to know whether we are inside a tag (and should - // pass things through unchanged) or outside (and should encode stuff). - boolean insideTag = false; - - // are we inside an HTML tag? - boolean insideHtmlTag = false; - boolean insideCloseTag = false; - byte htmlTagMode = TAG_NAME; - - // if we are inside a tag, we encode everything to make - // documentation work easier - boolean insideCodeTag = false; - boolean insidePreTag = false; - - // are we within a Helma <% macro %> tag? We treat macro tags and - // comments specially, since we can't rely on tag balancing - // to know when we leave a macro tag or comment. - boolean insideMacroTag = false; - - // are we inside an HTML comment? - boolean insideComment = false; - - // the quotation mark we are in within an HTML or Macro tag, if any - char htmlQuoteChar = '\u0000'; - char macroQuoteChar = '\u0000'; - - // number of newlines to ignore in \n ->
conversion - int swallowLinebreaks = 0; - - // number of newlines met since the last non-whitespace character - int linebreaks = 0; - - // did we meet a backslash escape? - boolean escape = false; - - for (int i = 0; i < l; i++) { - char c = str.charAt(i); - - // step one: check if this is the beginning of an HTML tag, comment or - // Helma macro. - if (c == '<') { - if (i < (l - 2)) { - if (!insideMacroTag && ('%' == str.charAt(i + 1))) { - // this is the beginning of a Helma macro tag - if (!insideCodeTag) { - insideMacroTag = insideTag = true; - macroQuoteChar = '\u0000'; - } - } else if (('!' == str.charAt(i + 1)) && ('-' == str.charAt(i + 2))) { - // the beginning of an HTML comment? - if (!insideCodeTag) { - insideComment = insideTag = ((i < (l - 3)) && - ('-' == str.charAt(i + 3))); - } - } else if (!insideTag) { - // check if this is a HTML tag. - insideCloseTag = ('/' == str.charAt(i + 1)); - int tagStart = insideCloseTag ? (i + 2) : (i + 1); - int j = tagStart; - - while ((j < l) && Character.isLetterOrDigit(str.charAt(j))) - j++; - - if ((j > tagStart) && (j < l)) { - String tagName = str.substring(tagStart, j).toLowerCase(); - - if ("code".equals(tagName) && insideCloseTag && - insideCodeTag) { - insideCodeTag = false; - } - - if (((allowedTags == null) || allowedTags.contains(tagName)) && - allTags.contains(tagName) && !insideCodeTag) { - insideHtmlTag = insideTag = true; - htmlQuoteChar = '\u0000'; - htmlTagMode = TAG_NAME; - - // set ignoreNewline on some tags, depending on wheather they're - // being opened or closed. - // what's going on here? we switch newline encoding on inside some tags, for - // others we switch it on when they're closed - linebreaks = Math.max(linebreaks - swallowLinebreaks, 0); - - if (swallowAll.contains(tagName)) { - swallowLinebreaks = 1000; - } else if (swallowTwo.contains(tagName)) { - swallowLinebreaks = 2; - } else if (swallowOne.contains(tagName)) { - swallowLinebreaks = 1; - } else { - swallowLinebreaks = 0; - } - - if (insideCloseTag) { - int t = openTags.search(tagName); - - if (t == -1) { - i = j; - insideHtmlTag = insideTag = false; - - continue; - } else if (t > 1) { - for (int k = 1; k < t; k++) { - Object tag = openTags.pop(); - if (!emptyTags.contains(tag)) { - ret.append(""); - } - } - } - - openTags.pop(); - } else { - openTags.push(tagName); - swallowLinebreaks = Math.max(swallowLinebreaks - 1, 0); - } - - if ("code".equals(tagName) && !insideCloseTag) { - insideCodeTag = true; - } - - if ("pre".equals(tagName)) { - insidePreTag = !insideCloseTag; - } - } - } - } - } - // if (i < l-2) - } - - if ((linebreaks > 0 || swallowLinebreaks > 0) && !Character.isWhitespace(c)) { - if (!insidePreTag && (linebreaks > swallowLinebreaks)) { - linebreaks -= swallowLinebreaks; - - for (int k = 0; k < linebreaks; k++) - ret.append("
\n"); - } - - if (!insideTag) { - swallowLinebreaks = 0; - } - - linebreaks = 0; - } - - switch (c) { - case '<': - - if (insideTag) { - ret.append('<'); - } else { - ret.append("<"); - } - - break; - - case '&': - - // check if this is an HTML entity already, - // in which case we pass it though unchanged - if ((i < (l - 3)) && !insideCodeTag) { - // is this a numeric entity? - if (str.charAt(i + 1) == '#') { - int j = i + 2; - - while ((j < l) && Character.isDigit(str.charAt(j))) - j++; - - if ((j < l) && (str.charAt(j) == ';')) { - ret.append("&"); - - break; - } - } else { - int j = i + 1; - - while ((j < l) && Character.isLetterOrDigit(str.charAt(j))) - j++; - - if ((j < l) && (str.charAt(j) == ';')) { - ret.append("&"); - - break; - } - } - } - - // we didn't reach a break, so encode the ampersand as HTML entity - ret.append("&"); - - break; - - case '\\': - ret.append(c); - - if (insideTag && !insideComment) { - escape = !escape; - } - - break; - - case '"': - case '\'': - ret.append(c); - - if (!insideComment) { - // check if the quote is escaped - if (insideMacroTag) { - if (escape) { - escape = false; - } else if (macroQuoteChar == c) { - macroQuoteChar = '\u0000'; - } else if (macroQuoteChar == '\u0000') { - macroQuoteChar = c; - } - } else if (insideHtmlTag) { - if (escape) { - escape = false; - } else if (htmlQuoteChar == c) { - htmlQuoteChar = '\u0000'; - htmlTagMode = TAG_SPACE; - } else if (htmlQuoteChar == '\u0000') { - htmlQuoteChar = c; - } - } - } - - break; - - case '\n': - ret.append('\n'); - - if (!insideTag) { - linebreaks++; - } - - break; - - case '>': - - // For Helma macro tags and comments, we overrule tag balancing, - // i.e. we don't require that '<' and '>' be balanced within - // macros and comments. Rather, we check for the matching closing tag. - if (insideComment) { - ret.append('>'); - insideComment = !((str.charAt(i - 2) == '-') && - (str.charAt(i - 1) == '-')); - } else if (insideMacroTag) { - ret.append('>'); - insideMacroTag = !((str.charAt(i - 1) == '%') && - (macroQuoteChar == '\u0000')); - } else if (insideHtmlTag) { - ret.append('>'); - - // only leave HTML tag if quotation marks are balanced - // within that tag. - insideHtmlTag = htmlQuoteChar != '\u0000'; - - // Check if this is an empty tag so we don't generate an - // additional tag. - if (str.charAt(i - 1) == '/') { - // this is to avoid misinterpreting tags like - // as empty - if (htmlTagMode != TAG_ATT_VAL && htmlTagMode != TAG_ATT_NAME) { - openTags.pop(); - } - } - } else { - ret.append(">"); - } - - // check if we still are inside any kind of tag - insideTag = insideComment || insideMacroTag || insideHtmlTag; - - break; - - default: - - if (insideHtmlTag && !insideCloseTag) { - switch(htmlTagMode) { - case TAG_NAME: - if (!Character.isLetterOrDigit(c)) { - htmlTagMode = TAG_SPACE; - } - break; - case TAG_SPACE: - if (Character.isLetterOrDigit(c)) { - htmlTagMode = TAG_ATT_NAME; - } - break; - case TAG_ATT_NAME: - if (c == '=') { - htmlTagMode = TAG_ATT_VAL; - } else if (c == ' ') { - htmlTagMode = TAG_SPACE; - } - break; - case TAG_ATT_VAL: - if (Character.isWhitespace(c) && htmlQuoteChar == '\u0000') { - htmlTagMode = TAG_SPACE; - } - break; - } - } - if (c < 128) { - ret.append(c); - } else if ((c >= 128) && (c < 256)) { - ret.append(transform[c - 128]); - } else { - ret.append("&#"); - ret.append((int) c); - ret.append(";"); - } - - escape = false; - } - } - - // if tags were opened but not closed, close them. - int o = openTags.size(); - - if (o > 0) { - for (int k = 0; k < o; k++) { - Object tag = openTags.pop(); - if (!emptyTags.contains(tag)) { - ret.append(""); - } - } - } - - // add remaining newlines we may have collected - if ((linebreaks > 0) && (linebreaks > swallowLinebreaks)) { - linebreaks -= swallowLinebreaks; - - for (int i = 0; i < linebreaks; i++) - ret.append("
\n"); - } - } - - /** - * - */ - public final static String encodeFormValue(String str) { - if (str == null) { - return null; - } - - int l = str.length(); - - if (l == 0) { - return ""; - } - - StringBuffer ret = new StringBuffer(Math.round(l * 1.2f)); - - encodeAll(str, ret, false); - - return ret.toString(); - } - - /** - * - */ - public final static void encodeFormValue(String str, StringBuffer ret) { - encodeAll(str, ret, false); - } - - /** - * - */ - public final static String encodeAll(String str) { - if (str == null) { - return null; - } - - int l = str.length(); - - if (l == 0) { - return ""; - } - - StringBuffer ret = new StringBuffer(Math.round(l * 1.2f)); - - encodeAll(str, ret, true); - - return ret.toString(); - } - - /** - * - */ - public final static void encodeAll(String str, StringBuffer ret) { - encodeAll(str, ret, true); - } - - /** - * - */ - public final static void encodeAll(String str, StringBuffer ret, boolean encodeNewline) { - if (str == null) { - return; - } - - int l = str.length(); - - for (int i = 0; i < l; i++) { - char c = str.charAt(i); - - switch (c) { - case '<': - ret.append("<"); - - break; - - case '>': - ret.append(">"); - - break; - - case '&': - ret.append("&"); - - break; - - case '"': - ret.append("""); - - break; - - case '\n': - ret.append('\n'); - - if (encodeNewline) { - ret.append("
"); - } - - break; - - default: - - // ret.append (c); - if (c < 128) { - ret.append(c); - } else if ((c >= 128) && (c < 256)) { - ret.append(transform[c - 128]); - } else { - ret.append("&#"); - ret.append((int) c); - ret.append(";"); - } - } - } - } - - /** - * - * - * @param str ... - * - * @return ... - */ - public final static String encodeXml(String str) { - if (str == null) { - return null; - } - - int l = str.length(); - - if (l == 0) { - return ""; - } - - StringBuffer ret = new StringBuffer(Math.round(l * 1.2f)); - - encodeXml(str, ret); - - return ret.toString(); - } - - /** - * - * - * @param str ... - * @param ret ... - */ - public final static void encodeXml(String str, StringBuffer ret) { - if (str == null) { - return; - } - - int l = str.length(); - - for (int i = 0; i < l; i++) { - char c = str.charAt(i); - - switch (c) { - case '<': - ret.append("<"); - - break; - - case '>': - ret.append(">"); - - break; - - case '&': - ret.append("&"); - - break; - - case '"': - ret.append("""); - - break; - - case '\'': - ret.append("'"); - - break; - - default: - - if (c < 0x20) { - // sort out invalid XML characters below 0x20 - all but 0x9, 0xA and 0xD. - // The trick is an adaption of java.lang.Character.isSpace(). - if (((((1L << 0x9) | (1L << 0xA) | (1L << 0xD)) >> c) & 1L) != 0) { - ret.append(c); - } - } else { - ret.append(c); - } - } - } - } - - // test method - public static String printCharRange(int from, int to) { - StringBuffer response = new StringBuffer(); - - for (int i = from; i < to; i++) { - response.append(i); - response.append(" "); - response.append((char) i); - response.append(" "); - - if (i < 128) { - response.append((char) i); - } else if ((i >= 128) && (i < 256)) { - response.append(transform[i - 128]); - } else { - response.append("&#"); - response.append(i); - response.append(";"); - } - - response.append("\r\n"); - } - - return response.toString(); - } - - // for testing... - public static void main(String[] args) { - for (int i = 0; i < args.length; i++) - System.err.println(encode(args[i])); - } -} - // end of class diff --git a/src/helma/util/HtmlParser.java b/src/helma/util/HtmlParser.java deleted file mode 100644 index eeb58e13..00000000 --- a/src/helma/util/HtmlParser.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import org.apache.html.dom.*; -import org.w3c.dom.html.HTMLDocument; -import org.xml.sax.SAXException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.EmptyStackException; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Stack; -import javax.swing.text.SimpleAttributeSet; -import javax.swing.text.html.parser.*; - -/** - * - */ -public class HtmlParser extends Parser { - static final HashSet stopNone = new HashSet(); - static final HashSet stopTable = new HashSet(); - static final HashSet stopList = new HashSet(); - static final HashSet stopDeflist = new HashSet(); - - static { - stopTable.add("TABLE"); - stopList.add("TABLE"); - stopList.add("UL"); - stopList.add("OL"); - stopDeflist.add("TABLE"); - stopDeflist.add("DL"); - } - - HTMLBuilder builder; - Attributes attributes = new Attributes(); - Stack stack = new Stack(); - - /** - * Creates a new HtmlParser object. - * - * @throws IOException ... - */ - public HtmlParser() throws IOException { - super(DTD.getDTD("html32")); - - // define elements to be treated as container tags, and undefine those - // to be treated as empty tags. - dtd.getElement("table"); - dtd.getElement("tr"); - dtd.getElement("td"); - dtd.getElement("span"); - dtd.getElement("div"); - dtd.getElement("font"); - dtd.getElement("b"); - dtd.getElement("i"); - dtd.getElement("a"); - dtd.getElement("blockquote"); - dtd.getElement("em"); - dtd.getElement("ul"); - dtd.getElement("ol"); - dtd.getElement("li"); - dtd.getElement("dl"); - dtd.getElement("dt"); - dtd.getElement("dd"); - dtd.getElement("h1"); - dtd.getElement("h2"); - dtd.getElement("h3"); - dtd.getElement("h4"); - dtd.getElement("h5"); - dtd.getElement("h6"); - dtd.getElement("form"); - dtd.getElement("option"); - dtd.elementHash.remove("meta"); - dtd.elementHash.remove("link"); - dtd.elementHash.remove("base"); - builder = new HTMLBuilder(); - - try { - builder.startDocument(); - } catch (SAXException x) { - System.err.println("Error in constructor"); - } - } - - /** - * Handle Start Tag. - */ - protected void handleStartTag(TagElement tag) { - // System.err.println ("handleStartTag ("+tag.getHTMLTag()+")"); - attributes.convert(getAttributes()); - flushAttributes(); - - String tagname = tag.getHTMLTag().toString().toUpperCase(); - - // immediately empty A anchor tag - if ("A".equals(tagname) && (attributes.getValue("href") == null)) { - try { - builder.startElement(tagname, attributes); - builder.endElement(tagname); - - return; - } catch (SAXException x) { - } - } - - if ("TD".equals(tagname)) { - closeOpenTags("TD", stopTable, 10); - } else if ("TR".equals(tagname)) { - closeOpenTags("TR", stopTable, 10); - } else if ("LI".equals(tagname)) { - closeOpenTags("LI", stopList, 6); - } else if ("DT".equals(tagname) || "DD".equals(tagname)) { - closeOpenTags("DT", stopDeflist, 6); - closeOpenTags("DL", stopDeflist, 6); - } else if ("OPTION".equals(tagname)) { - closeOpenTags("OPTION", stopNone, 1); - } else if ("P".equals(tagname)) { - closeOpenTags("P", stopNone, 1); - } - - stack.push(tagname); - - try { - builder.startElement(tagname, attributes); - } catch (SAXException x) { - System.err.println("Error in handleStartTag"); - } - } - - /** - * Handle End Tag. - */ - protected void handleEndTag(TagElement tag) { - // System.err.println ("handleEndTag ("+tag.getHTMLTag()+")"); - String tagname = tag.getHTMLTag().toString().toUpperCase(); - - try { - if (tagname.equals(stack.peek())) { - stack.pop(); - } - } catch (EmptyStackException es) { - } - - try { - builder.endElement(tagname); - } catch (SAXException x) { - System.err.println("Error in handleEndTag: " + x); - } - } - - /** - * Handle Empty Tag. - */ - protected void handleEmptyTag(TagElement tag) { - // System.err.println ("handleEmptyTag ("+tag.getHTMLTag()+")"); - attributes.convert(getAttributes()); - flushAttributes(); - - String tagname = tag.getHTMLTag().toString().toUpperCase(); - - try { - builder.startElement(tagname, attributes); - builder.endElement(tagname); - } catch (SAXException x) { - System.err.println("Error in handleEmptyTag: " + x); - } - } - - /** - * Handle Text. - */ - protected void handleText(char[] data) { - // System.err.println ("handleText ("+new String (data)+")"); - try { - builder.characters(data, 0, data.length); - } catch (SAXException x) { - System.err.println("Error in handleText"); - } - } - - /* - * Error handling. - */ - protected void handleError(int ln, String errorMsg) { - // System.err.println ("handleError ("+ln+": "+errorMsg+")"); - } - - /** - * Handle comment. - */ - protected void handleComment(char[] data) { - // System.err.println ("handleComment ("+new String (data)+")"); - - /* try { - builder.characters (data, 0, data.length); - } catch (SAXException x) { - System.err.println ("Error in handleComment"); - }*/ - } - - /** - * - * - * @return ... - */ - public HTMLDocument getDocument() { - try { - builder.endDocument(); - } catch (SAXException x) { - } - - return builder.getHTMLDocument(); - } - - private void closeOpenTags(String until, HashSet stoppers, int maxdepth) { - int l = stack.size(); - int stop = Math.max(0, l - maxdepth); - int found = -1; - - for (int i = l - 1; i >= stop; i--) { - Object o = stack.elementAt(i); - - if (stoppers.contains(o)) { - return; - } - - if (until.equals(o)) { - found = i; - - break; - } - } - - if (found > -1) { - for (int i = l - 1; i >= found; i--) { - try { - String t = (String) stack.pop(); - - builder.endElement(t); - } catch (Exception x) { - } - } - } - } - - class Attributes implements org.xml.sax.AttributeList { - HashMap map = new HashMap(); - ArrayList names = new ArrayList(); - ArrayList values = new ArrayList(); - - public int getLength() { - return names.size(); - } - - public String getName(int i) { - return (String) names.get(i); - } - - public String getType(int i) { - return "CDATA"; - } - - public String getType(String name) { - return "CDATA"; - } - - public String getValue(int i) { - return (String) values.get(i); - } - - public String getValue(String name) { - return (String) map.get(name); - } - - public void convert(SimpleAttributeSet attset) { - map.clear(); - names.clear(); - values.clear(); - - for (Enumeration e = attset.getAttributeNames(); e.hasMoreElements();) { - Object name = e.nextElement(); - Object value = attset.getAttribute(name).toString(); - - name = name.toString().toLowerCase(); - map.put(name, value); - names.add(name); - values.add(value); - } - } - } -} diff --git a/src/helma/util/InetAddressFilter.java b/src/helma/util/InetAddressFilter.java deleted file mode 100644 index 1bbc2138..00000000 --- a/src/helma/util/InetAddressFilter.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.*; -import java.net.*; -import java.util.*; - -/** - * A class for paranoid servers to filter IP addresses. - */ -public class InetAddressFilter { - private Vector patterns; - - /** - * Creates a new InetAddressFilter object. - */ - public InetAddressFilter() { - patterns = new Vector(); - } - - /** - * Addes an address template to the address filter. - * - * @param address The string representation of the IP address, either version 4 or 6. - * - * @throws IOException if the parameter does not represent a valid IP address - */ - public void addAddress(String address) throws IOException { - boolean v6 = false; - String separator = "."; - int length = 4; - int loop = 4; - - // check if this is a v4 or v6 IP address - if (address.indexOf(":") > -1) { - v6 = true; - separator = ":."; - length = 16; - loop = 8; - } - - int[] pattern = new int[length]; - - StringTokenizer st = new StringTokenizer(address, separator); - - if (st.countTokens() != loop) { - throw new IOException("\"" + address + - "\" does not represent a valid IP address"); - } - - for (int i = 0; i < loop; i++) { - String next = st.nextToken(); - - if (v6) { - if ("*".equals(next)) { - pattern[i*2] = pattern[i*2+1] = 256; - } else if (next.length() == 0) { - pattern[i*2] = pattern[i*2+1] = 0; - } else { - int n = Integer.parseInt(next, 16); - pattern[i*2] = (byte) ((n & 0xff00) >> 8); - pattern[i*2+1] = (byte) (n & 0xff); - } - } else { - if ("*".equals(next)) { - pattern[i] = 256; - } else { - pattern[i] = (byte) Integer.parseInt(next); - } - } - } - patterns.addElement(pattern); - } - - /** - * Check if the given address matches any of our patterns - * - * @param address the ip address to match - * - * @return true if we find a match - */ - public boolean matches(InetAddress address) { - if (address == null) { - return false; - } - - byte[] add = address.getAddress(); - - if (add == null) { - return false; - } - - int l = patterns.size(); - - for (int k = 0; k < l; k++) { - int[] pattern = (int[]) patterns.elementAt(k); - - // is the address different version than pattern? - if (pattern.length != add.length) - continue; - - for (int i = 0; i < add.length; i++) { - if ((pattern[i] < 255) && (pattern[i] != add[i])) { - // not wildcard and doesn't match - break; - } - - if (i == add.length-1) { - return true; - } - } - } - - return false; - } -} diff --git a/src/helma/util/Logger.java b/src/helma/util/Logger.java deleted file mode 100644 index 40a26add..00000000 --- a/src/helma/util/Logger.java +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.*; -import java.text.*; -import java.util.*; -import java.util.zip.GZIPOutputStream; - -/** - * Utility class for asynchronous logging. - */ -public final class Logger { - // we use one static thread for all Loggers - static Runner runner; - - // the list of active loggers - static ArrayList loggers; - - // hash map of loggers - static HashMap loggerMap; - - // fields for date rendering and caching - static DateFormat dformat = new SimpleDateFormat("[yyyy/MM/dd HH:mm] "); - static long dateLastRendered; - static String dateCache; - - // buffer for log items - private List entries; - - // fields used for logging to files - private String filename; - private File logdir; - private File logfile; - private PrintWriter writer; - - // the canonical name for this logger - String canonicalName; - - // used when logging to a PrintStream such as System.out - private PrintStream out = null; - - // flag to tell runner thread if this log should be closed/discarded - boolean closed = false; - - // number format for log file rotation - DecimalFormat nformat = new DecimalFormat("000"); - DateFormat aformat = new SimpleDateFormat("yyyy-MM-dd"); - - /** - * Create a logger for a PrintStream, such as System.out. - */ - public Logger(PrintStream out) { - this.out = out; - canonicalName = out.toString(); - - // create a synchronized list for log entries since different threads may - // attempt to modify the list at the same time - entries = Collections.synchronizedList(new LinkedList()); - - // register this instance with static logger list - start(this); - } - - /** - * Create a file logger. The actual file names do have numbers appended and are - * rotated every x bytes. - */ - private Logger(String dirname, String filename) { - this.filename = filename; - logdir = new File(dirname); - logfile = new File(logdir, filename + ".log"); - - try { - canonicalName = logfile.getCanonicalPath(); - } catch (IOException iox) { - canonicalName = logfile.getAbsolutePath(); - } - - if (!logdir.exists()) { - logdir.mkdirs(); - } - - try { - if (logfile.exists() && (logfile.lastModified() < lastMidnight())) { - // rotate if a log file exists and is NOT from today - rotateLogFile(); - } else { - // create a new log file, append to an existing file - writer = new PrintWriter(new FileWriter(logfile.getAbsolutePath(), true), - false); - } - } catch (IOException iox) { - System.err.println("Error creating log " + canonicalName + ": " + iox); - } - - // create a synchronized list for log entries since different threads may - // attempt to modify the list at the same time - entries = Collections.synchronizedList(new LinkedList()); - - // register this instance with static logger list - start(this); - } - - /** - * Get a logger with a symbolic file name within a directory. - */ - public static synchronized Logger getLogger(String dirname, String filename) { - if ((filename == null) || (dirname == null)) { - throw new RuntimeException("Logger can't use null as file or directory name"); - } - - File file = new File(dirname, filename + ".log"); - Logger log = null; - - if (loggerMap != null) { - try { - log = (Logger) loggerMap.get(file.getCanonicalPath()); - } catch (IOException iox) { - log = (Logger) loggerMap.get(file.getAbsolutePath()); - } - } - - if ((log == null) || log.isClosed()) { - log = new Logger(dirname, filename); - } - - return log; - } - - /** - * Append a message to the log. - */ - public void log(String msg) { - // if we are closed, drop message without further notice - if (closed) { - return; - } - - // it's enough to render the date every 5 seconds - if ((System.currentTimeMillis() - 5000) > dateLastRendered) { - renderDate(); - } - - entries.add(dateCache + msg); - } - - private static synchronized void renderDate() { - dateLastRendered = System.currentTimeMillis(); - dateCache = dformat.format(new Date()); - } - - /** - * Return an object which identifies this logger. - */ - public String getCanonicalName() { - return canonicalName; - } - - /** - * Get the list of unwritten entries - */ - public List getEntries() { - return entries; - } - - /** - * This is called by the runner thread to perform actual output. - */ - public void write() { - if (entries.isEmpty()) { - return; - } - - try { - int l = entries.size(); - - // check if writing to printstream or file - if (out != null) { - for (int i = 0; i < l; i++) { - String entry = (String) entries.get(0); - - entries.remove(0); - out.println(entry); - } - } else { - if ((writer == null) || !logfile.exists() || !logfile.canWrite()) { - // rotate the log file if we can't write to it - rotateLogFile(); - } - - for (int i = 0; i < l; i++) { - String entry = (String) entries.get(0); - - entries.remove(0); - writer.println(entry); - } - - writer.flush(); - } - } catch (Exception x) { - int e = entries.size(); - - if (e > 1000) { - // more than 1000 entries queued plus exception - something - // is definitely wrong with this logger. Write a message to std err and - // discard queued log entries. - System.err.println("Error writing log file " + this + ": " + x); - System.err.println("Discarding " + e + " log entries."); - entries.clear(); - } - } - } - - /** - * Rotate log files, closing, renaming and gzipping the old file and - * start a new one. - */ - private void rotateLogFile() throws IOException { - // if the logger is not file based do nothing. - if (logfile == null) { - return; - } - - if (writer != null) { - try { - writer.close(); - } catch (Exception ignore) { - } - } - - // only backup/rotate if the log file is not empty, - if (logfile.exists() && (logfile.length() > 0)) { - String today = aformat.format(new Date()); - int ct = 0; - File archive = null; - - // first append just the date - String archname = filename + "-" + today + ".log.gz"; - - while ((archive == null) || archive.exists()) { - archive = new File(logdir, archname); - - // for the next try we append a counter - String archidx = (ct > 999) ? Integer.toString(ct) : nformat.format(++ct); - - archname = filename + "-" + today + "-" + archidx + ".log.gz"; - } - - if (logfile.renameTo(archive)) { - (new GZipper(archive)).start(); - } else { - System.err.println("Error rotating log file " + canonicalName + - ". Old file will possibly be overwritten!"); - } - } - - writer = new PrintWriter(new FileWriter(logfile), false); - } - - /** - * Tell whether this log is closed. - */ - public boolean isClosed() { - return closed; - } - - /** - * Tells a log to close down. Only the flag is set, the actual closing is - * done by the runner thread next time it comes around. - */ - public void close() { - this.closed = true; - } - - /** - * Actually closes the file writer of a log. - */ - void closeFiles() { - if (writer != null) { - try { - writer.close(); - } catch (Exception ignore) { - } - } - } - - /** - * Return a string representation of this Logger - */ - public String toString() { - return "Logger[" + canonicalName + "]"; - } - - /** - * Add a log to the list of logs and - * create and start the runner thread if necessary. - */ - static synchronized void start(Logger log) { - if (loggers == null) { - loggers = new ArrayList(); - } - - if (loggerMap == null) { - loggerMap = new HashMap(); - } - - loggers.add(log); - loggerMap.put(log.canonicalName, log); - - if ((runner == null) || !runner.isAlive()) { - runner = new Runner(); - runner.start(); - } - } - - /** - * Return a list of all active Loggers - */ - public static List getLoggers() { - if (loggers == null) { - return null; - } - - return (List) loggers.clone(); - } - - /** - * Notify the runner thread that it should wake up and run. - */ - public static void wakeup() { - if (runner != null) { - runner.wakeup(); - } - } - - private static void rotateAllLogs() { - int nloggers = loggers.size(); - - for (int i = nloggers - 1; i >= 0; i--) { - Logger log = (Logger) loggers.get(i); - - try { - log.rotateLogFile(); - } catch (IOException io) { - System.err.println("Error rotating log " + log.getCanonicalName() + ": " + - io.toString()); - } - } - } - - /** - * - * - * @return ... - */ - public static long nextMidnight() { - Calendar cal = Calendar.getInstance(); - - cal.set(Calendar.DATE, 1 + cal.get(Calendar.DATE)); - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 1); - - // for testing, rotate the logs every minute: - // cal.set (Calendar.MINUTE, 1 + cal.get(Calendar.MINUTE)); - return cal.getTime().getTime(); - } - - /** - * - * - * @return ... - */ - public static long lastMidnight() { - return nextMidnight() - 86400000; - } - - /** - * test main method - */ - public static void main(String[] args) throws IOException { - Logger log = new Logger(".", "testlog"); - long start = System.currentTimeMillis(); - - for (int i = 0; i < 1000; i++) { - log.log("test log entry " + i); - - try { - Thread.sleep(100); - } catch (InterruptedException ie) { - } - } - - log.log("done: " + (System.currentTimeMillis() - start)); - System.err.println(System.currentTimeMillis() - start); - log.close(); - - // System.exit (0); - } - - /** - * The static runner class that loops through all loggers. - */ - static class Runner extends Thread { - public synchronized void run() { - long nextMidnight = nextMidnight(); - - while ((runner == this) && !isInterrupted()) { - if (nextMidnight < System.currentTimeMillis()) { - rotateAllLogs(); - nextMidnight = nextMidnight(); - } - - int nloggers = loggers.size(); - - for (int i = nloggers - 1; i >= 0; i--) { - try { - Logger log = (Logger) loggers.get(i); - - log.write(); - - if (log.closed && log.entries.isEmpty()) { - loggers.remove(log); - log.closeFiles(); - } - } catch (Exception x) { - System.err.println("Error in Logger main loop: " + x); - } - } - - // if there are no active logs, exit logger thread - if (loggers.size() == 0) { - return; - } - - try { - wait(250); - } catch (InterruptedException ix) { - } - } - } - - public synchronized void wakeup() { - notifyAll(); - } - } - - /** - * a Thread class that zips up a file, filename will stay the same. - */ - class GZipper extends Thread { - File file; - File temp; - - public GZipper(File file) { - this.file = file; - this.temp = new File(file.getAbsolutePath() + ".tmp"); - } - - public void run() { - try { - GZIPOutputStream zip = new GZIPOutputStream(new FileOutputStream(temp)); - BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); - byte[] b = new byte[1024]; - int len = 0; - - while ((len = in.read(b, 0, 1024)) != -1) { - zip.write(b, 0, len); - } - - zip.close(); - in.close(); - file.delete(); - temp.renameTo(file); - } catch (Exception e) { - System.err.println(e.toString()); - } - } - } -} diff --git a/src/helma/util/Logo.java b/src/helma/util/Logo.java deleted file mode 100644 index bbddbab8..00000000 --- a/src/helma/util/Logo.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.FileInputStream; - -/** - * class with byte data of helma logo - */ -public class Logo { - public static final byte[] hop = { - 71, 73, 70, 56, 57, 97, -82, 0, 35, 0, -60, 0, 0, - -1, -1, -1, -17, -17, -17, -33, -33, -33, -52, - -52, -52, -67, -67, -67, -84, -84, -84, -103, - -103, -103, -119, -119, -119, 120, 120, 120, 102, - 102, 102, 84, 84, 84, 67, 67, 67, 51, 51, 51, 33, - 33, 33, 18, 18, 18, 0, 0, 0, -2, 1, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 33, -7, 4, 4, 20, 0, -1, 0, - 44, 0, 0, 0, 0, -82, 0, 35, 0, 0, 5, -1, 32, 32, - -114, 100, 105, -98, 104, -86, -82, 108, -21, -66, - 112, 44, -49, 116, 109, -33, 120, -82, -45, -61, - -79, 52, -114, 96, 67, 113, 24, -20, -114, -56, - -92, -78, 21, 32, 32, 22, -63, -121, 116, 74, 109, - 44, -118, -127, -91, 118, -53, 125, 5, 122, 63, 7, - 117, 76, -106, 58, -84, -40, -82, 122, -83, 28, - 24, -62, -27, -72, -4, 113, 78, 20, -78, -20, -68, - -34, 21, 40, 36, 24, 98, 115, -126, -126, 14, 12, - 8, 4, 120, 123, -118, 122, 2, 5, 10, -127, -125, - -111, -111, 117, -120, -117, -106, 92, 5, -128, - -110, -101, -100, -123, 4, -105, -96, 72, 4, 64, - -100, -91, -110, 103, 70, -95, -86, 55, 9, -112, - 83, 12, 11, 12, -111, 86, 11, -90, 100, 14, 9, 47, - 4, 4, 2, 57, 77, -107, 55, -69, -67, 36, -65, - -119, 42, 2, -69, 54, -78, 100, -97, 4, -111, 8, - 34, -74, 100, 12, 47, 82, -48, 36, -50, 15, -97, - -70, 82, -37, 54, -42, 37, -39, -37, -75, 11, 40, - 8, 82, 54, -82, 83, 34, -25, -125, -51, -46, 99, - 14, 46, -30, 37, -19, -58, 44, -19, 56, -12, 36, - -7, -47, 15, -41, 38, -56, -91, -101, 38, 34, -63, - -126, 90, 85, -96, 76, -55, 114, 96, -116, -107, - 6, 15, -84, -72, 114, 112, 80, -99, -68, 19, -55, - 70, 52, 124, 48, -128, -41, 8, 100, -34, 0, 16, - 72, -11, 17, 24, 0, 5, 15, -88, -1, -91, 64, 118, - -49, -60, -58, -114, -61, 78, -90, 28, 33, -116, - -90, 55, 49, 9, 58, -34, 27, 105, -94, 35, 9, 117, - 15, 114, 1, -64, 51, -64, 76, 1, 17, 1, 106, 53, - 40, 40, -91, -41, -80, 0, 6, -112, 66, 124, 112, - -128, 4, -54, 41, 23, 73, 24, 8, -60, 0, 79, 2, - 51, 82, -114, 2, -112, -91, 64, 68, -127, 64, 101, - -121, 34, 116, 96, 100, -86, 20, -110, 34, 32, 78, - 117, -48, -53, 64, 83, 1, 82, -86, 126, -91, 19, - 54, 110, 80, 17, 118, 57, 2, 24, 48, 87, 0, 94, - -66, 116, -122, -99, -107, -110, 86, -82, -108, - 68, 64, -85, 2, 64, -112, 10, -30, 81, 3, -48, - -20, -90, -107, 117, -111, 64, 84, 0, 5, -60, -18, - 69, -96, 96, 65, -81, 108, 102, -62, -47, 41, 0, - 81, -78, -84, 6, 8, -60, -108, 3, 0, -82, -88, 3, - -42, 15, 122, -43, -6, -13, 15, -76, -75, -112, - 67, -91, 44, 24, 61, -103, -114, 111, 109, 99, 35, - -58, 126, 80, 46, 64, 94, 118, -24, 0, -120, 65, - 32, -117, 64, 1, 41, 9, -82, 70, -75, -115, 91, - -128, -13, -120, 7, 127, 50, 19, -39, -101, -10, - 108, -118, -28, -81, 9, 23, 17, 30, 64, 123, -124, - -122, 14, -111, -57, 90, -94, 22, 52, -5, -2, -96, - -111, -99, -1, 9, 127, -83, 93, -113, 61, 17, -43, - 62, -40, 116, -13, 93, 85, 2, -11, 3, -50, -1, - 126, -5, 8, -108, -51, 23, -120, -28, 67, -113, - 127, -38, 16, 56, 2, 80, 34, 52, -12, 73, 81, 81, - 5, 32, -33, 57, 27, -126, 35, -35, 53, 14, -112, - 72, 85, 9, 27, -91, -10, 81, 95, -32, 100, 115, - 20, 56, 27, 5, 112, -104, 2, -7, 124, -91, -46, 8, - -3, -44, -13, 24, 61, -32, -44, 66, -115, -117, - -76, -11, 102, 79, 126, -13, 1, -28, 99, 113, 15, - -56, -56, 88, 62, 67, -106, -96, -114, 74, 95, - 101, 97, 87, 76, 76, -43, -43, 23, 94, 71, 97, 9, - 0, 94, 42, 61, -63, 20, 125, 35, 4, -10, 69, 95, - 27, 9, 80, -44, 3, 71, 125, -75, 84, 96, 83, 44, - 5, -111, 80, 35, -96, 116, -93, 85, 17, 1, 16, - -29, -103, 71, -31, 100, 103, 83, 120, 2, -96, - -90, 8, 103, 118, 24, -56, 103, 122, -94, -76, - -90, 67, 50, 45, 101, -126, 58, 66, 49, -96, 104, - 108, -48, -127, -39, 78, 47, -41, 81, -102, -101, - 111, 85, 57, -41, 40, 21, 89, 21, 39, 79, 96, -67, - -4, 9, 106, 114, 101, -99, -45, -23, -127, 37, - -68, 121, 2, 68, 101, -119, 122, -41, 115, -82, - 94, -70, 31, 0, -127, -91, 18, 24, 93, -121, 85, - -59, -86, -89, -87, 62, -112, -106, -109, 99, 72, - -26, 43, 123, -77, 33, -76, -98, 123, -58, 77, - 118, 17, -92, -59, -67, -93, 30, -89, 36, 36, 88, - 39, -87, -59, 41, -38, 35, -1, 115, 5, 34, 55, 2, - -86, 37, 124, -89, -33, 95, -90, 30, -9, -55, 126, - -25, 88, 91, 94, -114, 72, 90, 103, -32, -75, -77, - 33, 37, 34, -80, 84, 56, 27, -51, 121, -80, -31, - 23, 100, -79, -8, -78, 119, 41, -120, -13, -127, - -87, 47, 52, 16, 61, -5, 109, 46, 19, -10, -122, - -39, 124, 125, 32, 112, 90, 55, 38, -120, -13, 93, - 84, -46, 62, 64, -92, 44, 4, 51, -116, 108, 57, 2, - 32, 16, 85, 55, 18, 50, -116, -33, -63, 22, 94, - 56, 70, -122, -56, -99, 41, 101, 91, 104, -118, - 32, 11, -119, 44, -117, 32, -58, 81, 61, 48, 20, - 15, 9, 13, 13, -111, 82, 22, -39, 40, -16, 21, 93, - 123, 38, -71, 39, 108, 127, 121, 123, -122, 8, - -39, 32, 112, 79, 59, 6, -51, -124, 44, 115, 98, - -4, -56, -40, -50, -67, 108, 36, 108, 111, -50, - -40, 76, -51, -111, 67, -42, 124, 78, 46, 77, -62, - 43, 5, -108, 62, 7, -106, 64, 22, 3, 92, -107, - -106, 93, 89, -90, -84, -27, 97, 12, -100, -106, - -59, 94, 109, 18, -77, -13, -40, 36, 59, -102, 82, - 42, 127, -86, 69, 7, -35, -76, -54, -106, 74, 82, - 77, -107, -128, 18, 90, -61, 108, -107, -46, 110, - 123, -38, -51, 64, 42, 2, -120, -79, 84, -96, 34, - -104, -99, 69, -95, -45, 2, -114, 75, 22, -122, - -94, -32, 22, 60, -100, -113, 49, 103, 12, -86, - -22, -80, -21, 125, 42, 48, 40, -44, -7, -23, 123, - -53, 32, 0, 3, -100, -63, 101, 3, -73, -92, -69, - 112, -64, -26, -88, -37, -30, -119, 12, 3, 28, - -108, -45, 14, -71, 47, -32, 122, -20, 43, 32, 64, - 74, -19, -90, 20, 34, 22, -16, -56, -65, -48, - -120, -23, -60, 15, 66, -111, 1, 45, 37, 47, -3, - 10, -115, 40, 48, 124, -13, 85, 40, 80, 0, -107, - -45, 119, -17, -123, 19, -102, -44, 94, -56, 33, - -47, 123, 111, -2, -9, -44, 69, 81, -54, -8, -37, - -97, -17, -66, 14, 77, 60, -95, 126, 28, 20, -111, - -1, -2, -3, 109, 28, -96, 0, 32, 66, 16, 49, 64, - -7, -8, 11, -96, 0, 7, -56, -122, 16, 0, 0, 59 - }; - - /** - * utitilty function to create byte array from file - */ - public static void main(String[] args) throws Exception { - FileInputStream fis = new FileInputStream(args[0]); - byte[] b = new byte[256]; - int linect = 0; - int ct = 0; - - System.out.print("\n\n\n static byte[] image = {\n "); - - while (ct > -1) { - ct = fis.read(b); - - for (int i = 0; i < ct; i++) { - System.out.print(b[i] + ","); - linect++; - - if (linect > 30) { - linect = 0; - System.out.print("\n "); - } - } - } - - System.out.print(" };\n\n\n"); - } -} diff --git a/src/helma/util/MD5Encoder.java b/src/helma/util/MD5Encoder.java deleted file mode 100644 index ee4e5a96..00000000 --- a/src/helma/util/MD5Encoder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * - */ -public class MD5Encoder { - private static MessageDigest md; - - /** used by commandline script to create admin username & password */ - public static void main(String[] args) throws Exception { - if (args.length < 2) { - System.out.println("\n\nUsage: helma.util.MD5Encoder "); - System.out.println("Output:"); - System.out.println("adminUsername="); - System.out.println("adminPassword=\n"); - System.exit(0); - } - - System.out.println("adminUsername=" + encode(args[0])); - System.out.println("adminPassword=" + encode(args[1])); - } - - /** - * - * - * @param str ... - * - * @return ... - * - * @throws NoSuchAlgorithmException ... - */ - public static String encode(String str) throws NoSuchAlgorithmException { - return encode(str.getBytes()); - } - - /** - * - * - * @param message ... - * - * @return ... - * - * @throws NoSuchAlgorithmException ... - */ - public static String encode(byte[] message) throws NoSuchAlgorithmException { - md = MessageDigest.getInstance("MD5"); - - byte[] b = md.digest(message); - StringBuffer buf = new StringBuffer(b.length * 2); - - for (int i = 0; i < b.length; i++) { - int j = (b[i] < 0) ? (256 + b[i]) : b[i]; - - if (j < 16) { - buf.append("0"); - } - - buf.append(Integer.toHexString(j)); - } - - return buf.toString(); - } - - /** - * Convert a long to a byte array. - */ - public static byte[] toBytes(long n) { - byte[] b = new byte[8]; - - b[0] = (byte) (n); - n >>>= 8; - b[1] = (byte) (n); - n >>>= 8; - b[2] = (byte) (n); - n >>>= 8; - b[3] = (byte) (n); - n >>>= 8; - b[4] = (byte) (n); - n >>>= 8; - b[5] = (byte) (n); - n >>>= 8; - b[6] = (byte) (n); - n >>>= 8; - b[7] = (byte) (n); - - return b; - } -} diff --git a/src/helma/util/MimePart.java b/src/helma/util/MimePart.java deleted file mode 100644 index fa18937e..00000000 --- a/src/helma/util/MimePart.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.*; -import java.util.Date; - -/** - * This represents a MIME part of a HTTP file upload - */ -public class MimePart implements Serializable { - public final String name; - public int contentLength; - public String contentType; - private byte[] content; - public Date lastModified; - public String eTag; - - /** - * Creates a new MimePart object. - * - * @param name ... - * @param content ... - * @param contentType ... - */ - public MimePart(String name, byte[] content, String contentType) { - this.name = name; - this.content = (content == null) ? new byte[0] : content; - this.contentType = contentType; - contentLength = (content == null) ? 0 : content.length; - } - - /** - * - * - * @return ... - */ - public String getContentType() { - return contentType; - } - - /** - * - * - * @return ... - */ - public int getContentLength() { - return contentLength; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } - - /** - * - * - * @return ... - */ - public byte[] getContent() { - return content; - } - - /** - * - * - * @return ... - */ - public String getText() { - if ((contentType == null) || contentType.startsWith("text/")) { - // FIXME: check for encoding - return new String(content); - } else { - return null; - } - } - - /** - * - * - * @param dir ... - * - * @return ... - */ - public String writeToFile(String dir) { - return writeToFile(dir, null); - } - - /** - * - * - * @param dir ... - * @param fname ... - * - * @return ... - */ - public String writeToFile(String dir, String fname) { - try { - File base = new File(dir); - - // make directories if they don't exist - if (!base.exists()) { - base.mkdirs(); - } - - String filename = name; - - if (fname != null) { - if (fname.indexOf(".") < 0) { - // check if we can use extension from name - int ndot = (name == null) ? (-1) : name.lastIndexOf("."); - - if (ndot > -1) { - filename = fname + name.substring(ndot); - } else { - filename = fname; - } - } else { - filename = fname; - } - } - - File file = new File(base, filename); - FileOutputStream fout = new FileOutputStream(file); - - fout.write(getContent()); - fout.close(); - - return filename; - } catch (Exception x) { - return null; - } - } -} diff --git a/src/helma/util/MimePartDataSource.java b/src/helma/util/MimePartDataSource.java deleted file mode 100644 index 7cd7fac7..00000000 --- a/src/helma/util/MimePartDataSource.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.*; -import javax.activation.*; - -/** - * Makes MimeParts usable as Datasources in the Java Activation Framework (JAF) - */ -public class MimePartDataSource implements DataSource { - private MimePart part; - private String name; - - /** - * Creates a new MimePartDataSource object. - * - * @param part ... - */ - public MimePartDataSource(MimePart part) { - this.part = part; - this.name = part.getName(); - } - - /** - * Creates a new MimePartDataSource object. - * - * @param part ... - * @param name ... - */ - public MimePartDataSource(MimePart part, String name) { - this.part = part; - this.name = name; - } - - /** - * - * - * @return ... - * - * @throws IOException ... - */ - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(part.getContent()); - } - - /** - * - * - * @return ... - * - * @throws IOException ... - */ - public OutputStream getOutputStream() throws IOException { - throw new IOException("Can't write to MimePart object."); - } - - /** - * - * - * @return ... - */ - public String getContentType() { - return part.contentType; - } - - /** - * - * - * @return ... - */ - public String getName() { - return name; - } -} diff --git a/src/helma/util/ParanoidServerSocket.java b/src/helma/util/ParanoidServerSocket.java deleted file mode 100644 index 30044d86..00000000 --- a/src/helma/util/ParanoidServerSocket.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.IOException; -import java.net.*; - -/** - * A server socket that can allow connections to only a few selected hosts. - */ -public class ParanoidServerSocket extends ServerSocket { - private InetAddressFilter filter; - - /** - * Creates a new ParanoidServerSocket object. - * - * @param port ... - * - * @throws IOException ... - */ - public ParanoidServerSocket(int port) throws IOException { - super(port); - } - - /** - * Creates a new ParanoidServerSocket object. - * - * @param port ... - * @param filter ... - * - * @throws IOException ... - */ - public ParanoidServerSocket(int port, InetAddressFilter filter) - throws IOException { - super(port); - this.filter = filter; - } - - /** - * - * - * @return ... - * - * @throws IOException ... - */ - public Socket accept() throws IOException { - Socket s = null; - - while (s == null) { - s = super.accept(); - - if ((filter != null) && !filter.matches(s.getInetAddress())) { - System.err.println("Refusing connection from " + s.getInetAddress()); - - try { - s.close(); - } catch (IOException ignore) { - } - - s = null; - } - } - - return s; - } - - /** - * - * - * @param filter ... - */ - public void setFilter(InetAddressFilter filter) { - this.filter = filter; - } - - /** - * - * - * @return ... - */ - public InetAddressFilter getFilter() { - return this.filter; - } -} diff --git a/src/helma/util/StringUtils.java b/src/helma/util/StringUtils.java deleted file mode 100644 index 34ddea38..00000000 --- a/src/helma/util/StringUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - - -import java.util.StringTokenizer; - -/** - * Utility class for String manipulation. - */ -public class StringUtils { - - - /** - * Split a string into an array of strings. Use comma and space - * as delimiters. - */ - public static String[] split(String str) { - return split(str, ", \t\n\r\f"); - } - - /** - * Split a string into an array of strings. - */ - public static String[] split(String str, String delim) { - if (str == null) { - return new String[0]; - } - StringTokenizer st = new StringTokenizer(str, delim); - String[] s = new String[st.countTokens()]; - for (int i=0; i lastread)) { - readFile(); - } - - lastcheck = System.currentTimeMillis(); - } - - /** - * Private method to read the underlying properties file. Assumes that the - * file exists and is readable. - */ - private synchronized void readFile() { - // IServer.getLogger().log ("Reading properties from file "+file); - FileInputStream bpin = null; - - try { - bpin = new FileInputStream(file); - load(bpin); - } catch (Exception x) { - System.err.println("Error reading properties from file " + file + ": " + x); - } finally { - try { - bpin.close(); - } catch (Exception ignore) { - } - } - } - - /** - * - * - * @param in ... - * - * @throws IOException ... - */ - public synchronized void load(InputStream in) throws IOException { - clear(); - super.load(in); - - if (additionalProps != null) { - for (Iterator i = additionalProps.values().iterator(); i.hasNext();) - putAll((Properties) i.next()); - } - - lastread = System.currentTimeMillis(); - } - - /** - * Similar to load(), but adds to the existing properties instead - * of discarding them. - */ - public synchronized void addProps(String key, InputStream in) - throws IOException { - Properties p = new SystemProperties(); - - p.load(in); - - if (additionalProps == null) { - additionalProps = new HashMap(); - } - - additionalProps.put(key, p); - putAll(p); - lastadd = System.currentTimeMillis(); - } - - /** - * Remove an additional properties dictionary. - */ - public synchronized void removeProps(String key) { - if (additionalProps != null) { - // remove added properties for this key. If we had - // properties associated with the key, mark props as updated. - Object p = additionalProps.remove(key); - - if (p != null) { - lastadd = System.currentTimeMillis(); - } - } - } - - /* - * This should not be used directly if properties are read from file, - * otherwise changes will be lost whe the file is next modified. - */ - public Object put(Object key, Object value) { - // cut off trailing whitespace - if (value != null) { - value = value.toString().trim(); - } - - return super.put(ignoreCase ? key.toString().toLowerCase() : key, value); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public Object get(Object key) { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.get(ignoreCase ? key.toString().toLowerCase() : key); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public Object remove(Object key) { - return super.remove(ignoreCase ? key.toString().toLowerCase() : key); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public boolean contains(Object obj) { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.contains(obj); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public boolean containsKey(Object key) { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.containsKey(ignoreCase ? key.toString().toLowerCase() : key); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public boolean isEmpty() { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.isEmpty(); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public String getProperty(String name) { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.getProperty(ignoreCase ? name.toLowerCase() : name); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public String getProperty(String name, String defaultValue) { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.getProperty(ignoreCase ? - name.toLowerCase() : name.toLowerCase(), defaultValue); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public Enumeration keys() { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.keys(); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public Set keySet() { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.keySet(); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public Enumeration elements() { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.elements(); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public int size() { - if ((System.currentTimeMillis() - lastcheck) > cacheTime) { - checkFile(); - } - - return super.size(); - } - - /** - * Overrides method to act on the wrapped properties object. - */ - public String toString() { - return super.toString(); - } - - /** - * Turns case sensitivity for keys in this Map on or off. - */ - public void setIgnoreCase(boolean ignore) { - if (!super.isEmpty()) { - throw new RuntimeException("setIgnoreCase() can only be called on empty Properties"); - } - ignoreCase = ignore; - } - - /** - * Returns true if this property map ignores key case - */ - public boolean isIgnoreCase() { - return ignoreCase; - } - -} diff --git a/src/helma/util/Timer.java b/src/helma/util/Timer.java deleted file mode 100644 index c59a5ee5..00000000 --- a/src/helma/util/Timer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.PrintStream; -import java.util.*; - -/** - * Utility class for timing a series of events - */ -public class Timer { - private Vector timeline; - private Hashtable events; - - /** - * Creates a new Timer object. - */ - public Timer() { - timeline = new Vector(); - events = new Hashtable(); - } - - /** - * - */ - public void reset() { - timeline.setSize(0); - events.clear(); - } - - /** - * - * - * @param name ... - */ - public void beginEvent(String name) { - timeline.addElement(name); - events.put(name, new Event(name)); - } - - /** - * - * - * @param name ... - */ - public void endEvent(String name) { - Event event = (Event) events.get(name); - - if (event != null) { - event.terminate(); - } - } - - /** - * - * - * @param out ... - */ - public void dump(PrintStream out) { - for (int i = 0; i < timeline.size(); i++) { - String name = (String) timeline.elementAt(i); - Event event = (Event) events.get(name); - - out.println(event); - } - } - - class Event { - String name; - long start; - long end; - - Event(String name) { - this.name = name; - start = System.currentTimeMillis(); - } - - void terminate() { - end = System.currentTimeMillis(); - } - - public String toString() { - long now = System.currentTimeMillis(); - - if (end == 0L) { - return (" + " + (now - start) + " " + name); - } else { - return (" " + (end - start) + " " + name); - } - } - } -} diff --git a/src/helma/util/Updatable.java b/src/helma/util/Updatable.java deleted file mode 100644 index 5a81f5d5..00000000 --- a/src/helma/util/Updatable.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - - -/** - * An interface of classes that can update themselves and know when to do so. - */ -public interface Updatable { - /** - * - * - * @return ... - */ - public boolean needsUpdate(); - - /** - * - */ - public void update(); - - /** - * - */ - public void remove(); -} diff --git a/src/helma/util/UrlEncoded.java b/src/helma/util/UrlEncoded.java deleted file mode 100644 index bc1db426..00000000 --- a/src/helma/util/UrlEncoded.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.net.URLEncoder; - -/** - * A proxy to java.net.URLEncoder which only encodes when - * there is actual work to do. This is necessary because - * URLEncoder is quite inefficient (e.g. it preallocates - * buffers and stuff), and we call it often with - * short string that don't need encoding. - */ -public final class UrlEncoded { - /** - * - * - * @param str ... - * - * @return ... - */ - public static String encode(String str) { - int l = str.length(); - boolean needsSpaceEncoding = false; - - for (int i = 0; i < l; i++) { - char c = str.charAt(i); - - if (c == ' ') { - needsSpaceEncoding = true; - } else if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || - ((c >= '0') && (c <= '9')))) { - return URLEncoder.encode(str); - } - } - - if (needsSpaceEncoding) { - return str.replace(' ', '+'); - } - - return str; - } -} diff --git a/src/helma/util/WebBroadcaster.java b/src/helma/util/WebBroadcaster.java deleted file mode 100644 index 8fe891d4..00000000 --- a/src/helma/util/WebBroadcaster.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.io.*; -import java.net.*; -import java.util.*; - -/** - * A utility hack to do "html web broadcasts". - */ -public class WebBroadcaster implements Runnable { - static String lastResult = ""; - static String reloadJS = "\r\n\r\n"; - static String scrollJS = "\r\n\r\n\r\n"; - private Vector connections; - private ServerSocket serverSocket; - private Thread listener; - private boolean paranoid; - private Vector accept; - private Vector deny; - long time; - int last; - - /** - * Creates a Web server at the specified port number. - */ - public WebBroadcaster(int port) throws IOException { - super(); - connections = new Vector(); - accept = new Vector(); - deny = new Vector(); - - // make a new server socket with extra large queue size - this.serverSocket = new ServerSocket(port, 2000); - listener = new Thread(this); - listener.start(); - } - - /** - * - */ - public static void main(String[] args) { - System.out.println("Usage: java helma.util.WebBroadcaster [port]"); - - int p = 8080; - - if (args.length > 0) { - try { - p = Integer.parseInt(args[0]); - } catch (NumberFormatException nfx) { - System.out.println("Error parsing port number: " + args[0]); - } - } - - try { - WebBroadcaster server = new WebBroadcaster(p); - - // webserver.setParanoid (false); - // webserver.acceptClient ("192.168.*.*"); - System.out.println("started web broadcast server on port " + p); - } catch (IOException x) { - System.out.println("Error creating web broadcast server: " + x); - } - } - - /** - * - * - * @param message ... - */ - public void broadcast(String message) { - long start = System.currentTimeMillis(); - int l = connections.size(); - - synchronized (this) { - if (l != last) { - System.out.println("broadcasting to " + l + " clients in " + time + - " millis."); - last = l; - } - } - - for (int i = l - 1; i >= 0; i--) { - try { - Connection c = (Connection) connections.elementAt(i); - - c.send(message); - } catch (Exception ignore) { - } - } - - time = System.currentTimeMillis() - start; - } - - /** - * Switch client filtering on/off. - * @see acceptClient(java.lang.String) - * @see denyClient(java.lang.String) - */ - public void setParanoid(boolean p) { - paranoid = p; - } - - /** - * Add an IP address to the list of accepted clients. The parameter can contain '*' as wildcard - * character, e.g. "192.168.*.*". You must call setParanoid(true) in order for this to have any - * effect. - * - * @see denyClient(java.lang.String) - * @see setParanoid(boolean) - */ - public void acceptClient(String address) throws IllegalArgumentException { - try { - AddressMatcher m = new AddressMatcher(address); - - accept.addElement(m); - } catch (Exception x) { - throw new IllegalArgumentException("\"" + address + - "\" does not represent a valid IP address"); - } - } - - /** - * Add an IP address to the list of denied clients. The parameter can contain '*' as wildcard - * character, e.g. "192.168.*.*". You must call setParanoid(true) in order for this to have any - * effect. - * - * @see acceptClient(java.lang.String) - * @see setParanoid(boolean) - */ - public void denyClient(String address) throws IllegalArgumentException { - try { - AddressMatcher m = new AddressMatcher(address); - - deny.addElement(m); - } catch (Exception x) { - throw new IllegalArgumentException("\"" + address + - "\" does not represent a valid IP address"); - } - } - - private boolean checkSocket(Socket s) { - int l = deny.size(); - byte[] address = s.getInetAddress().getAddress(); - - for (int i = 0; i < l; i++) { - AddressMatcher match = (AddressMatcher) deny.elementAt(i); - - if (match.matches(address)) { - return false; - } - } - - l = accept.size(); - - for (int i = 0; i < l; i++) { - AddressMatcher match = (AddressMatcher) accept.elementAt(i); - - if (match.matches(address)) { - return true; - } - } - - return false; - } - - /** - * Listens for client requests until stopped. - */ - public void run() { - Thread current = Thread.currentThread(); - - try { - while (listener == current) { - Socket socket = serverSocket.accept(); - - try { - // if (!paranoid || checkSocket (socket)) - new Connection(socket); - - // else - // socket.close (); - } catch (Exception x) { - System.out.println("Error in listener: " + x); - } - } - } catch (Exception exception) { - System.err.println("Error accepting Web connections (" + exception + ")."); - } finally { - try { - serverSocket.close(); - serverSocket = null; - } catch (IOException ignore) { - } - } - } - - class Connection implements Runnable { - private Socket socket; - private InputStream input; - private BufferedWriter output; - private Thread responder; - - public Connection(Socket socket) throws IOException { - super(); - this.socket = socket; - socket.setSoTimeout(30000); - input = new BufferedInputStream(socket.getInputStream()); - output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); - responder = new Thread(this); - responder.start(); - } - - /* public void run () { - Thread current = Thread.currentThread (); - if (current == cleaner) { - cleanup (); - } else if (current == responder) { - respond (); - } - } */ - public void run() { - boolean newConnection = false; - - try { - DataInputStream reader = new DataInputStream(input); - boolean keepalive = false; - int cycle = 0; - - // implement keep-alive connections - do { - // if (cycle > 0) System.out.println ("Reusing connection: "+cycle); - String line = reader.readLine(); - - if (line == null) { - throw new IOException("connection reset"); - } - - int contentLength = 0; - StringTokenizer tokens = new StringTokenizer(line); - String method = tokens.nextToken(); - String uri = tokens.nextToken(); - String httpversion = tokens.nextToken(); - - keepalive = "HTTP/1.1".equals(httpversion); - - do { - // System.out.println (line); - line = reader.readLine(); - - if (line != null) { - line = line.toLowerCase(); - - if (line.startsWith("content-length:")) { - contentLength = Integer.parseInt(line.substring(15).trim()); - } - - if (line.startsWith("connection:")) { - keepalive = line.indexOf("keep-alive") > -1; - } - } - } while ((line != null) && !line.equals("")); - - // System.out.println (""); - if ("GET".equals(method)) { - output.write(httpversion + " 200 OK\r\n"); - output.write("Server: helma.WebBroadcast\r\n"); - output.write("Content-Type: text/html\r\n"); - newConnection = uri.startsWith("/NEW"); - - if (!newConnection) { - output.write("Content-Length: 5\r\n"); - - if (keepalive) { - output.write("Connection: keep-alive\r\n"); - } - - output.write("\r\n"); - output.write("done."); - output.flush(); - cycle += 1; - - if (uri.startsWith("/MSG")) { - broadcast(uri + "
\r\n"); - } - - continue; - } - - output.write("Connection: close\r\n"); - output.write("\r\n"); - output.write(reloadJS); - output.write(scrollJS); - output.flush(); - - connections.addElement(this); - } else { - output.write("HTTP/1.0 400 Bad Request\r\n"); - output.write("Server: helma.WebBroadcast\r\n\r\n"); - output.write("Bad Request."); - - // output.write (lastResult); - output.flush(); - keepalive = false; - } - } while (keepalive && !newConnection); - } catch (Exception x) { - System.out.print("."); - } finally { - if (newConnection) { // leave connection open - - return; - } - - try { - output.close(); - } catch (IOException ignore) { - } - - try { - input.close(); - } catch (IOException ignore) { - } - - try { - socket.close(); - } catch (IOException ignore) { - } - } - } - - public void cleanup() { - } - - public synchronized void send(String message) { - try { - output.write(message); - output.flush(); - } catch (Exception exception) { - try { - connections.removeElement(this); - } catch (Exception ignore) { - } - - try { - output.close(); - } catch (IOException ignore) { - } - - try { - input.close(); - } catch (IOException ignore) { - } - - try { - socket.close(); - } catch (IOException ignore) { - } - } - } - - public String toString() { - return socket.getInetAddress().getHostName(); - } - } - - class AddressMatcher { - int[] pattern; - - public AddressMatcher(String address) throws Exception { - pattern = new int[4]; - - StringTokenizer st = new StringTokenizer(address, "."); - - if (st.countTokens() != 4) { - throw new Exception("\"" + address + - "\" does not represent a valid IP address"); - } - - for (int i = 0; i < 4; i++) { - String next = st.nextToken(); - - if ("*".equals(next)) { - pattern[i] = 256; - } else { - pattern[i] = (byte) Integer.parseInt(next); - } - } - } - - public boolean matches(byte[] address) { - for (int i = 0; i < 4; i++) { - if (pattern[i] > 255) { // wildcard - - continue; - } - - if (pattern[i] != address[i]) { - return false; - } - } - - return true; - } - } -} diff --git a/src/helma/util/WrappedMap.java b/src/helma/util/WrappedMap.java deleted file mode 100644 index 373a5de7..00000000 --- a/src/helma/util/WrappedMap.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import java.util.Map; -import java.util.Set; -import java.util.Collection; -import java.util.HashMap; - -/** - * A Map that wraps another map and can be set to read-only. - */ -public class WrappedMap implements Map { - - // the wrapped map - private Map wrapped = null; - - // is this map readonly? - boolean readonly = false; - - // isolate changes from the wrapped map? - boolean copyOnWrite = false; - - public final static int READ_ONLY = 1; - public final static int COPY_ON_WRITE = 2; - - /** - * Constructor - */ - public WrappedMap(Map map) { - if (map == null) { - throw new IllegalArgumentException( - "Argument must not be null in WrappedMap constructor"); - } - wrapped = map; - } - - /** - * Constructor - */ - public WrappedMap(Map map, int mode) { - this(map); - if (mode == READ_ONLY) { - readonly = true; - } else if (mode == COPY_ON_WRITE) { - copyOnWrite = true; - } - } - - /** - * Set the readonly flag on or off - */ - public void setReadonly(boolean ro) { - readonly = ro; - } - - /** - * Is this map readonly? - */ - public boolean isReadonly() { - return readonly; - } - - /** - * Set the copyOnWrite flag on or off - */ - public void setCopyOnWrite(boolean cow) { - copyOnWrite = cow; - } - - /** - * Is this map copyOnWrite? - */ - public boolean isCopyOnWrite() { - return copyOnWrite; - } - - // Methods from interface java.util.Map - - // these are just proxies to the wrapped map, except for - // readonly checks on modifiers. - - public int size() { - return wrapped.size(); - } - - public boolean isEmpty() { - return wrapped.isEmpty(); - } - - public boolean containsKey(Object key) { - return wrapped.containsKey(key); - } - - public boolean containsValue(Object value) { - return wrapped.containsValue(value); - } - - public Object get(Object key) { - return wrapped.get(key); - } - - // Modification Operations - check for readonly - - public Object put(Object key, Object value) { - if (readonly) { - throw new RuntimeException("Attempt to modify readonly map"); - } - if (copyOnWrite) { - wrapped = new HashMap (wrapped); - copyOnWrite = false; - } - return wrapped.put(key, value); - } - - public Object remove(Object key) { - if (readonly) { - throw new RuntimeException("Attempt to modify readonly map"); - } - if (copyOnWrite) { - wrapped = new HashMap (wrapped); - copyOnWrite = false; - } - return wrapped.remove(key); - } - - public void putAll(Map t) { - if (readonly) { - throw new RuntimeException("Attempt to modify readonly map"); - } - if (copyOnWrite) { - wrapped = new HashMap (wrapped); - copyOnWrite = false; - } - wrapped.putAll(t); - } - - public void clear() { - if (readonly) { - throw new RuntimeException("Attempt to modify readonly map"); - } - if (copyOnWrite) { - wrapped = new HashMap (wrapped); - copyOnWrite = false; - } - wrapped.clear(); - } - - - // Views - - public Set keySet() { - return wrapped.keySet(); - } - - public Collection values() { - return wrapped.values(); - } - - public Set entrySet() { - return wrapped.entrySet(); - } - - - // Comparison and hashing - - public boolean equals(Object o) { - return wrapped.equals(o); - } - - public int hashCode() { - return wrapped.hashCode(); - } - -} diff --git a/src/helma/util/XmlUtils.java b/src/helma/util/XmlUtils.java deleted file mode 100644 index df05f497..00000000 --- a/src/helma/util/XmlUtils.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.Parser; -import org.xml.sax.SAXException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.net.MalformedURLException; -import java.net.URL; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * - */ -public class XmlUtils { - private static DocumentBuilderFactory domBuilderFactory = null; - private static SAXParserFactory saxParserFactory = null; - - /** - * - * - * @param obj ... - * - * @return ... - * - * @throws SAXException ... - * @throws IOException ... - * @throws ParserConfigurationException ... - */ - public static Document parseXml(Object obj) - throws SAXException, IOException, - ParserConfigurationException { - if (domBuilderFactory == null) { - domBuilderFactory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); - } - - DocumentBuilder parser = domBuilderFactory.newDocumentBuilder(); - Document doc = null; - - if (obj instanceof String) { - try { - // first try to interpret string as URL - new URL(obj.toString()); - - doc = parser.parse(obj.toString()); - } catch (MalformedURLException nourl) { - // if not a URL, maybe it is the XML itself - doc = parser.parse(new InputSource(new StringReader(obj.toString()))); - } - } else if (obj instanceof InputStream) { - doc = parser.parse(new InputSource((InputStream) obj)); - } else if (obj instanceof Reader) { - doc = parser.parse(new InputSource((Reader) obj)); - } - - doc.normalize(); - - return doc; - } - - /** - * - * - * @param obj ... - * - * @return ... - * - * @throws SAXException ... - * @throws IOException ... - * @throws ParserConfigurationException ... - */ - public static Document parseHtml(Object obj) - throws SAXException, IOException, - ParserConfigurationException { - try { - Class.forName("org.apache.html.dom.HTMLBuilder"); - } catch (Throwable notfound) { - throw new IOException("Couldn't load nekohtml/Xerces HTML parser: " + - notfound); - } - - Document doc = null; - HtmlParser parser = new HtmlParser(); - - if (obj instanceof String) { - try { - // first try to interpret string as URL - URL url = new URL(obj.toString()); - - parser.parse(new InputStreamReader(url.openStream())); - } catch (MalformedURLException nourl) { - // if not a URL, maybe it is the XML itself - parser.parse(new StringReader(obj.toString())); - } - } else if (obj instanceof InputStream) { - parser.parse(new InputStreamReader((InputStream) obj)); - } else if (obj instanceof Reader) { - parser.parse((Reader) obj); - } - - doc = parser.getDocument(); - - return doc; - } -} diff --git a/src/helma/util/mime/LanguageTag.java b/src/helma/util/mime/LanguageTag.java deleted file mode 100644 index a1f42b13..00000000 --- a/src/helma/util/mime/LanguageTag.java +++ /dev/null @@ -1,161 +0,0 @@ -// LanguageTag.java -// $Id$ -// (c) COPYRIGHT MIT, INRIA and Keio, 1999 -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.*; -import java.io.*; - -/** - * This class is used to represent parsed Language tags, - * It creates a representation from a string based representation - * of the Language tag, as defined in RFC 1766 - * NOTE, we don't check that languages are defined according to ISO 639 - */ - -public class LanguageTag implements Serializable, Cloneable { - public static int NO_MATCH = -1; - public static int MATCH_LANGUAGE = 1; - public static int MATCH_SPECIFIC_LANGUAGE = 2; - // subtag is not dialect as subtype can be - // dialect or country identification or script variation, etc... - public static int MATCH_SUBTAG = 3; - public static int MATCH_SPECIFIC_SUBTAG = 4; - - /** - * String representation of the language - * - * @serial - */ - protected String language = null ; - /** - * String representation of subtag - * - * @serial - */ - protected String subtag = null ; - - /** - * external form of this language tag - * - * @serial - */ - protected String external = null ; - - /** - * How good the given LanguageTag matches the receiver of the method ? - * This method returns a matching level among: - *

- *
NO_MATCH
Language not matching,
- *
MATCH_LANGUAGE
Languages match roughly (with *),
- *
MATCH_SPECIFIC_LANGUAGE
Languages match exactly,
- *
MATCH_SUBTAG
Languages match, subtags matches roughly
- *
MATCH_SPECIFIC_SUBAG
Languages match, subtag matches exactly
- *
- * The matches are ranked from worst match to best match, a simple - * Max ( match[i], matched) will give the best match. - * @param other The other LanguageTag to match against ourself. - */ - - public int match (LanguageTag other) { - int match = NO_MATCH; - // match types: - if ( language.equals("*") || other.language.equals("*") ) { - match = MATCH_LANGUAGE; - } else if ( ! language.equalsIgnoreCase(other.language) ) { - return NO_MATCH ; - } else { - match = MATCH_SPECIFIC_LANGUAGE; - } - // match subtypes: - if ((subtag == null) || (other.subtag == null)) - return match; - if ( subtag.equals("*") || other.subtag.equals("*") ) { - match = MATCH_SUBTAG ; - } else if ( ! subtag.equalsIgnoreCase(other.subtag) ) { - return NO_MATCH; - } else { - match = MATCH_SPECIFIC_SUBTAG; - } - return match; - } - - /** - * A printable representation of this LanguageTag. - * The printed representation is guaranteed to be parseable by the - * String constructor. - */ - - public String toString () { - if ( external == null ) { - if (subtag != null) { - external = language + "-" + subtag; - } else { - external = language; - } - } - return external ; - } - - /** - * Get the language - * @return The language, encoded as a String. - */ - - public String getLanguage() { - return language; - } - - /** - * Get the subtag - * @return The subtag, encoded as a string - */ - - public String getSubtag() { - return language; - } - - /** - * Construct a Language tag from a spec - * @parameter spec, A string representing a LangateTag - */ - public LanguageTag(String spec) { - int strl = spec.length() ; - int start = 0, look = -1 ; - // skip leading/trailing blanks: - while ((start < strl) && (spec.charAt (start)) <= ' ') - start++ ; - while ((strl > start) && (spec.charAt (strl-1) <= ' ')) - strl-- ; - // get the type: - StringBuffer sb = new StringBuffer () ; - while ((start < strl) && ((look = spec.charAt(start)) != '-') - && ((look = spec.charAt(start)) != ';')) { - sb.append ((char) look) ; - start++ ; - } - this.language = sb.toString() ; - if ( look == '-' ) { - start++ ; - sb.setLength(0) ; - while ((start < strl) - && ((look = spec.charAt(start)) > ' ') && (look != ';')) { - sb.append ((char) look) ; - start++ ; - } - this.subtag = sb.toString() ; - } - } - - /** - * construct directly a language tag - * it NEEDS both language and subtype parameters - */ - - public LanguageTag(String language, String subtag) { - this.language = language; - this.subtag = subtag; - } -} diff --git a/src/helma/util/mime/MimeHeaderHolder.java b/src/helma/util/mime/MimeHeaderHolder.java deleted file mode 100644 index 886563dd..00000000 --- a/src/helma/util/mime/MimeHeaderHolder.java +++ /dev/null @@ -1,51 +0,0 @@ -// MimeHeaderHolder.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.io.*; - -public interface MimeHeaderHolder { - - /** - * A new header has been parsed. - * @param name The name of the encountered header. - * @param buf The byte buffer containing the value. - * @param off Offset of the header value in the above buffer. - * @param len Length of the value in the above header. - * @exception MimeParserException if the parsing failed - */ - - public void notifyHeader(String name, byte buf[], int off, int len) - throws MimeParserException; - - /** - * The parsing is now about to start, take any appropriate action. - * This hook can return a true boolean value to enforce - * the MIME parser into transparent mode (eg the parser will not - * try to parse any headers. - *

This hack is primarily defined for HTTP/0.9 support, it might - * also be usefull for other hacks. - * @param parser The Mime parser. - * @return A boolean true if the MimeParser shouldn't - * continue the parsing, false otherwise. - * @exception MimeParserException if the parsing failed - * @exception IOException if an IO error occurs. - */ - - public boolean notifyBeginParsing(MimeParser parser) - throws MimeParserException, IOException; - - /** - * All the headers have been parsed, take any appropriate actions. - * @param parser The Mime parser. - * @exception MimeParserException if the parsing failed - * @exception IOException if an IO error occurs. - */ - - public void notifyEndParsing(MimeParser parser) - throws MimeParserException, IOException; - -} diff --git a/src/helma/util/mime/MimeHeaders.java b/src/helma/util/mime/MimeHeaders.java deleted file mode 100644 index ff682b2e..00000000 --- a/src/helma/util/mime/MimeHeaders.java +++ /dev/null @@ -1,147 +0,0 @@ -// MimeHeaders.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.io.*; -import java.util.*; - -/** - * The most stupid MIME header holder. - * This class uses a hashtable mapping header names (as String), to header - * values (as String). Header names are lowered before entering the hashtable. - */ - -public class MimeHeaders implements MimeHeaderHolder { - Hashtable headers = null; - MimeParser parser = null; - - /** - * A new header has been parsed. - * @param name The name of the encountered header. - * @param buf The byte buffer containing the value. - * @param off Offset of the header value in the above buffer. - * @param len Length of the value in the above header. - * @exception MimeParserException if the parsing failed - */ - - public void notifyHeader(String name, byte buf[], int off, int len) - throws MimeParserException - { - String lname = name.toLowerCase(); - String oldval = null; - if ( headers == null ) { - headers = new Hashtable(5); - } else { - oldval = (String) headers.get(lname); - } - String newval = ((oldval != null) - ? oldval + "," + new String(buf, 0, off, len) - : new String(buf, 0, off, len)); - headers.put(lname, newval); - } - - /** - * The parsing is now about to start, take any appropriate action. - * This hook can return a true boolean value to enforce - * the MIME parser into transparent mode (eg the parser will not - * try to parse any headers. - *

This hack is primarily defined for HTTP/0.9 support, it might - * also be usefull for other hacks. - * @param parser The Mime parser. - * @return A boolean true if the MimeParser shouldn't - * continue the parsing, false otherwise. - * @exception IOException if an IO error occurs. - */ - - public boolean notifyBeginParsing(MimeParser parser) - throws IOException - { - return false; - } - - /** - * All the headers have been parsed, take any appropriate actions. - * @param parser The Mime parser. - * @exception IOException if an IO error occurs. - */ - - public void notifyEndParsing(MimeParser parser) - throws IOException - { - return; - } - - /** - * Set a header value. - * @param name The header name. - * @param value The header value. - */ - - public void setValue(String name, String value) { - if ( headers == null ) - headers = new Hashtable(5); - headers.put(name.toLowerCase(), value); - } - - /** - * Retreive a header value. - * @param name The name of the header. - * @return The value for this header, or null if - * undefined. - */ - - public String getValue(String name) { - return ((headers != null) - ? (String) headers.get(name.toLowerCase()) - : null); - } - - /** - * Enumerate the headers defined by the holder. - * @return A enumeration of header names, or null if no - * header is defined. - */ - - public Enumeration enumerateHeaders() { - if ( headers == null ) - return null; - return headers.keys(); - } - - /** - * Get the entity stream attached to these headers, if any. - * @return An InputStream instance, or null if no - * entity available. - */ - - public InputStream getInputStream() { - return ((parser != null) ? parser.getInputStream() : null); - } - - /** - * Dump all headers to the given stream. - * @param out The stream to dump to. - */ - - public void dump(PrintStream out) { - Enumeration names = enumerateHeaders(); - if ( names != null ) { - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - out.println(name+": "+headers.get(name)); - } - } - } - - public MimeHeaders(MimeParser parser) { - this.parser = parser; - } - - public MimeHeaders() { - } - - -} diff --git a/src/helma/util/mime/MimeHeadersFactory.java b/src/helma/util/mime/MimeHeadersFactory.java deleted file mode 100644 index a91ab8cd..00000000 --- a/src/helma/util/mime/MimeHeadersFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -// MimeHeadersFactory.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -/** - * A Mime header factory, that will build instances of the MimeHeaders class - * to hold MIME headers. - */ - -public class MimeHeadersFactory implements MimeParserFactory { - - /** - * Create a new header holder to hold the parser's result. - * @param parser The parser that has something to parse. - * @return A MimeParserHandler compliant object. - */ - - public MimeHeaderHolder createHeaderHolder(MimeParser parser) { - return new MimeHeaders(parser); - } - -} diff --git a/src/helma/util/mime/MimeParser.java b/src/helma/util/mime/MimeParser.java deleted file mode 100644 index e40b426c..00000000 --- a/src/helma/util/mime/MimeParser.java +++ /dev/null @@ -1,228 +0,0 @@ -// MimeParser.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.*; -import java.io.* ; - -/** - * The MimeParser class parses an input MIME stream. - */ - -public class MimeParser { - protected int ch = -1 ; - protected InputStream input = null ; - protected byte buffer[] = new byte[128] ; - protected int bsize = 0 ; - - /** - * The factory used to create new MIME header holders. - */ - protected MimeParserFactory factory = null ; - - protected void expect (int car) - throws MimeParserException, IOException - { - if ( car != ch ) { - String sc = (new Character((char) car)).toString() ; - String se = (new Character((char) ch)).toString() ; - throw new MimeParserException ("expecting " - + sc + "("+car+")" - + " got " - + se + "("+ch+")\n" - + "context: " - + new String (buffer, 0, 0, bsize) - + "\n") ; - } - ch = input.read() ; - } - - protected void skipSpaces () - throws MimeParserException, IOException - { - while ( (ch == ' ') || (ch == '\t') ) - ch = input.read() ; - } - - protected final void append (int c) { - if ( bsize+1 >= buffer.length ) { - byte nb[] = new byte[buffer.length*2] ; - System.arraycopy (buffer, 0, nb, 0, buffer.length) ; - buffer = nb ; - } - buffer[bsize++] = (byte) c ; - } - - /* - * Get the header name: - */ - - protected String parse822HeaderName () - throws MimeParserException, IOException - { - bsize = 0 ; - while ( (ch >= 32) && (ch != ':') ) { - append ((char) ch) ; - ch = input.read() ; - } - expect (':') ; - if ( bsize <= 0 ) - throw new MimeParserException ("expected a header name.") ; - return new String (buffer, 0, 0, bsize) ; - } - - /* - * Get the header body, still trying to be 822 compliant *and* HTTP - * robust, which is unfortunatelly a contrdiction. - */ - - protected void parse822HeaderBody () - throws MimeParserException, IOException - { - bsize = 0 ; - skipSpaces () ; - loop: - while ( true ) { - switch (ch) { - case -1: - break loop ; - case '\r': - if ( (ch = input.read()) != '\n' ) { - append ('\r') ; - continue ; - } - // no break intentional - case '\n': - // do as if '\r' had been received. This defeats 822, but - // makes HTTP more "robust". I wish HTTP were a binary - // protocol. - switch (ch = input.read()) { - case ' ': case '\t': - do { - ch = input.read () ; - } while ((ch == ' ') || (ch == '\t')) ; - append(ch); - break ; - default: - break loop ; - } - break ; - default: - append ((char) ch) ; - break ; - } - ch = input.read() ; - } - return ; - } - - /* - * Parse the given input stream for an HTTP 1.1 token. - */ - - protected String parseToken (boolean lower) - throws MimeParserException, IOException - { - bsize = 0 ; - while ( true ) { - switch ( ch ) { - // CTLs - case -1: - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - case 8: case 9: case 10: case 11: case 12: case 13: case 14: - case 15: case 16: case 17: case 18: case 19: case 20: case 21: - case 22: case 23: case 24: case 25: case 26: case 27: case 28: - case 29: case 30: case 31: - // tspecials - case '(': case ')': case '<': case '>': case '@': - case ',': case ';': case ':': case '\\': case '\"': - case '/': case '[': case ']': case '?': case '=': - case '{': case '}': case ' ': - return new String (buffer, 0, 0, bsize) ; - default: - append ((char) (lower - ? Character.toLowerCase((char) ch) - : ch)) ; - } - ch = input.read() ; - } - } - - protected void parse822Headers(MimeHeaderHolder msg) - throws MimeParserException, IOException - { - while ( true ) { - if ( ch == '\r' ) { - if ( (ch = input.read()) == '\n' ) - return ; - } else if ( ch == '\n' ) { - return ; - } - String name = parse822HeaderName () ; - skipSpaces() ; - parse822HeaderBody () ; - msg.notifyHeader(name, buffer, 0, bsize); - } - } - - public MimeHeaderHolder parse() - throws MimeParserException, IOException - { - MimeHeaderHolder msg = factory.createHeaderHolder(this); - ch = input.read() ; - cached = true ; - if ( ! msg.notifyBeginParsing(this) ) { - if ( ! cached ) - ch = input.read(); - parse822Headers (msg) ; - } - msg.notifyEndParsing(this); - return msg; - } - - boolean cached = false ; - - public int read() - throws IOException - { - if ( cached ) - cached = false; - else - ch = input.read(); - return ch; - } - - public void unread(int ch) { - if ( cached ) - throw new RuntimeException("cannot unread more then once !"); - this.ch = ch; - cached = true; - } - - /** - * Get the message body, as an input stream. - * @return The input stream used by the parser to get data, after - * a call to parse, this input stream contains exactly - * the body of the message. - */ - - public InputStream getInputStream () { - return input ; - } - - /** - * Create an instance of the MIMEParser class. - * @param in The input stream to be parsed as a MIME stream. - * @param factory The factory used to create MIME header holders. - */ - - public MimeParser (InputStream input, MimeParserFactory factory) { - this.input = input ; - this.factory = factory; - } - - -} diff --git a/src/helma/util/mime/MimeParserException.java b/src/helma/util/mime/MimeParserException.java deleted file mode 100644 index f4b05a98..00000000 --- a/src/helma/util/mime/MimeParserException.java +++ /dev/null @@ -1,14 +0,0 @@ -// MimeParserException.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -public class MimeParserException extends Exception { - - public MimeParserException(String msg) { - super(msg); - } - -} diff --git a/src/helma/util/mime/MimeParserFactory.java b/src/helma/util/mime/MimeParserFactory.java deleted file mode 100644 index 41e94044..00000000 --- a/src/helma/util/mime/MimeParserFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -// MimeParserFactory.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -/** - * This class is used by the MimeParser, to create new MIME message holders. - * Each MIME parse instances is custmozied wit hits own factory, which it - * will use to create MIME header holders. - */ - -public interface MimeParserFactory { - - /** - * Create a new header holder to hold the parser's result. - * @param parser The parser that has something to parse. - * @return A MimeParserHandler compliant object. - */ - - abstract public MimeHeaderHolder createHeaderHolder(MimeParser parser); - -} diff --git a/src/helma/util/mime/MimeType.java b/src/helma/util/mime/MimeType.java deleted file mode 100644 index 7cc85fa7..00000000 --- a/src/helma/util/mime/MimeType.java +++ /dev/null @@ -1,374 +0,0 @@ -// MimeType.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.*; -import java.io.*; - -/** - * This class is used to represent parsed MIME types. - * It creates this representation from a string based representation of - * the MIME type, as defined in the RFC 1345. - */ - -public class MimeType implements Serializable, Cloneable { - /** - * List of well known MIME types: - */ - public static MimeType TEXT_HTML = null ; - public static MimeType APPLICATION_POSTSCRIPT = null ; - public static MimeType TEXT_PLAIN = null ; - public static MimeType APPLICATION_X_WWW_FORM_URLENCODED = null ; - public static MimeType MULTIPART_FORM_DATA = null ; - public static MimeType APPLICATION_X_JAVA_AGENT = null ; - public static MimeType MESSAGE_HTTP = null ; - public static MimeType TEXT_CSS = null ; - public static MimeType TEXT = null ; - - static { - try { - TEXT_HTML - = new MimeType("text/html"); - APPLICATION_POSTSCRIPT - = new MimeType ("application/postscript") ; - TEXT_PLAIN - = new MimeType("text/plain") ; - APPLICATION_X_WWW_FORM_URLENCODED - = new MimeType("application/x-www-form-urlencoded") ; - MULTIPART_FORM_DATA - = new MimeType("multipart/form-data") ; - APPLICATION_X_JAVA_AGENT - = new MimeType("application/x-java-agent") ; - MESSAGE_HTTP - = new MimeType("message/http"); - TEXT_CSS - = new MimeType("text/css"); - TEXT - = new MimeType("text/*"); - } catch (MimeTypeFormatException e) { - System.out.println ("httpd.MimeType: invalid static init.") ; - System.exit (1) ; - } - } - - public final static int NO_MATCH = -1 ; - public final static int MATCH_TYPE = 1 ; - public final static int MATCH_SPECIFIC_TYPE = 2 ; - public final static int MATCH_SUBTYPE = 3 ; - public final static int MATCH_SPECIFIC_SUBTYPE = 4 ; - - /** - * String representation of type - * - * @serial - */ - protected String type = null ; - /** - * String representation of subtype - * - * @serial - */ - protected String subtype = null ; - /** - * parameter names - * - * @serial - */ - protected String pnames[] = null; - /** - * parameter values - * - * @serial - */ - protected String pvalues[] = null; - /** - * external form of this mime type - * - * @serial - */ - protected String external = null ; - - /** - * How good the given MimeType matches the receiver of the method ? - * This method returns a matching level among: - *

- *
NO_MATCH
Types not matching,
- *
MATCH_TYPE
Types match,
- *
MATCH_SPECIFIC_TYPE
Types match exactly,
- *
MATCH_SUBTYPE
Types match, subtypes matches too
- *
MATCH_SPECIFIC_SUBTYPE
Types match, subtypes matches exactly
- *
- * The matches are ranked from worst match to best match, a simple - * Max ( match[i], matched) will give the best match. - * @param other The other MimeType to match against ourself. - */ - - public int match (MimeType other) { - int match = NO_MATCH; - // match types: - if ( type.equals("*") || other.type.equals("*") ) { - return MATCH_TYPE; - } else if ( ! type.equals (other.type) ) { - return NO_MATCH ; - } else { - match = MATCH_SPECIFIC_TYPE; - } - // match subtypes: - if ( subtype.equals("*") || other.subtype.equals("*") ) { - match = MATCH_SUBTYPE ; - } else if ( ! subtype.equals (other.subtype) ) { - return NO_MATCH; - } else { - match = MATCH_SPECIFIC_SUBTYPE; - } - return match; - } - - /** - * A printable representation of this MimeType. - * The printed representation is guaranteed to be parseable by the - * String constructor. - */ - - public String toString () { - if ( external == null ) { - StringBuffer sb = new StringBuffer (type) ; - sb.append((char) '/') ; - sb.append (subtype) ; - if ( pnames != null ) { - for (int i = 0 ; i < pnames.length; i++) { - sb.append(';'); - sb.append(pnames[i]); - if ( pvalues[i] != null ) { - sb.append('='); - sb.append(pvalues[i]); - } - } - } - external = sb.toString() ; - } - return external ; - } - - - /** - * Does this MIME type has some value for the given parameter ? - * @param name The parameter to check. - * @return True if this parameter has a value, false - * otherwise. - */ - public boolean hasParameter (String name) { - if ( pnames != null ) { - for (int i = 0 ; i < pnames.length ; i++) { - if ( pnames[i].equals(name) ) - return true ; - } - } - return false ; - } - - /** - * Get the major type of this mime type. - * @return The major type, encoded as a String. - */ - - public String getType() { - return type; - } - - /** - * Get the minor type (subtype) of this mime type. - * @return The minor or subtype encoded as a String. - */ - public String getSubtype() { - return subtype; - } - - - /** - * Get a mime type parameter value. - * @param name The parameter whose value is to be returned. - * @return The parameter value, or null if not found. - */ - public String getParameterValue (String name) { - if ( pnames != null ) { - for (int i = 0 ; i < pnames.length ; i++) { - if ( pnames[i].equals(name) ) - return pvalues[i]; - } - } - return null ; - } - - /** - * adds some parameters to a MimeType - * @param param a String array of parameter names - * @param values the corresponding String array of values - */ - public void addParameters(String[] param, String[] values) { - // sanity check - if ((param == null) || (values == null) || - (values.length != param.length)) - return; - if (pnames == null) { - pnames = param; - pvalues = values; - } else { - String[] nparam = new String[pnames.length+param.length]; - String[] nvalues = new String[pvalues.length+values.length]; - System.arraycopy(pnames, 0, nparam, 0, pnames.length); - System.arraycopy(param, 0, nparam, pnames.length, param.length); - System.arraycopy(pvalues, 0, nvalues, 0, pvalues.length); - System.arraycopy(values,0, nvalues, pvalues.length, values.length); - pnames = nparam; - pvalues = nvalues; - } - external = null; - } - - /** - * get a clone of this object - * @return another cloned instance of MimeType - */ - public MimeType getClone() { - try { - return (MimeType) clone(); - } catch (CloneNotSupportedException ex) { - // should never happen as we are Cloneable! - } - // never reached - return null; - } - - /** - * adds a parameterto a MimeType - * @param param the parameter name, as a String - * @param value the parameter value, as a Sting - */ - public void addParameter(String param, String value) { - String[] p = new String[1]; - String[] v = new String[1]; - p[0] = param; - v[0] = value; - addParameters(p, v); - } - - /** - * Construct MimeType object for the given string. - * The string should be the representation of the type. This methods - * tries to be compliant with HTTP1.1, p 15, although it is not - * (because of quoted-text not being accepted). - * FIXME - * @parameter spec A string representing a MimeType - * @return A MimeType object - * @exception MimeTypeFormatException if the string couldn't be parsed. - */ - public MimeType (String spec) - throws MimeTypeFormatException - { - int strl = spec.length() ; - int start = 0, look = -1 ; - // skip leading/trailing blanks: - while ((start < strl) && (spec.charAt (start)) <= ' ') - start++ ; - while ((strl > start) && (spec.charAt (strl-1) <= ' ')) - strl-- ; - // get the type: - StringBuffer sb = new StringBuffer () ; - while ((start < strl) && ((look = spec.charAt(start)) != '/')) { - sb.append ((char) look) ; - start++ ; - } - if ( look != '/' ) - throw new MimeTypeFormatException (spec) ; - this.type = sb.toString() ; - // get the subtype: - start++ ; - sb.setLength(0) ; - while ((start < strl) - && ((look = spec.charAt(start)) > ' ') && (look != ';')) { - sb.append ((char) look) ; - start++ ; - } - this.subtype = sb.toString() ; - // get parameters, if any: - while ((start < strl) && ((look = spec.charAt(start)) <= ' ')) - start++ ; - if ( start < strl ) { - if (spec.charAt(start) != ';') - throw new MimeTypeFormatException (spec) ; - start++ ; - Vector vp = new Vector(4) ; - Vector vv = new Vector(4) ; - while ( start < strl ) { - while ((start < strl) && (spec.charAt(start) <= ' ')) start++ ; - // get parameter name: - sb.setLength (0) ; - while ((start < strl) - && ((look=spec.charAt(start)) > ' ') && (look != '=')) { - sb.append (Character.toLowerCase((char) look)) ; - start++ ; - } - String name = sb.toString() ; - // get the value: - while ((start < strl) && (spec.charAt(start) <= ' ')) start++ ; - if (spec.charAt(start) != '=') - throw new MimeTypeFormatException (spec) ; - start++ ; - while ((start < strl) && - ((spec.charAt(start) == '"') || - (spec.charAt(start) <= ' '))) start++ ; - sb.setLength(0) ; - while ((start < strl) - && ((look=spec.charAt(start)) > ' ') - && (look != ';') - && (look != '"')) { - sb.append ((char) look) ; - start++ ; - } - while ((start < strl) && (spec.charAt(start) != ';')) start++ ; - start++ ; - String value = sb.toString() ; - vp.addElement(name); - vv.addElement(value); - } - this.pnames = new String[vp.size()]; - vp.copyInto(pnames); - this.pvalues = new String[vv.size()]; - vv.copyInto(pvalues); - } - } - - public MimeType (String type, String subtype - , String pnames[], String pvalues[]) { - this.type = type ; - this.subtype = subtype ; - this.pnames = pnames; - this.pvalues = pvalues; - } - - public MimeType (String type, String subtype) { - this.type = type; - this.subtype = subtype; - } - - public static void main (String args[]) { - if ( args.length == 1) { - MimeType type = null ; - try { - type = new MimeType (args[0]) ; - } catch (MimeTypeFormatException e) { - } - if ( type != null ) - System.out.println (type) ; - else - System.out.println ("Invalid mime type specification.") ; - } else { - System.out.println ("Usage: java MimeType ") ; - } - } - -} diff --git a/src/helma/util/mime/MimeTypeFormatException.java b/src/helma/util/mime/MimeTypeFormatException.java deleted file mode 100644 index 227a4bbe..00000000 --- a/src/helma/util/mime/MimeTypeFormatException.java +++ /dev/null @@ -1,14 +0,0 @@ -// MimeType.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -public class MimeTypeFormatException extends Exception { - - public MimeTypeFormatException(String msg) { - super(msg); - } - -} diff --git a/src/helma/util/mime/MultipartInputStream.java b/src/helma/util/mime/MultipartInputStream.java deleted file mode 100644 index 5bb0b3ce..00000000 --- a/src/helma/util/mime/MultipartInputStream.java +++ /dev/null @@ -1,214 +0,0 @@ -// MultipartInputStream.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.io.* ; - -/** - * A class to handle multipart MIME input streams. See RC 1521. - * This class handles multipart input streams, as defined by the RFC 1521. - * It prvides a sequential interface to all MIME parts, and for each part - * it delivers a suitable InputStream for getting its body. - */ - -public class MultipartInputStream extends InputStream { - InputStream in = null; - byte boundary[] = null ; - byte buffer[] = null ; - boolean partEnd = false ; - boolean fileEnd = false ; - - // Read boundary bytes of input in buffer - // Return true if enough bytes available, false otherwise. - - private final boolean readBoundaryBytes() - throws IOException - { - int pos = 0; - while ( pos < buffer.length ) { - int got = in.read(buffer, pos, buffer.length-pos); - if ( got < 0 ) - return false; - pos += got; - } - return true; - } - - // Skip to next input boundary, set stream at begining of content: - // Returns true if boundary was found, false otherwise. - - protected boolean skipToBoundary() - throws IOException - { - int ch = in.read() ; - skip: - while ( ch != -1 ) { - if ( ch != '-' ) { - ch = in.read() ; - continue ; - } - if ((ch = in.read()) != '-') - continue ; - in.mark(boundary.length) ; - if ( ! readBoundaryBytes() ) { - in.reset(); - ch = in.read(); - continue skip; - } - for (int i = 0 ; i < boundary.length ; i++) { - if ( buffer[i] != boundary[i] ) { - in.reset() ; - ch = in.read() ; - continue skip ; - } - } - // FIXME: should we check for a properly syntaxed part, which - // means that we should expect '\r\n'. For now, we just skip - // as much as we can. - if ( (ch = in.read()) == '\r' ) { - ch = in.read() ; - } - in.mark(3); - if( in.read() == '-' ) { // check fileEnd! - if( in.read() == '\r' && in.read() == '\n' ) { - fileEnd = true ; - return false ; - } - } - in.reset(); - return true ; - } - fileEnd = true ; - return false ; - } - - /** - * Read one byte of data from the current part. - * @return A byte of data, or -1 if end of file. - * @exception IOException If some IO error occured. - */ - - public int read() - throws IOException - { - int ch ; - if ( partEnd ) - return -1 ; - switch (ch = in.read()) { - case '\r': - // check for a boundary - in.mark(boundary.length+3) ; - int c1 = in.read() ; - int c2 = in.read() ; - int c3 = in.read() ; - if ((c1 == '\n') && (c2 == '-') && (c3 == '-')) { - if ( ! readBoundaryBytes() ) { - in.reset(); - return ch; - } - for (int i = 0 ; i < boundary.length ; i++) { - if ( buffer[i] != boundary[i] ) { - in.reset() ; - return ch ; - } - } - partEnd = true ; - if ( (ch = in.read()) == '\r' ) { - in.read() ; - } else if (ch == '-') { - // FIXME, check the second hyphen - if (in.read() == '-') - fileEnd = true ; - } else { - fileEnd = (ch == -1); - } - return -1 ; - } else { - in.reset () ; - return ch ; - } - // not reached - case -1: - fileEnd = true ; - return -1 ; - default: - return ch ; - } - } - - /** - * Read n bytes of data from the current part. - * @return the number of bytes data, read or -1 - * if end of file. - * @exception IOException If some IO error occured. - */ - public int read (byte b[], int off, int len) - throws IOException - { - int got = 0 ; - int ch ; - - while ( got < len ) { - if ((ch = read()) == -1) - return (got == 0) ? -1 : got ; - b[off+(got++)] = (byte) (ch & 0xFF) ; - } - return got ; - } - - public long skip (long n) - throws IOException - { - while ((--n >= 0) && (read() != -1)) - ; - return n ; - } - - public int available () - throws IOException - { - return in.available(); - } - - /** - * Switch to the next available part of data. - * One can interrupt the current part, and use this method to switch - * to next part before current part was totally read. - * @return A boolean true if there next partis ready, - * or false if this was the last part. - */ - - public boolean nextInputStream() - throws IOException - { - if ( fileEnd ) { - return false ; - } - if ( ! partEnd ) { - return skipToBoundary() ; - } else { - partEnd = false ; - return true ; - } - } - - /** - * Construct a new multipart input stream. - * @param in The initial (multipart) input stream. - * @param boundary The input stream MIME boundary. - */ - - public MultipartInputStream (InputStream in, byte boundary[]) { - this.in = (in.markSupported() - ? in - : new BufferedInputStream(in, boundary.length+4)); - this.boundary = boundary ; - this.buffer = new byte[boundary.length] ; - this.partEnd = false ; - this.fileEnd = false ; - } - -} diff --git a/src/helma/util/mime/Utils.java b/src/helma/util/mime/Utils.java deleted file mode 100644 index 3889ff76..00000000 --- a/src/helma/util/mime/Utils.java +++ /dev/null @@ -1,143 +0,0 @@ -// Utils.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1998. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.Hashtable; - -/** - * @version $Revision$ - * @author Benoît Mahé (bmahe@w3.org) - */ -public class Utils { - - private static Hashtable extension_map = new Hashtable(); - - private static void setSuffix(String ext, String ct) { - extension_map.put(ext, ct); - } - - static { - setSuffix("", "content/unknown"); - setSuffix(".uu", "application/octet-stream"); - setSuffix(".saveme", "application/octet-stream"); - setSuffix(".dump", "application/octet-stream"); - setSuffix(".hqx", "application/octet-stream"); - setSuffix(".arc", "application/octet-stream"); - setSuffix(".o", "application/octet-stream"); - setSuffix(".a", "application/octet-stream"); - setSuffix(".bin", "application/octet-stream"); - setSuffix(".exe", "application/octet-stream"); - setSuffix(".z", "application/octet-stream"); - setSuffix(".gz", "application/octet-stream"); - setSuffix(".oda", "application/oda"); - setSuffix(".pdf", "application/pdf"); - setSuffix(".eps", "application/postscript"); - setSuffix(".ai", "application/postscript"); - setSuffix(".ps", "application/postscript"); - setSuffix(".rtf", "application/rtf"); - setSuffix(".dvi", "application/x-dvi"); - setSuffix(".hdf", "application/x-hdf"); - setSuffix(".latex", "application/x-latex"); - setSuffix(".cdf", "application/x-netcdf"); - setSuffix(".nc", "application/x-netcdf"); - setSuffix(".tex", "application/x-tex"); - setSuffix(".texinfo", "application/x-texinfo"); - setSuffix(".texi", "application/x-texinfo"); - setSuffix(".t", "application/x-troff"); - setSuffix(".tr", "application/x-troff"); - setSuffix(".roff", "application/x-troff"); - setSuffix(".man", "application/x-troff-man"); - setSuffix(".me", "application/x-troff-me"); - setSuffix(".ms", "application/x-troff-ms"); - setSuffix(".src", "application/x-wais-source"); - setSuffix(".wsrc", "application/x-wais-source"); - setSuffix(".zip", "application/zip"); - setSuffix(".bcpio", "application/x-bcpio"); - setSuffix(".cpio", "application/x-cpio"); - setSuffix(".gtar", "application/x-gtar"); - setSuffix(".shar", "application/x-shar"); - setSuffix(".sh", "application/x-shar"); - setSuffix(".sv4cpio", "application/x-sv4cpio"); - setSuffix(".sv4crc", "application/x-sv4crc"); - setSuffix(".tar", "application/x-tar"); - setSuffix(".ustar", "application/x-ustar"); - setSuffix(".snd", "audio/basic"); - setSuffix(".au", "audio/basic"); - setSuffix(".aifc", "audio/x-aiff"); - setSuffix(".aif", "audio/x-aiff"); - setSuffix(".aiff", "audio/x-aiff"); - setSuffix(".wav", "audio/x-wav"); - setSuffix(".gif", "image/gif"); - setSuffix(".ief", "image/ief"); - setSuffix(".jfif", "image/jpeg"); - setSuffix(".jfif-tbnl", "image/jpeg"); - setSuffix(".jpe", "image/jpeg"); - setSuffix(".jpg", "image/jpeg"); - setSuffix(".jpeg", "image/jpeg"); - setSuffix(".tif", "image/tiff"); - setSuffix(".tiff", "image/tiff"); - setSuffix(".ras", "image/x-cmu-rast"); - setSuffix(".pnm", "image/x-portable-anymap"); - setSuffix(".pbm", "image/x-portable-bitmap"); - setSuffix(".pgm", "image/x-portable-graymap"); - setSuffix(".ppm", "image/x-portable-pixmap"); - setSuffix(".rgb", "image/x-rgb"); - setSuffix(".xbm", "image/x-xbitmap"); - setSuffix(".xpm", "image/x-xpixmap"); - setSuffix(".xwd", "image/x-xwindowdump"); - setSuffix(".htm", "text/html"); - setSuffix(".html", "text/html"); - setSuffix(".text", "text/plain"); - setSuffix(".c", "text/plain"); - setSuffix(".cc", "text/plain"); - setSuffix(".c++", "text/plain"); - setSuffix(".h", "text/plain"); - setSuffix(".pl", "text/plain"); - setSuffix(".txt", "text/plain"); - setSuffix(".java", "text/plain"); - setSuffix(".rtx", "application/rtf"); - setSuffix(".tsv", "texyt/tab-separated-values"); - setSuffix(".etx", "text/x-setext"); - setSuffix(".mpg", "video/mpeg"); - setSuffix(".mpe", "video/mpeg"); - setSuffix(".mpeg", "video/mpeg"); - setSuffix(".mov", "video/quicktime"); - setSuffix(".qt", "video/quicktime"); - setSuffix(".avi", "application/x-troff-msvideo"); - setSuffix(".movie", "video/x-sgi-movie"); - setSuffix(".mv", "video/x-sgi-movie"); - setSuffix(".mime", "message/rfc822"); - } - - /** - * A useful utility routine that tries to guess the content-type - * of an object based upon its extension. - */ - public static String guessContentTypeFromName(String fname) { - String ext = ""; - int i = fname.lastIndexOf('#'); - - if (i != -1) - fname = fname.substring(0, i - 1); - i = fname.lastIndexOf('.'); - i = Math.max(i, fname.lastIndexOf('/')); - i = Math.max(i, fname.lastIndexOf('?')); - - if (i != -1 && fname.charAt(i) == '.') { - ext = fname.substring(i).toLowerCase(); - } - return (String) extension_map.get(ext); - } - - public static MimeType getMimeType(String filename) { - try { - return new MimeType(guessContentTypeFromName(filename)); - } catch (MimeTypeFormatException ex) { - return null; - } - } - -} diff --git a/static/helma.gif b/static/helma.gif deleted file mode 100644 index 475b94fc..00000000 Binary files a/static/helma.gif and /dev/null differ diff --git a/static/helma2.gif b/static/helma2.gif deleted file mode 100644 index 8bbb844b..00000000 Binary files a/static/helma2.gif and /dev/null differ diff --git a/static/test.txt b/static/test.txt deleted file mode 100644 index 6ab91ccb..00000000 --- a/static/test.txt +++ /dev/null @@ -1,3 +0,0 @@ - - This file should appear at http://:/static/test.txt - if you use the embedded Web server (-w option). \ No newline at end of file