Merge helma 1 trunk from revision 8828 to 9332 minus the commit 9325 for case sensitive HopObject properties which is going to Helma 1.7 exclusively.
svn merge -r 8828:HEAD https://dev.helma.org/svn/helma/helma/trunk/ svn merge -r 9325:9324 https://dev.helma.org/svn/helma/helma/trunk/
This commit is contained in:
parent
718d43690d
commit
d1f972591f
33 changed files with 458 additions and 1174 deletions
|
@ -1,4 +1,4 @@
|
|||
This is the README file for version 1.6.2 of the Helma Javascript
|
||||
This is the README file for version 1.6.3 of the Helma Javascript
|
||||
Web Application Framework.
|
||||
|
||||
==============
|
||||
|
|
541
build/build.xml
541
build/build.xml
|
@ -1,541 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<project name="Helma" default="usage" basedir=".">
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Initializes some variables -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="init">
|
||||
<property name="Name" value="helma"/>
|
||||
<property name="year" value="1998-${year}"/>
|
||||
<property name="version" value="1.6.2"/>
|
||||
<property name="project" value="helma"/>
|
||||
|
||||
<property name="cvs.root.apps" value=":pserver:anonymous@adele.helma.at:/opt/cvs/apps"/>
|
||||
<property name="cvs.root.helma" value=":pserver:anonymous@adele.helma.at:/opt/cvs/helma"/>
|
||||
<property name="cvs.apps.tag" value="HEAD"/>
|
||||
|
||||
<property name="home.dir" value=".."/>
|
||||
<property name="build.dir" value="${home.dir}/build"/>
|
||||
<property name="build.src" value="${home.dir}/src"/>
|
||||
<property name="build.lib" value="${home.dir}/lib"/>
|
||||
<property name="build.classes" value="${home.dir}/classes"/>
|
||||
<property name="build.docs" value="${home.dir}/docs"/>
|
||||
<property name="build.javadocs" value="${home.dir}/docs/api"/>
|
||||
<property name="build.externals" value="${build.dir}/externals"/>
|
||||
|
||||
<property name="build.work" value="${home.dir}/work"/>
|
||||
<property name="build.dist" value="${home.dir}/dist"/>
|
||||
|
||||
<property name="jar.name" value="${project}"/>
|
||||
<property name="package.name" value="${project}-${version}"/>
|
||||
<property name="core.name" value="${project}-core-${version}"/>
|
||||
|
||||
<property name="debug" value="on"/>
|
||||
<property name="optimize" value="on"/>
|
||||
<property name="deprecation" value="off"/>
|
||||
|
||||
<property name="build.jsdocs" value="${home.dir}/docs/framework"/>
|
||||
<property name="jsdoc" value="${home.dir}/work/reference/templates/jsdoc.pl"/>
|
||||
|
||||
<path id="build.class.path">
|
||||
<fileset dir="${home.dir}/lib">
|
||||
<exclude name="**/helma*.jar" />
|
||||
<include name="**/*.jar" />
|
||||
</fileset>
|
||||
</path>
|
||||
|
||||
<tstamp/>
|
||||
|
||||
<filter token="year" value="${year}"/>
|
||||
<filter token="version" value="${version}"/>
|
||||
<filter token="date" value="${TODAY}"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Help on usage -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="help" depends="usage" />
|
||||
<target name="usage">
|
||||
<echo message=""/>
|
||||
<echo message=""/>
|
||||
<echo message="Helma build instructions"/>
|
||||
<echo message="-------------------------------------------------------------"/>
|
||||
<echo message=""/>
|
||||
<echo message=" available targets are:"/>
|
||||
<echo message=""/>
|
||||
<echo message=" compile --> compiles the source code to ./classes"/>
|
||||
<echo message=" jar --> generates the ./lib/helma-YYYYMMDD.jar file"/>
|
||||
<echo message=" javadocs --> generates the API docs"/>
|
||||
<echo message=" jsdocs --> generates the framework docs"/>
|
||||
<!--<echo message=" docs -> tries to retrieve the HTML documentation "/> -->
|
||||
<!--<echo message=" (may need proxy settings in startscript)"/> -->
|
||||
<echo message=" package --> generates the distribution (zip and tar.gz)"/>
|
||||
<echo message=" app [name] --> gets an application from the cvs and zips it"/>
|
||||
<echo message=" module [name] --> gets a module from the cvs and zips it"/>
|
||||
<echo message=" core --> generates core for production updates (zip and tar.gz)"/>
|
||||
<echo message=" clean --> clean up temporary build directories and files"/>
|
||||
<echo message=""/>
|
||||
<echo message=" usage --> provides help on using the build tool (default)"/>
|
||||
<echo message=""/>
|
||||
<echo message=" See comments inside the build.xml file for more details."/>
|
||||
<echo message="-------------------------------------------------------------"/>
|
||||
<echo message=""/>
|
||||
<echo message=""/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Compiles the source directory -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="compile" depends="init">
|
||||
<mkdir dir="${build.classes}"/>
|
||||
<!-- copy the imageio file -->
|
||||
<copy file="${build.src}/META-INF/services/javax.imageio.spi.ImageWriterSpi"
|
||||
todir="${build.classes}/META-INF/services"/>
|
||||
<!-- copy helma db style sheet -->
|
||||
<copy file="${build.src}/helma/objectmodel/dom/helma.xsl"
|
||||
todir="${build.classes}/helma/objectmodel/dom" />
|
||||
<!-- copy source files over to work directory -->
|
||||
<delete dir="${build.work}/src" quiet="true"/>
|
||||
<mkdir dir="${build.work}/src" />
|
||||
<copy todir="${build.work}/src" overwrite="true">
|
||||
<fileset dir="${build.src}" includes="**/*.java"/>
|
||||
</copy>
|
||||
<replace file="${build.work}/src/helma/main/Server.java"
|
||||
token="__builddate__" value="${TODAY}"/>
|
||||
<javac srcdir="${build.work}/src"
|
||||
source="1.5"
|
||||
target="1.5"
|
||||
destdir="${build.classes}"
|
||||
debug="${debug}"
|
||||
deprecation="${deprecation}"
|
||||
optimize="${optimize}"
|
||||
includeAntRuntime="no">
|
||||
<classpath refid="build.class.path" />
|
||||
</javac>
|
||||
<delete dir="${build.work}/src"/>
|
||||
<rmic classname="helma.framework.core.RemoteApplication" base="${build.classes}"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Creates a helma.jar file (snapshot) in the lib-directory -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="jar" depends="compile">
|
||||
<jar jarfile="${build.lib}/${jar.name}-${DSTAMP}.jar"
|
||||
basedir="${build.classes}"
|
||||
excludes="**/package.html,**/main/launcher/**"/>
|
||||
<jar jarfile="${home.dir}/launcher.jar"
|
||||
basedir="${build.classes}"
|
||||
includes="**/main/launcher/**"
|
||||
manifest="${build.src}/helma/main/launcher/manifest.txt"/>
|
||||
<!-- Copy timestamped helma jar file to lib/helma.jar -->
|
||||
<copy file="${build.lib}/${jar.name}-${DSTAMP}.jar"
|
||||
tofile="${build.lib}/${jar.name}.jar"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Creates the javadoc API documentation -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="javadocs" depends="init">
|
||||
<mkdir dir="${build.javadocs}"/>
|
||||
<javadoc packagenames="helma.*"
|
||||
sourcepath="${build.src}"
|
||||
destdir="${build.javadocs}"
|
||||
author="false"
|
||||
private="false"
|
||||
version="false"
|
||||
windowtitle="${Name} ${version} API"
|
||||
doctitle="${Name} ${version} API"
|
||||
bottom="Copyright © ${year} Helma.org. All Rights Reserved."
|
||||
classpathref="build.class.path"
|
||||
/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Create the jsdoc Framework documentation -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="jsdocs" depends="init, package-modules">
|
||||
<!-- cvs cvsRoot="${cvs.root.apps}" command="export" tag="${cvs.apps.tag}" package="reference" dest="${build.work}" /-->
|
||||
|
||||
<!-- add a copy of the reference -->
|
||||
<mkdir dir="${build.work}/reference"/>
|
||||
<copy todir="${build.work}/reference">
|
||||
<fileset dir="${build.externals}/reference"/>
|
||||
</copy>
|
||||
|
||||
<!-- add a copy of the modules -->
|
||||
<mkdir dir="${build.work}/reference/modules"/>
|
||||
<copy todir="${build.work}/reference/modules">
|
||||
<fileset dir="${build.externals}/modules/"/>
|
||||
</copy>
|
||||
|
||||
<mkdir dir="${build.jsdocs}"/>
|
||||
<java dir="${home.dir}" fork="true" jar="${build.lib}/rhino.jar">
|
||||
<sysproperty key="jsdoc.dir" value="work/reference"/>
|
||||
<arg value="work/reference/app/run.js"/>
|
||||
<arg value="-t=work/reference/templates"/>
|
||||
<arg value="-d=docs/framework"/>
|
||||
<arg value="-r=3"/>
|
||||
<arg value="work/reference/coreEnvironment"/>
|
||||
<arg value="work/reference/coreExtensions"/>
|
||||
<arg value="work/reference/modules"/>
|
||||
</java>
|
||||
<delete dir="${build.work}/reference" />
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Get the documentation (currently can fail due to request time-out -->
|
||||
<!-- or missing support for proxies) -->
|
||||
<!-- =================================================================== -->
|
||||
<!-- <target name="docs" depends="init"> -->
|
||||
<!-- <get src="http://www.helma.org/docs/reference/print" -->
|
||||
<!-- dest="${build.docs}/reference.html" -->
|
||||
<!-- ignoreerrors="true" -->
|
||||
<!-- /> -->
|
||||
<!-- </target> -->
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Builds and packages only the core for the deployment and updating -->
|
||||
<!-- of production environments -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="core" depends="init, jar">
|
||||
<mkdir dir="${build.work}"/>
|
||||
|
||||
<!-- copy all libraries except helma-YYYYMMDD.jar -->
|
||||
<copy todir="${build.work}/lib">
|
||||
<fileset dir="${home.dir}/lib">
|
||||
<exclude name="**/helma-*.jar" />
|
||||
<include name="**/*.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
|
||||
<!-- copy the launcher jar and start files-->
|
||||
<copy file="${home.dir}/launcher.jar" todir="${build.work}/lib"/>
|
||||
|
||||
<!-- create lib/ext directory -->
|
||||
<mkdir dir="${build.work}/lib/ext"/>
|
||||
|
||||
<!-- copy the license files -->
|
||||
<copy todir="${build.work}/licenses">
|
||||
<fileset dir="${home.dir}/licenses" excludes="**/CVS**"/>
|
||||
</copy>
|
||||
<copy file="${home.dir}/license.txt" todir="${build.work}/licenses"/>
|
||||
|
||||
<!-- zip up the whole thing -->
|
||||
<antcall target="package-zip">
|
||||
<param name="filename" value="${core.name}"/>
|
||||
</antcall>
|
||||
<antcall target="package-tgz">
|
||||
<param name="filename" value="${core.name}"/>
|
||||
</antcall>
|
||||
|
||||
<!-- clean up -->
|
||||
<delete dir="${build.work}"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Creates the full helma distribution -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package" depends="init">
|
||||
<mkdir dir="${build.work}"/>
|
||||
|
||||
<!-- checkout the demo apps (and zip manage-app) -->
|
||||
<antcall target="package-apps" />
|
||||
|
||||
<!-- generate the framework and modules documentation -->
|
||||
<antcall target="jsdocs" />
|
||||
|
||||
<!-- create the main part of helma -->
|
||||
<antcall target="package-raw">
|
||||
<param name="distribution" value="main" />
|
||||
</antcall>
|
||||
|
||||
<chmod perm="755">
|
||||
<fileset dir="${build.work}">
|
||||
<include name="start.sh"/>
|
||||
</fileset>
|
||||
</chmod>
|
||||
|
||||
<!-- zip up the whole thing -->
|
||||
<antcall target="package-zip">
|
||||
<param name="filename" value="${package.name}"/>
|
||||
</antcall>
|
||||
<antcall target="package-tgz">
|
||||
<param name="filename" value="${package.name}"/>
|
||||
</antcall>
|
||||
|
||||
<!-- make the src distributions -->
|
||||
<antcall target="javadocs"/>
|
||||
<antcall target="package-src-zip">
|
||||
<param name="filename" value="${package.name}"/>
|
||||
</antcall>
|
||||
<antcall target="package-src-tgz">
|
||||
<param name="filename" value="${package.name}"/>
|
||||
</antcall>
|
||||
|
||||
<!-- clean up -->
|
||||
<delete dir="${build.work}"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Compile Helma and prepare the skeleton in a temporary directory. -->
|
||||
<!-- Used by package . -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-raw" depends="init, jar">
|
||||
|
||||
<!-- copy the framework (apps.props, server.props, hop/db, hop/static) -->
|
||||
<copy todir="${build.work}">
|
||||
<fileset dir="${build.dir}/${distribution}" excludes="**/CVS**"/>
|
||||
</copy>
|
||||
|
||||
<!-- copy the launcher jar and start files -->
|
||||
<copy file="${home.dir}/launcher.jar" todir="${build.work}/"/>
|
||||
<copy file="${home.dir}/start.sh" todir="${build.work}"/>
|
||||
<copy file="${home.dir}/start.bat" todir="${build.work}"/>
|
||||
|
||||
<!-- copy README.txt -->
|
||||
<copy file="${home.dir}/README.txt" todir="${build.work}/"/>
|
||||
|
||||
<!-- copy the whole docs-directory -->
|
||||
<copy todir="${build.work}/docs">
|
||||
<fileset dir="${build.docs}"/>
|
||||
</copy>
|
||||
|
||||
<!-- copy all libraries except helma-YYYYMMDD.jar -->
|
||||
<copy todir="${build.work}/lib">
|
||||
<fileset dir="${home.dir}/lib">
|
||||
<exclude name="**/helma-*.jar" />
|
||||
<include name="**/*.jar" />
|
||||
</fileset>
|
||||
</copy>
|
||||
|
||||
<!-- create lib/ext directory -->
|
||||
<mkdir dir="${build.work}/lib/ext"/>
|
||||
|
||||
<!-- copy the license files -->
|
||||
<copy todir="${build.work}/licenses">
|
||||
<fileset dir="${home.dir}/licenses" excludes="**/CVS**"/>
|
||||
</copy>
|
||||
<copy file="${home.dir}/license.txt" todir="${build.work}/licenses"/>
|
||||
|
||||
<!-- copy the scripts directory -->
|
||||
<copy todir="${build.work}/scripts">
|
||||
<fileset dir="${home.dir}/scripts" excludes="**/CVS**"/>
|
||||
</copy>
|
||||
|
||||
<!-- zip the sourcecode -->
|
||||
<!-- mkdir dir="${build.work}/src"/>
|
||||
<tar tarfile="${build.work}/src/helma-src.tar" basedir="${build.src}/">
|
||||
<tarfileset dir="${build.src}">
|
||||
<include name="${build.src}/**"/>
|
||||
</tarfileset>
|
||||
</tar>
|
||||
<gzip zipfile="${build.work}/src/helma-src.tar.gz" src="${build.work}/src/helma-src.tar"/>
|
||||
<delete file="${build.work}/src/helma-src.tar"/ -->
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Checkout demo apps, put them in work directory and zip manage app -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-apps" depends="init">
|
||||
|
||||
<mkdir dir="${build.work}/apps" />
|
||||
|
||||
<!-- get demo apps -->
|
||||
<!--cvs cvsRoot="${cvs.root.apps}" command="export" tag="${cvs.apps.tag}" package="welcome" dest="${build.work}/apps" /-->
|
||||
|
||||
<!-- add a copy of the welcome app -->
|
||||
<mkdir dir="${build.work}/apps/welcome"/>
|
||||
<copy todir="${build.work}/apps/welcome">
|
||||
<fileset dir="${build.externals}/welcome"/>
|
||||
</copy>
|
||||
|
||||
<antcall target="package-manage" />
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Checkout and zip manage application -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-manage" depends="init">
|
||||
<!--cvs cvsRoot="${cvs.root.apps}" command="export" tag="${cvs.apps.tag}" package="manage" dest="${build.work}" /-->
|
||||
<mkdir dir="${build.work}/apps/manage"/>
|
||||
<zip zipfile="${build.work}/apps/manage/manage.zip" basedir="${build.externals}/manage/" includes="**" excludes="**/properties,readme/**" />
|
||||
<copy todir="${build.work}/apps/manage">
|
||||
<fileset dir="${build.externals}/manage" includes="app.properties,class.properties,readme.txt"/>
|
||||
</copy>
|
||||
<!-- delete dir="${build.work}/manage" /-->
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Checkout modules, and include helmaTools -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-modules" depends="init">
|
||||
<!--cvs cvsRoot="${cvs.root.apps}" command="export" tag="${cvs.apps.tag}" package="modules" dest="${build.work}" /-->
|
||||
|
||||
<!-- add a copy of the modules -->
|
||||
<mkdir dir="${build.work}/modules"/>
|
||||
<copy todir="${build.work}/modules">
|
||||
<fileset dir="${build.externals}/modules"/>
|
||||
</copy>
|
||||
|
||||
<antcall target="package-helmaTools" />
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Checkout and zip helmaTools -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-helmaTools" depends="init">
|
||||
<!-- cvs cvsRoot="${cvs.root.apps}" command="export" package="helmaTools" dest="${build.work}" /-->
|
||||
<mkdir dir="${build.work}/modules"/>
|
||||
<zip zipfile="${build.work}/modules/helmaTools.zip" basedir="${build.externals}/helmaTools/" includes="**" excludes="**/*.txt, **/*.html, **/*.bat, **/*.sh" />
|
||||
<!--delete dir="${build.work}/helmaTools" /-->
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Packages the work directory with TAR-GZIP -->
|
||||
<!-- needs parameter ${filename} for final dist-file -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-tgz" depends="init">
|
||||
<mkdir dir="${build.dist}" />
|
||||
<fixcrlf srcdir="${build.work}" eol="lf" eof="remove" includes="**/*.txt, **/*.properties, **/*.hac, **/*.js, **/*.skin" />
|
||||
<tar tarfile="${build.dist}/${filename}.tar" basedir="${build.work}" excludes="**">
|
||||
<tarfileset prefix="${filename}" dir="${build.work}" mode="755">
|
||||
<include name="start.sh"/>
|
||||
</tarfileset>
|
||||
<tarfileset prefix="${filename}" dir="${build.work}">
|
||||
<include name="**"/>
|
||||
<exclude name="start.sh"/>
|
||||
<exclude name="lib/jimi.jar"/>
|
||||
<exclude name="lib/apache-dom.jar"/>
|
||||
<exclude name="docs/api/**"/>
|
||||
</tarfileset>
|
||||
</tar>
|
||||
<gzip zipfile="${build.dist}/${filename}.tar.gz" src="${build.dist}/${filename}.tar"/>
|
||||
<delete file="${build.dist}/${filename}.tar"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Packages the work directory with ZIP -->
|
||||
<!-- needs parameter ${filename} for final dist-file -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-zip" depends="init">
|
||||
<mkdir dir="${build.dist}" />
|
||||
<fixcrlf srcdir="${build.work}" eol="crlf" includes="**/*.txt, **/*.properties, **/*.hac, **/*.js, **/*.skin, **/*.xml" />
|
||||
<zip zipfile="${build.dist}/${filename}.zip">
|
||||
<zipfileset dir="${build.work}" prefix="${filename}">
|
||||
<include name="**"/>
|
||||
<exclude name="start.sh"/>
|
||||
<exclude name="lib/jimi.jar"/>
|
||||
<exclude name="lib/apache-dom.jar"/>
|
||||
<exclude name="docs/api/**"/>
|
||||
</zipfileset>
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Packages Helma src and build directories with TAR-GZIP -->
|
||||
<!-- needs parameter ${filename} for final dist-file -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-src-tgz" depends="init">
|
||||
<mkdir dir="${build.dist}" />
|
||||
<tar tarfile="${build.dist}/${filename}-src.tar">
|
||||
<tarfileset prefix="${filename}" dir="${home.dir}">
|
||||
<include name="src/**"/>
|
||||
<include name="build/**"/>
|
||||
<include name="docs/**"/>
|
||||
<include name="licenses/**"/>
|
||||
<include name="license.txt"/>
|
||||
<include name="lib/jimi.jar"/>
|
||||
<include name="lib/apache-dom.jar"/>
|
||||
<exclude name="docs/modules/**"/>
|
||||
</tarfileset>
|
||||
</tar>
|
||||
<gzip zipfile="${build.dist}/${filename}-src.tar.gz" src="${build.dist}/${filename}-src.tar"/>
|
||||
<delete file="${build.dist}/${filename}-src.tar"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Packages Helma src and build directories with ZIP -->
|
||||
<!-- needs parameter ${filename} for final dist-file -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="package-src-zip" depends="init">
|
||||
<mkdir dir="${build.dist}" />
|
||||
<zip zipfile="${build.dist}/${filename}-src.zip">
|
||||
<zipfileset dir="${home.dir}" prefix="${filename}">
|
||||
<include name="src/**"/>
|
||||
<include name="build/**"/>
|
||||
<include name="docs/**"/>
|
||||
<include name="licenses/**"/>
|
||||
<include name="license.txt"/>
|
||||
<include name="lib/jimi.jar"/>
|
||||
<include name="lib/apache-dom.jar"/>
|
||||
<exclude name="docs/modules/**"/>
|
||||
</zipfileset>
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Cleans up temporary build directories -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="clean" depends="init">
|
||||
<delete dir="${build.work}" />
|
||||
<delete dir="${build.classes}" />
|
||||
</target>
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Gets an application from the cvs and zips/targzs it -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="app" depends="init">
|
||||
<mkdir dir="${build.dist}" />
|
||||
<mkdir dir="${build.work}" />
|
||||
|
||||
<!-- to retrieve special versions of an application insert
|
||||
additional attributes: tag="TAGNAME" or date="1972-09-24 20:05" -->
|
||||
<!--cvs cvsRoot="${cvs.root.apps}" command="export" tag="${cvs.apps.tag}" package="${application}" dest="${build.work}" /-->
|
||||
|
||||
<fixcrlf srcdir="${build.work}" eol="crlf" eof="add" includes="**/*.txt, **/*.properties, **/*.hac, **/*.js, **/*.skin, **/*.xml" />
|
||||
<zip zipfile="${build.dist}/${application}-${DSTAMP}.zip" basedir="${build.work}" includes="**"/>
|
||||
|
||||
<fixcrlf srcdir="${build.work}" eol="lf" eof="remove" includes="**/*.txt, **/*.properties, **/*.hac, **/*.js, **/*.skin" />
|
||||
<tar tarfile="${build.dist}/${application}-${DSTAMP}.tar" basedir="${build.work}">
|
||||
<tarfileset dir="${build.work}">
|
||||
<include name="${build.work}/**"/>
|
||||
</tarfileset>
|
||||
</tar>
|
||||
<gzip zipfile="${build.dist}/${application}-${DSTAMP}.tar.gz" src="${build.dist}/${application}-${DSTAMP}.tar" />
|
||||
|
||||
<delete file="${build.dist}/${application}-${DSTAMP}.tar" />
|
||||
<!--delete dir="${build.work}" /-->
|
||||
</target>
|
||||
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- Checkout and zip a module -->
|
||||
<!-- =================================================================== -->
|
||||
<target name="module" depends="init">
|
||||
<cvs cvsRoot="${cvs.root.apps}" command="export" tag="${cvs.apps.tag}" package="${application}" dest="${build.work}" />
|
||||
<mkdir dir="${build.work}/modules"/>
|
||||
<zip zipfile="${build.work}/modules/${application}-${DSTAMP}.zip" basedir="${build.work}/${application}/" includes="**" excludes="**/*.txt, **/*.html, **/*.bat, **/*.sh" />
|
||||
<delete dir="${build.work}/${application}" />
|
||||
</target>
|
||||
|
||||
|
||||
</project>
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 1999-2006 Helma Project. All rights reserved.
|
||||
Copyright (c) 1999-2008 Helma Project. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
|
|
@ -164,7 +164,18 @@ public class RequestTrans implements Serializable {
|
|||
* @return true if this might be an XML-RPC request.
|
||||
*/
|
||||
public synchronized boolean checkXmlRpc() {
|
||||
return "POST".equals(method) && "text/xml".equals(request.getContentType());
|
||||
if ("POST".equalsIgnoreCase(method)) {
|
||||
String contentType = request.getContentType();
|
||||
if (contentType == null) {
|
||||
return false;
|
||||
}
|
||||
int semi = contentType.indexOf(";");
|
||||
if (semi > -1) {
|
||||
contentType = contentType.substring(0, semi);
|
||||
}
|
||||
return "text/xml".equalsIgnoreCase(contentType.trim());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -493,11 +493,11 @@ public final class ResponseTrans extends Writer implements Serializable {
|
|||
|
||||
/**
|
||||
* 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[].
|
||||
* overwrite the previous output.
|
||||
* @param bytes an arbitrary byte array
|
||||
*/
|
||||
public void writeBinary(byte[] what) {
|
||||
response = what;
|
||||
public void writeBinary(byte[] bytes) {
|
||||
response = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -649,6 +649,11 @@ public final class ResponseTrans extends Writer implements Serializable {
|
|||
// there's no point in closing the response buffer
|
||||
HttpServletResponse res = reqtrans.getServletResponse();
|
||||
if (res != null && res.isCommitted()) {
|
||||
// response was committed using HttpServletResponse directly. We need
|
||||
// set response to null and notify waiters in order to let attached
|
||||
// requests know they can't reuse this response.
|
||||
response = null;
|
||||
notifyAll();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -664,7 +669,8 @@ public final class ResponseTrans extends Writer implements Serializable {
|
|||
|
||||
boolean encodingError = false;
|
||||
|
||||
// only close if the response hasn't been closed yet
|
||||
// only close if the response hasn't been closed yet, and if no
|
||||
// response was generated using writeBinary().
|
||||
if (response == null) {
|
||||
// if debug buffer exists, append it to main buffer
|
||||
if (contentType != null &&
|
||||
|
@ -747,7 +753,7 @@ public final class ResponseTrans extends Writer implements Serializable {
|
|||
* @return the response body
|
||||
*/
|
||||
public byte[] getContent() {
|
||||
return (response == null) ? new byte[0] : response;
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -342,7 +342,7 @@ public final class Application implements Runnable {
|
|||
String ignoreDirs;
|
||||
|
||||
Initializer(String dirs) {
|
||||
super("INIT-" + name);
|
||||
super(name + "-init");
|
||||
ignoreDirs = dirs;
|
||||
}
|
||||
|
||||
|
@ -489,7 +489,7 @@ public final class Application implements Runnable {
|
|||
releaseEvaluator(eval);
|
||||
}
|
||||
|
||||
worker = new Thread(this, "Worker-" + name);
|
||||
worker = new Thread(this, name + "-worker");
|
||||
worker.setPriority(Thread.NORM_PRIORITY + 1);
|
||||
worker.start();
|
||||
}
|
||||
|
@ -720,6 +720,14 @@ public final class Application implements Runnable {
|
|||
|
||||
if (ev != null) {
|
||||
res = ev.attachHttpRequest(req);
|
||||
if (res != null) {
|
||||
// we can only use the existing response object if the response
|
||||
// wasn't written to the HttpServletResponse directly.
|
||||
res.waitForClose();
|
||||
if (res.getContent() == null) {
|
||||
res = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res == null) {
|
||||
|
@ -752,8 +760,6 @@ public final class Application implements Runnable {
|
|||
} catch (UnsupportedEncodingException uee) {
|
||||
logError("Unsupported response encoding", uee);
|
||||
}
|
||||
} else {
|
||||
res.waitForClose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1468,7 @@ public final class Application implements Runnable {
|
|||
/**
|
||||
* get the app's event log.
|
||||
*/
|
||||
Log getEventLog() {
|
||||
public Log getEventLog() {
|
||||
if (eventLog == null) {
|
||||
eventLog = getLogger(eventLogName);
|
||||
// set log level for event log in case it is a helma.util.Logger
|
||||
|
@ -1479,7 +1485,7 @@ public final class Application implements Runnable {
|
|||
/**
|
||||
* get the app's access log.
|
||||
*/
|
||||
Log getAccessLog() {
|
||||
public Log getAccessLog() {
|
||||
if (accessLog == null) {
|
||||
accessLog = getLogger(accessLogName);
|
||||
}
|
||||
|
@ -1735,28 +1741,6 @@ public final class Application implements Runnable {
|
|||
return Collections.unmodifiableList(repositories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the code resource currently being evaluated/compiled. This is used
|
||||
* to set the proper parent repository when a new repository is added
|
||||
* via app.addRepository().
|
||||
*
|
||||
* @param resource the resource being currently evaluated/compiled
|
||||
*/
|
||||
public void setCurrentCodeResource(Resource resource) {
|
||||
currentCodeResource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the code resource currently being evaluated/compiled. This is used
|
||||
* to set the proper parent repository when a new repository is added
|
||||
* via app.addRepository().
|
||||
|
||||
* @return the resource being currently evaluated/compiled
|
||||
*/
|
||||
public Resource getCurrentCodeResource() {
|
||||
return currentCodeResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the directory of the Helma server
|
||||
*/
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
* application specific functionality.
|
||||
*/
|
||||
public class ApplicationBean implements Serializable {
|
||||
Application app;
|
||||
transient Application app;
|
||||
WrappedMap properties = null;
|
||||
|
||||
/**
|
||||
|
@ -137,33 +137,27 @@ public class ApplicationBean implements Serializable {
|
|||
*
|
||||
* @param obj the repository, relative or absolute path to the library.
|
||||
*/
|
||||
public void addRepository(Object obj) {
|
||||
Resource current = app.getCurrentCodeResource();
|
||||
Repository parent = current == null ?
|
||||
null : current.getRepository().getRootRepository();
|
||||
public synchronized void addRepository(Object obj) {
|
||||
Repository rep;
|
||||
if (obj instanceof String) {
|
||||
String path = (String) obj;
|
||||
File file = new File(path).getAbsoluteFile();
|
||||
File file = findResource(null, path);
|
||||
if (!file.exists()) {
|
||||
file = new File(path + ".zip").getAbsoluteFile();
|
||||
file = findResource(app.hopHome, path);
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file = new File(path + ".js").getAbsoluteFile();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
throw new RuntimeException("Repository path does not exist: " + obj);
|
||||
throw new RuntimeException("Repository path does not exist: " + file);
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
rep = new FileRepository(file, parent);
|
||||
rep = new FileRepository(file);
|
||||
} else if (file.isFile()) {
|
||||
if (file.getName().endsWith(".zip")) {
|
||||
rep = new ZipRepository(file, parent);
|
||||
rep = new ZipRepository(file);
|
||||
} else {
|
||||
rep = new SingleFileRepository(file, parent);
|
||||
rep = new SingleFileRepository(file);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Unrecognized file type in addRepository: " + obj);
|
||||
throw new RuntimeException("Unsupported file type in addRepository: " + file);
|
||||
}
|
||||
} else if (obj instanceof Repository) {
|
||||
rep = (Repository) obj;
|
||||
|
@ -178,6 +172,23 @@ public class ApplicationBean implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to resolve a repository path.
|
||||
* @param parent the parent file
|
||||
* @param path the repository path
|
||||
* @return our best guess of what the file may be
|
||||
*/
|
||||
private File findResource(File parent, String path) {
|
||||
File file = new File(parent, path).getAbsoluteFile();
|
||||
if (!file.exists()) {
|
||||
file = new File(parent, path + ".zip").getAbsoluteFile();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file = new File(parent, path + ".js").getAbsoluteFile();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the app's classloader
|
||||
* @return the app's classloader
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.*;
|
|||
|
||||
import org.apache.xmlrpc.XmlRpcRequestProcessor;
|
||||
import org.apache.xmlrpc.XmlRpcServerRequest;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
/**
|
||||
* This class does the work for incoming requests. It holds a transactor thread
|
||||
|
@ -79,6 +80,10 @@ public final class RequestEvaluator implements Runnable {
|
|||
// the exception thrown by the evaluator, if any.
|
||||
private volatile Exception exception;
|
||||
|
||||
// For numbering threads.
|
||||
private int threadId;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RequestEvaluator for this application.
|
||||
* @param app the application
|
||||
|
@ -155,6 +160,12 @@ public final class RequestEvaluator implements Runnable {
|
|||
// request path object
|
||||
RequestPath requestPath = new RequestPath(app);
|
||||
|
||||
String txname = req.getMethod().toLowerCase() + ":" + req.getPath();
|
||||
Log eventLog = app.getEventLog();
|
||||
if (eventLog.isDebugEnabled()) {
|
||||
eventLog.debug(txname + " starting");
|
||||
}
|
||||
|
||||
int tries = 0;
|
||||
boolean done = false;
|
||||
Throwable error = null;
|
||||
|
@ -198,14 +209,14 @@ public final class RequestEvaluator implements Runnable {
|
|||
throw new IllegalStateException("No function name in non-internal request ");
|
||||
}
|
||||
|
||||
// Transaction name is used for logging etc.
|
||||
StringBuffer txname = new StringBuffer(app.getName());
|
||||
txname.append(":").append(req.getMethod().toLowerCase()).append(":");
|
||||
txname.append((error == null) ? req.getPath() : "error");
|
||||
// Update transaction name in case we're processing an error
|
||||
if (error != null) {
|
||||
txname = "error:" + txname;
|
||||
}
|
||||
|
||||
// begin transaction
|
||||
transactor = Transactor.getInstance(app.nmgr);
|
||||
transactor.begin(txname.toString());
|
||||
transactor.begin(txname);
|
||||
|
||||
Object root = app.getDataRoot();
|
||||
initGlobals(root, requestPath);
|
||||
|
@ -398,6 +409,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
ScriptingEngine.ARGS_WRAP_XMLRPC,
|
||||
false);
|
||||
res.writeXmlRpcResponse(result);
|
||||
app.xmlrpcCount += 1;
|
||||
} else {
|
||||
scriptingEngine.invoke(currentElement,
|
||||
actionProcessor,
|
||||
|
@ -478,7 +490,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
return;
|
||||
}
|
||||
abortTransaction();
|
||||
app.logError(txname + ": " + error, x);
|
||||
app.logError(txname + " " + error, x);
|
||||
|
||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
||||
// bother for the error message, just quit.
|
||||
|
@ -514,7 +526,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
return;
|
||||
}
|
||||
abortTransaction();
|
||||
app.logError(txname + ": " + error, x);
|
||||
app.logError(txname + " " + error, x);
|
||||
|
||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
||||
// bother for the error message, just quit.
|
||||
|
@ -598,9 +610,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
done = false;
|
||||
error = x;
|
||||
|
||||
Transactor tx = Transactor.getInstance();
|
||||
String txname = tx == null ? "no-txn" : tx.getTransactionName();
|
||||
app.logError(txname + ": " + error, x);
|
||||
app.logError(txname + " " + error, x);
|
||||
|
||||
if (req.isXmlRpc()) {
|
||||
// if it's an XML-RPC exception immediately generate error response
|
||||
|
@ -619,10 +629,11 @@ public final class RequestEvaluator implements Runnable {
|
|||
} finally {
|
||||
app.setCurrentRequestEvaluator(null);
|
||||
// exit execution context
|
||||
if (scriptingEngine != null)
|
||||
if (scriptingEngine != null) {
|
||||
scriptingEngine.exitContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notifyAndWait();
|
||||
|
||||
|
@ -667,7 +678,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
|
||||
if ((thread == null) || !thread.isAlive()) {
|
||||
// app.logEvent ("Starting Thread");
|
||||
thread = new Thread(app.threadgroup, this);
|
||||
thread = new Thread(app.threadgroup, this, app.getName() + "-" + (++threadId));
|
||||
thread.setContextClassLoader(app.getClassLoader());
|
||||
thread.start();
|
||||
} else {
|
||||
|
@ -783,7 +794,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
// Get a reference to the res object at the time we enter
|
||||
ResponseTrans localRes = res;
|
||||
|
||||
if ((localRes == null) || !req.equals(this.req)) {
|
||||
if (localRes == null || !req.equals(this.req)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ import java.util.*;
|
|||
*/
|
||||
public class Session implements Serializable {
|
||||
|
||||
static final long serialVersionUID = -6149094040363012913L;
|
||||
|
||||
transient protected Application app;
|
||||
protected String sessionId;
|
||||
|
||||
|
|
|
@ -437,13 +437,8 @@ public final class Skin {
|
|||
|
||||
if (state == PARSE_MACRONAME && "//".equals(b.toString())) {
|
||||
isCommentMacro = true;
|
||||
// search macro end tag
|
||||
while (i < length - 1 &&
|
||||
(source[i] != '%' || source[i + 1] != '>')) {
|
||||
i++;
|
||||
}
|
||||
state = PARSE_DONE;
|
||||
break loop;
|
||||
// just continue parsing the macro as this is the only way
|
||||
// to correctly catch embedded macros - see bug 588
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -639,7 +634,7 @@ public final class Skin {
|
|||
}
|
||||
|
||||
if ((sandbox != null) && !sandbox.contains(name)) {
|
||||
throw new RuntimeException("Macro " + name + " not allowed in sandbox");
|
||||
throw new MacroException("Macro not allowed in sandbox: " + name);
|
||||
}
|
||||
|
||||
Object handler = null;
|
||||
|
@ -705,7 +700,7 @@ public final class Skin {
|
|||
buffer.setLength(bufLength);
|
||||
}
|
||||
} else if (standardParams.verboseFailmode(handler, engine)) {
|
||||
throw new UnhandledMacroException(name);
|
||||
throw new MacroException("Unhandled macro: " + name);
|
||||
}
|
||||
} else {
|
||||
value = engine.getProperty(handler, propName);
|
||||
|
@ -713,7 +708,7 @@ public final class Skin {
|
|||
return filter(value, cx);
|
||||
}
|
||||
} else if (standardParams.verboseFailmode(handler, engine)) {
|
||||
throw new UnhandledMacroException(name);
|
||||
throw new MacroException("Unhandled macro: " + name);
|
||||
}
|
||||
return filter(null, cx);
|
||||
}
|
||||
|
@ -786,8 +781,8 @@ public final class Skin {
|
|||
throw concur;
|
||||
} catch (TimeoutException timeout) {
|
||||
throw timeout;
|
||||
} catch (UnhandledMacroException unhandled) {
|
||||
String msg = "Unhandled Macro: " + unhandled.getMessage();
|
||||
} catch (MacroException mx) {
|
||||
String msg = mx.getMessage();
|
||||
cx.reval.getResponse().write(" [" + msg + "] ");
|
||||
app.logError(msg);
|
||||
} catch (Exception x) {
|
||||
|
@ -816,9 +811,9 @@ public final class Skin {
|
|||
throws Exception {
|
||||
|
||||
if (name == null) {
|
||||
throw new RuntimeException("Empty macro filter");
|
||||
throw new MacroException("Empty macro filter");
|
||||
} else if (sandbox != null && !sandbox.contains(name)) {
|
||||
throw new RuntimeException("Macro " + name + " not allowed in sandbox");
|
||||
throw new MacroException("Macro not allowed in sandbox: " + name);
|
||||
}
|
||||
Object handlerObject = null;
|
||||
|
||||
|
@ -840,7 +835,7 @@ public final class Skin {
|
|||
|
||||
return filter(retval, cx);
|
||||
} else {
|
||||
throw new RuntimeException("Undefined Filter " + name);
|
||||
throw new MacroException("Undefined macro filter: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1103,9 +1098,9 @@ public final class Skin {
|
|||
// limiting to 50 passes to avoid infinite loops
|
||||
int maxloop = 50;
|
||||
while (obj != null && maxloop-- > 0) {
|
||||
Prototype proto = app.getPrototype(obj);
|
||||
String protoName = app.getPrototypeName(obj);
|
||||
|
||||
if ((proto != null) && proto.isInstanceOf(handlerName)) {
|
||||
if (handlerName.equalsIgnoreCase(protoName)) {
|
||||
if (handlerCache != null)
|
||||
handlerCache.put(handlerName, obj);
|
||||
return obj;
|
||||
|
@ -1126,12 +1121,13 @@ public final class Skin {
|
|||
}
|
||||
|
||||
/**
|
||||
* Exception type for unhandled macros
|
||||
* Exception type for unhandled, forbidden or failed macros
|
||||
*/
|
||||
class UnhandledMacroException extends Exception {
|
||||
UnhandledMacroException(String name) {
|
||||
super(name);
|
||||
}
|
||||
class MacroException extends Exception {
|
||||
MacroException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ public final class TypeManager {
|
|||
* Run through application's prototype directories and create prototypes, but don't
|
||||
* compile or evaluate any scripts.
|
||||
*/
|
||||
public void createPrototypes() throws IOException {
|
||||
public synchronized void createPrototypes() throws IOException {
|
||||
// create standard prototypes.
|
||||
for (int i = 0; i < standardTypes.length; i++) {
|
||||
createPrototype(standardTypes[i], null);
|
||||
|
@ -126,7 +126,7 @@ public final class TypeManager {
|
|||
lastCheck = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
protected void checkRepository(Repository repository, boolean update) throws IOException {
|
||||
protected synchronized void checkRepository(Repository repository, boolean update) throws IOException {
|
||||
Repository[] list = repository.getRepositories();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
|
||||
|
@ -183,7 +183,7 @@ public final class TypeManager {
|
|||
* Run through application's prototype sources and check if
|
||||
* there are any prototypes to be created.
|
||||
*/
|
||||
private void checkRepositories() throws IOException {
|
||||
private synchronized void checkRepositories() throws IOException {
|
||||
List list = app.getRepositories();
|
||||
|
||||
// walk through repositories and check if any of them have changed.
|
||||
|
@ -197,12 +197,21 @@ public final class TypeManager {
|
|||
}
|
||||
}
|
||||
|
||||
boolean debug = "true".equalsIgnoreCase(app.getProperty("helma.debugTypeManager"));
|
||||
if (debug) {
|
||||
System.err.println("Starting CHECK loop in " + Thread.currentThread());
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
if (debug) {
|
||||
System.err.println("CHECK: " + proto.getName() + " in " + Thread.currentThread());
|
||||
}
|
||||
|
||||
// update prototype's type mapping
|
||||
DbMapping dbmap = proto.getDbMapping();
|
||||
|
||||
|
@ -216,6 +225,9 @@ public final class TypeManager {
|
|||
dbmap.update();
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
System.err.println("Finished CHECK in " + Thread.currentThread());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidTypeName(String str) {
|
||||
|
@ -263,14 +275,14 @@ public final class TypeManager {
|
|||
*
|
||||
* @return a collection containing the prototypes
|
||||
*/
|
||||
public Collection getPrototypes() {
|
||||
public synchronized Collection getPrototypes() {
|
||||
return Collections.unmodifiableCollection(prototypes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a prototype defined for this application
|
||||
*/
|
||||
public Prototype getPrototype(String typename) {
|
||||
public synchronized Prototype getPrototype(String typename) {
|
||||
if (typename == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -284,12 +296,14 @@ public final class TypeManager {
|
|||
* @param repository the first prototype source
|
||||
* @return the newly created prototype
|
||||
*/
|
||||
public Prototype createPrototype(String typename, Repository repository) {
|
||||
public synchronized Prototype createPrototype(String typename, Repository repository) {
|
||||
if ("true".equalsIgnoreCase(app.getProperty("helma.debugTypeManager"))) {
|
||||
System.err.println("CREATE: " + typename + " from " + repository + " in " + Thread.currentThread());
|
||||
// Thread.dumpStack();
|
||||
}
|
||||
Prototype proto = new Prototype(typename, repository, app);
|
||||
|
||||
// put the prototype into our map
|
||||
prototypes.put(proto.getLowerCaseName(), proto);
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
|
|
|
@ -281,6 +281,14 @@ public class ApplicationManager implements XmlRpcHandler {
|
|||
return server.getLogger();
|
||||
}
|
||||
|
||||
private String findResource(String path) {
|
||||
File file = new File(path);
|
||||
if (!file.isAbsolute() && !file.exists()) {
|
||||
file = new File(server.getHopHome(), path);
|
||||
}
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class that describes an application and its start settings.
|
||||
*/
|
||||
|
@ -350,7 +358,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
|||
ignoreDirs = conf.getProperty("ignore");
|
||||
|
||||
// read and configure app repositories
|
||||
ArrayList<Repository> repositoryList = new ArrayList<Repository>();
|
||||
ArrayList repositoryList = new ArrayList();
|
||||
Class[] parameters = { String.class };
|
||||
for (int i = 0; true; i++) {
|
||||
String repositoryArgs = conf.getProperty("repository." + i);
|
||||
|
@ -362,10 +370,13 @@ public class ApplicationManager implements XmlRpcHandler {
|
|||
if (repositoryImpl == null) {
|
||||
// implementation not set manually, have to guess it
|
||||
if (repositoryArgs.endsWith(".zip")) {
|
||||
repositoryArgs = findResource(repositoryArgs);
|
||||
repositoryImpl = "helma.framework.repository.ZipRepository";
|
||||
} else if (repositoryArgs.endsWith(".js")) {
|
||||
repositoryArgs = findResource(repositoryArgs);
|
||||
repositoryImpl = "helma.framework.repository.SingleFileRepository";
|
||||
} else {
|
||||
repositoryArgs = findResource(repositoryArgs);
|
||||
repositoryImpl = "helma.framework.repository.FileRepository";
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +384,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
|||
try {
|
||||
Repository newRepository = (Repository) Class.forName(repositoryImpl)
|
||||
.getConstructor(parameters)
|
||||
.newInstance(repositoryArgs);
|
||||
.newInstance(new Object[] {repositoryArgs});
|
||||
repositoryList.add(newRepository);
|
||||
} catch (Exception ex) {
|
||||
getLogger().error("Adding repository " + repositoryArgs + " failed. " +
|
||||
|
@ -397,7 +408,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
|||
new File(server.getAppsHome(), appName)));
|
||||
}
|
||||
repositories = new Repository[repositoryList.size()];
|
||||
repositories = repositoryList.toArray(repositories);
|
||||
repositories = (Repository[]) repositoryList.toArray(repositories);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@ import java.io.*;
|
|||
import java.rmi.registry.*;
|
||||
import java.rmi.server.*;
|
||||
import java.util.*;
|
||||
import java.net.Socket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import helma.util.ResourceProperties;
|
||||
|
||||
|
@ -44,7 +40,7 @@ import helma.util.ResourceProperties;
|
|||
*/
|
||||
public class Server implements Runnable {
|
||||
// version string
|
||||
public static final String version = "1.6.2 (__builddate__)";
|
||||
public static final String version = "1.6.3 (__builddate__)";
|
||||
|
||||
// static server instance
|
||||
private static Server server;
|
||||
|
@ -109,8 +105,10 @@ public class Server implements Runnable {
|
|||
|
||||
// create system properties
|
||||
sysProps = new ResourceProperties();
|
||||
if (config.hasPropFile()) {
|
||||
sysProps.addResource(new FileResource(config.getPropFile()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -304,13 +302,6 @@ public class Server implements Runnable {
|
|||
if (!config.hasHomeDir()) {
|
||||
throw new Exception ("couldn't determine helma directory");
|
||||
}
|
||||
|
||||
// try to transform hopHome directory to its canonical representation
|
||||
try {
|
||||
config.setHomeDir(config.getHomeDir().getCanonicalFile());
|
||||
} catch (IOException iox) {
|
||||
config.setHomeDir(config.getHomeDir().getAbsoluteFile());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public class ServerConfig {
|
|||
}
|
||||
|
||||
public void setPropFile(File propFile) {
|
||||
this.propFile = propFile;
|
||||
this.propFile = propFile == null ? null : propFile.getAbsoluteFile();
|
||||
}
|
||||
|
||||
public File getHomeDir() {
|
||||
|
@ -101,6 +101,6 @@ public class ServerConfig {
|
|||
}
|
||||
|
||||
public void setHomeDir(File homeDir) {
|
||||
this.homeDir = homeDir;
|
||||
this.homeDir = homeDir == null ? null : homeDir.getAbsoluteFile();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package helma.objectmodel;
|
|||
import helma.framework.IPathElement;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.objectmodel.db.Relation;
|
||||
import helma.objectmodel.db.Node;
|
||||
import helma.util.*;
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
|
@ -588,7 +589,7 @@ public class TransientNode implements INode, Serializable {
|
|||
}
|
||||
|
||||
private Property makeVirtualNode(String propname, Relation rel) {
|
||||
INode node = new helma.objectmodel.db.Node(rel.getPropName(), rel.getPrototype(),
|
||||
INode node = new Node(rel.getPropName(), rel.getPrototype(),
|
||||
dbmap.getWrappedNodeManager());
|
||||
|
||||
// node.setState (TRANSIENT);
|
||||
|
|
|
@ -124,7 +124,10 @@ public final class DbMapping {
|
|||
HashSet dependentMappings = new HashSet();
|
||||
|
||||
// does this DbMapping describe a virtual node (collection, mountpoint, groupnode)?
|
||||
private boolean virtual = false;
|
||||
private boolean isVirtual = false;
|
||||
|
||||
// does this Dbmapping describe a group node?
|
||||
private boolean isGroup = false;
|
||||
|
||||
/**
|
||||
* Create an internal DbMapping used for "virtual" mappings aka collections, mountpoints etc.
|
||||
|
@ -132,7 +135,7 @@ public final class DbMapping {
|
|||
public DbMapping(Application app, String parentTypeName) {
|
||||
this(app, parentTypeName, null);
|
||||
// DbMappings created with this constructor always define virtual nodes
|
||||
virtual = true;
|
||||
isVirtual = true;
|
||||
if (parentTypeName != null) {
|
||||
parentMapping = app.getDbMapping(parentTypeName);
|
||||
if (parentMapping == null) {
|
||||
|
@ -311,9 +314,6 @@ public final class DbMapping {
|
|||
}
|
||||
|
||||
rel.update(dbField, props);
|
||||
|
||||
// store relation with lower case property name
|
||||
// (ResourceProperties now preserve key capitalization!)
|
||||
p2d.put(propName.toLowerCase(), rel);
|
||||
|
||||
if ((rel.columnName != null) && rel.isPrimitiveOrReference()) {
|
||||
|
@ -758,7 +758,7 @@ public final class DbMapping {
|
|||
public synchronized DbMapping getGroupbyMapping() {
|
||||
if ((subRelation == null) && (parentMapping != null)) {
|
||||
return parentMapping.getGroupbyMapping();
|
||||
} else if (subRelation.groupby == null) {
|
||||
} else if (subRelation == null || subRelation.groupby == null) {
|
||||
return null;
|
||||
} else if (groupbyMapping == null) {
|
||||
initGroupbyMapping();
|
||||
|
@ -774,6 +774,7 @@ public final class DbMapping {
|
|||
// 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, subRelation.groupbyPrototype);
|
||||
groupbyMapping.isGroup = true;
|
||||
|
||||
// set subnode and property relations
|
||||
groupbyMapping.subRelation = subRelation.getGroupbySubnodeRelation();
|
||||
|
@ -1547,7 +1548,7 @@ public final class DbMapping {
|
|||
* a utility method to escape single quotes used for inserting
|
||||
* string-values into relational databases.
|
||||
* Searches for "'" characters and escapes them by duplicating them (= "''")
|
||||
* @param str the string to escape
|
||||
* @param value the string to escape
|
||||
* @return the escaped string
|
||||
*/
|
||||
static String escapeString(Object value) {
|
||||
|
@ -1574,7 +1575,7 @@ public final class DbMapping {
|
|||
|
||||
/**
|
||||
* Utility method to check whether the argument is a number literal.
|
||||
* @param str a string representing a number literal
|
||||
* @param value a string representing a number literal
|
||||
* @return the argument, if it conforms to the number literal syntax
|
||||
* @throws IllegalArgumentException if the argument does not represent a number
|
||||
*/
|
||||
|
@ -1596,6 +1597,14 @@ public final class DbMapping {
|
|||
* @return true if this instance describes a virtual node.
|
||||
*/
|
||||
public boolean isVirtual() {
|
||||
return virtual;
|
||||
return isVirtual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find if this DbMapping describes a group node.
|
||||
* @return true if this instance describes a group node.
|
||||
*/
|
||||
public boolean isGroup() {
|
||||
return isGroup;
|
||||
}
|
||||
}
|
|
@ -869,27 +869,11 @@ public final class Node implements INode, Serializable {
|
|||
loadNodes();
|
||||
|
||||
// check if this node has a group-by subnode-relation
|
||||
if (dbmap != null) {
|
||||
Relation srel = dbmap.getSubnodeRelation();
|
||||
|
||||
if ((srel != null) && (srel.groupby != null)) {
|
||||
Relation groupbyRel = srel.otherType.columnNameToRelation(srel.groupby);
|
||||
String groupbyProp = (groupbyRel != null) ? groupbyRel.propName
|
||||
: srel.groupby;
|
||||
String groupbyValue = node.getString(groupbyProp);
|
||||
INode groupbyNode = (INode) getChildElement(groupbyValue);
|
||||
|
||||
// if group-by node doesn't exist, we'll create it
|
||||
if (groupbyNode == null) {
|
||||
groupbyNode = getGroupbySubnode(groupbyValue, true);
|
||||
} else {
|
||||
groupbyNode.setDbMapping(dbmap.getGroupbyMapping());
|
||||
}
|
||||
|
||||
INode groupbyNode = getGroupbySubnode(node, true);
|
||||
if (groupbyNode != null) {
|
||||
groupbyNode.addNode(node);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
NodeHandle nhandle = node.getHandle();
|
||||
|
||||
|
@ -1198,6 +1182,38 @@ public final class Node implements INode, Serializable {
|
|||
return retval;
|
||||
}
|
||||
|
||||
protected Node getGroupbySubnode(Node node, boolean create) {
|
||||
if (node.dbmap != null && node.dbmap.isGroup()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (dbmap != null) {
|
||||
Relation srel = dbmap.getSubnodeRelation();
|
||||
|
||||
if ((srel != null) && (srel.groupby != null)) {
|
||||
Relation groupbyRel = srel.otherType.columnNameToRelation(srel.groupby);
|
||||
String groupbyProp = (groupbyRel != null) ? groupbyRel.propName
|
||||
: srel.groupby;
|
||||
String groupbyValue = node.getString(groupbyProp);
|
||||
Node groupbyNode = (Node) getChildElement(groupbyValue);
|
||||
|
||||
// if group-by node doesn't exist, we'll create it
|
||||
if (groupbyNode == null) {
|
||||
groupbyNode = getGroupbySubnode(groupbyValue, create);
|
||||
// mark subnodes as changed as we have a new group node
|
||||
if (create && groupbyNode != null) {
|
||||
Transactor.getInstance().visitParentNode(this);
|
||||
}
|
||||
} else {
|
||||
groupbyNode.setDbMapping(dbmap.getGroupbyMapping());
|
||||
}
|
||||
|
||||
return groupbyNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
@ -1211,10 +1227,7 @@ public final class Node implements INode, Serializable {
|
|||
throw new IllegalArgumentException("Can't create group by null");
|
||||
}
|
||||
|
||||
if (state == TRANSIENT) {
|
||||
throw new RuntimeException("Can't add grouped child on transient node. "+
|
||||
"Make parent persistent before adding grouped nodes.");
|
||||
}
|
||||
boolean persistent = state != TRANSIENT;
|
||||
|
||||
loadNodes();
|
||||
|
||||
|
@ -1228,27 +1241,36 @@ public final class Node implements INode, Serializable {
|
|||
boolean relational = groupbyMapping.getSubnodeMapping().isRelational();
|
||||
|
||||
if (relational || create) {
|
||||
Node node = relational ? new Node(this, sid, nmgr, null)
|
||||
: new Node(sid, null, nmgr);
|
||||
Node node;
|
||||
if (relational && persistent) {
|
||||
node = new Node(this, sid, nmgr, null);
|
||||
} else {
|
||||
node = new Node(sid, null, nmgr);
|
||||
node.setParent(this);
|
||||
}
|
||||
|
||||
// set "groupname" property to value of groupby field
|
||||
node.setString("groupname", sid);
|
||||
|
||||
// Set the dbmapping on the group node
|
||||
node.setDbMapping(groupbyMapping);
|
||||
node.setPrototype(groupbyMapping.getTypeName());
|
||||
|
||||
if (!relational) {
|
||||
// if we're not transient, make new node persistable
|
||||
if (state != TRANSIENT) {
|
||||
// if we're relational and persistent, make new node persistable
|
||||
if (!relational && persistent) {
|
||||
node.makePersistable();
|
||||
node.checkWriteLock();
|
||||
}
|
||||
subnodes.add(node.getHandle());
|
||||
|
||||
// if we created a new node, check if we need to add it to subnodes
|
||||
if (create) {
|
||||
NodeHandle handle = node.getHandle();
|
||||
if (!subnodes.contains(handle))
|
||||
subnodes.add(handle);
|
||||
}
|
||||
|
||||
// Set the dbmapping on the group node
|
||||
node.setPrototype(groupbyMapping.getTypeName());
|
||||
// If we created the group node, we register it with the
|
||||
// nodemanager. Otherwise, we just evict whatever was there before
|
||||
if (persistent) {
|
||||
if (create) {
|
||||
// register group node with transactor
|
||||
Transactor tx = Transactor.getInstanceOrFail();
|
||||
|
@ -1257,6 +1279,7 @@ public final class Node implements INode, Serializable {
|
|||
} else {
|
||||
nmgr.evictKey(node.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -1299,6 +1322,13 @@ public final class Node implements INode, Serializable {
|
|||
* {@link #removeNode(INode)}.
|
||||
*/
|
||||
protected void releaseNode(Node node) {
|
||||
|
||||
Node groupNode = getGroupbySubnode(node, false);
|
||||
if (groupNode != null) {
|
||||
groupNode.releaseNode(node);
|
||||
return;
|
||||
}
|
||||
|
||||
INode parent = node.getParent();
|
||||
|
||||
checkWriteLock();
|
||||
|
@ -1314,7 +1344,9 @@ public final class Node implements INode, Serializable {
|
|||
synchronized (subnodes) {
|
||||
removed = subnodes.remove(node.getHandle());
|
||||
}
|
||||
if (removed) {
|
||||
if (dbmap != null && dbmap.isGroup() && subnodes.size() == 0) {
|
||||
remove();
|
||||
} else if (removed) {
|
||||
registerSubnodeChange();
|
||||
}
|
||||
}
|
||||
|
@ -1341,6 +1373,12 @@ public final class Node implements INode, Serializable {
|
|||
nmgr.evictKey(new SyntheticKey(getKey(), prop));
|
||||
}
|
||||
}
|
||||
} else if (prel.groupby != null) {
|
||||
String prop = node.getString("groupname");
|
||||
if (prop != null && state != TRANSIENT) {
|
||||
nmgr.evictKey(new SyntheticKey(getKey(), prop));
|
||||
}
|
||||
|
||||
}
|
||||
// TODO: We should unset constraints to actually remove subnodes here,
|
||||
// but omit it by convention and to keep backwards compatible.
|
||||
|
@ -2443,7 +2481,7 @@ public final class Node implements INode, Serializable {
|
|||
|
||||
lastmodified = System.currentTimeMillis();
|
||||
|
||||
if (state == CLEAN) {
|
||||
if (state == CLEAN && isPersistableProperty(propname)) {
|
||||
markAs(MODIFIED);
|
||||
}
|
||||
} else if (dbmap != null) {
|
||||
|
|
|
@ -381,7 +381,7 @@ public class OrderedSubnodeList extends SubnodeList {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public List getOrderedView (String order) {
|
||||
public SubnodeList getOrderedView (String order) {
|
||||
if (origin != null) {
|
||||
return origin.getOrderedView(order);
|
||||
} else {
|
||||
|
|
|
@ -104,7 +104,7 @@ public class SubnodeList extends ArrayList {
|
|||
}
|
||||
}
|
||||
|
||||
public List getOrderedView (String order) {
|
||||
public SubnodeList getOrderedView (String order) {
|
||||
String key = order.trim().toLowerCase();
|
||||
// long start = System.currentTimeMillis();
|
||||
if (views == null) {
|
||||
|
|
|
@ -24,6 +24,8 @@ import java.sql.Statement;
|
|||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
/**
|
||||
* A subclass of thread that keeps track of changed nodes and triggers
|
||||
* changes in the database when a transaction is commited.
|
||||
|
@ -34,13 +36,13 @@ public class Transactor {
|
|||
NodeManager nmgr;
|
||||
|
||||
// List of nodes to be updated
|
||||
private HashMap dirtyNodes;
|
||||
private Map dirtyNodes;
|
||||
|
||||
// List of visited clean nodes
|
||||
private HashMap cleanNodes;
|
||||
private Map cleanNodes;
|
||||
|
||||
// List of nodes whose child index has been modified
|
||||
private HashSet parentNodes;
|
||||
private Set parentNodes;
|
||||
|
||||
// Is a transaction in progress?
|
||||
private volatile boolean active;
|
||||
|
@ -50,10 +52,10 @@ public class Transactor {
|
|||
protected ITransaction txn;
|
||||
|
||||
// Transactions for SQL data sources
|
||||
private HashMap sqlConnections;
|
||||
private Map sqlConnections;
|
||||
|
||||
// Set of SQL connections that already have been verified
|
||||
private HashSet testedConnections;
|
||||
private Map testedConnections;
|
||||
|
||||
// when did the current transaction start?
|
||||
private long tstart;
|
||||
|
@ -64,7 +66,7 @@ public class Transactor {
|
|||
// the thread we're associated with
|
||||
private Thread thread;
|
||||
|
||||
private static final ThreadLocal <Transactor> txtor = new ThreadLocal <Transactor> ();
|
||||
private static final ThreadLocal txtor = new ThreadLocal();
|
||||
|
||||
/**
|
||||
* Creates a new Transactor object.
|
||||
|
@ -75,12 +77,12 @@ public class Transactor {
|
|||
this.thread = Thread.currentThread();
|
||||
this.nmgr = nmgr;
|
||||
|
||||
dirtyNodes = new HashMap();
|
||||
dirtyNodes = new LinkedHashMap();
|
||||
cleanNodes = new HashMap();
|
||||
parentNodes = new HashSet();
|
||||
|
||||
sqlConnections = new HashMap();
|
||||
testedConnections = new HashSet();
|
||||
testedConnections = new HashMap();
|
||||
active = false;
|
||||
killed = false;
|
||||
}
|
||||
|
@ -90,7 +92,7 @@ public class Transactor {
|
|||
* @return the transactor associated with the current thread
|
||||
*/
|
||||
public static Transactor getInstance() {
|
||||
return txtor.get();
|
||||
return (Transactor) txtor.get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +101,7 @@ public class Transactor {
|
|||
* @throws IllegalStateException if no transactor is associated with the current thread
|
||||
*/
|
||||
public static Transactor getInstanceOrFail() throws IllegalStateException {
|
||||
Transactor tx = txtor.get();
|
||||
Transactor tx = (Transactor) txtor.get();
|
||||
if (tx == null)
|
||||
throw new IllegalStateException("Operation requires a Transactor, " +
|
||||
"but current thread does not have one.");
|
||||
|
@ -112,7 +114,7 @@ public class Transactor {
|
|||
* @return the transactor associated with the current thread
|
||||
*/
|
||||
public static Transactor getInstance(NodeManager nmgr) {
|
||||
Transactor t = txtor.get();
|
||||
Transactor t = (Transactor) txtor.get();
|
||||
if (t == null) {
|
||||
t = new Transactor(nmgr);
|
||||
txtor.set(t);
|
||||
|
@ -240,7 +242,7 @@ public class Transactor {
|
|||
public void registerConnection(DbSource src, Connection con) {
|
||||
sqlConnections.put(src, con);
|
||||
// we assume a freshly created connection is ok.
|
||||
testedConnections.add(src);
|
||||
testedConnections.put(src, new Long(System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,13 +252,15 @@ public class Transactor {
|
|||
*/
|
||||
public Connection getConnection(DbSource src) {
|
||||
Connection con = (Connection) sqlConnections.get(src);
|
||||
if (con != null && !testedConnections.contains(src)) {
|
||||
Long tested = (Long) testedConnections.get(src);
|
||||
long now = System.currentTimeMillis();
|
||||
if (con != null && (tested == null || now - tested.longValue() > 10000)) {
|
||||
// Check if the connection is still alive by executing a simple statement.
|
||||
try {
|
||||
Statement stmt = con.createStatement();
|
||||
stmt.execute("SELECT 1");
|
||||
stmt.close();
|
||||
testedConnections.add(src);
|
||||
testedConnections.put(src, new Long(now));
|
||||
} catch (SQLException sx) {
|
||||
try {
|
||||
con.close();
|
||||
|
@ -326,6 +330,7 @@ public class Transactor {
|
|||
|
||||
// the set to collect DbMappings to be marked as changed
|
||||
HashSet dirtyDbMappings = new HashSet();
|
||||
Log eventLog = nmgr.app.getEventLog();
|
||||
|
||||
for (int i = 0; i < dirty.length; i++) {
|
||||
Node node = (Node) dirty[i];
|
||||
|
@ -346,8 +351,10 @@ public class Transactor {
|
|||
}
|
||||
|
||||
inserted++;
|
||||
nmgr.app.logEvent("inserted: Node " + node.getPrototype() + "/" +
|
||||
if (eventLog.isDebugEnabled()) {
|
||||
eventLog.debug("inserted node: " + node.getPrototype() + "/" +
|
||||
node.getID());
|
||||
}
|
||||
} else if (nstate == Node.MODIFIED) {
|
||||
// only mark DbMapping as dirty if updateNode returns true
|
||||
if (nmgr.updateNode(nmgr.db, txn, node)) {
|
||||
|
@ -363,8 +370,10 @@ public class Transactor {
|
|||
}
|
||||
|
||||
updated++;
|
||||
nmgr.app.logEvent("updated: Node " + node.getPrototype() + "/" +
|
||||
if (eventLog.isDebugEnabled()) {
|
||||
eventLog.debug("updated node: " + node.getPrototype() + "/" +
|
||||
node.getID());
|
||||
}
|
||||
} else if (nstate == Node.DELETED) {
|
||||
nmgr.deleteNode(nmgr.db, txn, node);
|
||||
dirtyDbMappings.add(node.getDbMapping());
|
||||
|
@ -377,6 +386,10 @@ public class Transactor {
|
|||
}
|
||||
|
||||
deleted++;
|
||||
if (eventLog.isDebugEnabled()) {
|
||||
eventLog.debug("removed node: " + node.getPrototype() + "/" +
|
||||
node.getID());
|
||||
}
|
||||
}
|
||||
|
||||
node.clearWriteLock();
|
||||
|
@ -419,10 +432,15 @@ public class Transactor {
|
|||
txn = null;
|
||||
}
|
||||
|
||||
nmgr.app.logAccess(tname + " " + inserted +
|
||||
" inserted, " + updated +
|
||||
" updated, " + deleted + " deleted in " +
|
||||
(now - tstart) + " millis");
|
||||
StringBuffer msg = new StringBuffer(tname).append(" done in ")
|
||||
.append(now - tstart).append(" millis");
|
||||
if(inserted + updated + deleted > 0) {
|
||||
msg.append(" [+")
|
||||
.append(inserted).append(", ~")
|
||||
.append(updated).append(", -")
|
||||
.append(deleted).append("]");
|
||||
}
|
||||
nmgr.app.logAccess(msg.toString());
|
||||
|
||||
// unset transaction name
|
||||
tname = null;
|
||||
|
|
|
@ -268,7 +268,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
|||
throws IOException {
|
||||
Enumeration e = null;
|
||||
|
||||
if (dbmode && node instanceof helma.objectmodel.db.Node) {
|
||||
if (dbmode && node instanceof 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();
|
||||
|
@ -392,7 +392,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
|||
* loop through the children-array and print them as <hop:child>
|
||||
*/
|
||||
private void writeChildren(INode node, int level) throws IOException {
|
||||
if (dbmode && node instanceof helma.objectmodel.db.Node) {
|
||||
if (dbmode && node instanceof Node) {
|
||||
Node dbNode = (Node) node;
|
||||
DbMapping smap = (dbNode.getDbMapping() == null) ? null
|
||||
: dbNode.getDbMapping()
|
||||
|
|
|
@ -20,6 +20,7 @@ import helma.framework.core.*;
|
|||
import helma.framework.repository.Resource;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import helma.objectmodel.db.Node;
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -170,13 +171,13 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
*/
|
||||
private void checkNode() {
|
||||
if (node != null && node.getState() == INode.INVALID) {
|
||||
if (node instanceof helma.objectmodel.db.Node) {
|
||||
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
|
||||
if (node instanceof Node) {
|
||||
NodeHandle handle = ((Node) node).getHandle();
|
||||
node = handle.getNode(core.app.getWrappedNodeManager());
|
||||
if (node == null) {
|
||||
// we probably have a deleted node. Replace with empty transient node
|
||||
// to avoid throwing an exception.
|
||||
node = new helma.objectmodel.TransientNode();
|
||||
node = new TransientNode();
|
||||
// throw new RuntimeException("Tried to access invalid/removed node " + handle + ".");
|
||||
}
|
||||
}
|
||||
|
@ -455,14 +456,14 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
}
|
||||
|
||||
private void prefetchChildren(int start, int length) {
|
||||
if (!(node instanceof helma.objectmodel.db.Node)) {
|
||||
if (!(node instanceof Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkNode();
|
||||
|
||||
try {
|
||||
((helma.objectmodel.db.Node) node).prefetchChildren(start, length);
|
||||
((Node) node).prefetchChildren(start, length);
|
||||
} catch (Exception x) {
|
||||
core.app.logError("Error in HopObject.prefetchChildren: " + x, x);
|
||||
}
|
||||
|
@ -638,8 +639,8 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
|
||||
checkNode();
|
||||
|
||||
if (node instanceof helma.objectmodel.db.Node) {
|
||||
((helma.objectmodel.db.Node) node).persist();
|
||||
if (node instanceof Node) {
|
||||
((Node) node).persist();
|
||||
return node.getID();
|
||||
}
|
||||
return null;
|
||||
|
@ -649,19 +650,19 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
* Invalidate the node itself or a subnode
|
||||
*/
|
||||
public boolean jsFunction_invalidate(Object childId) {
|
||||
if (childId != null && node instanceof helma.objectmodel.db.Node) {
|
||||
if (childId != null && node instanceof Node) {
|
||||
if (childId == Undefined.instance) {
|
||||
|
||||
if (node.getState() == INode.INVALID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
((helma.objectmodel.db.Node) node).invalidate();
|
||||
((Node) node).invalidate();
|
||||
} else {
|
||||
|
||||
checkNode();
|
||||
|
||||
((helma.objectmodel.db.Node) node).invalidateNode(childId.toString());
|
||||
((Node) node).invalidateNode(childId.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -675,7 +676,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
* @return true if the the wrapped Node has a valid database id.
|
||||
*/
|
||||
public boolean jsFunction_isPersistent() {
|
||||
if (!(node instanceof helma.objectmodel.db.Node)) {
|
||||
if (!(node instanceof Node)) {
|
||||
return false;
|
||||
}
|
||||
checkNode();
|
||||
|
@ -690,7 +691,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
* @return true if the the wrapped Node is not stored in a database.
|
||||
*/
|
||||
public boolean jsFunction_isTransient() {
|
||||
if (!(node instanceof helma.objectmodel.db.Node)) {
|
||||
if (!(node instanceof Node)) {
|
||||
return true;
|
||||
}
|
||||
checkNode();
|
||||
|
@ -1096,10 +1097,10 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
* do have a higher id than the last record loaded by this collection
|
||||
*/
|
||||
public int jsFunction_update() {
|
||||
if (!(node instanceof helma.objectmodel.db.Node))
|
||||
if (!(node instanceof Node))
|
||||
throw new RuntimeException ("update only callabel on persistent HopObjects");
|
||||
checkNode();
|
||||
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
|
||||
Node n = (Node) node;
|
||||
return n.updateSubnodes();
|
||||
}
|
||||
|
||||
|
@ -1111,18 +1112,19 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
|||
* @return ListViewWrapper holding the information of the ordered view
|
||||
*/
|
||||
public Object jsFunction_getOrderedView(String expr) {
|
||||
if (!(node instanceof helma.objectmodel.db.Node)) {
|
||||
if (!(node instanceof Node)) {
|
||||
throw new RuntimeException (
|
||||
"getOrderedView only callable on persistent HopObjects");
|
||||
}
|
||||
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
|
||||
Node n = (Node) node;
|
||||
n.loadNodes();
|
||||
SubnodeList subnodes = n.getSubnodeList();
|
||||
if (subnodes == null) {
|
||||
throw new RuntimeException (
|
||||
"getOrderedView only callable on already existing subnode-collections");
|
||||
}
|
||||
return new ListViewWrapper (subnodes.getOrderedView(expr),
|
||||
core, core.app.getWrappedNodeManager(), this);
|
||||
Node subnode = new Node("OrderedView", "HopObject", core.app.getWrappedNodeManager());
|
||||
subnode.setSubnodes(subnodes.getOrderedView(expr));
|
||||
return new HopObject("HopObject", core, subnode, core.getPrototype("HopObject"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,15 @@
|
|||
*/
|
||||
package helma.scripting.rhino;
|
||||
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import helma.objectmodel.INode;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.objectmodel.db.DbKey;
|
||||
import helma.objectmodel.db.Node;
|
||||
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
public class HopObjectCtor extends FunctionObject {
|
||||
|
||||
|
@ -89,7 +90,7 @@ public class HopObjectCtor extends FunctionObject {
|
|||
throw new EvaluatorException(x.toString());
|
||||
}
|
||||
} else {
|
||||
INode node = new helma.objectmodel.db.Node(protoname, protoname,
|
||||
INode node = new Node(protoname, protoname,
|
||||
core.app.getWrappedNodeManager());
|
||||
Scriptable proto = core.getPrototype(protoname);
|
||||
HopObject hobj = new HopObject(protoname, core, node, proto);
|
||||
|
|
|
@ -1,337 +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.objectmodel.INode;
|
||||
import helma.objectmodel.db.Key;
|
||||
import helma.objectmodel.db.NodeHandle;
|
||||
import helma.objectmodel.db.OrderedSubnodeList;
|
||||
import helma.objectmodel.db.WrappedNodeManager;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.EvaluatorException;
|
||||
import org.mozilla.javascript.FunctionObject;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.Undefined;
|
||||
import org.mozilla.javascript.Wrapper;
|
||||
import org.mozilla.javascript.ScriptRuntime;
|
||||
|
||||
|
||||
public class ListViewWrapper extends ScriptableObject implements Wrapper, Scriptable {
|
||||
final List list;
|
||||
final RhinoCore core;
|
||||
final WrappedNodeManager wnm;
|
||||
final HopObject hObj;
|
||||
INode node;
|
||||
|
||||
static ListViewWrapper listViewProto;
|
||||
|
||||
/**
|
||||
* Private constructor used to create the object prototype.
|
||||
*/
|
||||
private ListViewWrapper() {
|
||||
list = null;
|
||||
core = null;
|
||||
wnm = null;
|
||||
node = null;
|
||||
hObj = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JS wrapper around a subnode list.
|
||||
* @param list
|
||||
* @param core
|
||||
* @param wnm
|
||||
* @param hObj
|
||||
*/
|
||||
ListViewWrapper (List list, RhinoCore core, WrappedNodeManager wnm, HopObject hObj) {
|
||||
if (list == null) {
|
||||
throw new IllegalArgumentException ("ListWrapper unable to wrap null list.");
|
||||
}
|
||||
this.core = core;
|
||||
this.list = list;
|
||||
this.wnm = wnm;
|
||||
this.hObj = hObj;
|
||||
this.node = hObj.node;
|
||||
if (listViewProto == null) {
|
||||
listViewProto = new ListViewWrapper();
|
||||
listViewProto.init();
|
||||
}
|
||||
setPrototype(listViewProto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init JS functions from methods.
|
||||
*/
|
||||
void init() {
|
||||
int attributes = DONTENUM | PERMANENT;
|
||||
|
||||
Method[] methods = getClass().getDeclaredMethods();
|
||||
for (int i=0; i<methods.length; i++) {
|
||||
String methodName = methods[i].getName();
|
||||
|
||||
if (methodName.startsWith("jsFunction_")) {
|
||||
methodName = methodName.substring(11);
|
||||
FunctionObject func = new FunctionObject(methodName,
|
||||
methods[i], this);
|
||||
this.defineProperty(methodName, func, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object unwrap() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public Object jsFunction_get(Object idxObj) {
|
||||
if (idxObj instanceof Number)
|
||||
return jsFunction_get(((Number) idxObj).intValue());
|
||||
else // fallback to this View's HopObject's get-function
|
||||
return hObj.jsFunction_get(idxObj);
|
||||
}
|
||||
|
||||
public Object jsFunction_get(int idx) {
|
||||
// return null if given index is out of bounds
|
||||
if (list.size() <= idx)
|
||||
return null;
|
||||
Object obj = list.get(idx);
|
||||
// return null if indexed object is null
|
||||
if (obj == null)
|
||||
return null;
|
||||
|
||||
// return HopObject in case of a NodeHandle
|
||||
if (obj instanceof NodeHandle) {
|
||||
return Context.toObject(((NodeHandle) obj).getNode(wnm), core.global);
|
||||
} else if (!(obj instanceof Scriptable)) {
|
||||
// do NOT wrap primitives - otherwise they'll be wrapped as Objects,
|
||||
// which makes them unusable for many purposes (e.g. ==)
|
||||
if (obj instanceof String ||
|
||||
obj instanceof Number ||
|
||||
obj instanceof Boolean) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
return Context.toObject(obj, core.global);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Object jsFunction_getById(Object id) {
|
||||
return hObj.jsFunction_getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch child objects from (relational) database.
|
||||
*/
|
||||
public void jsFunction_prefetchChildren(Object startArg, Object lengthArg)
|
||||
throws Exception {
|
||||
// check if we were called with no arguments
|
||||
if (startArg == Undefined.instance && lengthArg == Undefined.instance) {
|
||||
prefetchChildren(0, 1000);
|
||||
} else {
|
||||
int start = (int) ScriptRuntime.toNumber(startArg);
|
||||
int length = (int) ScriptRuntime.toNumber(lengthArg);
|
||||
prefetchChildren(start, length);
|
||||
}
|
||||
}
|
||||
|
||||
private void prefetchChildren(int start, int length) {
|
||||
if (!(node instanceof helma.objectmodel.db.Node))
|
||||
return;
|
||||
checkNode();
|
||||
start = Math.max(start, 0);
|
||||
length = Math.min(list.size() - start, length);
|
||||
if (length < 1)
|
||||
return;
|
||||
Key[] keys = new Key[length];
|
||||
for (int i = start; i < start+length; i++) {
|
||||
keys[i - start] = ((NodeHandle) list.get(i)).getKey();
|
||||
}
|
||||
try {
|
||||
((helma.objectmodel.db.Node) node).prefetchChildren(keys);
|
||||
} catch (Exception x) {
|
||||
System.err.println("Error in HopObject.prefetchChildren(): " + x);
|
||||
}
|
||||
}
|
||||
|
||||
public int jsFunction_size() {
|
||||
if (list==null)
|
||||
return 0;
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public int jsFunction_count() {
|
||||
return jsFunction_size();
|
||||
}
|
||||
|
||||
public void jsFunction_add(Object child) {
|
||||
if (this.hObj==null)
|
||||
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
|
||||
hObj.jsFunction_add(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full list of child objects in a JavaScript Array.
|
||||
* This is called by jsFunction_list() if called with no arguments.
|
||||
*
|
||||
* @return A JavaScript Array containing all child objects
|
||||
*/
|
||||
private Scriptable list() {
|
||||
checkNode();
|
||||
|
||||
ArrayList a = new ArrayList();
|
||||
for (Iterator i = list.iterator(); i.hasNext(); ) {
|
||||
NodeHandle nh = (NodeHandle) i.next();
|
||||
if (nh!=null)
|
||||
a.add(Context.toObject(nh.getNode(wnm), core.global));
|
||||
}
|
||||
return Context.getCurrentContext().newArray(core.global, a.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JS array of child objects with the given start and length.
|
||||
*
|
||||
* @return A JavaScript Array containing the specified child objects
|
||||
*/
|
||||
public Scriptable jsFunction_list(Object startArg, Object lengthArg) {
|
||||
if (startArg == Undefined.instance && lengthArg == Undefined.instance) {
|
||||
return list();
|
||||
}
|
||||
|
||||
int start = (int) ScriptRuntime.toNumber(startArg);
|
||||
int length = (int) ScriptRuntime.toNumber(lengthArg);
|
||||
|
||||
if (start < 0 || length < 0) {
|
||||
throw new EvaluatorException("Arguments must not be negative in HopObject.list(start, length)");
|
||||
}
|
||||
|
||||
checkNode();
|
||||
start = Math.max(start, 0);
|
||||
length = Math.min(list.size() - start, length);
|
||||
|
||||
prefetchChildren(start, length);
|
||||
ArrayList a = new ArrayList();
|
||||
|
||||
for (int i=start; i<start+length; i++) {
|
||||
NodeHandle nh = (NodeHandle) list.get(i);
|
||||
if (nh != null)
|
||||
a.add(Context.toObject(nh.getNode(wnm), core.global));
|
||||
}
|
||||
|
||||
return Context.getCurrentContext().newArray(core.global, a.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this object from the database.
|
||||
*/
|
||||
public boolean jsFunction_remove(Object arg) {
|
||||
if (this.hObj==null)
|
||||
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
|
||||
return hObj.jsFunction_remove(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a child node from this node's collection without deleting
|
||||
* it from the database.
|
||||
*/
|
||||
public boolean jsFunction_removeChild(Object child) {
|
||||
if (this.hObj==null)
|
||||
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
|
||||
return hObj.jsFunction_removeChild(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the node itself or a subnode
|
||||
*/
|
||||
public boolean jsFunction_invalidate(Object childId) {
|
||||
if (this.hObj==null)
|
||||
throw new RuntimeException("ListWrapper has no knowledge about any HopObject or collection");
|
||||
return hObj.jsFunction_invalidate(childId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if node is contained in subnodes
|
||||
*/
|
||||
public int jsFunction_contains(Object obj) {
|
||||
if (obj instanceof HopObject) {
|
||||
INode n = ((HopObject) obj).node;
|
||||
if (n instanceof helma.objectmodel.db.Node)
|
||||
return list.indexOf(((helma.objectmodel.db.Node) n).getHandle());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method represents the Java-Script-exposed function for updating Subnode-Collections.
|
||||
* The following conditions must be met to make a subnodecollection updateable.
|
||||
* .) the collection must be specified with collection.updateable=true
|
||||
* .) the id's of this collection must be in ascending order, meaning, that new records
|
||||
* do have a higher id than the last record loaded by this collection
|
||||
*/
|
||||
public int jsFunction_update() {
|
||||
if (!(node instanceof helma.objectmodel.db.Node))
|
||||
throw new RuntimeException ("updateSubnodes only callabel on persistent HopObjects");
|
||||
checkNode();
|
||||
helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node;
|
||||
return n.updateSubnodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a view having a different order from this Node's subnodelist.
|
||||
* The underlying OrderedSubnodeList will keep those views and updates them
|
||||
* if the original collection has been updated.
|
||||
* @param expr the order (like sql-order using the properties instead)
|
||||
* @return ListViewWrapper holding the information of the ordered view
|
||||
*/
|
||||
public Object jsFunction_getOrderedView(String expr) {
|
||||
if (!(list instanceof OrderedSubnodeList))
|
||||
throw new RuntimeException ("getOrderedView only callable on persistent HopObjects");
|
||||
checkNode();
|
||||
|
||||
OrderedSubnodeList osl = (OrderedSubnodeList) list;
|
||||
return new ListViewWrapper (osl.getOrderedView(expr), core, wnm, hObj);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (list==null)
|
||||
return "[ListWrapper{}]";
|
||||
else
|
||||
return "[ListWrapper"+ list.toString() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node has been invalidated. If so, it has to be re-fetched
|
||||
* from the db via the app's node manager.
|
||||
*/
|
||||
private final void checkNode() {
|
||||
if (node != null && node.getState() == INode.INVALID) {
|
||||
if (node instanceof helma.objectmodel.db.Node) {
|
||||
NodeHandle handle = ((helma.objectmodel.db.Node) node).getHandle();
|
||||
node = handle.getNode(core.app.getWrappedNodeManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "[ListWrapper]";
|
||||
}
|
||||
}
|
|
@ -131,7 +131,7 @@ public final class RhinoCore implements ScopeProvider {
|
|||
wrapper = new WrapMaker();
|
||||
wrapper.setJavaPrimitiveWrap(false);
|
||||
|
||||
Context context = contextFactory.enter();
|
||||
Context context = contextFactory.enterContext();
|
||||
|
||||
try {
|
||||
// create global object
|
||||
|
@ -182,7 +182,7 @@ public final class RhinoCore implements ScopeProvider {
|
|||
app.logError("Cannot initialize interpreter", e);
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} finally {
|
||||
contextFactory.exit();
|
||||
Context.exit();
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
@ -799,9 +799,6 @@ public final class RhinoCore implements ScopeProvider {
|
|||
String sourceName = code.getName();
|
||||
Reader reader = null;
|
||||
|
||||
Resource previousCurrentResource = app.getCurrentCodeResource();
|
||||
app.setCurrentCodeResource(code);
|
||||
|
||||
String encoding = app.getProperty("sourceCharset");
|
||||
|
||||
try {
|
||||
|
@ -837,7 +834,6 @@ public final class RhinoCore implements ScopeProvider {
|
|||
wrappercache.clear();
|
||||
}
|
||||
} finally {
|
||||
app.setCurrentCodeResource(previousCurrentResource);
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
|
@ -1128,7 +1124,7 @@ public final class RhinoCore implements ScopeProvider {
|
|||
protected void onContextCreated(Context cx) {
|
||||
cx.setWrapFactory(wrapper);
|
||||
cx.setOptimizationLevel(optLevel);
|
||||
// cx.setInstructionObserverThreshold(5000);
|
||||
cx.setInstructionObserverThreshold(10000);
|
||||
if (cx.isValidLanguageVersion(languageVersion)) {
|
||||
cx.setLanguageVersion(languageVersion);
|
||||
} else {
|
||||
|
@ -1159,9 +1155,11 @@ public final class RhinoCore implements ScopeProvider {
|
|||
* This can be used to customize {@link Context} without introducing
|
||||
* additional subclasses.
|
||||
*/
|
||||
/* protected void observeInstructionCount(Context cx, int instructionCount) {
|
||||
if (instructionCount >= 0xfffffff)
|
||||
throw new EvaluatorException("Exceeded instruction count, interrupting");
|
||||
} */
|
||||
protected void observeInstructionCount(Context cx, int instructionCount) {
|
||||
RhinoEngine engine = RhinoEngine.getRhinoEngine();
|
||||
if (engine != null && engine.thread != Thread.currentThread()) {
|
||||
throw new EvaluatorException("Request timed out");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import helma.main.Server;
|
|||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.objectmodel.db.Relation;
|
||||
import helma.objectmodel.db.Node;
|
||||
import helma.scripting.*;
|
||||
import helma.scripting.rhino.debug.Tracer;
|
||||
import helma.util.StringUtils;
|
||||
|
@ -86,7 +87,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
this.reval = reval;
|
||||
initRhinoCore(app);
|
||||
|
||||
context = core.contextFactory.enter();
|
||||
context = core.contextFactory.enterContext();
|
||||
|
||||
try {
|
||||
extensionGlobals = new HashMap();
|
||||
|
@ -113,7 +114,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
app.logError("Cannot initialize interpreter", e);
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} finally {
|
||||
core.contextFactory.exit ();
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +163,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
// (chicken and egg problem, kind of)
|
||||
thread = Thread.currentThread();
|
||||
global = new GlobalObject(core, app, true);
|
||||
context = core.contextFactory.enter();
|
||||
context = core.contextFactory.enterContext();
|
||||
|
||||
if (core.hasTracer) {
|
||||
context.setDebugger(new Tracer(getResponse()), null);
|
||||
|
@ -214,7 +215,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
public synchronized void exitContext() {
|
||||
// unregister the engine threadlocal
|
||||
engines.set(null);
|
||||
core.contextFactory.exit();
|
||||
Context.exit();
|
||||
thread = null;
|
||||
global = null;
|
||||
}
|
||||
|
@ -528,7 +529,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
* @throws java.io.IOException
|
||||
*/
|
||||
public void serialize(Object obj, OutputStream out) throws IOException {
|
||||
core.contextFactory.enter();
|
||||
core.contextFactory.enterContext();
|
||||
engines.set(this);
|
||||
try {
|
||||
// use a special ScriptableOutputStream that unwraps Wrappers
|
||||
|
@ -536,8 +537,8 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
protected Object replaceObject(Object obj) throws IOException {
|
||||
if (obj instanceof HopObject)
|
||||
return new HopObjectProxy((HopObject) obj);
|
||||
if (obj instanceof helma.objectmodel.db.Node)
|
||||
return new HopObjectProxy((helma.objectmodel.db.Node) obj);
|
||||
if (obj instanceof Node)
|
||||
return new HopObjectProxy((Node) obj);
|
||||
if (obj instanceof GlobalObject)
|
||||
return new GlobalProxy((GlobalObject) obj);
|
||||
if (obj instanceof ApplicationBean)
|
||||
|
@ -557,7 +558,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
sout.writeObject(obj);
|
||||
sout.flush();
|
||||
} finally {
|
||||
core.contextFactory.exit();
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,7 +572,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
* @throws java.io.IOException
|
||||
*/
|
||||
public Object deserialize(InputStream in) throws IOException, ClassNotFoundException {
|
||||
core.contextFactory.enter();
|
||||
core.contextFactory.enterContext();
|
||||
engines.set(this);
|
||||
try {
|
||||
ObjectInputStream sin = new ScriptableInputStream(in, core.global) {
|
||||
|
@ -584,7 +585,7 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
};
|
||||
return sin.readObject();
|
||||
} finally {
|
||||
core.contextFactory.exit();
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package helma.scripting.rhino;
|
|||
|
||||
import helma.objectmodel.INode;
|
||||
import helma.objectmodel.db.NodeHandle;
|
||||
import helma.objectmodel.db.Node;
|
||||
import org.mozilla.javascript.Context;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -80,18 +81,19 @@ class HopObjectProxy implements SerializationProxy {
|
|||
|
||||
HopObjectProxy(HopObject obj) {
|
||||
INode n = obj.getNode();
|
||||
if (n == null)
|
||||
if (n == null) {
|
||||
ref = obj.getClassName();
|
||||
else {
|
||||
if (n instanceof helma.objectmodel.db.Node)
|
||||
ref = new NodeHandle(((helma.objectmodel.db.Node) n).getKey());
|
||||
else
|
||||
} else {
|
||||
if (n instanceof Node) {
|
||||
ref = new NodeHandle((Node) n);
|
||||
} else {
|
||||
ref = n;
|
||||
}
|
||||
}
|
||||
wrapped = true;
|
||||
}
|
||||
|
||||
HopObjectProxy(helma.objectmodel.db.Node node) {
|
||||
HopObjectProxy(Node node) {
|
||||
ref = new NodeHandle(node.getKey());
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ public class XmlObject {
|
|||
converter = new XmlConverter();
|
||||
}
|
||||
|
||||
INode node = new helma.objectmodel.db.Node(null, null,
|
||||
INode node = new Node(null, null,
|
||||
core.getApplication().getWrappedNodeManager());
|
||||
INode result = converter.convert(url, node);
|
||||
|
||||
|
|
|
@ -345,20 +345,20 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
res.setContentLength(hopres.getContentLength());
|
||||
res.setContentType(hopres.getContentType());
|
||||
|
||||
if ("HEAD".equalsIgnoreCase(req.getMethod())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!"HEAD".equalsIgnoreCase(req.getMethod())) {
|
||||
byte[] content = hopres.getContent();
|
||||
if (content != null) {
|
||||
try {
|
||||
OutputStream out = res.getOutputStream();
|
||||
|
||||
out.write(hopres.getContent());
|
||||
out.write(content);
|
||||
out.flush();
|
||||
} catch (Exception iox) {
|
||||
log("Exception in writeResponse: " + iox);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendError(HttpServletResponse response, int code, String message)
|
||||
throws IOException {
|
||||
|
@ -545,22 +545,23 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
addIPAddress(buffer, request.getHeader("X-Forwarded-For"));
|
||||
addIPAddress(buffer, request.getHeader("Client-ip"));
|
||||
if (reqtrans.getSession() == null || !reqtrans.getSession().startsWith(buffer.toString())) {
|
||||
response.addCookie(createSession(buffer.toString(), reqtrans, domain));
|
||||
createSession(response, buffer.toString(), reqtrans, domain);
|
||||
}
|
||||
} else if (reqtrans.getSession() == null) {
|
||||
response.addCookie(createSession("", reqtrans, domain));
|
||||
createSession(response, "", reqtrans, domain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new session cookie.
|
||||
*
|
||||
* @param response the servlet response
|
||||
* @param prefix the session id prefix
|
||||
* @param reqtrans the request object
|
||||
* @param domain the cookie domain
|
||||
* @return the session cookie
|
||||
*/
|
||||
private Cookie createSession(String prefix,
|
||||
private void createSession(HttpServletResponse response,
|
||||
String prefix,
|
||||
RequestTrans reqtrans,
|
||||
String domain) {
|
||||
Application app = getApplication();
|
||||
|
@ -575,12 +576,20 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
}
|
||||
|
||||
reqtrans.setSession(id);
|
||||
Cookie cookie = new Cookie(sessionCookieName, id);
|
||||
cookie.setPath("/");
|
||||
if (domain != null)
|
||||
cookie.setDomain(domain);
|
||||
|
||||
return cookie;
|
||||
StringBuffer buffer = new StringBuffer(sessionCookieName);
|
||||
buffer.append("=").append(id).append("; Path=/");
|
||||
if (domain != null) {
|
||||
// lowercase domain for IE
|
||||
buffer.append("; Domain=").append(domain.toLowerCase());
|
||||
}
|
||||
if (!"false".equalsIgnoreCase(app.getProperty("httpOnlySessionCookie"))) {
|
||||
buffer.append("; HttpOnly");
|
||||
}
|
||||
if ("true".equalsIgnoreCase(app.getProperty("secureSessionCookie"))) {
|
||||
buffer.append("; Secure");
|
||||
}
|
||||
response.addHeader("Set-Cookie", buffer.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,9 @@ package helma.servlet;
|
|||
import helma.framework.repository.Repository;
|
||||
import helma.framework.core.Application;
|
||||
import helma.framework.repository.FileRepository;
|
||||
import helma.main.ServerConfig;
|
||||
import helma.main.Server;
|
||||
|
||||
import java.io.*;
|
||||
import javax.servlet.*;
|
||||
import java.util.*;
|
||||
|
@ -40,7 +43,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
|||
private String appName;
|
||||
private String appDir;
|
||||
private String dbDir;
|
||||
// private String hopDir;
|
||||
private String hopDir;
|
||||
private Repository[] repositories;
|
||||
|
||||
/**
|
||||
|
@ -53,7 +56,12 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
|||
public void init(ServletConfig init) throws ServletException {
|
||||
super.init(init);
|
||||
|
||||
// hopDir = init.getInitParameter("hopdir");
|
||||
hopDir = init.getInitParameter("hopdir");
|
||||
|
||||
if (hopDir == null) {
|
||||
// assume helmaDir to be current directory
|
||||
hopDir = ".";
|
||||
}
|
||||
|
||||
appName = init.getInitParameter("application");
|
||||
|
||||
|
@ -70,7 +78,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
|||
}
|
||||
|
||||
Class[] parameters = { String.class };
|
||||
ArrayList<Repository> repositoryList = new ArrayList<Repository>();
|
||||
ArrayList repositoryList = new ArrayList();
|
||||
|
||||
for (int i = 0; true; i++) {
|
||||
String repositoryArgs = init.getInitParameter("repository." + i);
|
||||
|
@ -92,7 +100,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
|||
try {
|
||||
Repository newRepository = (Repository) Class.forName(repositoryImpl)
|
||||
.getConstructor(parameters)
|
||||
.newInstance(repositoryArgs);
|
||||
.newInstance(new Object[] {repositoryArgs});
|
||||
repositoryList.add(newRepository);
|
||||
log("adding repository: " + repositoryArgs);
|
||||
} catch (Exception ex) {
|
||||
|
@ -115,7 +123,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
|||
}
|
||||
|
||||
repositories = new Repository[repositoryList.size()];
|
||||
repositories = repositoryList.toArray(repositories);
|
||||
repositories = (Repository[]) repositoryList.toArray(repositories);
|
||||
|
||||
}
|
||||
|
||||
|
@ -146,8 +154,14 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
|||
try {
|
||||
File dbHome = new File(dbDir);
|
||||
File appHome = new File(appDir);
|
||||
File hopHome = new File(hopDir);
|
||||
|
||||
app = new Application(appName, null, repositories, appHome, dbHome);
|
||||
ServerConfig config = new ServerConfig();
|
||||
config.setHomeDir(hopHome);
|
||||
Server server = new Server(config);
|
||||
server.init();
|
||||
|
||||
app = new Application(appName, server, repositories, appHome, dbHome);
|
||||
app.init();
|
||||
app.start();
|
||||
} catch (Exception x) {
|
||||
|
|
|
@ -633,9 +633,12 @@ public final class HtmlEncoder {
|
|||
}
|
||||
}
|
||||
|
||||
// we didn't reach a break, so encode the ampersand as HTML entity
|
||||
// we didn't reach a break, so encode as entity unless inside a tag
|
||||
if (insideMacroTag) {
|
||||
ret.append('&');
|
||||
} else {
|
||||
ret.append("&");
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
|
@ -763,7 +766,7 @@ public final class HtmlEncoder {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (c < 128) {
|
||||
if (c < 128 || insideMacroTag) {
|
||||
ret.append(c);
|
||||
} else if ((c >= 128) && (c < 256)) {
|
||||
ret.append(transform[c - 128]);
|
||||
|
|
|
@ -143,7 +143,9 @@ public class Logger implements Log {
|
|||
// has gone. the 2000 entries threshold is somewhat arbitrary.
|
||||
if (entries.size() < 2000) {
|
||||
String message = msg == null ? "null" : msg.toString();
|
||||
entries.add(new Entry(dateCache, level, message, exception));
|
||||
Thread thread = Thread.currentThread();
|
||||
String threadId = "[" + thread.getName() + "] ";
|
||||
entries.add(new Entry(dateCache, level, message, threadId, exception));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,6 +166,7 @@ public class Logger implements Log {
|
|||
Entry entry = (Entry) entries.remove(0);
|
||||
writer.print(entry.date);
|
||||
writer.print(entry.level);
|
||||
writer.print(entry.threadId);
|
||||
writer.println(entry.message);
|
||||
if (entry.exception != null)
|
||||
entry.exception.printStackTrace(writer);
|
||||
|
@ -294,13 +297,14 @@ public class Logger implements Log {
|
|||
}
|
||||
|
||||
class Entry {
|
||||
final String date, level, message;
|
||||
final String date, level, message, threadId;
|
||||
final Throwable exception;
|
||||
|
||||
Entry(String date, String level, String message, Throwable exception) {
|
||||
Entry(String date, String level, String message, String threadId, Throwable exception) {
|
||||
this.date = date;
|
||||
this.level = level;
|
||||
this.message = message;
|
||||
this.threadId = threadId;
|
||||
this.exception = exception;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,12 @@ public class ResourceProperties extends Properties {
|
|||
// lower case key to original key mapping for case insensitive lookups
|
||||
private Properties keyMap = new Properties();
|
||||
|
||||
// prefix for sub-properties
|
||||
private String prefix;
|
||||
|
||||
// parent properties for sub-properties
|
||||
private ResourceProperties parentProperties;
|
||||
|
||||
/**
|
||||
* Constructs an empty ResourceProperties
|
||||
* Resources must be added manually afterwards
|
||||
|
@ -123,6 +129,22 @@ public class ResourceProperties extends Properties {
|
|||
forceUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a properties object containing all entries where the key matches
|
||||
* the given string prefix from the source map to the target map, cutting off
|
||||
* the prefix from the original key.
|
||||
* @see #getSubProperties(String)
|
||||
* @param parentProperties the parent properties
|
||||
* @param prefix the property name prefix
|
||||
*/
|
||||
private ResourceProperties(ResourceProperties parentProperties, String prefix) {
|
||||
this.parentProperties = parentProperties;
|
||||
this.prefix = prefix;
|
||||
resources = new HashSet();
|
||||
setIgnoreCase(parentProperties.ignoreCase);
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the properties regardless of an actual need
|
||||
*/
|
||||
|
@ -208,6 +230,21 @@ public class ResourceProperties extends Properties {
|
|||
}
|
||||
}
|
||||
|
||||
// if these are subproperties, reload them from the parent properties
|
||||
if (parentProperties != null && prefix != null) {
|
||||
parentProperties.update();
|
||||
Iterator it = parentProperties.entrySet().iterator();
|
||||
int prefixLength = prefix.length();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
String key = entry.getKey().toString();
|
||||
if (key.regionMatches(ignoreCase, 0, prefix, 0, prefixLength)) {
|
||||
temp.put(key.substring(prefixLength), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// at last we try to load properties from the resource list
|
||||
if (resources != null) {
|
||||
Iterator iterator = resources.iterator();
|
||||
|
@ -247,25 +284,13 @@ public class ResourceProperties extends Properties {
|
|||
* against the prefix.
|
||||
*
|
||||
* @param prefix the string prefix to match against
|
||||
* @return a new subproperties instance
|
||||
*/
|
||||
public ResourceProperties getSubProperties(String prefix) {
|
||||
if (prefix == null)
|
||||
if (prefix == null) {
|
||||
throw new NullPointerException("prefix");
|
||||
if ((System.currentTimeMillis() - lastCheck) > CACHE_TIME) {
|
||||
update();
|
||||
}
|
||||
ResourceProperties subprops = new ResourceProperties();
|
||||
subprops.setIgnoreCase(ignoreCase);
|
||||
Iterator it = entrySet().iterator();
|
||||
int prefixLength = prefix.length();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
String key = entry.getKey().toString();
|
||||
if (key.regionMatches(ignoreCase, 0, prefix, 0, prefixLength)) {
|
||||
subprops.put(key.substring(prefixLength), entry.getValue());
|
||||
}
|
||||
}
|
||||
return subprops;
|
||||
return new ResourceProperties(this, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -322,7 +347,7 @@ public class ResourceProperties extends Properties {
|
|||
if (strkey == null)
|
||||
return null;
|
||||
}
|
||||
return (String) super.get(strkey);
|
||||
return super.get(strkey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue