Merged in repository_patch branch. Plus these changes:
* Renamed helma.util.SourceProperties to helma.util.ResourceProperties * Removed timing from helma.framework.core.RequestEvaluator
This commit is contained in:
parent
343fad7638
commit
9f842e8c5d
37 changed files with 2163 additions and 1768 deletions
|
@ -17,10 +17,13 @@
|
||||||
package helma.doc;
|
package helma.doc;
|
||||||
|
|
||||||
import helma.framework.IPathElement;
|
import helma.framework.IPathElement;
|
||||||
|
import helma.framework.repository.FileResource;
|
||||||
|
import helma.framework.repository.FileResource;
|
||||||
import helma.main.Server;
|
import helma.main.Server;
|
||||||
import helma.util.SystemProperties;
|
import helma.util.ResourceProperties;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -94,12 +97,13 @@ public class DocApplication extends DocDirElement {
|
||||||
*/
|
*/
|
||||||
private void readProps() {
|
private void readProps() {
|
||||||
File propsFile = new File(location, "app.properties");
|
File propsFile = new File(location, "app.properties");
|
||||||
SystemProperties serverProps = null;
|
ResourceProperties serverProps = null;
|
||||||
if (Server.getServer()!=null) {
|
if (Server.getServer()!=null) {
|
||||||
serverProps = Server.getServer().getProperties();
|
serverProps = Server.getServer().getProperties();
|
||||||
}
|
}
|
||||||
SystemProperties appProps = new SystemProperties(propsFile.getAbsolutePath(),
|
ResourceProperties appProps = new ResourceProperties();
|
||||||
serverProps);
|
appProps.setDefaultProperties(serverProps);
|
||||||
|
appProps.addResource(new FileResource(propsFile));
|
||||||
|
|
||||||
excluded = new HashSet();
|
excluded = new HashSet();
|
||||||
addExclude("cvs");
|
addExclude("cvs");
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package helma.framework;
|
package helma.framework;
|
||||||
|
|
||||||
import helma.framework.core.Skin;
|
import helma.framework.core.Skin;
|
||||||
|
import helma.framework.core.Application;
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -124,15 +125,24 @@ public final class ResponseTrans implements Serializable {
|
||||||
// the message digest used to generate composed digests for ETag headers
|
// the message digest used to generate composed digests for ETag headers
|
||||||
private transient MessageDigest digest;
|
private transient MessageDigest digest;
|
||||||
|
|
||||||
// the appliciation checksum to make ETag headers sensitive to app changes
|
// the application
|
||||||
long applicationChecksum;
|
Application app;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ResponseTrans object.
|
||||||
|
*/
|
||||||
|
public ResponseTrans(Application app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new ResponseTrans object.
|
* Creates a new ResponseTrans object.
|
||||||
*
|
*
|
||||||
* @param req the RequestTrans for this response
|
* @param req the RequestTrans for this response
|
||||||
*/
|
*/
|
||||||
public ResponseTrans(RequestTrans req) {
|
public ResponseTrans(Application app, RequestTrans req) {
|
||||||
|
this.app = app;
|
||||||
reqtrans = req;
|
reqtrans = req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,27 +691,13 @@ public final class ResponseTrans implements Serializable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] b = digest.digest(MD5Encoder.toBytes(applicationChecksum));
|
// add the application checksum as dependency to make ETag
|
||||||
|
// generation sensitive to changes in the app
|
||||||
|
byte[] b = digest.digest(MD5Encoder.toBytes(app.getChecksum()));
|
||||||
|
|
||||||
/* StringBuffer buf = new StringBuffer(b.length*2);
|
|
||||||
for ( int i=0; i<b.length; i++ ) {
|
|
||||||
int j = (b[i]<0) ? 256+b[i] : b[i];
|
|
||||||
if ( j<16 ) buf.append("0");
|
|
||||||
buf.append(Integer.toHexString(j));
|
|
||||||
}
|
|
||||||
setETag (buf.toString ()); */
|
|
||||||
setETag(new String(Base64.encode(b)));
|
setETag(new String(Base64.encode(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param n ...
|
|
||||||
*/
|
|
||||||
public void setApplicationChecksum(long n) {
|
|
||||||
applicationChecksum = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,18 +19,21 @@ package helma.framework.core;
|
||||||
import helma.extensions.ConfigurationException;
|
import helma.extensions.ConfigurationException;
|
||||||
import helma.extensions.HelmaExtension;
|
import helma.extensions.HelmaExtension;
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
|
import helma.framework.repository.ResourceComparator;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
|
import helma.framework.repository.FileResource;
|
||||||
|
import helma.framework.repository.FileRepository;
|
||||||
import helma.main.Server;
|
import helma.main.Server;
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
import helma.objectmodel.db.*;
|
import helma.objectmodel.db.*;
|
||||||
import helma.scripting.*;
|
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.rmi.*;
|
import java.rmi.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,16 +47,16 @@ public final class Application implements IPathElement, Runnable {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
// properties and db-properties
|
// properties and db-properties
|
||||||
SystemProperties props;
|
ResourceProperties props;
|
||||||
|
|
||||||
// properties and db-properties
|
// properties and db-properties
|
||||||
SystemProperties dbProps;
|
ResourceProperties dbProps;
|
||||||
|
|
||||||
// Helma server home directory
|
// Helma server home directory
|
||||||
File home;
|
File home;
|
||||||
|
|
||||||
// application directory
|
// application sources
|
||||||
File appDir;
|
ArrayList repositories;
|
||||||
|
|
||||||
// embedded db directory
|
// embedded db directory
|
||||||
File dbDir;
|
File dbDir;
|
||||||
|
@ -129,10 +132,10 @@ public final class Application implements IPathElement, Runnable {
|
||||||
String charset;
|
String charset;
|
||||||
|
|
||||||
// password file to use for authenticate() function
|
// password file to use for authenticate() function
|
||||||
private CryptFile pwfile;
|
private CryptResource pwfile;
|
||||||
|
|
||||||
// Map of java class names to object prototypes
|
// Map of java class names to object prototypes
|
||||||
SystemProperties classMapping;
|
ResourceProperties classMapping;
|
||||||
|
|
||||||
// Map of extensions allowed for public skins
|
// Map of extensions allowed for public skins
|
||||||
Properties skinExtensions;
|
Properties skinExtensions;
|
||||||
|
@ -151,6 +154,8 @@ public final class Application implements IPathElement, Runnable {
|
||||||
// the list of custom cron jobs
|
// the list of custom cron jobs
|
||||||
Hashtable customCronJobs = null;
|
Hashtable customCronJobs = null;
|
||||||
|
|
||||||
|
private ResourceComparator resourceComparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple constructor for dead application instances.
|
* Simple constructor for dead application instances.
|
||||||
*/
|
*/
|
||||||
|
@ -159,12 +164,12 @@ public final class Application implements IPathElement, Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build an application with the given name in the app directory. No Server-wide
|
* Build an application with the given name with the given sources. No
|
||||||
* properties are created or used.
|
* Server-wide properties are created or used.
|
||||||
*/
|
*/
|
||||||
public Application(String name, File appDir, File dbDir)
|
public Application(String name, Repository[] repositories, File dbDir)
|
||||||
throws RemoteException, IllegalArgumentException {
|
throws RemoteException, IllegalArgumentException {
|
||||||
this(name, null, appDir, dbDir);
|
this(name, null, repositories, dbDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,28 +178,34 @@ public final class Application implements IPathElement, Runnable {
|
||||||
*/
|
*/
|
||||||
public Application(String name, Server server)
|
public Application(String name, Server server)
|
||||||
throws RemoteException, IllegalArgumentException {
|
throws RemoteException, IllegalArgumentException {
|
||||||
this(name, server, null, null);
|
this(name, server, new Repository[0], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build an application with the given name, server instance, app and
|
* Build an application with the given name, server instance, sources and
|
||||||
* db directories.
|
* db directory.
|
||||||
*/
|
*/
|
||||||
public Application(String name, Server server, File customAppDir, File customDbDir)
|
public Application(String name, Server server, Repository[] repositories, File customDbDir)
|
||||||
throws RemoteException, IllegalArgumentException {
|
throws RemoteException, IllegalArgumentException {
|
||||||
if ((name == null) || (name.trim().length() == 0)) {
|
if ((name == null) || (name.trim().length() == 0)) {
|
||||||
throw new IllegalArgumentException("Invalid application name: " + name);
|
throw new IllegalArgumentException("Invalid application name: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
appDir = customAppDir;
|
if (repositories.length > 0) {
|
||||||
|
this.repositories = new ArrayList();
|
||||||
|
this.repositories.addAll(Arrays.asList(repositories));
|
||||||
|
resourceComparator = new ResourceComparator(this);
|
||||||
|
} else {
|
||||||
|
throw new java.lang.IllegalArgumentException("No sources defined for application: " + name);
|
||||||
|
}
|
||||||
dbDir = customDbDir;
|
dbDir = customDbDir;
|
||||||
|
|
||||||
// system-wide properties, default to null
|
// system-wide properties, default to null
|
||||||
SystemProperties sysProps;
|
ResourceProperties sysProps;
|
||||||
|
|
||||||
// system-wide properties, default to null
|
// system-wide properties, default to null
|
||||||
SystemProperties sysDbProps;
|
ResourceProperties sysDbProps;
|
||||||
|
|
||||||
sysProps = sysDbProps = null;
|
sysProps = sysDbProps = null;
|
||||||
home = null;
|
home = null;
|
||||||
|
@ -202,12 +213,6 @@ public final class Application implements IPathElement, Runnable {
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
home = server.getHopHome();
|
home = server.getHopHome();
|
||||||
|
|
||||||
// if appDir and dbDir weren't explicitely passed, use the
|
|
||||||
// standard subdirectories of the Hop home directory
|
|
||||||
if (appDir == null) {
|
|
||||||
appDir = new File(server.getAppsHome(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dbDir == null) {
|
if (dbDir == null) {
|
||||||
dbDir = new File(server.getDbHome(), name);
|
dbDir = new File(server.getDbHome(), name);
|
||||||
}
|
}
|
||||||
|
@ -217,11 +222,6 @@ public final class Application implements IPathElement, Runnable {
|
||||||
sysDbProps = server.getDbProperties();
|
sysDbProps = server.getDbProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the directories if they do not exist already
|
|
||||||
if (!appDir.exists()) {
|
|
||||||
appDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dbDir.exists()) {
|
if (!dbDir.exists()) {
|
||||||
dbDir.mkdirs();
|
dbDir.mkdirs();
|
||||||
}
|
}
|
||||||
|
@ -230,32 +230,26 @@ public final class Application implements IPathElement, Runnable {
|
||||||
threadgroup = new ThreadGroup("TX-" + name);
|
threadgroup = new ThreadGroup("TX-" + name);
|
||||||
|
|
||||||
// create app-level properties
|
// create app-level properties
|
||||||
File propfile = new File(appDir, "app.properties");
|
props = new ResourceProperties(this, "app.properties", sysProps);
|
||||||
|
|
||||||
props = new SystemProperties(propfile.getAbsolutePath(), sysProps);
|
|
||||||
|
|
||||||
// get log names
|
// get log names
|
||||||
accessLogName = props.getProperty("accessLog", "helma."+name+".access");
|
accessLogName = props.getProperty("accessLog", "helma."+name+".access");
|
||||||
eventLogName = props.getProperty("eventLog", "helma."+name+".event");
|
eventLogName = props.getProperty("eventLog", "helma."+name+".event");
|
||||||
|
|
||||||
// create app-level db sources
|
// create app-level db sources
|
||||||
File dbpropfile = new File(appDir, "db.properties");
|
dbProps = new ResourceProperties(this, "db.properties", sysDbProps);
|
||||||
|
|
||||||
dbProps = new SystemProperties(dbpropfile.getAbsolutePath(), sysDbProps);
|
|
||||||
|
|
||||||
// the passwd file, to be used with the authenticate() function
|
// the passwd file, to be used with the authenticate() function
|
||||||
CryptFile parentpwfile = null;
|
CryptResource parentpwfile = null;
|
||||||
|
|
||||||
if (home != null) {
|
if (home != null) {
|
||||||
parentpwfile = new CryptFile(new File(home, "passwd"), null);
|
parentpwfile = new CryptResource(new FileResource(new File(home, "passwd")), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pwfile = new CryptFile(new File(appDir, "passwd"), parentpwfile);
|
pwfile = new CryptResource(repositories[0].getResource("passwd"), parentpwfile);
|
||||||
|
|
||||||
// the properties that map java class names to prototype names
|
// the properties that map java class names to prototype names
|
||||||
File classMappingFile = new File(appDir, "class.properties");
|
classMapping = new ResourceProperties(this, "class.properties");
|
||||||
|
|
||||||
classMapping = new SystemProperties(classMappingFile.getAbsolutePath());
|
|
||||||
classMapping.setIgnoreCase(false);
|
classMapping.setIgnoreCase(false);
|
||||||
|
|
||||||
// get class name of root object if defined. Otherwise native Helma objectmodel will be used.
|
// get class name of root object if defined. Otherwise native Helma objectmodel will be used.
|
||||||
|
@ -274,9 +268,8 @@ public final class Application implements IPathElement, Runnable {
|
||||||
* Get the application ready to run, initializing the evaluators and type manager.
|
* Get the application ready to run, initializing the evaluators and type manager.
|
||||||
*/
|
*/
|
||||||
public synchronized void init()
|
public synchronized void init()
|
||||||
throws DatabaseException, MalformedURLException,
|
throws DatabaseException, IllegalAccessException,
|
||||||
IllegalAccessException, InstantiationException,
|
InstantiationException, ClassNotFoundException {
|
||||||
ClassNotFoundException {
|
|
||||||
|
|
||||||
// create and init type mananger
|
// create and init type mananger
|
||||||
typemgr = new TypeManager(this);
|
typemgr = new TypeManager(this);
|
||||||
|
@ -346,8 +339,8 @@ public final class Application implements IPathElement, Runnable {
|
||||||
|
|
||||||
// The whole user/userroot handling is basically old
|
// The whole user/userroot handling is basically old
|
||||||
// ugly obsolete crap. Don't bother.
|
// ugly obsolete crap. Don't bother.
|
||||||
SystemProperties p = new SystemProperties();
|
ResourceProperties p = new ResourceProperties();
|
||||||
String usernameField = userMapping.getNameField();
|
String usernameField = (userMapping != null) ? userMapping.getNameField() : null;
|
||||||
|
|
||||||
if (usernameField == null) {
|
if (usernameField == null) {
|
||||||
usernameField = "name";
|
usernameField = "name";
|
||||||
|
@ -438,6 +431,18 @@ public final class Application implements IPathElement, Runnable {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getAppDir() {
|
||||||
|
try {
|
||||||
|
return new File(((FileRepository) getRepositories().next()).getName());
|
||||||
|
} catch (ClassCastException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceComparator getResourceComparator() {
|
||||||
|
return resourceComparator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a free evaluator to handle a request.
|
* Returns a free evaluator to handle a request.
|
||||||
*/
|
*/
|
||||||
|
@ -554,6 +559,8 @@ public final class Application implements IPathElement, Runnable {
|
||||||
* Execute a request coming in from a web client.
|
* Execute a request coming in from a web client.
|
||||||
*/
|
*/
|
||||||
public ResponseTrans execute(RequestTrans req) {
|
public ResponseTrans execute(RequestTrans req) {
|
||||||
|
System.setProperty("request.start", String.valueOf(System.currentTimeMillis()));
|
||||||
|
|
||||||
requestCount += 1;
|
requestCount += 1;
|
||||||
|
|
||||||
// get user for this request's session
|
// get user for this request's session
|
||||||
|
@ -594,7 +601,7 @@ public final class Application implements IPathElement, Runnable {
|
||||||
throw stopped;
|
throw stopped;
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
errorCount += 1;
|
errorCount += 1;
|
||||||
res = new ResponseTrans(req);
|
res = new ResponseTrans(this, req);
|
||||||
res.writeErrorReport(name, x.getMessage());
|
res.writeErrorReport(name, x.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
if (primaryRequest) {
|
if (primaryRequest) {
|
||||||
|
@ -808,7 +815,7 @@ public final class Application implements IPathElement, Runnable {
|
||||||
* Return a skin for a given object. The skin is found by determining the prototype
|
* Return a skin for a given object. The skin is found by determining the prototype
|
||||||
* to use for the object, then looking up the skin for the prototype.
|
* to use for the object, then looking up the skin for the prototype.
|
||||||
*/
|
*/
|
||||||
public Skin getSkin(String protoname, String skinname, Object[] skinpath) {
|
public Skin getSkin(String protoname, String skinname, Object[] skinpath) throws IOException {
|
||||||
Prototype proto = getPrototypeByName(protoname);
|
Prototype proto = getPrototypeByName(protoname);
|
||||||
|
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
|
@ -1616,10 +1623,23 @@ public final class Application implements IPathElement, Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the directory of this application
|
* Searches for the index of the given repository for this app.
|
||||||
|
* The arguement must be a root argument, or -1 will be returned.
|
||||||
|
*
|
||||||
|
* @param rep one of this app's root repositories.
|
||||||
|
* @return the index of the first occurrence of the argument in this
|
||||||
|
* list; returns <tt>-1</tt> if the object is not found.
|
||||||
*/
|
*/
|
||||||
public File getAppDir() {
|
public int getRepositoryIndex(Repository rep) {
|
||||||
return appDir;
|
return repositories.indexOf(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the repositories of this application
|
||||||
|
* @return iterator through application repositories
|
||||||
|
*/
|
||||||
|
public Iterator getRepositories() {
|
||||||
|
return repositories.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1721,7 +1741,7 @@ public final class Application implements IPathElement, Runnable {
|
||||||
* change, too.
|
* change, too.
|
||||||
*/
|
*/
|
||||||
public long getChecksum() {
|
public long getChecksum() {
|
||||||
return starttime + typemgr.getChecksum() + props.getChecksum();
|
return starttime + typemgr.lastCodeUpdate() + props.getChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1743,7 +1763,7 @@ public final class Application implements IPathElement, Runnable {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public SystemProperties getProperties() {
|
public ResourceProperties getProperties() {
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -490,7 +490,7 @@ public class ApplicationBean implements Serializable {
|
||||||
File f = app.getServerDir();
|
File f = app.getServerDir();
|
||||||
|
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
f = app.getAppDir();
|
return app.getAppDir().getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.getAbsolutePath();
|
return f.getAbsolutePath();
|
||||||
|
|
|
@ -17,9 +17,12 @@
|
||||||
package helma.framework.core;
|
package helma.framework.core;
|
||||||
|
|
||||||
import helma.objectmodel.db.DbMapping;
|
import helma.objectmodel.db.DbMapping;
|
||||||
import helma.scripting.*;
|
|
||||||
import helma.util.SystemMap;
|
import helma.util.SystemMap;
|
||||||
import helma.util.SystemProperties;
|
import helma.util.ResourceProperties;
|
||||||
|
import helma.framework.repository.Resource;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
|
import helma.framework.repository.ResourceTracker;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -30,81 +33,77 @@ import java.util.*;
|
||||||
* relational database table.
|
* relational database table.
|
||||||
*/
|
*/
|
||||||
public final class Prototype {
|
public final class Prototype {
|
||||||
|
Application app;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
String lowerCaseName;
|
String lowerCaseName;
|
||||||
Application app;
|
|
||||||
File directory;
|
Resource[] resources;
|
||||||
File[] files;
|
long lastResourceListing;
|
||||||
long lastDirectoryListing;
|
|
||||||
long checksum;
|
// lastCheck is the time the prototype's files were last checked
|
||||||
HashMap code;
|
long lastChecksum;
|
||||||
HashMap zippedCode;
|
long newChecksum;
|
||||||
HashMap skins;
|
// lastUpdate is the time at which any of the prototype's files were found updated the last time
|
||||||
HashMap zippedSkins;
|
long lastCodeUpdate;
|
||||||
HashMap updatables;
|
|
||||||
|
TreeSet code;
|
||||||
|
TreeSet skins;
|
||||||
|
|
||||||
|
HashMap trackers;
|
||||||
|
|
||||||
|
HashSet repositories;
|
||||||
|
|
||||||
// a map of this prototype's skins as raw strings
|
// a map of this prototype's skins as raw strings
|
||||||
// used for exposing skins to application (script) code (via app.skinfiles).
|
// used for exposing skins to application (script) code (via app.skinfiles).
|
||||||
SkinMap skinMap;
|
HashMap skinMap;
|
||||||
|
|
||||||
DbMapping dbmap;
|
DbMapping dbmap;
|
||||||
|
|
||||||
// lastCheck is the time the prototype's files were last checked
|
|
||||||
private long lastChecksum;
|
|
||||||
|
|
||||||
// lastUpdate is the time at which any of the prototype's files were
|
|
||||||
// found updated the last time
|
|
||||||
private long lastUpdate;
|
|
||||||
private Prototype parent;
|
private Prototype parent;
|
||||||
|
|
||||||
// Tells us whether this prototype is used to script a generic Java object,
|
// Tells us whether this prototype is used to script a generic Java object,
|
||||||
// as opposed to a Helma objectmodel node object.
|
// as opposed to a Helma objectmodel node object.
|
||||||
boolean isJavaPrototype;
|
boolean isJavaPrototype;
|
||||||
|
|
||||||
|
ResourceProperties props;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Prototype object.
|
* Creates a new Prototype object.
|
||||||
*
|
*
|
||||||
* @param name the prototype's name
|
* @param name the prototype's name
|
||||||
* @param dir the prototype directory, if known
|
* @param repository the first prototype's repository
|
||||||
* @param app the application this prototype is a part of
|
* @param app the application this prototype is a part of
|
||||||
*/
|
*/
|
||||||
public Prototype(String name, File dir, Application app) {
|
public Prototype(String name, Repository repository, Application app) {
|
||||||
// app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
|
// app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
repositories = new HashSet();
|
||||||
|
if (repository != null) {
|
||||||
|
repositories.add(repository);
|
||||||
|
}
|
||||||
lowerCaseName = name.toLowerCase();
|
lowerCaseName = name.toLowerCase();
|
||||||
|
|
||||||
if (dir != null) {
|
|
||||||
directory = dir;
|
|
||||||
} else {
|
|
||||||
directory = new File(app.appDir, name);
|
|
||||||
// a little bit of overkill to maintain backwards compatibility
|
|
||||||
// with lower case type names...
|
|
||||||
if (!directory.isDirectory()) {
|
|
||||||
File lowerDir = new File(app.appDir, lowerCaseName);
|
|
||||||
if (lowerDir.isDirectory()) {
|
|
||||||
directory = lowerDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and register type properties file
|
// Create and register type properties file
|
||||||
File propfile = new File(directory, "type.properties");
|
props = new ResourceProperties();
|
||||||
SystemProperties props = new SystemProperties(propfile.getAbsolutePath());
|
if (repository != null) {
|
||||||
|
props.addResource(repository.getResource("type.properties"));
|
||||||
|
}
|
||||||
dbmap = new DbMapping(app, name, props);
|
dbmap = new DbMapping(app, name, props);
|
||||||
// we don't need to put the DbMapping into proto.updatables, because
|
// we don't need to put the DbMapping into proto.updatables, because
|
||||||
// dbmappings are checked separately in TypeManager.checkFiles() for
|
// dbmappings are checked separately in TypeManager.checkFiles() for
|
||||||
// each request
|
// each request
|
||||||
|
|
||||||
code = new HashMap();
|
code = new TreeSet(app.getResourceComparator());
|
||||||
zippedCode = new HashMap();
|
skins = new TreeSet(app.getResourceComparator());
|
||||||
skins = new HashMap();
|
|
||||||
zippedSkins = new HashMap();
|
|
||||||
updatables = new HashMap();
|
|
||||||
|
|
||||||
skinMap = new SkinMap();
|
trackers = new HashMap();
|
||||||
|
|
||||||
|
skinMap = new HashMap();
|
||||||
|
|
||||||
isJavaPrototype = app.isJavaPrototype(name);
|
isJavaPrototype = app.isJavaPrototype(name);
|
||||||
lastUpdate = lastChecksum = 0;
|
lastCodeUpdate = lastChecksum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,42 +114,58 @@ public final class Prototype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this prototype's directory.
|
* Adds an repository to the list of repositories
|
||||||
|
* @param repository repository to add
|
||||||
*/
|
*/
|
||||||
public File getDirectory() {
|
public void addRepository(Repository repository) {
|
||||||
return directory;
|
if (!repositories.contains(repository)) {
|
||||||
|
repositories.add(repository);
|
||||||
|
props.addResource(repository.getResource("type.properties"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of files in this prototype's directory
|
* Returns the list of resources in this prototype's repositories
|
||||||
*/
|
*/
|
||||||
public File[] getFiles() {
|
public Resource[] getResources() {
|
||||||
if ((files == null) || (directory.lastModified() != lastDirectoryListing)) {
|
long resourceListing = getChecksum();
|
||||||
lastDirectoryListing = directory.lastModified();
|
|
||||||
files = directory.listFiles();
|
|
||||||
|
|
||||||
if (files == null) {
|
if (resources == null || resourceListing != lastResourceListing) {
|
||||||
files = new File[0];
|
lastResourceListing = resourceListing;
|
||||||
|
ArrayList list = new ArrayList();
|
||||||
|
Iterator iterator = repositories.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
try {
|
||||||
|
list.addAll(((Repository) iterator.next()).getAllResources());
|
||||||
|
} catch (IOException iox) {
|
||||||
|
iox.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
resources = (Resource[]) list.toArray(new Resource[list.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a checksum over the files in this prototype's directory
|
* Get a checksum over this prototype's sources
|
||||||
*/
|
*/
|
||||||
public long getChecksum() {
|
public long getChecksum() {
|
||||||
// long start = System.currentTimeMillis();
|
long checksum = 0;
|
||||||
File[] f = getFiles();
|
Iterator iterator = repositories.iterator();
|
||||||
long c = directory.lastModified();
|
|
||||||
|
|
||||||
for (int i = 0; i < f.length; i++)
|
while (iterator.hasNext()) {
|
||||||
c += f[i].lastModified();
|
try {
|
||||||
|
checksum += ((Repository) iterator.next()).getChecksum();
|
||||||
|
} catch (IOException iox) {
|
||||||
|
iox.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checksum = c;
|
newChecksum = checksum;
|
||||||
|
|
||||||
// System.err.println ("CHECKSUM "+name+": "+(System.currentTimeMillis()-start));
|
|
||||||
return checksum;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +175,8 @@ public final class Prototype {
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean isUpToDate() {
|
public boolean isUpToDate() {
|
||||||
return checksum == lastChecksum;
|
return (newChecksum == 0 && lastChecksum == 0) ?
|
||||||
|
false : newChecksum == lastChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +185,7 @@ public final class Prototype {
|
||||||
*/
|
*/
|
||||||
public void setParentPrototype(Prototype parent) {
|
public void setParentPrototype(Prototype parent) {
|
||||||
// this is not allowed for the hopobject and global prototypes
|
// this is not allowed for the hopobject and global prototypes
|
||||||
if ("HopObject".equals(name) || "global".equals(name)) {
|
if ("hopobject".equals(lowerCaseName) || "global".equals(lowerCaseName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,11 +204,11 @@ public final class Prototype {
|
||||||
* Check if the given prototype is within this prototype's parent chain.
|
* Check if the given prototype is within this prototype's parent chain.
|
||||||
*/
|
*/
|
||||||
public final boolean isInstanceOf(String pname) {
|
public final boolean isInstanceOf(String pname) {
|
||||||
if (name.equals(pname) || lowerCaseName.equals(pname)) {
|
if (name.equalsIgnoreCase(pname)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parent != null) && !"HopObject".equals(parent.getName())) {
|
if (parent != null) {
|
||||||
return parent.isInstanceOf(pname);
|
return parent.isInstanceOf(pname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,14 +264,8 @@ public final class Prototype {
|
||||||
* residing in the prototype directory, not for skin files in
|
* residing in the prototype directory, not for skin files in
|
||||||
* other locations or database stored skins.
|
* other locations or database stored skins.
|
||||||
*/
|
*/
|
||||||
public SkinFile getSkinFile(String sfname) {
|
public Resource getSkinResource(String sname) {
|
||||||
SkinFile sf = (SkinFile) skins.get(sfname);
|
return (Resource) skinMap.get(sname);
|
||||||
|
|
||||||
if (sf == null) {
|
|
||||||
sf = (SkinFile) zippedSkins.get(sfname);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,11 +273,11 @@ public final class Prototype {
|
||||||
* residing in the prototype directory, not for skins files in
|
* residing in the prototype directory, not for skins files in
|
||||||
* other locations or database stored skins.
|
* other locations or database stored skins.
|
||||||
*/
|
*/
|
||||||
public Skin getSkin(String sfname) {
|
public Skin getSkin(String sname) throws IOException {
|
||||||
SkinFile sf = getSkinFile(sfname);
|
Resource res = getSkinResource(sname);
|
||||||
|
|
||||||
if (sf != null) {
|
if (res != null) {
|
||||||
return sf.getSkin();
|
return Skin.getSkin(res, app);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -294,8 +304,8 @@ public final class Prototype {
|
||||||
/**
|
/**
|
||||||
* Get the last time any script has been re-read for this prototype.
|
* Get the last time any script has been re-read for this prototype.
|
||||||
*/
|
*/
|
||||||
public long getLastUpdate() {
|
public long lastCodeUpdate() {
|
||||||
return lastUpdate;
|
return lastCodeUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,7 +314,7 @@ public final class Prototype {
|
||||||
* the evaluators.
|
* the evaluators.
|
||||||
*/
|
*/
|
||||||
public void markUpdated() {
|
public void markUpdated() {
|
||||||
lastUpdate = System.currentTimeMillis();
|
lastCodeUpdate = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -313,7 +323,7 @@ public final class Prototype {
|
||||||
*/
|
*/
|
||||||
public void markChecked() {
|
public void markChecked() {
|
||||||
// lastCheck = System.currentTimeMillis ();
|
// lastCheck = System.currentTimeMillis ();
|
||||||
lastChecksum = checksum;
|
lastChecksum = newChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,145 +331,30 @@ public final class Prototype {
|
||||||
* to not return a map in a transient state where it is just being
|
* to not return a map in a transient state where it is just being
|
||||||
* updated by the type manager.
|
* updated by the type manager.
|
||||||
*/
|
*/
|
||||||
public synchronized Map getCode() {
|
public synchronized Iterator getCodeResources() {
|
||||||
return (Map) code.clone();
|
return code.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a clone of this prototype's functions container. Synchronized
|
* Add a code resource to this prototype
|
||||||
* to not return a map in a transient state where it is just being
|
*
|
||||||
* updated by the type manager.
|
* @param res a code resource
|
||||||
*/
|
*/
|
||||||
public synchronized Map getZippedCode() {
|
public synchronized void addCodeResource(Resource res) {
|
||||||
return (Map) zippedCode.clone();
|
code.add(res);
|
||||||
|
trackers.put(res.getName(), new ResourceTracker(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Add a skin resource to this prototype
|
||||||
*
|
*
|
||||||
*
|
* @param res a skin resource
|
||||||
* @param action ...
|
|
||||||
*/
|
*/
|
||||||
public synchronized void addActionFile(ActionFile action) {
|
public synchronized void addSkinResource(Resource res) {
|
||||||
File f = action.getFile();
|
skins.add(res);
|
||||||
|
skinMap.put(res.getShortName(), res);
|
||||||
if (f != null) {
|
trackers.put(res.getName(), new ResourceTracker(res));
|
||||||
code.put(action.getSourceName(), action);
|
|
||||||
updatables.put(f.getName(), action);
|
|
||||||
} else {
|
|
||||||
zippedCode.put(action.getSourceName(), action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param template ...
|
|
||||||
*/
|
|
||||||
public synchronized void addTemplate(Template template) {
|
|
||||||
File f = template.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
code.put(template.getSourceName(), template);
|
|
||||||
updatables.put(f.getName(), template);
|
|
||||||
} else {
|
|
||||||
zippedCode.put(template.getSourceName(), template);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param funcfile ...
|
|
||||||
*/
|
|
||||||
public synchronized void addFunctionFile(FunctionFile funcfile) {
|
|
||||||
File f = funcfile.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
code.put(funcfile.getSourceName(), funcfile);
|
|
||||||
updatables.put(f.getName(), funcfile);
|
|
||||||
} else {
|
|
||||||
zippedCode.put(funcfile.getSourceName(), funcfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param skinfile ...
|
|
||||||
*/
|
|
||||||
public synchronized void addSkinFile(SkinFile skinfile) {
|
|
||||||
File f = skinfile.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
skins.put(skinfile.getName(), skinfile);
|
|
||||||
updatables.put(f.getName(), skinfile);
|
|
||||||
} else {
|
|
||||||
zippedSkins.put(skinfile.getName(), skinfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param action ...
|
|
||||||
*/
|
|
||||||
public synchronized void removeActionFile(ActionFile action) {
|
|
||||||
File f = action.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
code.remove(action.getSourceName());
|
|
||||||
updatables.remove(f.getName());
|
|
||||||
} else {
|
|
||||||
zippedCode.remove(action.getSourceName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param funcfile ...
|
|
||||||
*/
|
|
||||||
public synchronized void removeFunctionFile(FunctionFile funcfile) {
|
|
||||||
File f = funcfile.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
code.remove(funcfile.getSourceName());
|
|
||||||
updatables.remove(f.getName());
|
|
||||||
} else {
|
|
||||||
zippedCode.remove(funcfile.getSourceName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param template ...
|
|
||||||
*/
|
|
||||||
public synchronized void removeTemplate(Template template) {
|
|
||||||
File f = template.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
code.remove(template.getSourceName());
|
|
||||||
updatables.remove(f.getName());
|
|
||||||
} else {
|
|
||||||
zippedCode.remove(template.getSourceName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param skinfile ...
|
|
||||||
*/
|
|
||||||
public synchronized void removeSkinFile(SkinFile skinfile) {
|
|
||||||
File f = skinfile.getFile();
|
|
||||||
|
|
||||||
if (f != null) {
|
|
||||||
skins.remove(skinfile.getName());
|
|
||||||
updatables.remove(f.getName());
|
|
||||||
} else {
|
|
||||||
zippedSkins.remove(skinfile.getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -475,7 +370,7 @@ public final class Prototype {
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public SkinMap getSkinMap() {
|
public SkinMap getSkinMap() {
|
||||||
return skinMap;
|
return new SkinMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// not yet implemented
|
// not yet implemented
|
||||||
|
@ -529,13 +424,17 @@ public final class Prototype {
|
||||||
|
|
||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
|
|
||||||
SkinFile sf = (SkinFile) super.get(key);
|
Resource res = (Resource) super.get(key);
|
||||||
|
|
||||||
if (sf == null) {
|
if (res == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sf.getSkin().getSource();
|
try {
|
||||||
|
return res.getContent();
|
||||||
|
} catch (IOException iox) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
@ -589,26 +488,20 @@ public final class Prototype {
|
||||||
app.typemgr.updatePrototype(Prototype.this);
|
app.typemgr.updatePrototype(Prototype.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastUpdate > lastSkinmapLoad) {
|
if (lastCodeUpdate > lastSkinmapLoad) {
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void load() {
|
private synchronized void load() {
|
||||||
if (lastUpdate == lastSkinmapLoad) {
|
if (lastCodeUpdate == lastSkinmapLoad) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.clear();
|
super.clear();
|
||||||
|
|
||||||
// load Skins from zip files first, then from directories
|
// load Skins
|
||||||
for (Iterator i = zippedSkins.entrySet().iterator(); i.hasNext();) {
|
for (Iterator i = skins.iterator(); i.hasNext();) {
|
||||||
Map.Entry e = (Map.Entry) i.next();
|
|
||||||
|
|
||||||
super.put(e.getKey(), e.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Iterator i = skins.entrySet().iterator(); i.hasNext();) {
|
|
||||||
Map.Entry e = (Map.Entry) i.next();
|
Map.Entry e = (Map.Entry) i.next();
|
||||||
|
|
||||||
super.put(e.getKey(), e.getValue());
|
super.put(e.getKey(), e.getValue());
|
||||||
|
@ -628,7 +521,7 @@ public final class Prototype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSkinmapLoad = lastUpdate;
|
lastSkinmapLoad = lastCodeUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -305,10 +305,6 @@ public final class RequestEvaluator implements Runnable {
|
||||||
// set the req.action property, cutting off the _action suffix
|
// set the req.action property, cutting off the _action suffix
|
||||||
req.action = action.substring(0, action.length() - 7);
|
req.action = action.substring(0, action.length() - 7);
|
||||||
|
|
||||||
// set the application checksum in response to make ETag
|
|
||||||
// generation sensitive to changes in the app
|
|
||||||
res.setApplicationChecksum(app.getChecksum());
|
|
||||||
|
|
||||||
// reset skin recursion detection counter
|
// reset skin recursion detection counter
|
||||||
skinDepth = 0;
|
skinDepth = 0;
|
||||||
|
|
||||||
|
@ -856,7 +852,7 @@ public final class RequestEvaluator implements Runnable {
|
||||||
this.req = req;
|
this.req = req;
|
||||||
this.reqtype = HTTP;
|
this.reqtype = HTTP;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
res = new ResponseTrans(req);
|
res = new ResponseTrans(app, req);
|
||||||
result = null;
|
result = null;
|
||||||
exception = null;
|
exception = null;
|
||||||
}
|
}
|
||||||
|
@ -875,7 +871,7 @@ public final class RequestEvaluator implements Runnable {
|
||||||
req = new RequestTrans(reqtypeName);
|
req = new RequestTrans(reqtypeName);
|
||||||
req.path = functionName;
|
req.path = functionName;
|
||||||
session = new Session(functionName, app);
|
session = new Session(functionName, app);
|
||||||
res = new ResponseTrans(req);
|
res = new ResponseTrans(app, req);
|
||||||
result = null;
|
result = null;
|
||||||
exception = null;
|
exception = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package helma.framework.core;
|
package helma.framework.core;
|
||||||
|
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
|
import helma.framework.repository.Resource;
|
||||||
import helma.objectmodel.ConcurrencyException;
|
import helma.objectmodel.ConcurrencyException;
|
||||||
import helma.util.HtmlEncoder;
|
import helma.util.HtmlEncoder;
|
||||||
import helma.util.SystemMap;
|
import helma.util.SystemMap;
|
||||||
|
@ -24,6 +25,9 @@ import helma.util.WrappedMap;
|
||||||
import helma.util.UrlEncoded;
|
import helma.util.UrlEncoded;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a Helma skin, i.e. a template created from containing Macro tags
|
* This represents a Helma skin, i.e. a template created from containing Macro tags
|
||||||
|
@ -80,6 +84,22 @@ public final class Skin {
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Skin getSkin(Resource res, Application app) throws IOException {
|
||||||
|
String encoding = app.getProperty("skinCharset");
|
||||||
|
Reader reader;
|
||||||
|
if (encoding == null) {
|
||||||
|
reader = new InputStreamReader(res.getInputStream());
|
||||||
|
} else {
|
||||||
|
reader = new InputStreamReader(res.getInputStream(), encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] characterBuffer = new char[(int) res.getLength()];
|
||||||
|
int length = reader.read(characterBuffer);
|
||||||
|
|
||||||
|
reader.close();
|
||||||
|
return new Skin(characterBuffer, length, app);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a skin object from source text
|
* Parse a skin object from source text
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.framework.core;
|
|
||||||
|
|
||||||
import helma.util.Updatable;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This represents a File containing a Hop skin
|
|
||||||
*/
|
|
||||||
public final class SkinFile implements Updatable {
|
|
||||||
String name;
|
|
||||||
Prototype prototype;
|
|
||||||
Application app;
|
|
||||||
File file;
|
|
||||||
Skin skin;
|
|
||||||
long lastmod = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new SkinFile object.
|
|
||||||
*
|
|
||||||
* @param file ...
|
|
||||||
* @param name ...
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public SkinFile(File file, String name, Prototype proto) {
|
|
||||||
this.prototype = proto;
|
|
||||||
this.file = file;
|
|
||||||
this.name = name;
|
|
||||||
this.app = proto.app;
|
|
||||||
skin = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a skinfile without a file, passing the skin body directly. This is used for
|
|
||||||
* Skins contained in zipped applications. The whole update mechanism is bypassed
|
|
||||||
* by immediately setting the skin member.
|
|
||||||
*/
|
|
||||||
public SkinFile(String body, String name, Prototype proto) {
|
|
||||||
this.prototype = proto;
|
|
||||||
this.app = proto.app;
|
|
||||||
this.name = name;
|
|
||||||
this.file = null;
|
|
||||||
skin = new Skin(body, app);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a skinfile that doesn't belong to a prototype, or at
|
|
||||||
* least it doesn't know about its prototype and isn't managed by the prototype.
|
|
||||||
*/
|
|
||||||
public SkinFile(File file, String name, Application app) {
|
|
||||||
this.app = app;
|
|
||||||
this.file = file;
|
|
||||||
this.name = name;
|
|
||||||
this.prototype = null;
|
|
||||||
skin = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the type manager whether we need an update. this is the case when
|
|
||||||
* the file has been modified or deleted.
|
|
||||||
*/
|
|
||||||
public boolean needsUpdate() {
|
|
||||||
// if skin object is null we only need to call update if the file doesn't
|
|
||||||
// exist anymore, while if the skin is initialized, we'll catch both
|
|
||||||
// cases (file deleted and file changed) by just calling lastModified().
|
|
||||||
return (skin != null) ? (lastmod != file.lastModified()) : (!file.exists());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void update() {
|
|
||||||
if (!file.exists()) {
|
|
||||||
// remove skin from prototype
|
|
||||||
remove();
|
|
||||||
} else {
|
|
||||||
// we only need to update if the skin has already been initialized
|
|
||||||
if (skin != null) {
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void read() {
|
|
||||||
String encoding = app.getProperty("skinCharset");
|
|
||||||
try {
|
|
||||||
Reader reader;
|
|
||||||
if (encoding == null) {
|
|
||||||
reader = new FileReader(file);
|
|
||||||
} else {
|
|
||||||
FileInputStream in = new FileInputStream(file);
|
|
||||||
reader = new InputStreamReader(in, encoding);
|
|
||||||
}
|
|
||||||
char[] c = new char[(int) file.length()];
|
|
||||||
int length = reader.read(c);
|
|
||||||
|
|
||||||
reader.close();
|
|
||||||
skin = new Skin(c, length, app);
|
|
||||||
} catch (IOException x) {
|
|
||||||
app.logEvent("Error reading Skin " + file + ": " + x);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastmod = file.lastModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void remove() {
|
|
||||||
if (prototype != null) {
|
|
||||||
prototype.removeSkinFile(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public File getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public Skin getSkin() {
|
|
||||||
if (skin == null) {
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
|
|
||||||
return skin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
return new StringBuffer("[SkinFile ").append(prototype.getName())
|
|
||||||
.append("/").append(name).append("]").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to produce hash code depending on file name
|
|
||||||
*
|
|
||||||
* @return a hash code value for this object.
|
|
||||||
*/
|
|
||||||
public int hashCode() {
|
|
||||||
return toString().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to equal other SkinFile with the same source name
|
|
||||||
*
|
|
||||||
* @param obj the object to compare to
|
|
||||||
* @return true if obj is a SkinFile with the same source name
|
|
||||||
*/
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return (obj instanceof SkinFile) &&
|
|
||||||
toString().equals(obj.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -17,6 +17,8 @@
|
||||||
package helma.framework.core;
|
package helma.framework.core;
|
||||||
|
|
||||||
import helma.objectmodel.INode;
|
import helma.objectmodel.INode;
|
||||||
|
import helma.framework.repository.FileResource;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -41,7 +43,7 @@ public final class SkinManager implements FilenameFilter {
|
||||||
skinExtension = ".skin";
|
skinExtension = ".skin";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Skin getSkin(Prototype proto, String skinname, Object[] skinpath) {
|
protected Skin getSkin(Prototype proto, String skinname, Object[] skinpath) throws IOException {
|
||||||
if (proto == null) {
|
if (proto == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +79,7 @@ public final class SkinManager implements FilenameFilter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Skin getSkinInternal(Object skinset, String prototype, String skinname) {
|
protected Skin getSkinInternal(Object skinset, String prototype, String skinname) throws IOException {
|
||||||
if ((prototype == null) || (skinset == null)) {
|
if ((prototype == null) || (skinset == null)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -101,19 +103,16 @@ public final class SkinManager implements FilenameFilter {
|
||||||
} else {
|
} else {
|
||||||
// Skinset is interpreted as directory name from which to
|
// Skinset is interpreted as directory name from which to
|
||||||
// retrieve the skin
|
// retrieve the skin
|
||||||
File f = new File(skinset.toString(), prototype);
|
StringBuffer b = new StringBuffer(skinset.toString());
|
||||||
|
b.append(File.separatorChar).append(prototype).append(File.separatorChar)
|
||||||
|
.append(skinname).append(skinExtension);
|
||||||
|
|
||||||
// if directory does not exist use lower case property name
|
// TODO: check for lower case prototype name for backwards compat
|
||||||
if (!f.isDirectory()) {
|
|
||||||
f = new File(skinset.toString(), prototype.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
f = new File(f, skinname + skinExtension);
|
File f = new File(b.toString());
|
||||||
|
|
||||||
if (f.exists() && f.canRead()) {
|
if (f.exists() && f.canRead()) {
|
||||||
SkinFile sf = new SkinFile(f, skinname, app);
|
return Skin.getSkin(new FileResource(f), app);
|
||||||
|
|
||||||
return sf.getSkin();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ public final class SkinManager implements FilenameFilter {
|
||||||
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
|
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
|
||||||
File file = new File(dir, skinNames[i]);
|
File file = new File(dir, skinNames[i]);
|
||||||
|
|
||||||
map.put(name, new SkinFile(file, name, proto));
|
map.put(name, (new FileResource(file)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
package helma.framework.core;
|
package helma.framework.core;
|
||||||
|
|
||||||
import helma.objectmodel.db.DbMapping;
|
import helma.objectmodel.db.DbMapping;
|
||||||
import helma.scripting.*;
|
import helma.framework.repository.ZipRepository;
|
||||||
import helma.util.*;
|
import helma.framework.repository.Resource;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
|
import helma.framework.repository.ResourceTracker;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -37,24 +39,16 @@ public final class TypeManager {
|
||||||
final static String skinExtension = ".skin";
|
final static String skinExtension = ".skin";
|
||||||
|
|
||||||
private Application app;
|
private Application app;
|
||||||
private File appDir;
|
Repository[] repositories;
|
||||||
|
long[] modified;
|
||||||
// map of prototypes
|
// map of prototypes
|
||||||
private HashMap prototypes;
|
private HashMap prototypes;
|
||||||
// map of zipped script files
|
|
||||||
private HashMap zipfiles;
|
|
||||||
// set of Java archives
|
// set of Java archives
|
||||||
private HashSet jarfiles;
|
private HashSet jarfiles;
|
||||||
|
|
||||||
private long lastCheck = 0;
|
private long lastCheck = 0;
|
||||||
private long appDirMod = 0;
|
private long lastCodeUpdate;
|
||||||
|
|
||||||
// a checksum that changes whenever something in the application files changes.
|
|
||||||
private long checksum;
|
|
||||||
|
|
||||||
// the hopobject prototype
|
|
||||||
// private Prototype hopobjectProto;
|
|
||||||
|
|
||||||
// the global prototype
|
|
||||||
// private Prototype globalProto;
|
|
||||||
|
|
||||||
// app specific class loader, includes jar files in the app directory
|
// app specific class loader, includes jar files in the app directory
|
||||||
private AppClassLoader loader;
|
private AppClassLoader loader;
|
||||||
|
@ -64,31 +58,14 @@ public final class TypeManager {
|
||||||
*
|
*
|
||||||
* @param app ...
|
* @param app ...
|
||||||
*
|
*
|
||||||
* @throws MalformedURLException ...
|
|
||||||
* @throws RuntimeException ...
|
* @throws RuntimeException ...
|
||||||
*/
|
*/
|
||||||
public TypeManager(Application app) throws MalformedURLException {
|
public TypeManager(Application app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
appDir = app.appDir;
|
repositories = new Repository[app.repositories.size()];
|
||||||
|
app.repositories.toArray(repositories);
|
||||||
// make sure the directories for the standard prototypes exist,
|
modified = new long[repositories.length];
|
||||||
// and lament otherwise
|
|
||||||
if (appDir.list().length == 0) {
|
|
||||||
for (int i = 0; i < standardTypes.length; i++) {
|
|
||||||
File f = new File(appDir, standardTypes[i]);
|
|
||||||
|
|
||||||
if (!f.exists() && !f.mkdir()) {
|
|
||||||
app.logEvent("Warning: directory " + f.getAbsolutePath() +
|
|
||||||
" could not be created.");
|
|
||||||
} else if (!f.isDirectory()) {
|
|
||||||
app.logEvent("Warning: " + f.getAbsolutePath() +
|
|
||||||
" is not a directory.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prototypes = new HashMap();
|
prototypes = new HashMap();
|
||||||
zipfiles = new HashMap();
|
|
||||||
jarfiles = new HashSet();
|
jarfiles = new HashSet();
|
||||||
|
|
||||||
URL helmajar = TypeManager.class.getResource("/");
|
URL helmajar = TypeManager.class.getResource("/");
|
||||||
|
@ -139,90 +116,63 @@ public final class TypeManager {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
checkFiles();
|
checkFiles();
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {}
|
||||||
}
|
|
||||||
|
|
||||||
lastCheck = System.currentTimeMillis();
|
lastCheck = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkRepository(Repository repository) throws IOException {
|
||||||
|
Repository[] list = repository.getRepositories();
|
||||||
|
for (int i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].isScriptRoot()) {
|
||||||
|
// this is an embedded top-level script repository
|
||||||
|
checkRepository(list[i]);
|
||||||
|
} else {
|
||||||
|
// its an prototype
|
||||||
|
String name = null;
|
||||||
|
name = ((Repository) list[i]).getShortName();
|
||||||
|
Prototype proto = getPrototype(name);
|
||||||
|
|
||||||
|
// if prototype doesn't exist, create it
|
||||||
|
if ((proto == null) && isValidTypeName(name)) {
|
||||||
|
// create new prototype
|
||||||
|
createPrototype(name, (Repository) list[i]);
|
||||||
|
} else {
|
||||||
|
proto.addRepository((Repository) list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator resources = repository.getResources();
|
||||||
|
while (resources.hasNext()) {
|
||||||
|
// check for jar files to add to class loader
|
||||||
|
Resource resource = (Resource) resources.next();
|
||||||
|
String name = resource.getName();
|
||||||
|
if (name.endsWith(".jar")) {
|
||||||
|
if (!jarfiles.contains(name)) {
|
||||||
|
jarfiles.add(name);
|
||||||
|
loader.addURL(resource.getUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run through application's prototype directories and check if
|
* Run through application's prototype sources and check if
|
||||||
* there are any prototypes to be created.
|
* there are any prototypes to be created.
|
||||||
*/
|
*/
|
||||||
private void checkFiles() {
|
private void checkFiles() {
|
||||||
// check if any files have been created/removed since last time we
|
// check if any files have been created/removed since last time we checked...
|
||||||
// checked...
|
for (int i = 0; i < repositories.length; i++) {
|
||||||
if (appDir.lastModified() > appDirMod) {
|
|
||||||
appDirMod = appDir.lastModified();
|
|
||||||
|
|
||||||
String[] list = appDir.list();
|
|
||||||
|
|
||||||
if (list == null) {
|
|
||||||
throw new RuntimeException("Can't read app directory " + appDir +
|
|
||||||
" - check permissions");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < list.length; i++) {
|
|
||||||
if (list[i].endsWith(".zip")) {
|
|
||||||
ZippedAppFile zipped = (ZippedAppFile) zipfiles.get(list[i]);
|
|
||||||
|
|
||||||
if (zipped == null) {
|
|
||||||
File f = new File(appDir, list[i]);
|
|
||||||
|
|
||||||
if (!f.isDirectory() && f.exists()) {
|
|
||||||
zipped = new ZippedAppFile(f, app);
|
|
||||||
zipfiles.put(list[i], zipped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list[i].endsWith(".jar")) {
|
|
||||||
if (!jarfiles.contains(list[i])) {
|
|
||||||
jarfiles.add(list[i]);
|
|
||||||
|
|
||||||
File f = new File(appDir, list[i]);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loader.addURL(new URL("file:" + f.getAbsolutePath()));
|
if (repositories[i].lastModified() > modified[i]) {
|
||||||
} catch (MalformedURLException ignore) {
|
modified[i] = repositories[i].lastModified();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
checkRepository(repositories[i]);
|
||||||
}
|
}
|
||||||
|
} catch (IOException iox) {
|
||||||
if (list[i].indexOf('.') > -1) {
|
iox.printStackTrace();
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Prototype proto = getPrototype(list[i]);
|
|
||||||
|
|
||||||
// if prototype doesn't exist, create it
|
|
||||||
if ((proto == null) && isValidTypeName(list[i])) {
|
|
||||||
File f = new File(appDir, list[i]);
|
|
||||||
|
|
||||||
if (f.isDirectory()) {
|
|
||||||
// create new prototype
|
|
||||||
createPrototype(list[i], f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate this app's checksum by adding all checksums from all prototypes
|
|
||||||
long newChecksum = 0;
|
|
||||||
|
|
||||||
// loop through zip files to check for updates
|
|
||||||
for (Iterator it = zipfiles.values().iterator(); it.hasNext();) {
|
|
||||||
ZippedAppFile zipped = (ZippedAppFile) it.next();
|
|
||||||
|
|
||||||
if (zipped.needsUpdate()) {
|
|
||||||
zipped.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
newChecksum += zipped.lastmod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through prototypes and check if type.properties needs updates
|
// loop through prototypes and check if type.properties needs updates
|
||||||
|
@ -231,9 +181,6 @@ public final class TypeManager {
|
||||||
for (Iterator i = prototypes.values().iterator(); i.hasNext();) {
|
for (Iterator i = prototypes.values().iterator(); i.hasNext();) {
|
||||||
Prototype proto = (Prototype) i.next();
|
Prototype proto = (Prototype) i.next();
|
||||||
|
|
||||||
// calculate this app's type checksum
|
|
||||||
newChecksum += proto.getChecksum();
|
|
||||||
|
|
||||||
// update prototype's type mapping
|
// update prototype's type mapping
|
||||||
DbMapping dbmap = proto.getDbMapping();
|
DbMapping dbmap = proto.getDbMapping();
|
||||||
|
|
||||||
|
@ -243,25 +190,10 @@ public final class TypeManager {
|
||||||
// global and HopObject, which is a bit awkward...
|
// global and HopObject, which is a bit awkward...
|
||||||
// I mean we're the type manager, so this should
|
// I mean we're the type manager, so this should
|
||||||
// be part of our job, right?
|
// be part of our job, right?
|
||||||
|
proto.props.update();
|
||||||
dbmap.update();
|
dbmap.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checksum = newChecksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void removeZipFile(String zipname) {
|
|
||||||
zipfiles.remove(zipname);
|
|
||||||
|
|
||||||
for (Iterator i = prototypes.values().iterator(); i.hasNext();) {
|
|
||||||
Prototype proto = (Prototype) i.next();
|
|
||||||
|
|
||||||
// update prototype's type mapping
|
|
||||||
DbMapping dbmap = proto.getDbMapping();
|
|
||||||
SystemProperties props = dbmap.getProperties();
|
|
||||||
|
|
||||||
props.removeProps(zipname);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidTypeName(String str) {
|
private boolean isValidTypeName(String str) {
|
||||||
|
@ -283,8 +215,8 @@ public final class TypeManager {
|
||||||
* Return a checksum over all files in all prototypes in this application.
|
* Return a checksum over all files in all prototypes in this application.
|
||||||
* The checksum can be used to find out quickly if any file has changed.
|
* The checksum can be used to find out quickly if any file has changed.
|
||||||
*/
|
*/
|
||||||
public long getChecksum() {
|
public long lastCodeUpdate() {
|
||||||
return checksum;
|
return lastCodeUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -320,12 +252,11 @@ public final class TypeManager {
|
||||||
* Create and register a new Prototype.
|
* Create and register a new Prototype.
|
||||||
*
|
*
|
||||||
* @param typename the name of the prototype
|
* @param typename the name of the prototype
|
||||||
* @param dir the prototype directory if it is know, or null if we
|
* @param repository the first prototype source
|
||||||
* ought to find out by ourselves
|
|
||||||
* @return the newly created prototype
|
* @return the newly created prototype
|
||||||
*/
|
*/
|
||||||
public Prototype createPrototype(String typename, File dir) {
|
public Prototype createPrototype(String typename, Repository repository) {
|
||||||
Prototype proto = new Prototype(typename, dir, app);
|
Prototype proto = new Prototype(typename, repository, app);
|
||||||
|
|
||||||
// put the prototype into our map
|
// put the prototype into our map
|
||||||
prototypes.put(proto.getLowerCaseName(), proto);
|
prototypes.put(proto.getLowerCaseName(), proto);
|
||||||
|
@ -334,124 +265,86 @@ public final class TypeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a prototype to the files in the prototype directory.
|
* Check a prototype for new or updated resources.
|
||||||
*/
|
|
||||||
public void updatePrototype(String name) {
|
|
||||||
// System.err.println ("UPDATE PROTO: "+app.getName()+"/"+name);
|
|
||||||
Prototype proto = getPrototype(name);
|
|
||||||
|
|
||||||
updatePrototype(proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a prototype to the files in the prototype directory.
|
|
||||||
*/
|
*/
|
||||||
public void updatePrototype(Prototype proto) {
|
public void updatePrototype(Prototype proto) {
|
||||||
if ((proto == null) || proto.isUpToDate()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (proto) {
|
synchronized (proto) {
|
||||||
// check again because another thread may have checked the
|
// check again because another thread may have checked the
|
||||||
// prototype while we were waiting for access to the synchronized section
|
// prototype while we were waiting for access to the synchronized section
|
||||||
|
|
||||||
/* if (System.currentTimeMillis() - proto.getLastCheck() < 1000)
|
boolean updatedResources = false;
|
||||||
return; */
|
List createdResources = null;
|
||||||
HashSet updateSet = null;
|
|
||||||
HashSet createSet = null;
|
|
||||||
|
|
||||||
// our plan is to do as little as possible, so first check if
|
// our plan is to do as little as possible, so first check if
|
||||||
// anything the prototype knows about has changed on disk
|
// anything the prototype knows about has changed on disk
|
||||||
for (Iterator i = proto.updatables.values().iterator(); i.hasNext();) {
|
for (Iterator i = proto.trackers.values().iterator(); i.hasNext();) {
|
||||||
Updatable upd = (Updatable) i.next();
|
ResourceTracker tracker = (ResourceTracker) i.next();
|
||||||
|
|
||||||
if (upd.needsUpdate()) {
|
try {
|
||||||
if (updateSet == null) {
|
if (tracker.hasChanged()) {
|
||||||
updateSet = new HashSet();
|
updatedResources = true;
|
||||||
|
tracker.markClean();
|
||||||
}
|
}
|
||||||
|
} catch (IOException iox) {
|
||||||
updateSet.add(upd);
|
iox.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// next we check if files have been created or removed since last update
|
// next we check if files have been created or removed since last update
|
||||||
// if (proto.getLastCheck() < dir.lastModified ()) {
|
Resource[] resources = proto.getResources();
|
||||||
File[] list = proto.getFiles();
|
|
||||||
|
|
||||||
for (int i = 0; i < list.length; i++) {
|
for (int i = 0; i < resources.length; i++) {
|
||||||
String fn = list[i].getName();
|
String name = resources[i].getName();
|
||||||
|
if (!proto.trackers.containsKey(name)) {
|
||||||
// ignore files starting with ".".
|
if (name.endsWith(templateExtension) ||
|
||||||
if (fn.startsWith(".")) {
|
name.endsWith(scriptExtension) ||
|
||||||
continue;
|
name.endsWith(actionExtension) ||
|
||||||
|
name.endsWith(skinExtension)) {
|
||||||
|
if (createdResources == null) {
|
||||||
|
createdResources = new ArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!proto.updatables.containsKey(fn)) {
|
createdResources.add(resources[i]);
|
||||||
if (fn.endsWith(templateExtension) || fn.endsWith(scriptExtension) ||
|
|
||||||
fn.endsWith(actionExtension) || fn.endsWith(skinExtension) ||
|
|
||||||
"type.properties".equalsIgnoreCase(fn)) {
|
|
||||||
if (createSet == null) {
|
|
||||||
createSet = new HashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
createSet.add(list[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// }
|
|
||||||
// if nothing needs to be updated, mark prototype as checked and return
|
// if nothing needs to be updated, mark prototype as checked and return
|
||||||
if ((updateSet == null) && (createSet == null)) {
|
if (!updatedResources && createdResources == null) {
|
||||||
proto.markChecked();
|
proto.markChecked();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first go through new files and create new items
|
// first go through new files and create new items
|
||||||
if (createSet != null) {
|
if (createdResources != null) {
|
||||||
Object[] newFiles = createSet.toArray();
|
Resource[] newResources = new Resource[createdResources.size()];
|
||||||
|
createdResources.toArray(newResources);
|
||||||
|
|
||||||
for (int i = 0; i < newFiles.length; i++) {
|
for (int i = 0; i < newResources.length; i++) {
|
||||||
File file = (File) newFiles[i];
|
String resourceName = newResources[i].getName();
|
||||||
String filename = file.getName();
|
if (resourceName.endsWith(templateExtension) ||
|
||||||
int dot = filename.lastIndexOf(".");
|
resourceName.endsWith(scriptExtension) ||
|
||||||
String tmpname = filename.substring(0, dot);
|
resourceName.endsWith(actionExtension)) {
|
||||||
String srcName = getSourceName(file);
|
|
||||||
|
|
||||||
if (filename.endsWith(templateExtension)) {
|
|
||||||
try {
|
try {
|
||||||
Template t = new Template(file, tmpname, srcName, proto);
|
proto.addCodeResource(newResources[i]);
|
||||||
|
|
||||||
proto.addTemplate(t);
|
|
||||||
} catch (Throwable x) {
|
} catch (Throwable x) {
|
||||||
app.logEvent("Error updating prototype: " + x);
|
app.logEvent("Error updating prototype: " + x);
|
||||||
}
|
}
|
||||||
} else if (filename.endsWith(scriptExtension)) {
|
} else if (resourceName.endsWith(skinExtension)) {
|
||||||
try {
|
try {
|
||||||
FunctionFile ff = new FunctionFile(file, srcName, proto);
|
proto.addSkinResource(newResources[i]);
|
||||||
|
|
||||||
proto.addFunctionFile(ff);
|
|
||||||
} catch (Throwable x) {
|
} catch (Throwable x) {
|
||||||
app.logEvent("Error updating prototype: " + x);
|
app.logEvent("Error updating prototype: " + x);
|
||||||
}
|
}
|
||||||
} else if (filename.endsWith(actionExtension)) {
|
|
||||||
try {
|
|
||||||
ActionFile af = new ActionFile(file, tmpname, srcName, proto);
|
|
||||||
|
|
||||||
proto.addActionFile(af);
|
|
||||||
} catch (Throwable x) {
|
|
||||||
app.logEvent("Error updating prototype: " + x);
|
|
||||||
}
|
|
||||||
} else if (filename.endsWith(skinExtension)) {
|
|
||||||
SkinFile sf = new SkinFile(file, tmpname, proto);
|
|
||||||
|
|
||||||
proto.addSkinFile(sf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// next go through existing updatables
|
// next go through existing updatables
|
||||||
if (updateSet != null) {
|
if (updatedResources) {
|
||||||
|
/*
|
||||||
for (Iterator i = updateSet.iterator(); i.hasNext();) {
|
for (Iterator i = updateSet.iterator(); i.hasNext();) {
|
||||||
Updatable upd = (Updatable) i.next();
|
Updatable upd = (Updatable) i.next();
|
||||||
|
|
||||||
|
@ -467,21 +360,15 @@ public final class TypeManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark prototype as checked and updated.
|
// mark prototype as checked and updated.
|
||||||
proto.markChecked();
|
proto.markChecked();
|
||||||
proto.markUpdated();
|
proto.markUpdated();
|
||||||
}
|
lastCodeUpdate = proto.lastCodeUpdate();
|
||||||
// end of synchronized (proto)
|
|
||||||
|
} // end of synchronized (proto)
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSourceName(File file) {
|
|
||||||
StringBuffer b = new StringBuffer(app.getName());
|
|
||||||
b.append(":");
|
|
||||||
b.append(file.getParentFile().getName());
|
|
||||||
b.append("/");
|
|
||||||
b.append(file.getName());
|
|
||||||
return b.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,246 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.framework.core;
|
|
||||||
|
|
||||||
import helma.objectmodel.db.DbMapping;
|
|
||||||
import helma.scripting.*;
|
|
||||||
import helma.util.SystemProperties;
|
|
||||||
import helma.util.Updatable;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.zip.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This represents a Zip-File which may contain other Updatables for one or more prototypes.
|
|
||||||
*/
|
|
||||||
public class ZippedAppFile implements Updatable {
|
|
||||||
Application app;
|
|
||||||
File file;
|
|
||||||
long lastmod;
|
|
||||||
// Set of updatables provided by this zip file
|
|
||||||
Set updatables;
|
|
||||||
// Set of prototypes this zip files provides updatables for
|
|
||||||
Set prototypes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ZippedAppFile object.
|
|
||||||
*
|
|
||||||
* @param file ...
|
|
||||||
* @param app ...
|
|
||||||
*/
|
|
||||||
public ZippedAppFile(File file, Application app) {
|
|
||||||
this.app = app;
|
|
||||||
this.file = file;
|
|
||||||
updatables = new HashSet();
|
|
||||||
prototypes = new HashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the type manager whether we need an update. this is the case when
|
|
||||||
* the file has been modified or deleted.
|
|
||||||
*/
|
|
||||||
public boolean needsUpdate() {
|
|
||||||
return !file.exists() || (lastmod != file.lastModified());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public synchronized void update() {
|
|
||||||
if (!file.exists()) {
|
|
||||||
remove();
|
|
||||||
} else {
|
|
||||||
ZipFile zip = null;
|
|
||||||
Set newUpdatables = new HashSet();
|
|
||||||
Set newPrototypes = new HashSet();
|
|
||||||
|
|
||||||
try {
|
|
||||||
lastmod = file.lastModified();
|
|
||||||
|
|
||||||
zip = new ZipFile(file);
|
|
||||||
|
|
||||||
for (Enumeration en = zip.entries(); en.hasMoreElements();) {
|
|
||||||
ZipEntry entry = (ZipEntry) en.nextElement();
|
|
||||||
String ename = entry.getName();
|
|
||||||
StringTokenizer st = new StringTokenizer(ename, "/");
|
|
||||||
|
|
||||||
int tokens = st.countTokens();
|
|
||||||
if (tokens == 1) {
|
|
||||||
String fname = st.nextToken();
|
|
||||||
|
|
||||||
if ("app.properties".equalsIgnoreCase(fname)) {
|
|
||||||
app.props.addProps(file.getName(), zip.getInputStream(entry));
|
|
||||||
} else if ("db.properties".equalsIgnoreCase(fname)) {
|
|
||||||
app.dbProps.addProps(file.getName(), zip.getInputStream(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (tokens == 2) {
|
|
||||||
String dir = st.nextToken();
|
|
||||||
String fname = st.nextToken();
|
|
||||||
|
|
||||||
// System.err.println ("ZIPENTRY: "+ dir +" ~ "+fname);
|
|
||||||
Prototype proto = app.typemgr.getPrototype(dir);
|
|
||||||
|
|
||||||
if (proto == null) {
|
|
||||||
proto = app.typemgr.createPrototype(dir, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fname.endsWith(".hac")) {
|
|
||||||
String name = fname.substring(0, fname.lastIndexOf("."));
|
|
||||||
String srcName = getSourceName(ename);
|
|
||||||
String content = getZipEntryContent(zip, entry);
|
|
||||||
|
|
||||||
// System.err.println ("["+content+"]");
|
|
||||||
ActionFile act = new ActionFile(content, name, srcName,
|
|
||||||
proto);
|
|
||||||
|
|
||||||
proto.addActionFile(act);
|
|
||||||
newUpdatables.add(act);
|
|
||||||
|
|
||||||
} else if (fname.endsWith(".hsp")) {
|
|
||||||
String name = fname.substring(0, fname.lastIndexOf("."));
|
|
||||||
String srcName = getSourceName(ename);
|
|
||||||
String content = getZipEntryContent(zip, entry);
|
|
||||||
|
|
||||||
// System.err.println ("["+content+"]");
|
|
||||||
Template tmp = new Template(content, name, srcName, proto);
|
|
||||||
|
|
||||||
proto.addTemplate(tmp);
|
|
||||||
newUpdatables.add(tmp);
|
|
||||||
|
|
||||||
} else if (fname.endsWith(".skin")) {
|
|
||||||
String name = fname.substring(0, fname.lastIndexOf("."));
|
|
||||||
String content = getZipEntryContent(zip, entry);
|
|
||||||
|
|
||||||
// System.err.println ("["+content+"]");
|
|
||||||
SkinFile skin = new SkinFile(content, name, proto);
|
|
||||||
|
|
||||||
proto.addSkinFile(skin);
|
|
||||||
newUpdatables.add(skin);
|
|
||||||
|
|
||||||
} else if (fname.endsWith(".js")) {
|
|
||||||
String srcName = getSourceName(ename);
|
|
||||||
String content = getZipEntryContent(zip, entry);
|
|
||||||
|
|
||||||
// System.err.println ("["+content+"]");
|
|
||||||
FunctionFile ff = new FunctionFile(content, srcName, proto);
|
|
||||||
|
|
||||||
proto.addFunctionFile(ff);
|
|
||||||
newUpdatables.add(ff);
|
|
||||||
|
|
||||||
} else if ("type.properties".equalsIgnoreCase(fname)) {
|
|
||||||
DbMapping dbmap = proto.getDbMapping();
|
|
||||||
SystemProperties props = dbmap.getProperties();
|
|
||||||
|
|
||||||
props.addProps(file.getName(), zip.getInputStream(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark prototype as updated
|
|
||||||
newPrototypes.add(proto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable x) {
|
|
||||||
System.err.println("Error updating ZipFile: " + x);
|
|
||||||
if (app.debug) {
|
|
||||||
x.printStackTrace();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
// remove updatables that have gone
|
|
||||||
updatables.removeAll(newUpdatables);
|
|
||||||
for (Iterator it = updatables.iterator(); it.hasNext();) {
|
|
||||||
((Updatable) it.next()).remove();
|
|
||||||
}
|
|
||||||
updatables = newUpdatables;
|
|
||||||
|
|
||||||
// mark both old and new prototypes as updated
|
|
||||||
prototypes.addAll(newPrototypes);
|
|
||||||
for (Iterator it = prototypes.iterator(); it.hasNext();) {
|
|
||||||
((Prototype) it.next()).markUpdated();
|
|
||||||
}
|
|
||||||
prototypes = newPrototypes;
|
|
||||||
|
|
||||||
try {
|
|
||||||
zip.close();
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void remove() {
|
|
||||||
// remove updatables from prototypes
|
|
||||||
for (Iterator it = updatables.iterator(); it.hasNext();) {
|
|
||||||
((Updatable) it.next()).remove();
|
|
||||||
}
|
|
||||||
// mark affected prototypes as updated
|
|
||||||
for (Iterator it = prototypes.iterator(); it.hasNext();) {
|
|
||||||
((Prototype) it.next()).markUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove self from type manager
|
|
||||||
app.typemgr.removeZipFile(file.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param zip ...
|
|
||||||
* @param entry ...
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*
|
|
||||||
* @throws IOException ...
|
|
||||||
*/
|
|
||||||
public String getZipEntryContent(ZipFile zip, ZipEntry entry)
|
|
||||||
throws IOException {
|
|
||||||
int size = (int) entry.getSize();
|
|
||||||
char[] c = new char[size];
|
|
||||||
InputStreamReader reader = new InputStreamReader(zip.getInputStream(entry));
|
|
||||||
|
|
||||||
int read = 0;
|
|
||||||
while (read < size) {
|
|
||||||
int r = reader.read(c, read, size-read);
|
|
||||||
if (r == -1)
|
|
||||||
break;
|
|
||||||
read += r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
return file.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private String getSourceName(String entry) {
|
|
||||||
StringBuffer b = new StringBuffer(app.getName());
|
|
||||||
b.append(":");
|
|
||||||
b.append(file.getName());
|
|
||||||
b.append("/");
|
|
||||||
b.append(entry);
|
|
||||||
return b.toString();
|
|
||||||
}
|
|
||||||
}
|
|
122
src/helma/framework/repository/AbstractRepository.java
Normal file
122
src/helma/framework/repository/AbstractRepository.java
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides common methods and fields for the default implementations of the
|
||||||
|
* repository interface
|
||||||
|
*/
|
||||||
|
public abstract class AbstractRepository implements Repository {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent repository this repository is contained in.
|
||||||
|
*/
|
||||||
|
Repository parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds direct child repositories
|
||||||
|
*/
|
||||||
|
Repository[] repositories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds direct resources
|
||||||
|
*/
|
||||||
|
HashMap resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached name for faster access
|
||||||
|
*/
|
||||||
|
String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached short name for faster access
|
||||||
|
*/
|
||||||
|
String shortName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract void update();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getShortName() {
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repository getRootRepository() {
|
||||||
|
if (parent == null) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
return parent.getRootRepository();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource getResource(String name) {
|
||||||
|
update();
|
||||||
|
|
||||||
|
return (Resource) resources.get(getName() + "/" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator getResources() {
|
||||||
|
update();
|
||||||
|
|
||||||
|
return resources.values().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repository[] getRepositories() {
|
||||||
|
update();
|
||||||
|
|
||||||
|
return repositories;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repository getParentRepository() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getAllResources() throws IOException {
|
||||||
|
update();
|
||||||
|
|
||||||
|
ArrayList allResources = new ArrayList();
|
||||||
|
allResources.addAll(resources.values());
|
||||||
|
|
||||||
|
for (int i = 0; i < repositories.length; i++) {
|
||||||
|
allResources.addAll(repositories[i].getAllResources());
|
||||||
|
}
|
||||||
|
|
||||||
|
return allResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
165
src/helma/framework/repository/FileRepository.java
Normal file
165
src/helma/framework/repository/FileRepository.java
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository implementation for directories providing file resources
|
||||||
|
*/
|
||||||
|
public class FileRepository extends AbstractRepository {
|
||||||
|
|
||||||
|
// Directory serving sub-repositories and file resources
|
||||||
|
private File dir;
|
||||||
|
|
||||||
|
private long lastModified = -1;
|
||||||
|
private long lastChecksum = 0;
|
||||||
|
private long lastChecksumTime = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines how long the checksum of the repository will be cached
|
||||||
|
*/
|
||||||
|
private final long cacheTime = 1000L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a FileRepository using the given argument
|
||||||
|
* @param initArgs absolute path to the directory
|
||||||
|
*/
|
||||||
|
public FileRepository(String initArgs) {
|
||||||
|
this(new File(initArgs), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a FileRepository using the given directory as top-level
|
||||||
|
* repository
|
||||||
|
* @param dir directory
|
||||||
|
*/
|
||||||
|
public FileRepository(File dir) {
|
||||||
|
this(dir, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a FileRepository using the given directory and top-level
|
||||||
|
* repository
|
||||||
|
* @param dir directory
|
||||||
|
* @param parent top-level repository
|
||||||
|
*/
|
||||||
|
private FileRepository(File dir, FileRepository parent) {
|
||||||
|
this.dir = dir;
|
||||||
|
if (!dir.exists()) {
|
||||||
|
create();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent == null) {
|
||||||
|
name = shortName = dir.getAbsolutePath();
|
||||||
|
} else {
|
||||||
|
this.parent = parent;
|
||||||
|
shortName = dir.getName();
|
||||||
|
name = parent.getName() + "/" + shortName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
if (dir.exists() && dir.isDirectory()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create() {
|
||||||
|
if (!dir.exists() || !dir.isDirectory()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the repository is to be considered a top-level
|
||||||
|
* repository from a scripting point of view. For example, a zip
|
||||||
|
* file within a file repository is not a root repository from
|
||||||
|
* a physical point of view, but from the scripting point of view it is.
|
||||||
|
*
|
||||||
|
* @return true if the repository is to be considered a top-level script repository
|
||||||
|
*/
|
||||||
|
public boolean isScriptRoot() {
|
||||||
|
return parent == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastModified() {
|
||||||
|
return dir.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getChecksum() throws IOException {
|
||||||
|
// delay checksum check if already checked recently
|
||||||
|
if (System.currentTimeMillis() > lastChecksumTime + cacheTime) {
|
||||||
|
|
||||||
|
update();
|
||||||
|
long checksum = lastModified;
|
||||||
|
|
||||||
|
for (int i = 0; i < repositories.length; i++) {
|
||||||
|
checksum += repositories[i].getChecksum();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastChecksum = checksum;
|
||||||
|
lastChecksumTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastChecksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the content cache of the repository
|
||||||
|
* Gets called from within all methods returning sub-repositories or
|
||||||
|
* resources
|
||||||
|
*/
|
||||||
|
public synchronized void update() {
|
||||||
|
if (dir.lastModified() != lastModified) {
|
||||||
|
lastModified = dir.lastModified();
|
||||||
|
|
||||||
|
File[] list = dir.listFiles();
|
||||||
|
|
||||||
|
ArrayList newRepositories = new ArrayList(list.length);
|
||||||
|
HashMap newResources = new HashMap(list.length);
|
||||||
|
|
||||||
|
for (int i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].isDirectory()) {
|
||||||
|
// a nested directory aka child file repository
|
||||||
|
newRepositories.add(new FileRepository(list[i], this));
|
||||||
|
} else if (list[i].getName().endsWith(".zip")) {
|
||||||
|
// a nested zip repository
|
||||||
|
newRepositories.add(new ZipRepository(list[i], this));
|
||||||
|
} else if (list[i].isFile()) {
|
||||||
|
// a file resource
|
||||||
|
FileResource resource = new FileResource(list[i], this);
|
||||||
|
newResources.put(resource.getName(), resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories = (Repository[])
|
||||||
|
newRepositories.toArray(new Repository[newRepositories.size()]);
|
||||||
|
resources = newResources;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return new StringBuffer("FileRepository[").append(name).append("]").toString();
|
||||||
|
}
|
||||||
|
}
|
106
src/helma/framework/repository/FileResource.java
Normal file
106
src/helma/framework/repository/FileResource.java
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class FileResource implements Resource {
|
||||||
|
|
||||||
|
File file;
|
||||||
|
Repository repository;
|
||||||
|
String name;
|
||||||
|
String shortName;
|
||||||
|
|
||||||
|
public FileResource(File file) {
|
||||||
|
this(file, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FileResource(File file, FileRepository repository) {
|
||||||
|
this.file = file;
|
||||||
|
|
||||||
|
if (repository == null) {
|
||||||
|
name = shortName = file.getName();
|
||||||
|
} else {
|
||||||
|
this.repository = repository;
|
||||||
|
name = repository.getName() + "/" + file.getName();
|
||||||
|
if (name.lastIndexOf(".") != -1) {
|
||||||
|
shortName = file.getName().substring(0, file.getName().lastIndexOf("."));
|
||||||
|
} else {
|
||||||
|
shortName = file.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getShortName() {
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return new FileInputStream(file);
|
||||||
|
} catch (FileNotFoundException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getUrl() {
|
||||||
|
try {
|
||||||
|
return new URL("file:" + file.getAbsolutePath());
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastModified() {
|
||||||
|
return file.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
try {
|
||||||
|
InputStream in = getInputStream();
|
||||||
|
byte[] byteBuffer = new byte[in.available()];
|
||||||
|
|
||||||
|
in.read(byteBuffer);
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
return new String(byteBuffer);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLength() {
|
||||||
|
return file.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repository getRepository() {
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
135
src/helma/framework/repository/Repository.java
Normal file
135
src/helma/framework/repository/Repository.java
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository represents an abstract container of resources (e.g. code, skins, ...).
|
||||||
|
* In addition to resources, repositories may contain other repositories, building
|
||||||
|
* a hierarchical structure.
|
||||||
|
*/
|
||||||
|
public interface Repository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checksum of the repository and all its content. Implementations
|
||||||
|
* should make sure
|
||||||
|
*
|
||||||
|
* @return checksum
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public long getChecksum() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date the repository was last modified.
|
||||||
|
*
|
||||||
|
* @return last modified date
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public long lastModified() throws IOException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific direct resource of the repository
|
||||||
|
*
|
||||||
|
* @param resourceName name of the child resource to return
|
||||||
|
* @return specified child resource
|
||||||
|
*/
|
||||||
|
public Resource getResource(String resourceName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all direct resources
|
||||||
|
*
|
||||||
|
* @return direct resources
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Iterator getResources() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all direct and indirect resources
|
||||||
|
*
|
||||||
|
* @return resources recursive
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public List getAllResources() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this repository's direct child repositories
|
||||||
|
*
|
||||||
|
* @return direct repositories
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Repository[] getRepositories() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the repository actually (or still) exists
|
||||||
|
*
|
||||||
|
* @return true if the repository exists
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public boolean exists() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the repository if does not exist yet
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void create() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the repository is to be considered a top-level
|
||||||
|
* repository from a scripting point of view. For example, a zip
|
||||||
|
* file within a file repository is not a root repository from
|
||||||
|
* a physical point of view, but from the scripting point of view it is.
|
||||||
|
*
|
||||||
|
* @return true if the repository is to be considered a top-level script repository
|
||||||
|
*/
|
||||||
|
public boolean isScriptRoot();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this repository's parent repository.
|
||||||
|
* Returns null if this repository already is the top-level repository
|
||||||
|
*
|
||||||
|
* @return the parent repository
|
||||||
|
*/
|
||||||
|
public Repository getParentRepository();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the top-level repository this repository is contained in
|
||||||
|
*
|
||||||
|
* @return top-level repository
|
||||||
|
*/
|
||||||
|
public Repository getRootRepository();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the repository; this is a full name including all
|
||||||
|
* parent repositories.
|
||||||
|
*
|
||||||
|
* @return full name of the repository
|
||||||
|
*/
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the repository.
|
||||||
|
*
|
||||||
|
* @return name of the repository
|
||||||
|
*/
|
||||||
|
public String getShortName();
|
||||||
|
|
||||||
|
}
|
86
src/helma/framework/repository/Resource.java
Normal file
86
src/helma/framework/repository/Resource.java
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource represents a pointer to some kind of information (code, skin, ...)
|
||||||
|
* from which the content can be fetched
|
||||||
|
*/
|
||||||
|
public interface Resource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date the resource was last modified
|
||||||
|
* @return last modified date
|
||||||
|
*/
|
||||||
|
public long lastModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether this resource actually (still) exists
|
||||||
|
* @return true if the resource exists
|
||||||
|
*/
|
||||||
|
public boolean exists();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the lengh of the resource's content
|
||||||
|
* @return content length
|
||||||
|
*/
|
||||||
|
public long getLength() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an input stream to the content of the resource
|
||||||
|
* @return content input stream
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of the resource
|
||||||
|
* @return content
|
||||||
|
*/
|
||||||
|
public String getContent() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the resource; does not include the name of the
|
||||||
|
* repository the resource was fetched from
|
||||||
|
* @return name of the resource
|
||||||
|
*/
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the short name of the resource which is its name exclusive file
|
||||||
|
* ending if it exists
|
||||||
|
* @return short name of the resource
|
||||||
|
*/
|
||||||
|
public String getShortName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an url to the resource if the repository of this resource is
|
||||||
|
* able to provide urls
|
||||||
|
* @return url to the resource
|
||||||
|
*/
|
||||||
|
public URL getUrl() throws UnsupportedOperationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the repository the resource does belong to
|
||||||
|
* @return upper repository
|
||||||
|
*/
|
||||||
|
public Repository getRepository();
|
||||||
|
|
||||||
|
}
|
118
src/helma/framework/repository/ResourceComparator.java
Normal file
118
src/helma/framework/repository/ResourceComparator.java
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import helma.framework.core.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts resources according to the order of their repositories
|
||||||
|
*/
|
||||||
|
public class ResourceComparator implements Comparator {
|
||||||
|
|
||||||
|
// the application where the top-level repositories can be found
|
||||||
|
protected Application app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructcs a ResourceComparator sorting according to the top-level
|
||||||
|
* repositories of the given application
|
||||||
|
* @param app application that provides the top-level repositories
|
||||||
|
*/
|
||||||
|
public ResourceComparator(Application app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two Repositories, Resources or RepositoryTrackers
|
||||||
|
* @param obj1 Repository, Resource or RepositoryTrackers
|
||||||
|
* @param obj2 Repository, Resource or RepositoryTrackers
|
||||||
|
* @return a negative integer, zero, or a positive integer as the
|
||||||
|
* first argument is less than, equal to, or greater than the
|
||||||
|
* second.
|
||||||
|
* @throws ClassCastException if the arguments' types prevent them from
|
||||||
|
* being compared by this Comparator.
|
||||||
|
*/
|
||||||
|
public int compare(Object obj1, Object obj2) {
|
||||||
|
if (obj1.equals(obj2))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Repository rep1 = getRootRepository(obj1);
|
||||||
|
Repository rep2 = getRootRepository(obj2);
|
||||||
|
|
||||||
|
int pos1 = app.getRepositoryIndex(rep1);
|
||||||
|
int pos2 = app.getRepositoryIndex(rep2);
|
||||||
|
|
||||||
|
if (rep1 == rep2 || (pos1 == -1 && pos2 == -1)) {
|
||||||
|
// Same root repository, but we must not return 0 unless objects are equal
|
||||||
|
// (see JavaDoc on java.util.TreeSet) so we compare full names
|
||||||
|
return getFullName(obj1).compareTo(getFullName(obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos1 - pos2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the comparator is equal to the given comparator
|
||||||
|
* A ResourceComparator is equal to another ResourceComparator if the
|
||||||
|
* applications they belong to are equal
|
||||||
|
*
|
||||||
|
* @param obj comparator
|
||||||
|
* @return true if the given comparator equals
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return (obj instanceof ResourceComparator) &&
|
||||||
|
app == ((ResourceComparator) obj).getApplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the application we're comparing resources for
|
||||||
|
*
|
||||||
|
* @return the application instance
|
||||||
|
*/
|
||||||
|
public Application getApplication() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Repository getRootRepository(Object obj) {
|
||||||
|
if (obj instanceof Resource)
|
||||||
|
return ((Resource) obj).getRepository()
|
||||||
|
.getRootRepository();
|
||||||
|
if (obj instanceof ResourceTracker)
|
||||||
|
return ((ResourceTracker) obj).getResource()
|
||||||
|
.getRepository()
|
||||||
|
.getRootRepository();
|
||||||
|
if (obj instanceof Repository)
|
||||||
|
return ((Repository) obj).getRootRepository();
|
||||||
|
|
||||||
|
// something we can't compare
|
||||||
|
throw new IllegalArgumentException("Can't compare "+obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFullName(Object obj) {
|
||||||
|
if (obj instanceof Resource)
|
||||||
|
return ((Resource) obj).getName();
|
||||||
|
if (obj instanceof ResourceTracker)
|
||||||
|
return ((ResourceTracker) obj).getResource()
|
||||||
|
.getName();
|
||||||
|
if (obj instanceof Repository)
|
||||||
|
return ((Repository) obj).getName();
|
||||||
|
|
||||||
|
// something we can't compare
|
||||||
|
throw new IllegalArgumentException("Can't compare "+obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
46
src/helma/framework/repository/ResourceTracker.java
Normal file
46
src/helma/framework/repository/ResourceTracker.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class that allows Resource consumers to track changes
|
||||||
|
* on resources.
|
||||||
|
*/
|
||||||
|
public class ResourceTracker {
|
||||||
|
|
||||||
|
Resource resource;
|
||||||
|
long lastModified;
|
||||||
|
|
||||||
|
public ResourceTracker(Resource resource) {
|
||||||
|
this.resource = resource;
|
||||||
|
markClean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasChanged() throws IOException {
|
||||||
|
return lastModified != resource.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markClean() {
|
||||||
|
lastModified = resource.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource getResource() {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
}
|
187
src/helma/framework/repository/ZipRepository.java
Normal file
187
src/helma/framework/repository/ZipRepository.java
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import helma.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public final class ZipRepository extends AbstractRepository {
|
||||||
|
|
||||||
|
// zip file serving sub-repositories and zip file resources
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
// the nested directory depth of this repository
|
||||||
|
private int depth;
|
||||||
|
|
||||||
|
private long lastModified = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ZipRespository using the given argument
|
||||||
|
* @param initArgs absolute path to the zip file
|
||||||
|
*/
|
||||||
|
public ZipRepository(String initArgs) {
|
||||||
|
this(new File(initArgs), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ZipRepository using the given zip file as top-level
|
||||||
|
* repository
|
||||||
|
* @param file a zip file
|
||||||
|
*/
|
||||||
|
protected ZipRepository(File file, Repository parent) {
|
||||||
|
this(file, parent, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ZipRepository using the zip entry belonging to the given
|
||||||
|
* zip file and top-level repository
|
||||||
|
* @param file a zip file
|
||||||
|
* @param zipentry zip entry
|
||||||
|
* @param parent repository
|
||||||
|
*/
|
||||||
|
private ZipRepository(File file, Repository parent, ZipEntry zipentry) {
|
||||||
|
this.file = file;
|
||||||
|
this.parent = parent;
|
||||||
|
|
||||||
|
if (zipentry == null) {
|
||||||
|
name = shortName = file.getName();
|
||||||
|
depth = 0;
|
||||||
|
} else {
|
||||||
|
String[] entrypath = StringUtils.split(zipentry.getName(), "/");
|
||||||
|
depth = entrypath.length;
|
||||||
|
shortName = entrypath[depth - 1];
|
||||||
|
name = new StringBuffer(parent.getName())
|
||||||
|
.append('/').append(shortName).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a java.util.zip.ZipFile for this repository. It is the caller's
|
||||||
|
* responsability to call close() in it when it is no longer needed.
|
||||||
|
* @return a ZipFile for reading
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected ZipFile getZipFile() throws IOException {
|
||||||
|
return new ZipFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void update() {
|
||||||
|
if (file.lastModified() != lastModified) {
|
||||||
|
lastModified = file.lastModified();
|
||||||
|
ZipFile zipfile = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
zipfile = getZipFile();
|
||||||
|
Enumeration enum = zipfile.entries();
|
||||||
|
ArrayList newRepositories = new ArrayList();
|
||||||
|
HashMap newResources = new HashMap();
|
||||||
|
|
||||||
|
while (enum.hasMoreElements()) {
|
||||||
|
ZipEntry entry = (ZipEntry) enum.nextElement();
|
||||||
|
String entryname = entry.getName();
|
||||||
|
String[] entrypath = StringUtils.split(entryname, "/");
|
||||||
|
|
||||||
|
// create new repositories and resources for all entries with a
|
||||||
|
// path depth of this.depth + 1
|
||||||
|
if (entrypath.length == depth + 1) {
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
newRepositories.add(new ZipRepository(file, this, entry));
|
||||||
|
} else {
|
||||||
|
ZipResource resource = new ZipResource(file, entry, this);
|
||||||
|
newResources.put(resource.getName(), resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories = (Repository[])
|
||||||
|
newRepositories.toArray(new Repository[newRepositories.size()]);
|
||||||
|
resources = newResources;
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
repositories = new Repository[0];
|
||||||
|
if (resources == null) {
|
||||||
|
resources = new HashMap();
|
||||||
|
} else {
|
||||||
|
resources.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
// unlocks the zip file in the underlying filesystem
|
||||||
|
zipfile.close();
|
||||||
|
} catch (Exception ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getChecksum() {
|
||||||
|
return file.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
ZipFile zipfile = null;
|
||||||
|
try {
|
||||||
|
/* a ZipFile needs to be created to see if the zip file actually
|
||||||
|
exists; this is not cached to provide blocking the zip file in
|
||||||
|
the underlying filesystem */
|
||||||
|
zipfile = getZipFile();
|
||||||
|
return true;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
// unlocks the zip file in the underlying filesystem
|
||||||
|
zipfile.close();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create() {
|
||||||
|
// we do not create zip files as it makes no sense
|
||||||
|
throw new UnsupportedOperationException("create() not implemented for ZipRepository");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the repository is to be considered a top-level
|
||||||
|
* repository from a scripting point of view. For example, a zip
|
||||||
|
* file within a file repository is not a root repository from
|
||||||
|
* a physical point of view, but from the scripting point of view it is.
|
||||||
|
*
|
||||||
|
* @return true if the repository is to be considered a top-level script repository
|
||||||
|
*/
|
||||||
|
public boolean isScriptRoot() {
|
||||||
|
return depth == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastModified() {
|
||||||
|
return file.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return new StringBuffer("ZipRepository[").append(name).append("]").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
139
src/helma/framework/repository/ZipResource.java
Normal file
139
src/helma/framework/repository/ZipResource.java
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public final class ZipResource implements Resource {
|
||||||
|
|
||||||
|
private ZipEntry zipentry;
|
||||||
|
private File zipfile;
|
||||||
|
private ZipRepository repository;
|
||||||
|
private String name;
|
||||||
|
private String shortName;
|
||||||
|
|
||||||
|
protected ZipResource(File zipfile, ZipEntry zipentry, ZipRepository repository) {
|
||||||
|
this.zipentry = zipentry;
|
||||||
|
this.zipfile = zipfile;
|
||||||
|
this.repository = repository;
|
||||||
|
|
||||||
|
String entryname = zipentry.getName();
|
||||||
|
int lastDot = entryname.lastIndexOf('.');
|
||||||
|
int lastSlash = entryname.lastIndexOf('/');
|
||||||
|
|
||||||
|
if (lastDot != -1 && lastDot > lastSlash) {
|
||||||
|
shortName = entryname.substring(lastSlash + 1, lastDot);
|
||||||
|
} else {
|
||||||
|
shortName = entryname.substring(lastSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer buf = new StringBuffer(repository.getName())
|
||||||
|
.append('/').append(shortName);
|
||||||
|
if (lastDot != -1 && lastDot > lastSlash) {
|
||||||
|
name = buf.append(entryname.substring(lastDot)).toString();
|
||||||
|
} else {
|
||||||
|
name = buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastModified() {
|
||||||
|
return zipfile.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
ZipFile zipfile = null;
|
||||||
|
try {
|
||||||
|
zipfile = repository.getZipFile();
|
||||||
|
int size = (int) zipentry.getSize();
|
||||||
|
byte[] buf = new byte[size];
|
||||||
|
InputStream in = zipfile.getInputStream(zipentry);
|
||||||
|
int read = 0;
|
||||||
|
while (read < size) {
|
||||||
|
int r = in.read(buf, read, size-read);
|
||||||
|
if (r == -1)
|
||||||
|
break;
|
||||||
|
read += r;
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
return new ByteArrayInputStream(buf);
|
||||||
|
} finally {
|
||||||
|
zipfile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists() {
|
||||||
|
ZipFile zipfile = null;
|
||||||
|
try {
|
||||||
|
zipfile = repository.getZipFile();
|
||||||
|
return (zipfile.getEntry(zipentry.getName()) != null);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
zipfile.close();
|
||||||
|
} catch (Exception ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() throws IOException {
|
||||||
|
ZipFile zipfile = null;
|
||||||
|
try {
|
||||||
|
zipfile = repository.getZipFile();
|
||||||
|
InputStreamReader in = new InputStreamReader(zipfile.getInputStream(zipentry));
|
||||||
|
int size = (int) zipentry.getSize();
|
||||||
|
char[] buf = new char[size];
|
||||||
|
int read = 0;
|
||||||
|
while (read < size) {
|
||||||
|
int r = in.read(buf, read, size-read);
|
||||||
|
if (r == -1)
|
||||||
|
break;
|
||||||
|
read += r;
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
return new String(buf);
|
||||||
|
} finally {
|
||||||
|
zipfile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getShortName() {
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getUrl() {
|
||||||
|
throw new UnsupportedOperationException("getUrl() not implemented for ZipResource");
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLength() {
|
||||||
|
return zipentry.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repository getRepository() {
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,9 @@
|
||||||
package helma.main;
|
package helma.main;
|
||||||
|
|
||||||
import helma.framework.core.*;
|
import helma.framework.core.*;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
|
import helma.framework.repository.FileRepository;
|
||||||
import helma.util.StringUtils;
|
import helma.util.StringUtils;
|
||||||
import helma.util.SystemProperties;
|
|
||||||
import org.apache.xmlrpc.XmlRpcHandler;
|
import org.apache.xmlrpc.XmlRpcHandler;
|
||||||
import org.mortbay.http.*;
|
import org.mortbay.http.*;
|
||||||
import org.mortbay.http.handler.*;
|
import org.mortbay.http.handler.*;
|
||||||
|
@ -26,6 +27,7 @@ import org.mortbay.jetty.servlet.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.rmi.*;
|
import java.rmi.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import helma.util.ResourceProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for starting and stopping Helma applications.
|
* This class is responsible for starting and stopping Helma applications.
|
||||||
|
@ -35,7 +37,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
private Hashtable applications;
|
private Hashtable applications;
|
||||||
private Hashtable xmlrpcHandlers;
|
private Hashtable xmlrpcHandlers;
|
||||||
private int rmiPort;
|
private int rmiPort;
|
||||||
private SystemProperties props;
|
private ResourceProperties props;
|
||||||
private Server server;
|
private Server server;
|
||||||
private long lastModified;
|
private long lastModified;
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
* @param server the server instance
|
* @param server the server instance
|
||||||
* @param port The RMI port we're binding to
|
* @param port The RMI port we're binding to
|
||||||
*/
|
*/
|
||||||
public ApplicationManager(SystemProperties props,
|
public ApplicationManager(ResourceProperties props,
|
||||||
Server server, int port) {
|
Server server, int port) {
|
||||||
this.props = props;
|
this.props = props;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
@ -282,6 +284,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
String uploadLimit;
|
String uploadLimit;
|
||||||
String debug;
|
String debug;
|
||||||
boolean encode;
|
boolean encode;
|
||||||
|
Repository[] repositories;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AppDescriptor from the properties.
|
* Creates an AppDescriptor from the properties.
|
||||||
|
@ -313,6 +316,60 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
appDir = (appDirName == null) ? null : new File(appDirName);
|
appDir = (appDirName == null) ? null : new File(appDirName);
|
||||||
String dbDirName = props.getProperty(name + ".dbdir");
|
String dbDirName = props.getProperty(name + ".dbdir");
|
||||||
dbDir = (dbDirName == null) ? null : new File(dbDirName);
|
dbDir = (dbDirName == null) ? null : new File(dbDirName);
|
||||||
|
|
||||||
|
// read and configure app repositories
|
||||||
|
ArrayList repositoryList = new ArrayList();
|
||||||
|
for (int i = 0; true; i++) {
|
||||||
|
Class[] parameters = { String.class };
|
||||||
|
|
||||||
|
String[] repositoryArgs = { props.getProperty(name + ".repository." + i) };
|
||||||
|
|
||||||
|
if (repositoryArgs[0] != null) {
|
||||||
|
// lookup repository implementation
|
||||||
|
String repositoryImpl = props.getProperty(name + ".repository." + i +
|
||||||
|
".implementation");
|
||||||
|
if (repositoryImpl == null) {
|
||||||
|
// implementation not set manually, have to guess it
|
||||||
|
if (repositoryArgs[0].endsWith(".zip")) {
|
||||||
|
repositoryImpl = "helma.framework.repository.ZipRepository";
|
||||||
|
} else {
|
||||||
|
repositoryImpl = "helma.framework.repository.FileRepository";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repository newRepository = null;
|
||||||
|
try {
|
||||||
|
newRepository = (Repository) Class.forName(repositoryImpl)
|
||||||
|
.getConstructor(parameters).newInstance(repositoryArgs);
|
||||||
|
repositoryList.add(newRepository);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
System.out.println("Adding repository " + repositoryArgs + " failed. " +
|
||||||
|
"Will not use that repository. Check your initArgs!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no more repositories to add
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repositoryList.size() > 0) {
|
||||||
|
repositories = new Repository[repositoryList.size()];
|
||||||
|
repositoryList.toArray(repositories);
|
||||||
|
} else {
|
||||||
|
repositories = new Repository[1];
|
||||||
|
if (appDir != null) {
|
||||||
|
repositories[0] = new FileRepository(appDir);
|
||||||
|
} else {
|
||||||
|
repositories[0] = new FileRepository(new File(server.getAppsHome(), appName));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!repositories[0].exists()) {
|
||||||
|
repositories[0].create();
|
||||||
|
}
|
||||||
|
} catch (Exception swallow) {
|
||||||
|
// couldn't create repository
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,7 +378,7 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// create the application instance
|
// create the application instance
|
||||||
app = new Application(appName, server, appDir, dbDir);
|
app = new Application(appName, server, repositories, dbDir);
|
||||||
|
|
||||||
// register ourselves
|
// register ourselves
|
||||||
descriptors.put(appName, this);
|
descriptors.put(appName, this);
|
||||||
|
|
|
@ -18,6 +18,7 @@ package helma.main;
|
||||||
|
|
||||||
import helma.extensions.HelmaExtension;
|
import helma.extensions.HelmaExtension;
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
|
import helma.framework.repository.FileResource;
|
||||||
import helma.framework.core.*;
|
import helma.framework.core.*;
|
||||||
import helma.objectmodel.db.DbSource;
|
import helma.objectmodel.db.DbSource;
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
|
@ -31,10 +32,10 @@ import org.mortbay.util.LogSink;
|
||||||
import org.mortbay.util.MultiException;
|
import org.mortbay.util.MultiException;
|
||||||
import org.mortbay.util.Frame;
|
import org.mortbay.util.Frame;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
|
||||||
import java.rmi.registry.*;
|
import java.rmi.registry.*;
|
||||||
import java.rmi.server.*;
|
import java.rmi.server.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import helma.util.ResourceProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helma server main class.
|
* Helma server main class.
|
||||||
|
@ -50,9 +51,9 @@ public class Server implements IPathElement, Runnable {
|
||||||
protected File hopHome;
|
protected File hopHome;
|
||||||
|
|
||||||
// server-wide properties
|
// server-wide properties
|
||||||
SystemProperties appsProps;
|
ResourceProperties appsProps;
|
||||||
SystemProperties dbProps;
|
ResourceProperties dbProps;
|
||||||
SystemProperties sysProps;
|
ResourceProperties sysProps;
|
||||||
|
|
||||||
// our logger
|
// our logger
|
||||||
private Log logger;
|
private Log logger;
|
||||||
|
@ -105,7 +106,8 @@ public class Server implements IPathElement, Runnable {
|
||||||
hopHome = config.homeDir;
|
hopHome = config.homeDir;
|
||||||
|
|
||||||
// create system properties
|
// create system properties
|
||||||
sysProps = new SystemProperties(config.propFile.getAbsolutePath());
|
sysProps = new ResourceProperties();
|
||||||
|
sysProps.addResource(new FileResource(config.propFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,7 +186,8 @@ public class Server implements IPathElement, Runnable {
|
||||||
guessConfig(config);
|
guessConfig(config);
|
||||||
|
|
||||||
// create system properties
|
// create system properties
|
||||||
SystemProperties sysProps = new SystemProperties(config.propFile.getAbsolutePath());
|
ResourceProperties sysProps = new ResourceProperties();
|
||||||
|
sysProps.addResource(new FileResource(config.propFile));
|
||||||
|
|
||||||
// check if there's a property setting for those ports not specified via command line
|
// check if there's a property setting for those ports not specified via command line
|
||||||
if ((config.websrvPort == null) && (sysProps.getProperty("webPort") != null)) {
|
if ((config.websrvPort == null) && (sysProps.getProperty("webPort") != null)) {
|
||||||
|
@ -283,7 +286,8 @@ public class Server implements IPathElement, Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create system properties
|
// create system properties
|
||||||
SystemProperties sysProps = new SystemProperties(config.propFile.getAbsolutePath());
|
ResourceProperties sysProps = new ResourceProperties();
|
||||||
|
sysProps.addResource(new FileResource(config.propFile));
|
||||||
|
|
||||||
// try to get hopHome from property file
|
// try to get hopHome from property file
|
||||||
if (config.homeDir == null && sysProps.getProperty("hophome") != null) {
|
if (config.homeDir == null && sysProps.getProperty("hophome") != null) {
|
||||||
|
@ -442,18 +446,21 @@ public class Server implements IPathElement, Runnable {
|
||||||
|
|
||||||
|
|
||||||
// read db.properties file in helma home directory
|
// read db.properties file in helma home directory
|
||||||
File helper = new File(hopHome, "db.properties");
|
dbProps = new ResourceProperties();
|
||||||
dbProps = new SystemProperties(helper.getAbsolutePath());
|
dbProps.addResource(new FileResource(new File(hopHome, "db.properties")));
|
||||||
DbSource.setDefaultProps(dbProps);
|
DbSource.setDefaultProps(dbProps);
|
||||||
|
|
||||||
// read apps.properties file
|
// read apps.properties file
|
||||||
String appsPropfile = sysProps.getProperty("appsPropFile");
|
String appsPropfile = sysProps.getProperty("appsPropFile");
|
||||||
|
File file;
|
||||||
if ((appsPropfile != null) && !"".equals(appsPropfile.trim())) {
|
if ((appsPropfile != null) && !"".equals(appsPropfile.trim())) {
|
||||||
helper = new File(appsPropfile);
|
file = new File(appsPropfile);
|
||||||
|
appsProps = new ResourceProperties();
|
||||||
} else {
|
} else {
|
||||||
helper = new File(hopHome, "apps.properties");
|
file = new File(hopHome, "apps.properties");
|
||||||
|
appsProps = new ResourceProperties();
|
||||||
}
|
}
|
||||||
appsProps = new SystemProperties(helper.getAbsolutePath());
|
appsProps.addResource(new FileResource(file));
|
||||||
|
|
||||||
paranoid = "true".equalsIgnoreCase(sysProps.getProperty("paranoid"));
|
paranoid = "true".equalsIgnoreCase(sysProps.getProperty("paranoid"));
|
||||||
|
|
||||||
|
@ -804,7 +811,7 @@ public class Server implements IPathElement, Runnable {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public SystemProperties getProperties() {
|
public ResourceProperties getProperties() {
|
||||||
return sysProps;
|
return sysProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +820,7 @@ public class Server implements IPathElement, Runnable {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public SystemProperties getDbProperties() {
|
public ResourceProperties getDbProperties() {
|
||||||
return dbProps;
|
return dbProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@ package helma.objectmodel.db;
|
||||||
|
|
||||||
import helma.framework.core.Application;
|
import helma.framework.core.Application;
|
||||||
import helma.framework.core.Prototype;
|
import helma.framework.core.Prototype;
|
||||||
import helma.util.SystemProperties;
|
import helma.util.ResourceProperties;
|
||||||
import helma.util.Updatable;
|
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -29,7 +28,7 @@ import java.util.*;
|
||||||
* relational database table. Basically it consists of a set of JavaScript property-to-
|
* relational database table. Basically it consists of a set of JavaScript property-to-
|
||||||
* Database row bindings which are represented by instances of the Relation class.
|
* Database row bindings which are represented by instances of the Relation class.
|
||||||
*/
|
*/
|
||||||
public final class DbMapping implements Updatable {
|
public final class DbMapping {
|
||||||
// DbMappings belong to an application
|
// DbMappings belong to an application
|
||||||
protected Application app;
|
protected Application app;
|
||||||
|
|
||||||
|
@ -37,7 +36,7 @@ public final class DbMapping implements Updatable {
|
||||||
private String typename;
|
private String typename;
|
||||||
|
|
||||||
// properties from where the mapping is read
|
// properties from where the mapping is read
|
||||||
private SystemProperties props;
|
private ResourceProperties props;
|
||||||
|
|
||||||
// name of data dbSource to which this mapping writes
|
// name of data dbSource to which this mapping writes
|
||||||
private DbSource dbSource;
|
private DbSource dbSource;
|
||||||
|
@ -131,7 +130,7 @@ public final class DbMapping implements Updatable {
|
||||||
/**
|
/**
|
||||||
* Create a DbMapping from a type.properties property file
|
* Create a DbMapping from a type.properties property file
|
||||||
*/
|
*/
|
||||||
public DbMapping(Application app, String typename, SystemProperties props) {
|
public DbMapping(Application app, String typename, ResourceProperties props) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
// create a unique instance of the string. This is useful so
|
// create a unique instance of the string. This is useful so
|
||||||
// we can compare types just by using == instead of equals.
|
// we can compare types just by using == instead of equals.
|
||||||
|
@ -1349,7 +1348,7 @@ public final class DbMapping implements Updatable {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public SystemProperties getProperties() {
|
public ResourceProperties getProperties() {
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package helma.objectmodel.db;
|
package helma.objectmodel.db;
|
||||||
|
|
||||||
import helma.util.SystemProperties;
|
import helma.util.ResourceProperties;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
|
@ -28,10 +28,10 @@ import java.util.Properties;
|
||||||
* This class describes a releational data source (URL, driver, user and password).
|
* This class describes a releational data source (URL, driver, user and password).
|
||||||
*/
|
*/
|
||||||
public class DbSource {
|
public class DbSource {
|
||||||
private static SystemProperties defaultProps = null;
|
private static ResourceProperties defaultProps = null;
|
||||||
private Properties conProps;
|
private Properties conProps;
|
||||||
private String name;
|
private String name;
|
||||||
private SystemProperties props;
|
private ResourceProperties props;
|
||||||
protected String url;
|
protected String url;
|
||||||
private String driver;
|
private String driver;
|
||||||
private boolean isOracle;
|
private boolean isOracle;
|
||||||
|
@ -45,7 +45,7 @@ public class DbSource {
|
||||||
*
|
*
|
||||||
* @throws ClassNotFoundException ...
|
* @throws ClassNotFoundException ...
|
||||||
*/
|
*/
|
||||||
public DbSource(String name, SystemProperties props)
|
public DbSource(String name, ResourceProperties props)
|
||||||
throws ClassNotFoundException {
|
throws ClassNotFoundException {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.props = props;
|
this.props = props;
|
||||||
|
@ -158,7 +158,7 @@ public class DbSource {
|
||||||
*
|
*
|
||||||
* @param props ...
|
* @param props ...
|
||||||
*/
|
*/
|
||||||
public static void setDefaultProps(SystemProperties props) {
|
public static void setDefaultProps(ResourceProperties props) {
|
||||||
defaultProps = props;
|
defaultProps = props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.scripting;
|
|
||||||
|
|
||||||
import helma.framework.core.*;
|
|
||||||
import helma.util.Updatable;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An ActionFile is a file containing function code that is exposed as a URI
|
|
||||||
* of objects of this class/type. It is
|
|
||||||
* usually represented by a file with extension .hac (hop action file)
|
|
||||||
* that contains the raw body of the function.
|
|
||||||
*/
|
|
||||||
public class ActionFile implements Updatable {
|
|
||||||
String name;
|
|
||||||
String sourceName;
|
|
||||||
Prototype prototype;
|
|
||||||
File file;
|
|
||||||
String content;
|
|
||||||
long lastmod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ActionFile object.
|
|
||||||
*
|
|
||||||
* @param file ...
|
|
||||||
* @param name ...
|
|
||||||
* @param sourceName ...
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public ActionFile(File file, String name, String sourceName, Prototype proto) {
|
|
||||||
this.prototype = proto;
|
|
||||||
this.name = name;
|
|
||||||
this.sourceName = sourceName;
|
|
||||||
this.file = file;
|
|
||||||
this.lastmod = file.lastModified();
|
|
||||||
this.content = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ActionFile object.
|
|
||||||
*
|
|
||||||
* @param content ...
|
|
||||||
* @param name ...
|
|
||||||
* @param sourceName ...
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public ActionFile(String content, String name, String sourceName, Prototype proto) {
|
|
||||||
this.prototype = proto;
|
|
||||||
this.name = name;
|
|
||||||
this.sourceName = sourceName;
|
|
||||||
this.file = null;
|
|
||||||
this.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the type manager whether we need an update. this is the case when
|
|
||||||
* the file has been modified or deleted.
|
|
||||||
*/
|
|
||||||
public boolean needsUpdate() {
|
|
||||||
return lastmod != file.lastModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void update() {
|
|
||||||
if (!file.exists()) {
|
|
||||||
// remove functions declared by this from all object prototypes
|
|
||||||
remove();
|
|
||||||
} else {
|
|
||||||
lastmod = file.lastModified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void remove() {
|
|
||||||
prototype.removeActionFile(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public File getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getSourceName() {
|
|
||||||
return sourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*
|
|
||||||
* @throws FileNotFoundException ...
|
|
||||||
*/
|
|
||||||
public Reader getReader() throws FileNotFoundException {
|
|
||||||
if (content != null) {
|
|
||||||
return new StringReader(content);
|
|
||||||
} else if (file.length() == 0) {
|
|
||||||
return new StringReader(";");
|
|
||||||
} else {
|
|
||||||
return new FileReader(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getContent() {
|
|
||||||
if (content != null) {
|
|
||||||
return content;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
FileReader reader = new FileReader(file);
|
|
||||||
char[] cbuf = new char[(int) file.length()];
|
|
||||||
|
|
||||||
reader.read(cbuf);
|
|
||||||
reader.close();
|
|
||||||
|
|
||||||
return new String(cbuf);
|
|
||||||
} catch (Exception filex) {
|
|
||||||
prototype.getApplication().logEvent("Error reading " + this + ": " + filex);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getFunctionName() {
|
|
||||||
return name + "_action";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public Prototype getPrototype() {
|
|
||||||
return prototype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
return "ActionFile[" + sourceName + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to produce hash code depending on source name
|
|
||||||
*
|
|
||||||
* @return a hash code value for this object.
|
|
||||||
*/
|
|
||||||
public int hashCode() {
|
|
||||||
return sourceName.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to equal other ActionFile with the same source name
|
|
||||||
*
|
|
||||||
* @param obj the object to compare to
|
|
||||||
* @return true if obj is a ActionFile with the same source name
|
|
||||||
*/
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return (obj instanceof ActionFile) &&
|
|
||||||
sourceName.equals(((ActionFile) obj).getSourceName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,146 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.scripting;
|
|
||||||
|
|
||||||
import helma.framework.core.*;
|
|
||||||
import helma.util.Updatable;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This represents a File containing script functions for a given class/prototype.
|
|
||||||
*/
|
|
||||||
public class FunctionFile implements Updatable {
|
|
||||||
Prototype prototype;
|
|
||||||
File file;
|
|
||||||
String sourceName;
|
|
||||||
String content;
|
|
||||||
long lastmod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new FunctionFile object.
|
|
||||||
*
|
|
||||||
* @param file ...
|
|
||||||
* @param sourceName ...
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public FunctionFile(File file, String sourceName, Prototype proto) {
|
|
||||||
this.prototype = proto;
|
|
||||||
this.sourceName = sourceName;
|
|
||||||
this.file = file;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a function file without a file, passing the code directly. This is used for
|
|
||||||
* files contained in zipped applications. The whole update mechanism is bypassed
|
|
||||||
* by immediately parsing the code.
|
|
||||||
*
|
|
||||||
* @param body ...
|
|
||||||
* @param sourceName ...
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public FunctionFile(String body, String sourceName, Prototype proto) {
|
|
||||||
this.prototype = proto;
|
|
||||||
this.sourceName = sourceName;
|
|
||||||
this.file = null;
|
|
||||||
this.content = body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the type manager whether we need an update. this is the case when
|
|
||||||
* the file has been modified or deleted.
|
|
||||||
*/
|
|
||||||
public boolean needsUpdate() {
|
|
||||||
return (file != null) && (lastmod != file.lastModified());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void update() {
|
|
||||||
if (file != null) {
|
|
||||||
if (!file.exists()) {
|
|
||||||
remove();
|
|
||||||
} else {
|
|
||||||
lastmod = file.lastModified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public File getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getSourceName() {
|
|
||||||
return sourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void remove() {
|
|
||||||
prototype.removeFunctionFile(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
return sourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to produce hash code depending on source name
|
|
||||||
*
|
|
||||||
* @return a hash code value for this object.
|
|
||||||
*/
|
|
||||||
public int hashCode() {
|
|
||||||
return sourceName.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to equal other FunctionFiles with the same source name
|
|
||||||
*
|
|
||||||
* @param obj the object to compare to
|
|
||||||
* @return true if obj is a FunctionFile with the same source name
|
|
||||||
*/
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return (obj instanceof FunctionFile) &&
|
|
||||||
sourceName.equals(((FunctionFile) obj).getSourceName());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,259 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.scripting;
|
|
||||||
|
|
||||||
import helma.framework.core.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This represents a Helma template, i.e. a file with the extension .hsp
|
|
||||||
* (Helma server page) that contains both parts that are to be evaluated
|
|
||||||
* as EcmaScript and parts that are to be delivered to the client as-is.
|
|
||||||
* Internally, templates are regular functions.
|
|
||||||
* Helma templates are callable via URL, but this is just a leftover from the
|
|
||||||
* days when there were no .hac (action) files. The recommended way
|
|
||||||
* now is to have a .hac file with all the logic which in turn calls one or more
|
|
||||||
* template files to do the formatting.
|
|
||||||
*/
|
|
||||||
public class Template extends ActionFile {
|
|
||||||
/**
|
|
||||||
* Creates a new Template object.
|
|
||||||
*
|
|
||||||
* @param file ...
|
|
||||||
* @param name ...
|
|
||||||
* @param sourceName
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public Template(File file, String name, String sourceName, Prototype proto) {
|
|
||||||
super(file, name, sourceName, proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Template object.
|
|
||||||
*
|
|
||||||
* @param content ...
|
|
||||||
* @param name ...
|
|
||||||
* @param sourceName ...
|
|
||||||
* @param proto ...
|
|
||||||
*/
|
|
||||||
public Template(String content, String name, String sourceName, Prototype proto) {
|
|
||||||
super(content, name, sourceName, proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getFunctionName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public Reader getReader() {
|
|
||||||
return new StringReader(getContent());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public String getContent() {
|
|
||||||
Vector partBuffer = new Vector();
|
|
||||||
String cstring = super.getContent();
|
|
||||||
char[] cnt = cstring.toCharArray();
|
|
||||||
int l = cnt.length;
|
|
||||||
|
|
||||||
if (l == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// if last charackter is whitespace, swallow it. this is necessary for some inner templates to look ok.
|
|
||||||
if (Character.isWhitespace(cnt[l - 1])) {
|
|
||||||
l -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lastIdx = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < (l - 1); i++) {
|
|
||||||
if ((cnt[i] == '<') && (cnt[i + 1] == '%')) {
|
|
||||||
int j = i + 2;
|
|
||||||
|
|
||||||
while ((j < (l - 1)) && ((cnt[j] != '%') || (cnt[j + 1] != '>'))) {
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j > (i + 2)) {
|
|
||||||
if ((i - lastIdx) > 0) {
|
|
||||||
partBuffer.addElement(new Part(this,
|
|
||||||
new String(cnt, lastIdx,
|
|
||||||
i - lastIdx), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
String script = new String(cnt, i + 2, (j - i) - 2);
|
|
||||||
|
|
||||||
partBuffer.addElement(new Part(this, script, false));
|
|
||||||
lastIdx = j + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = j + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastIdx < l) {
|
|
||||||
partBuffer.addElement(new Part(this, new String(cnt, lastIdx, l - lastIdx),
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuffer templateBody = new StringBuffer();
|
|
||||||
int nparts = partBuffer.size();
|
|
||||||
|
|
||||||
for (int k = 0; k < nparts; k++) {
|
|
||||||
Part nextPart = (Part) partBuffer.elementAt(k);
|
|
||||||
|
|
||||||
if (nextPart.isStatic || nextPart.content.trim().startsWith("=")) {
|
|
||||||
// check for <%= ... %> statements
|
|
||||||
if (!nextPart.isStatic) {
|
|
||||||
nextPart.content = nextPart.content.trim().substring(1).trim();
|
|
||||||
|
|
||||||
// cut trailing ";"
|
|
||||||
while (nextPart.content.endsWith(";"))
|
|
||||||
nextPart.content = nextPart.content.substring(0,
|
|
||||||
nextPart.content.length() -
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringTokenizer st = new StringTokenizer(nextPart.content, "\r\n", true);
|
|
||||||
String nextLine = st.hasMoreTokens() ? st.nextToken() : null;
|
|
||||||
|
|
||||||
// count newLines we "swallow", see explanation below
|
|
||||||
int newLineCount = 0;
|
|
||||||
|
|
||||||
templateBody.append("res.write (");
|
|
||||||
|
|
||||||
if (nextPart.isStatic) {
|
|
||||||
templateBody.append("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (nextLine != null) {
|
|
||||||
if ("\n".equals(nextLine)) {
|
|
||||||
// append a CRLF
|
|
||||||
newLineCount++;
|
|
||||||
templateBody.append("\\r\\n");
|
|
||||||
} else if (!"\r".equals(nextLine)) {
|
|
||||||
try {
|
|
||||||
StringReader lineReader = new StringReader(nextLine);
|
|
||||||
int c = lineReader.read();
|
|
||||||
|
|
||||||
while (c > -1) {
|
|
||||||
if (nextPart.isStatic &&
|
|
||||||
(((char) c == '"') || ((char) c == '\\'))) {
|
|
||||||
templateBody.append('\\');
|
|
||||||
}
|
|
||||||
|
|
||||||
templateBody.append((char) c);
|
|
||||||
c = lineReader.read();
|
|
||||||
}
|
|
||||||
} catch (IOException srx) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nextLine = st.hasMoreTokens() ? st.nextToken() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextPart.isStatic) {
|
|
||||||
templateBody.append("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
templateBody.append("); ");
|
|
||||||
|
|
||||||
// append the number of lines we have "swallowed" into
|
|
||||||
// one write statement, so error messages will *approximately*
|
|
||||||
// give correct line numbers.
|
|
||||||
for (int i = 0; i < newLineCount; i++) {
|
|
||||||
templateBody.append("\r\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
templateBody.append(nextPart.content);
|
|
||||||
|
|
||||||
if (!nextPart.content.trim().endsWith(";")) {
|
|
||||||
templateBody.append(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// templateBody.append ("\r\nreturn null;\r\n");
|
|
||||||
return templateBody.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void remove() {
|
|
||||||
prototype.removeTemplate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Part {
|
|
||||||
String content;
|
|
||||||
Template parent;
|
|
||||||
boolean isPart;
|
|
||||||
boolean isStatic;
|
|
||||||
|
|
||||||
public Part(Template parent, String content, boolean isStatic) {
|
|
||||||
isPart = false;
|
|
||||||
this.parent = parent;
|
|
||||||
this.content = content;
|
|
||||||
this.isStatic = isStatic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return isStatic ? null : content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "Template.Part [" + content + "," + isStatic + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to produce hash code depending on source name
|
|
||||||
*
|
|
||||||
* @return a hash code value for this object.
|
|
||||||
*/
|
|
||||||
public int hashCode() {
|
|
||||||
return sourceName.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to equal other Template with the same source name
|
|
||||||
*
|
|
||||||
* @param obj the object to compare to
|
|
||||||
* @return true if obj is a Template with the same source name
|
|
||||||
*/
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return (obj instanceof Template) &&
|
|
||||||
sourceName.equals(((Template) obj).getSourceName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -105,7 +105,7 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder {
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean renderSkin(Object skinobj, Object paramobj)
|
public boolean renderSkin(Object skinobj, Object paramobj)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -139,7 +139,7 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder {
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public String renderSkinAsString(Object skinobj, Object paramobj)
|
public String renderSkinAsString(Object skinobj, Object paramobj)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -250,7 +251,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean jsFunction_renderSkin(Object skinobj, Object paramobj)
|
public boolean jsFunction_renderSkin(Object skinobj, Object paramobj)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -284,7 +285,7 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public String jsFunction_renderSkinAsString(Object skinobj, Object paramobj)
|
public String jsFunction_renderSkinAsString(Object skinobj, Object paramobj)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -319,7 +320,8 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public Object jsFunction_href(Object action) throws UnsupportedEncodingException {
|
public Object jsFunction_href(Object action) throws UnsupportedEncodingException,
|
||||||
|
IOException {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -790,9 +792,6 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public Object get(String name, Scriptable start) {
|
public Object get(String name, Scriptable start) {
|
||||||
// System.err.println("GET from "+this+": "+name+" ->"+super.get(name, start));
|
|
||||||
Object retval = null;
|
|
||||||
|
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return super.get(name, start);
|
return super.get(name, start);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -70,7 +71,7 @@ public class JavaObject extends NativeJavaObject {
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean renderSkin(Object skinobj, Object paramobj)
|
public boolean renderSkin(Object skinobj, Object paramobj)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -104,7 +105,7 @@ public class JavaObject extends NativeJavaObject {
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public String renderSkinAsString(Object skinobj, Object paramobj)
|
public String renderSkinAsString(Object skinobj, Object paramobj)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -139,7 +140,8 @@ public class JavaObject extends NativeJavaObject {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public Object href(Object action) throws UnsupportedEncodingException {
|
public Object href(Object action) throws UnsupportedEncodingException,
|
||||||
|
IOException {
|
||||||
if (javaObject == null) {
|
if (javaObject == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package helma.scripting.rhino;
|
package helma.scripting.rhino;
|
||||||
|
|
||||||
import helma.scripting.*;
|
import helma.framework.repository.Resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An class that updates fesi interpreters with actionfiles and templates.
|
* An class that updates fesi interpreters with actionfiles and templates.
|
||||||
|
@ -31,9 +33,9 @@ public class RhinoActionAdapter {
|
||||||
*
|
*
|
||||||
* @param action ...
|
* @param action ...
|
||||||
*/
|
*/
|
||||||
public RhinoActionAdapter(ActionFile action) {
|
public RhinoActionAdapter(Resource action) throws IOException {
|
||||||
String content = action.getContent();
|
String content = action.getContent();
|
||||||
String functionName = action.getFunctionName().replace('.', '_');
|
String functionName = action.getShortName().replace('.', '_');
|
||||||
|
|
||||||
sourceName = action.toString();
|
sourceName = action.toString();
|
||||||
function = composeFunction(functionName,
|
function = composeFunction(functionName,
|
||||||
|
@ -41,7 +43,7 @@ public class RhinoActionAdapter {
|
||||||
content);
|
content);
|
||||||
|
|
||||||
// check if this is a template and we need to generate an "_as_string" variant
|
// check if this is a template and we need to generate an "_as_string" variant
|
||||||
if (action instanceof Template) {
|
if (action.getName().endsWith(".hsp")) {
|
||||||
functionAsString = composeFunction(functionName + "_as_string",
|
functionAsString = composeFunction(functionName + "_as_string",
|
||||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||||
"res.pushStringBuffer(); " + content +
|
"res.pushStringBuffer(); " + content +
|
||||||
|
|
|
@ -18,6 +18,7 @@ package helma.scripting.rhino;
|
||||||
|
|
||||||
import helma.scripting.rhino.extensions.*;
|
import helma.scripting.rhino.extensions.*;
|
||||||
import helma.framework.core.*;
|
import helma.framework.core.*;
|
||||||
|
import helma.framework.repository.Resource;
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
import helma.objectmodel.db.DbMapping;
|
import helma.objectmodel.db.DbMapping;
|
||||||
import helma.objectmodel.db.DbKey;
|
import helma.objectmodel.db.DbKey;
|
||||||
|
@ -215,18 +216,9 @@ public final class RhinoCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through the prototype's code elements and evaluate them
|
// loop through the prototype's code elements and evaluate them
|
||||||
// first the zipped ones ...
|
Iterator code = prototype.getCodeResources();
|
||||||
for (Iterator it = prototype.getZippedCode().values().iterator(); it.hasNext();) {
|
while (code.hasNext()) {
|
||||||
Object code = it.next();
|
evaluate(type, (Resource) code.next());
|
||||||
|
|
||||||
evaluate(type, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// then the unzipped ones (this is to make sure unzipped code overwrites zipped code)
|
|
||||||
for (Iterator it = prototype.getCode().values().iterator(); it.hasNext();) {
|
|
||||||
Object code = it.next();
|
|
||||||
|
|
||||||
evaluate(type, code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type.commitCompilation();
|
type.commitCompilation();
|
||||||
|
@ -310,7 +302,9 @@ public final class RhinoCore {
|
||||||
|
|
||||||
TypeInfo type = (TypeInfo) prototypes.get("global");
|
TypeInfo type = (TypeInfo) prototypes.get("global");
|
||||||
|
|
||||||
|
if (type != null) {
|
||||||
updatePrototype(type, checked);
|
updatePrototype(type, checked);
|
||||||
|
}
|
||||||
|
|
||||||
for (Iterator i = protos.iterator(); i.hasNext();) {
|
for (Iterator i = protos.iterator(); i.hasNext();) {
|
||||||
Prototype proto = (Prototype) i.next();
|
Prototype proto = (Prototype) i.next();
|
||||||
|
@ -624,7 +618,7 @@ public final class RhinoCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String postProcessHref(Object obj, String protoName, String basicHref)
|
protected String postProcessHref(Object obj, String protoName, String basicHref)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException, IOException {
|
||||||
// check if the app.properties specify a href-function to post-process the
|
// check if the app.properties specify a href-function to post-process the
|
||||||
// basic href.
|
// basic href.
|
||||||
String hrefFunction = app.getProperty("hrefFunction", null);
|
String hrefFunction = app.getProperty("hrefFunction", null);
|
||||||
|
@ -750,46 +744,10 @@ public final class RhinoCore {
|
||||||
// private evaluation/compilation methods
|
// private evaluation/compilation methods
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
private synchronized void evaluate(TypeInfo type, Object code) {
|
private synchronized void evaluate (TypeInfo type, Resource code) {
|
||||||
if (code instanceof FunctionFile) {
|
|
||||||
FunctionFile funcfile = (FunctionFile) code;
|
|
||||||
File file = funcfile.getFile();
|
|
||||||
|
|
||||||
if (file != null) {
|
|
||||||
try {
|
|
||||||
FileReader fr = new FileReader(file);
|
|
||||||
|
|
||||||
updateEvaluator(type, fr, funcfile.getSourceName(), 1);
|
|
||||||
} catch (IOException iox) {
|
|
||||||
app.logEvent("Error updating function file: " + iox);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
StringReader reader = new StringReader(funcfile.getContent());
|
|
||||||
|
|
||||||
updateEvaluator(type, reader, funcfile.getSourceName(), 1);
|
|
||||||
}
|
|
||||||
} else if (code instanceof ActionFile) {
|
|
||||||
ActionFile action = (ActionFile) code;
|
|
||||||
RhinoActionAdapter fa = new RhinoActionAdapter(action);
|
|
||||||
|
|
||||||
try {
|
|
||||||
updateEvaluator(type, new StringReader(fa.function),
|
|
||||||
action.getSourceName(), 0);
|
|
||||||
if (fa.functionAsString != null) {
|
|
||||||
// templates have an _as_string variant that needs to be compiled
|
|
||||||
updateEvaluator(type, new StringReader(fa.functionAsString),
|
|
||||||
action.getSourceName(), 0);
|
|
||||||
}
|
|
||||||
} catch (Exception esx) {
|
|
||||||
app.logEvent("Error parsing " + action + ": " + esx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void updateEvaluator(TypeInfo type, Reader reader,
|
|
||||||
String sourceName, int firstline) {
|
|
||||||
// System.err.println("UPDATE EVALUATOR: "+prototype+" - "+sourceName);
|
|
||||||
Scriptable threadScope = global.unregisterScope();
|
Scriptable threadScope = global.unregisterScope();
|
||||||
|
String sourceName = code.getName();
|
||||||
|
Reader reader = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// get the current context
|
// get the current context
|
||||||
|
@ -798,8 +756,14 @@ public final class RhinoCore {
|
||||||
Scriptable op = type.objProto;
|
Scriptable op = type.objProto;
|
||||||
|
|
||||||
// do the update, evaluating the file
|
// do the update, evaluating the file
|
||||||
// Script script = cx.compileReader(reader, sourceName, firstline, null);
|
if (sourceName.endsWith(".js")) {
|
||||||
cx.evaluateReader(op, reader, sourceName, firstline, null);
|
reader = new InputStreamReader(code.getInputStream());
|
||||||
|
cx.evaluateReader(op, reader, sourceName, 1, null);
|
||||||
|
} else if (sourceName.endsWith(".hac")) {
|
||||||
|
RhinoActionAdapter raa = new RhinoActionAdapter(code);
|
||||||
|
reader = new StringReader(raa.function);
|
||||||
|
cx.evaluateReader(op, reader, sourceName, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
app.logEvent("Error parsing file " + sourceName + ": " + e);
|
app.logEvent("Error parsing file " + sourceName + ": " + e);
|
||||||
|
@ -935,7 +899,7 @@ public final class RhinoCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark this type as updated
|
// mark this type as updated
|
||||||
lastUpdate = frameworkProto.getLastUpdate();
|
lastUpdate = frameworkProto.lastCodeUpdate();
|
||||||
|
|
||||||
// If this prototype defines a postCompile() function, call it
|
// If this prototype defines a postCompile() function, call it
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
|
@ -953,7 +917,7 @@ public final class RhinoCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needsUpdate() {
|
public boolean needsUpdate() {
|
||||||
return frameworkProto.getLastUpdate() > lastUpdate;
|
return frameworkProto.lastCodeUpdate() > lastUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParentType(TypeInfo type) {
|
public void setParentType(TypeInfo type) {
|
||||||
|
|
|
@ -30,6 +30,8 @@ import helma.scripting.rhino.debug.Tracer;
|
||||||
import org.mozilla.javascript.*;
|
import org.mozilla.javascript.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -432,7 +434,7 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
*/
|
*/
|
||||||
public IPathElement getIntrospector() {
|
public IPathElement getIntrospector() {
|
||||||
if (doc == null) {
|
if (doc == null) {
|
||||||
doc = new DocApplication(app.getName(), app.getAppDir().toString());
|
doc = new DocApplication(app.getName(), new File(Server.getServer().getAppsHome(), app.getName()));
|
||||||
doc.readApplication();
|
doc.readApplication();
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
|
@ -482,7 +484,7 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
* skinpath set in the current response object and does per-response skin
|
* skinpath set in the current response object and does per-response skin
|
||||||
* caching.
|
* caching.
|
||||||
*/
|
*/
|
||||||
public Skin getSkin(String protoName, String skinName) {
|
public Skin getSkin(String protoName, String skinName) throws IOException {
|
||||||
SkinKey key = new SkinKey(protoName, skinName);
|
SkinKey key = new SkinKey(protoName, skinName);
|
||||||
|
|
||||||
Skin skin = reval.res.getCachedSkin(key);
|
Skin skin = reval.res.getCachedSkin(key);
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
package helma.servlet;
|
package helma.servlet;
|
||||||
|
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
import helma.framework.core.Application;
|
import helma.framework.core.Application;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
|
import helma.framework.repository.FileRepository;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
|
|
||||||
|
@ -92,10 +95,11 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File appHome = new File(appDir);
|
Repository[] repositories = new Repository[1];
|
||||||
|
repositories[0] = new FileRepository(new File(appDir));
|
||||||
File dbHome = new File(dbDir);
|
File dbHome = new File(dbDir);
|
||||||
|
|
||||||
app = new Application(appName, appHome, dbHome);
|
app = new Application(appName, repositories, dbHome);
|
||||||
app.init();
|
app.init();
|
||||||
app.start();
|
app.start();
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
|
|
124
src/helma/util/CryptResource.java
Normal file
124
src/helma/util/CryptResource.java
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
import helma.framework.repository.Resource;
|
||||||
|
import helma.framework.repository.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file authenticates against a passwd source
|
||||||
|
*/
|
||||||
|
public class CryptResource {
|
||||||
|
|
||||||
|
private Properties users;
|
||||||
|
private CryptResource parentResource;
|
||||||
|
private Resource resource;
|
||||||
|
private long lastRead = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new CryptSource object.
|
||||||
|
*
|
||||||
|
* @param resource ...
|
||||||
|
* @param parentResource ...
|
||||||
|
*/
|
||||||
|
public CryptResource(Resource resource, CryptResource parentResource) {
|
||||||
|
this.resource = resource;
|
||||||
|
this.parentResource = parentResource;
|
||||||
|
users = new Properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param username ...
|
||||||
|
* @param pw ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean authenticate(String username, String pw) {
|
||||||
|
if (resource.exists() && (resource.lastModified() > lastRead)) {
|
||||||
|
readFile();
|
||||||
|
} else if (!resource.exists() && (users.size() > 0)) {
|
||||||
|
users.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
String realpw = users.getProperty(username);
|
||||||
|
|
||||||
|
if (realpw != null) {
|
||||||
|
try {
|
||||||
|
// check if password matches
|
||||||
|
// first we try with unix crypt algorithm
|
||||||
|
String cryptpw = Crypt.crypt(realpw, pw);
|
||||||
|
|
||||||
|
if (realpw.equals(cryptpw)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// then try MD5
|
||||||
|
if (realpw.equals(MD5Encoder.encode(pw))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception x) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parentResource != null) {
|
||||||
|
return parentResource.authenticate(username, pw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void readFile() {
|
||||||
|
BufferedReader reader = null;
|
||||||
|
|
||||||
|
users = new Properties();
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(new StringReader(resource.getContent()));
|
||||||
|
|
||||||
|
String line = reader.readLine();
|
||||||
|
|
||||||
|
while (line != null) {
|
||||||
|
StringTokenizer st = new StringTokenizer(line, ":");
|
||||||
|
|
||||||
|
if (st.countTokens() > 1) {
|
||||||
|
users.put(st.nextToken(), st.nextToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
} finally {
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (Exception x) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastRead = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
411
src/helma/util/ResourceProperties.java
Normal file
411
src/helma/util/ResourceProperties.java
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import helma.framework.core.*;
|
||||||
|
import helma.framework.repository.Resource;
|
||||||
|
import helma.framework.repository.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A property dictionary that is updated from property resources
|
||||||
|
*/
|
||||||
|
public final class ResourceProperties extends Properties {
|
||||||
|
|
||||||
|
// Delay between checks
|
||||||
|
private final long cacheTime = 1500L;
|
||||||
|
|
||||||
|
// Default properties
|
||||||
|
public ResourceProperties defaultProperties;
|
||||||
|
|
||||||
|
// Defines wether keys are case-sensitive or not
|
||||||
|
private boolean ignoreCase = true;
|
||||||
|
|
||||||
|
// Cached checksum of last check
|
||||||
|
private long lastChecksum = -1;
|
||||||
|
|
||||||
|
// Time of last check
|
||||||
|
private long lastCheck = 0;
|
||||||
|
|
||||||
|
// Time porperties were last modified
|
||||||
|
private long lastModified = 0;
|
||||||
|
|
||||||
|
// Application where to fetch additional resources
|
||||||
|
private Application app;
|
||||||
|
|
||||||
|
// Name of possible resources to fetch from the applications's repositories
|
||||||
|
private String resourceName;
|
||||||
|
|
||||||
|
// Sorted map of resources
|
||||||
|
private TreeSet resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an empty ResourceProperties
|
||||||
|
* Resources must be added manually afterwards
|
||||||
|
*/
|
||||||
|
public ResourceProperties() {
|
||||||
|
resources = new TreeSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ResourceProperties retrieving resources from the given
|
||||||
|
* application using the given name to fetch resources
|
||||||
|
* @param app application to fetch resources from
|
||||||
|
* @param resourceName name to use when fetching resources from the application
|
||||||
|
*/
|
||||||
|
public ResourceProperties(Application app, String resourceName) {
|
||||||
|
this.app = app;
|
||||||
|
this.resourceName = resourceName;
|
||||||
|
resources = new TreeSet(app.getResourceComparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a ResourceProperties retrieving resources from the given
|
||||||
|
* application using the given name to fetch resources and falling back
|
||||||
|
* to the given default properties
|
||||||
|
* @param app application to fetch resources from
|
||||||
|
* @param sourceName name to use when fetching resources from the application
|
||||||
|
* @param defaultProperties default properties
|
||||||
|
*/
|
||||||
|
public ResourceProperties(Application app, String sourceName, ResourceProperties defaultProperties) {
|
||||||
|
this(app, sourceName);
|
||||||
|
this.defaultProperties = defaultProperties;
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the properties regardless of an actual need
|
||||||
|
*/
|
||||||
|
private void forceUpdate() {
|
||||||
|
lastChecksum = -1;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default properties and updates all properties
|
||||||
|
* @param defaultProperties default properties
|
||||||
|
*/
|
||||||
|
public void setDefaultProperties(ResourceProperties defaultProperties) {
|
||||||
|
this.defaultProperties = defaultProperties;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a resource to the list of resources and updates all properties if
|
||||||
|
* needed
|
||||||
|
* @param resource resource to add
|
||||||
|
*/
|
||||||
|
public void addResource(Resource resource) {
|
||||||
|
if (resource != null) {
|
||||||
|
resources.add(resource);
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a resource from the list of resources and updates all properties
|
||||||
|
* if needed
|
||||||
|
* @param resource resource to remove
|
||||||
|
*/
|
||||||
|
public void removeResource(Resource resource) {
|
||||||
|
if (resources.contains(resource)) {
|
||||||
|
resources.remove(resource);
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the properties need to be updated
|
||||||
|
* @return true if the properties need tu be updated
|
||||||
|
*/
|
||||||
|
public boolean needsUpdate() {
|
||||||
|
lastCheck = System.currentTimeMillis();
|
||||||
|
if (getChecksum() != lastChecksum) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all properties if there is a need to update
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
if (needsUpdate() || (defaultProperties != null && defaultProperties.needsUpdate())) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// first of all, properties are load from default properties
|
||||||
|
if (defaultProperties != null) {
|
||||||
|
defaultProperties.update();
|
||||||
|
this.putAll(defaultProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next we try to load properties from the application's
|
||||||
|
repositories, if we blong to any application */
|
||||||
|
if (app != null) {
|
||||||
|
Iterator iterator = app.getRepositories();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
try {
|
||||||
|
Repository repository = (Repository) iterator.next();
|
||||||
|
Resource resource = repository.getResource(resourceName);
|
||||||
|
if (resource != null) {
|
||||||
|
load(resource.getInputStream());
|
||||||
|
}
|
||||||
|
} catch (IOException iox) {
|
||||||
|
iox.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// at last we try to load properties from the resource list
|
||||||
|
if (resources != null) {
|
||||||
|
Iterator iterator = resources.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
try {
|
||||||
|
load(((Resource) iterator.next()).getInputStream());
|
||||||
|
} catch (IOException ignore) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastChecksum = getChecksum();
|
||||||
|
lastCheck = lastModified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the given object is in the value list
|
||||||
|
* @param value value to look for
|
||||||
|
* @return true if the value is found in the value list
|
||||||
|
*/
|
||||||
|
public boolean contains(Object value) {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.contains(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the given object is in the key list
|
||||||
|
* @param key key to look for
|
||||||
|
* @return true if the key is found in the key list
|
||||||
|
*/
|
||||||
|
public boolean containsKey(Object key) {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.containsKey(key.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an enumeration of all values
|
||||||
|
* @return values enumeration
|
||||||
|
*/
|
||||||
|
public Enumeration elements() {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.elements();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value in this list fetched by the given key
|
||||||
|
* @param key key to use for fetching the value
|
||||||
|
* @return value belonging to the given key
|
||||||
|
*/
|
||||||
|
public Object get(Object key) {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String) super.get(ignoreCase == true ? key.toString().toLowerCase() : key.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date the resources were last modified
|
||||||
|
* @return last modified date
|
||||||
|
*/
|
||||||
|
public long lastModified() {
|
||||||
|
return lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a checksum for all resources
|
||||||
|
* @return checksum
|
||||||
|
*/
|
||||||
|
public long getChecksum() {
|
||||||
|
long checksum = 0;
|
||||||
|
|
||||||
|
if (app != null) {
|
||||||
|
Iterator iterator = app.getRepositories();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
try {
|
||||||
|
Repository repository = (Repository) iterator.next();
|
||||||
|
Resource resource = repository.getResource(resourceName);
|
||||||
|
checksum += resource != null ?
|
||||||
|
resource.lastModified() : repository.lastModified();
|
||||||
|
} catch (IOException iox) {
|
||||||
|
iox.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resources != null) {
|
||||||
|
Iterator iterator = resources.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
checksum += ((Resource) iterator.next()).lastModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value in the list fetched by the given key or a default value
|
||||||
|
* if no corresponding key is found
|
||||||
|
* @param key key to use for fetching the value
|
||||||
|
* @param defaultValue default value to return if key is not found
|
||||||
|
* @return spiecific value or default value if not found
|
||||||
|
*/
|
||||||
|
public String getProperty(String key, String defaultValue) {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getProperty(ignoreCase == true ? key.toLowerCase() : key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value in this list fetched by the given key
|
||||||
|
* @param key key to use for fetching the value
|
||||||
|
* @return value belonging to the given key
|
||||||
|
*/
|
||||||
|
public String getProperty(String key) {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getProperty(ignoreCase == true ? key.toLowerCase() : key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether the properties list is empty
|
||||||
|
* @return true if the properties list is empty
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wether case-sensitivity is ignored for keys
|
||||||
|
* @return true if case-sensitivity is ignored for keys
|
||||||
|
*/
|
||||||
|
public boolean isIgnoreCase() {
|
||||||
|
return ignoreCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an enumeration of all keys
|
||||||
|
* @return keys enumeration
|
||||||
|
*/
|
||||||
|
public Enumeration keys() {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of all keys
|
||||||
|
* @return keys set
|
||||||
|
*/
|
||||||
|
public Set keySet() {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a new key-value pair into the properties list
|
||||||
|
* @param key key
|
||||||
|
* @param value value
|
||||||
|
* @return the old value, if an old value got replaced
|
||||||
|
*/
|
||||||
|
public Object put(Object key, Object value) {
|
||||||
|
if (value != null) {
|
||||||
|
value = value.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.put(ignoreCase == true ? key.toString().toLowerCase() : key.toString(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a key-value pair from the properties list
|
||||||
|
* @param key key
|
||||||
|
* @return the old value
|
||||||
|
*/
|
||||||
|
public Object remove(Object key) {
|
||||||
|
return super.remove(ignoreCase == true ? key.toString().toLowerCase() : key.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes how keys are handled
|
||||||
|
* @param ignore true if to ignore case-sensitivity for keys
|
||||||
|
*/
|
||||||
|
public void setIgnoreCase(boolean ignore) {
|
||||||
|
if (!super.isEmpty()) {
|
||||||
|
throw new RuntimeException("setIgnoreCase() can only be called on empty Properties");
|
||||||
|
}
|
||||||
|
ignoreCase = ignore;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of peroperties in the list
|
||||||
|
* @return number of properties
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
if ((System.currentTimeMillis() - lastCheck) > cacheTime) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string-representation of the class
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.util;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface of classes that can update themselves and know when to do so.
|
|
||||||
*/
|
|
||||||
public interface Updatable {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*/
|
|
||||||
public boolean needsUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void update();
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void remove();
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue