The list of files belonging to a prototype is now managed by the prototype itself.

The prototype also keeps a checksum over its files which allows it to recognize
changes in any of the files quickly and easily.
This commit is contained in:
hns 2002-10-29 17:27:19 +00:00
parent 24dece80bb
commit f4002ac605
2 changed files with 85 additions and 35 deletions

View file

@ -24,6 +24,11 @@ public final class Prototype {
String name; String name;
Application app; Application app;
File directory;
File [] files;
long lastDirectoryListing;
long checksum;
HashMap code, zippedCode; HashMap code, zippedCode;
HashMap skins, zippedSkins; HashMap skins, zippedSkins;
@ -36,7 +41,7 @@ public final class Prototype {
DbMapping dbmap; DbMapping dbmap;
// lastCheck is the time the prototype's files were last checked // lastCheck is the time the prototype's files were last checked
private long lastCheck; private long lastChecksum;
// lastUpdate is the time at which any of the prototype's files were // lastUpdate is the time at which any of the prototype's files were
// found updated the last time // found updated the last time
private long lastUpdate; private long lastUpdate;
@ -47,10 +52,11 @@ public final class Prototype {
// as opposed to a Helma objectmodel node object. // as opposed to a Helma objectmodel node object.
boolean isJavaPrototype; boolean isJavaPrototype;
public Prototype (String name, Application app) { public Prototype (String name, File dir, 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;
this.directory = dir;
code = new HashMap (); code = new HashMap ();
zippedCode = new HashMap (); zippedCode = new HashMap ();
@ -61,7 +67,7 @@ public final class Prototype {
skinMap = new SkinMap (); skinMap = new SkinMap ();
isJavaPrototype = app.isJavaPrototype (name); isJavaPrototype = app.isJavaPrototype (name);
lastUpdate = lastCheck = 0; lastUpdate = lastChecksum = 0;
} }
/** /**
@ -71,6 +77,43 @@ public final class Prototype {
return app; return app;
} }
/**
* Return this prototype's directory.
*/
public File getDirectory () {
return directory;
}
/**
* Get the list of files in this prototype's directory
*/
public File[] getFiles () {
if (files == null || directory.lastModified() != lastDirectoryListing) {
lastDirectoryListing = directory.lastModified ();
files = directory.listFiles();
if (files == null)
files = new File[0];
}
return files;
}
/**
* Get a checksum over the files in this prototype's directory
*/
public long getChecksum () {
// long start = System.currentTimeMillis();
File[] f = getFiles ();
long c = 0;
for (int i=0; i<f.length; i++)
c += f[i].lastModified();
checksum = c;
// System.err.println ("CHECKSUM "+name+": "+(System.currentTimeMillis()-start));
return checksum;
}
public boolean isUpToDate () {
return checksum == lastChecksum;
}
/** /**
* Set the parent prototype of this prototype, i.e. the prototype this * Set the parent prototype of this prototype, i.e. the prototype this
@ -130,17 +173,6 @@ public final class Prototype {
return name; return name;
} }
/* Updatable[] upd = null;
public Updatable[] getUpdatables () {
if (upd == null) {
upd = new Updatable[updatables.size()];
int i = 0;
for (Iterator it = updatables.values().iterator(); it.hasNext(); ) {
upd[i++] = (Updatable) it.next();
}
}
return upd;
} */
/** /**
* 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.
@ -162,18 +194,20 @@ public final class Prototype {
* Get the time at which this prototype's scripts were checked * Get the time at which this prototype's scripts were checked
* for changes for the last time. * for changes for the last time.
*/ */
public long getLastCheck () { /* public long getLastCheck () {
return lastCheck; return lastCheck;
} } */
/** /**
* Signal that the prototype's scripts have been checked for * Signal that the prototype's scripts have been checked for
* changes. * changes.
*/ */
public void markChecked () { public void markChecked () {
lastCheck = System.currentTimeMillis (); // lastCheck = System.currentTimeMillis ();
lastChecksum = checksum;
} }
/** /**
* Return a clone of this prototype's actions container. Synchronized * Return a clone of this prototype's actions container. Synchronized
* 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
@ -381,7 +415,7 @@ public final class Prototype {
private void checkForUpdates () { private void checkForUpdates () {
if (lastCheck < System.currentTimeMillis()- 2000l) if (/* lastCheck < System.currentTimeMillis()- 2000l*/ !isUpToDate())
app.typemgr.updatePrototype (Prototype.this); app.typemgr.updatePrototype (Prototype.this);
if (lastUpdate > lastSkinmapLoad) if (lastUpdate > lastSkinmapLoad)
load (); load ();

View file

@ -24,6 +24,8 @@ public final class TypeManager {
HashMap zipfiles; HashMap zipfiles;
long lastCheck = 0; long lastCheck = 0;
long appDirMod = 0; long appDirMod = 0;
// a checksum that changes whenever something in the application files changes.
long checksum;
// the hopobject prototype // the hopobject prototype
Prototype hopobjectProto; Prototype hopobjectProto;
@ -123,12 +125,16 @@ public final class TypeManager {
} }
} }
// calculate this app's checksum by adding all checksums from all prototypes
long newChecksum = 0;
// loop through zip files to check for updates // loop through zip files to check for updates
for (Iterator it=zipfiles.values ().iterator (); it.hasNext (); ) { for (Iterator it=zipfiles.values ().iterator (); it.hasNext (); ) {
ZippedAppFile zipped = (ZippedAppFile) it.next (); ZippedAppFile zipped = (ZippedAppFile) it.next ();
if (zipped.needsUpdate ()) { if (zipped.needsUpdate ()) {
zipped.update (); 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
@ -136,6 +142,8 @@ public final class TypeManager {
// have been created in the previous loop. // have been created in the previous loop.
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 ();
if (dbmap != null && dbmap.needsUpdate ()) { if (dbmap != null && dbmap.needsUpdate ()) {
@ -150,7 +158,7 @@ public final class TypeManager {
} }
} }
} }
checksum = newChecksum;
} }
protected void removeZipFile (String zipname) { protected void removeZipFile (String zipname) {
@ -175,6 +183,14 @@ public final class TypeManager {
return true; return true;
} }
/**
* Return a checksum over all files in all prototypes in this application.
* The checksum can be used to find out quickly if any file has changed.
*/
public long getChecksum () {
return checksum;
}
/** /**
* Get a prototype defined for this application * Get a prototype defined for this application
*/ */
@ -184,7 +200,7 @@ public final class TypeManager {
/** /**
* Get a prototype, creating it if it doesn't already exist. Note * Get a prototype, creating it if it doesn't already exist. Note
* that it doesn't create a DbMapping - this is left to the * that it doesn't create a DbMapping - this is left to the
* caller (e.g. ZippedAppFile). * caller (e.g. ZippedAppFile).
*/ */
public Prototype createPrototype (String typename) { public Prototype createPrototype (String typename) {
@ -196,7 +212,7 @@ public final class TypeManager {
* Create a prototype from a directory containing scripts and other stuff * Create a prototype from a directory containing scripts and other stuff
*/ */
public Prototype createPrototype (String typename, File dir) { public Prototype createPrototype (String typename, File dir) {
Prototype proto = new Prototype (typename, app); Prototype proto = new Prototype (typename, dir, app);
// Create and register type properties file // Create and register type properties file
File propfile = new File (dir, "type.properties"); File propfile = new File (dir, "type.properties");
SystemProperties props = new SystemProperties (propfile.getAbsolutePath ()); SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
@ -224,16 +240,16 @@ public final class TypeManager {
* Update a prototype to the files in the prototype directory. * Update a prototype to the files in the prototype directory.
*/ */
public void updatePrototype (Prototype proto) { public void updatePrototype (Prototype proto) {
if (proto == null) if (proto == null || proto.isUpToDate())
return; 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) /* if (System.currentTimeMillis() - proto.getLastCheck() < 1000)
return; return; */
File dir = new File (appDir, proto.getName()); File dir = proto.getDirectory ();
HashSet updateSet = null; HashSet updateSet = null;
HashSet createSet = null; HashSet createSet = null;
@ -249,10 +265,10 @@ public final class TypeManager {
} }
// 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 ()) { // if (proto.getLastCheck() < dir.lastModified ()) {
String[] list = dir.list(); File[] list = proto.getFiles();
for (int i=0; i<list.length; i++) { for (int i=0; i<list.length; i++) {
String fn = list[i]; String fn = list[i].getName();
if (!proto.updatables.containsKey (fn)) { if (!proto.updatables.containsKey (fn)) {
if (fn.endsWith (templateExtension) || if (fn.endsWith (templateExtension) ||
fn.endsWith (scriptExtension) || fn.endsWith (scriptExtension) ||
@ -266,7 +282,7 @@ public final class TypeManager {
} }
} }
} }
} // }
// 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 (updateSet == null && createSet == null) {
@ -278,34 +294,34 @@ public final class TypeManager {
if (createSet != null) { if (createSet != null) {
Object[] newFiles = createSet.toArray (); Object[] newFiles = createSet.toArray ();
for (int i=0; i<newFiles.length; i++) { for (int i=0; i<newFiles.length; i++) {
String filename = (String) newFiles[i]; File file = (File) newFiles[i];
String filename = file.getName ();
int dot = filename.lastIndexOf ("."); int dot = filename.lastIndexOf (".");
String tmpname = filename.substring(0, dot); String tmpname = filename.substring(0, dot);
File tmpfile = new File (dir, filename);
if (filename.endsWith (templateExtension)) { if (filename.endsWith (templateExtension)) {
try { try {
Template t = new Template (tmpfile, tmpname, proto); Template t = new Template (file, tmpname, proto);
proto.addTemplate (t); 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 (filename.endsWith (scriptExtension)) {
try { try {
FunctionFile ff = new FunctionFile (tmpfile, proto); FunctionFile ff = new FunctionFile (file, proto);
proto.addFunctionFile (ff); 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)) { } else if (filename.endsWith (actionExtension)) {
try { try {
ActionFile af = new ActionFile (tmpfile, tmpname, proto); ActionFile af = new ActionFile (file, tmpname, proto);
proto.addActionFile (af); proto.addActionFile (af);
} catch (Throwable x) { } catch (Throwable x) {
app.logEvent ("Error updating prototype: "+x); app.logEvent ("Error updating prototype: "+x);
} }
} else if (filename.endsWith (skinExtension)) { } else if (filename.endsWith (skinExtension)) {
SkinFile sf = new SkinFile (tmpfile, tmpname, proto); SkinFile sf = new SkinFile (file, tmpname, proto);
proto.addSkinFile (sf); proto.addSkinFile (sf);
} }
} }