Move TypeManager.updatePrototype(Prototype) to Prototype.checkForUpdates().

Additionally, the inner workings of the Prototype update logic were vastly simplified.
This commit is contained in:
hns 2005-03-25 00:12:59 +00:00
parent 57efa85f29
commit fdf3915d9e
4 changed files with 95 additions and 160 deletions

View file

@ -1743,7 +1743,9 @@ public final class Application implements IPathElement, Runnable {
* change, too.
*/
public long getChecksum() {
return starttime + typemgr.lastCodeUpdate() + props.getChecksum();
return starttime +
typemgr.getLastCodeUpdate() +
props.getChecksum();
}
/**

View file

@ -33,19 +33,21 @@ import java.util.*;
* relational database table.
*/
public final class Prototype {
// the app this prototype belongs to
Application app;
// this prototype's name in natural and lower case
String name;
String lowerCaseName;
// this prototype's resources
Resource[] resources;
long lastResourceListing;
// lastCheck is the time the prototype's files were last checked
long lastChecksum;
long newChecksum;
// lastUpdate is the time at which any of the prototype's files were found updated the last time
long lastCodeUpdate;
// tells us the checksum of the repositories at the time we last updated them
long lastChecksum = 0;
// the time at which any of the prototype's files were found updated the last time
long lastCodeUpdate = 0;
TreeSet code;
TreeSet skins;
@ -103,7 +105,6 @@ public final class Prototype {
skinMap = new HashMap();
isJavaPrototype = app.isJavaPrototype(name);
lastCodeUpdate = lastChecksum = 0;
}
/**
@ -125,13 +126,73 @@ public final class Prototype {
}
/**
* Returns the list of resources in this prototype's repositories
* Check a prototype for new or updated resources. After this has been
* called the code and skins collections of this prototype should be
* up-to-date and the lastCodeUpdate be set if there has been any changes.
*/
public Resource[] getResources() {
long resourceListing = getChecksum();
public void checkForUpdates() {
if (resources == null || resourceListing != lastResourceListing) {
lastResourceListing = resourceListing;
boolean updatedResources = false;
// check if any resource the prototype knows about has changed or gone
for (Iterator i = trackers.values().iterator(); i.hasNext();) {
ResourceTracker tracker = (ResourceTracker) i.next();
try {
if (tracker.hasChanged()) {
updatedResources = true;
tracker.markClean();
if (!tracker.getResource().exists()) {
i.remove();
String name = tracker.getResource().getName();
if (name.endsWith(TypeManager.skinExtension)) {
skins.remove(tracker.getResource());
} else {
code.remove(tracker.getResource());
}
}
}
} catch (IOException iox) {
iox.printStackTrace();
}
}
// next we check if resources have been created or removed
Resource[] resources = getResources();
for (int i = 0; i < resources.length; i++) {
String name = resources[i].getName();
if (!trackers.containsKey(name)) {
if (name.endsWith(TypeManager.templateExtension) ||
name.endsWith(TypeManager.scriptExtension) ||
name.endsWith(TypeManager.actionExtension) ||
name.endsWith(TypeManager.skinExtension)) {
if (name.endsWith(TypeManager.skinExtension)) {
addSkinResource(resources[i]);
} else {
addCodeResource(resources[i]);
}
}
}
}
if (updatedResources) {
// mark prototype as dirty and the code as updated
lastCodeUpdate = System.currentTimeMillis();
app.typemgr.setLastCodeUpdate(lastCodeUpdate);
}
}
/**
* Returns the list of resources in this prototype's repositories. Used
* by checkForUpdates() to see whether there is anything new.
*/
Resource[] getResources() {
long checksum = getRepositoryChecksum();
// reload resources if the repositories checksum has changed
if (checksum != lastChecksum) {
ArrayList list = new ArrayList();
Iterator iterator = repositories.iterator();
@ -144,15 +205,16 @@ public final class Prototype {
}
resources = (Resource[]) list.toArray(new Resource[list.size()]);
lastChecksum = checksum;
}
return resources;
}
/**
* Get a checksum over this prototype's sources
* Get a checksum over this prototype's repositories. This tells us
* if any resources were added or removed.
*/
public long getChecksum() {
long getRepositoryChecksum() {
long checksum = 0;
Iterator iterator = repositories.iterator();
@ -164,20 +226,9 @@ public final class Prototype {
}
}
newChecksum = checksum;
return checksum;
}
/**
*
*
* @return ...
*/
public boolean isUpToDate() {
return (newChecksum == 0 && lastChecksum == 0) ?
false : newChecksum == lastChecksum;
}
/**
* Set the parent prototype of this prototype, i.e. the prototype this
* prototype inherits from.
@ -241,18 +292,14 @@ public final class Prototype {
}
/**
*
*
* @param dbmap ...
* Set the DbMapping associated with this prototype
*/
protected void setDbMapping(DbMapping dbmap) {
this.dbmap = dbmap;
}
/**
*
*
* @return ...
* Get the DbMapping associated with this prototype
*/
public DbMapping getDbMapping() {
return dbmap;
@ -316,15 +363,6 @@ public final class Prototype {
lastCodeUpdate = System.currentTimeMillis();
}
/**
* Signal that the prototype's scripts have been checked for
* changes.
*/
public void markChecked() {
// lastCheck = System.currentTimeMillis ();
lastChecksum = newChecksum;
}
/**
* Return a clone of this prototype's actions container. Synchronized
* to not return a map in a transient state where it is just being
@ -483,10 +521,6 @@ public final class Prototype {
}
private void checkForUpdates() {
if (!isUpToDate()) {
app.typemgr.updatePrototype(Prototype.this);
}
if (lastCodeUpdate > lastSkinmapLoad) {
load();
}

View file

@ -19,7 +19,6 @@ package helma.framework.core;
import helma.objectmodel.db.DbMapping;
import helma.framework.repository.Resource;
import helma.framework.repository.Repository;
import helma.framework.repository.ResourceTracker;
import java.io.*;
import java.net.URL;
@ -212,13 +211,20 @@ public final class TypeManager {
}
/**
* 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.
* Returns the last time any resource in this app was modified.
* This can be used to find out quickly if any file has changed.
*/
public long lastCodeUpdate() {
public long getLastCodeUpdate() {
return lastCodeUpdate;
}
/**
* Set the last time any resource in this app was modified.
*/
public void setLastCodeUpdate(long update) {
lastCodeUpdate = update;
}
/**
* Return the class loader used by this application.
*
@ -264,111 +270,4 @@ public final class TypeManager {
return proto;
}
/**
* Check a prototype for new or updated resources.
*/
public void updatePrototype(Prototype proto) {
synchronized (proto) {
// check again because another thread may have checked the
// prototype while we were waiting for access to the synchronized section
boolean updatedResources = false;
List createdResources = null;
// our plan is to do as little as possible, so first check if
// anything the prototype knows about has changed on disk
for (Iterator i = proto.trackers.values().iterator(); i.hasNext();) {
ResourceTracker tracker = (ResourceTracker) i.next();
try {
if (tracker.hasChanged()) {
updatedResources = true;
tracker.markClean();
}
} catch (IOException iox) {
iox.printStackTrace();
}
}
// next we check if files have been created or removed since last update
Resource[] resources = proto.getResources();
for (int i = 0; i < resources.length; i++) {
String name = resources[i].getName();
if (!proto.trackers.containsKey(name)) {
if (name.endsWith(templateExtension) ||
name.endsWith(scriptExtension) ||
name.endsWith(actionExtension) ||
name.endsWith(skinExtension)) {
if (createdResources == null) {
createdResources = new ArrayList();
}
createdResources.add(resources[i]);
}
}
}
// if nothing needs to be updated, mark prototype as checked and return
if (!updatedResources && createdResources == null) {
proto.markChecked();
return;
}
// first go through new files and create new items
if (createdResources != null) {
Resource[] newResources = new Resource[createdResources.size()];
createdResources.toArray(newResources);
for (int i = 0; i < newResources.length; i++) {
String resourceName = newResources[i].getName();
if (resourceName.endsWith(templateExtension) ||
resourceName.endsWith(scriptExtension) ||
resourceName.endsWith(actionExtension)) {
try {
proto.addCodeResource(newResources[i]);
} catch (Throwable x) {
app.logEvent("Error updating prototype: " + x);
}
} else if (resourceName.endsWith(skinExtension)) {
try {
proto.addSkinResource(newResources[i]);
} catch (Throwable x) {
app.logEvent("Error updating prototype: " + x);
}
}
}
}
// next go through existing updatables
if (updatedResources) {
/*
for (Iterator i = updateSet.iterator(); i.hasNext();) {
Updatable upd = (Updatable) i.next();
try {
upd.update();
} catch (Exception x) {
if (upd instanceof DbMapping) {
app.logEvent("Error updating db mapping for type " +
proto.getName() + ": " + x);
} else {
app.logEvent("Error updating " + upd + " of prototye type " +
proto.getName() + ": " + x);
}
}
}
*/
}
// mark prototype as checked and updated.
proto.markChecked();
proto.markUpdated();
lastCodeUpdate = proto.lastCodeUpdate();
} // end of synchronized (proto)
}
}

View file

@ -376,8 +376,8 @@ public final class RhinoCore implements ScopeProvider {
updatePrototype(type.getParentType(), checked);
}
// let the type manager scan the prototype's directory
app.typemgr.updatePrototype(type.frameworkProto);
// let the prototype check if its resources have changed
type.frameworkProto.checkForUpdates();
// and re-evaluate if necessary
if (type.needsUpdate()) {
@ -428,7 +428,7 @@ public final class RhinoCore implements ScopeProvider {
// otherwise, it has already been evaluated for this request by updatePrototypes(),
// which is called before a request is handled.
if ((type != null) && (type.lastUpdate == -1)) {
app.typemgr.updatePrototype(type.frameworkProto);
type.frameworkProto.checkForUpdates();
if (type.needsUpdate()) {
evaluatePrototype(type);