First implementation of zipped applications or zipped application parts.

Not especially clean architecture. A later version should try to better
abstract ordinary and zipped files.
This commit is contained in:
hns 2001-05-14 14:43:30 +00:00
parent 3c2e97fd20
commit bb0d9c02fd
5 changed files with 216 additions and 101 deletions

View file

@ -26,6 +26,7 @@ public class FunctionFile implements Updatable {
Prototype prototype;
Application app;
File file;
String content;
long lastmod;
// a set of funcion names defined by this file. We keep this to be able to
@ -41,6 +42,32 @@ public class FunctionFile implements Updatable {
update ();
}
/**
* Create a function file without a file, passing the code directly. This is used for
* files contained in zipped applications. The whole update mechanism is bypassed
* by immediately parsing the code.
*/
public FunctionFile (String body, String name, Prototype proto) {
this.prototype = proto;
this.app = proto.app;
this.name = name;
this.file = null;
this.content = body;
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) {
try {
StringEvaluationSource es = new StringEvaluationSource (body, null);
StringReader reader = new StringReader (body);
RequestEvaluator reval = (RequestEvaluator) evals.next ();
updateRequestEvaluator (reval, reader, es);
} catch (Exception ignore) {}
}
}
/**
* Tell the type manager whether we need an update. this is the case when
@ -66,7 +93,9 @@ public class FunctionFile implements Updatable {
try {
RequestEvaluator reval = (RequestEvaluator) evals.next ();
updateRequestEvaluator (reval);
FileReader fr = new FileReader(file);
EvaluationSource es = new FileEvaluationSource(file.getPath(), null);
updateRequestEvaluator (reval, fr, es);
} catch (Exception ignore) {}
}
@ -74,10 +103,22 @@ public class FunctionFile implements Updatable {
}
public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
EvaluationSource es = new FileEvaluationSource(file.getPath(), null);
FileReader fr = null;
public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
if (file != null) {
try {
FileReader fr = new FileReader (file);
EvaluationSource es = new FileEvaluationSource (file.getPath (), null);
updateRequestEvaluator (reval, fr, es);
} catch (Exception ignore) {}
} else {
StringReader reader = new StringReader (content);
StringEvaluationSource es = new StringEvaluationSource (content, null);
updateRequestEvaluator (reval, reader, es);
}
}
public synchronized void updateRequestEvaluator (RequestEvaluator reval, Reader reader, EvaluationSource source) {
HashMap priorProps = null;
HashSet newProps = null;
@ -100,8 +141,7 @@ public class FunctionFile implements Updatable {
}
// do the update, evaluating the file
fr = new FileReader(file);
reval.evaluator.evaluate(fr, op, es, false);
reval.evaluator.evaluate(reader, op, source, false);
// check what's new
if (declaredPropsTimestamp != lastmod) try {
@ -113,14 +153,13 @@ public class FunctionFile implements Updatable {
}
} catch (Exception ignore) {}
} catch (IOException e) {
app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
} catch (EcmaScriptException e) {
app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
} catch (Exception e) {
// app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
app.logEvent ("Error parsing function file "+source+": "+e);
} finally {
if (fr!=null) {
if (reader != null) {
try {
fr.close();
reader.close();
} catch (IOException ignore) {}
}
@ -183,7 +222,10 @@ public class FunctionFile implements Updatable {
}
public String toString () {
return prototype.getName()+"/"+file.getName();
if (file == null)
return "[Zipped script file]";
else
return prototype.getName()+"/"+file.getName();
}

View file

@ -26,26 +26,20 @@ public class Prototype {
String name;
Application app;
HashMap templates, functions, actions, skins, updatables;
File codeDir;
long lastUpdate;
DbMapping dbmap;
// DbMapping dbmap;
Prototype prototype;
public Prototype (File codeDir, Application app) {
public Prototype (String name, Application app) {
app.logEvent ("Constructing Prototype "+app.getName()+"/"+codeDir.getName ());
app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
this.codeDir = codeDir;
this.app = app;
this.name = codeDir.getName ();
this.name = name;
File propfile = new File (codeDir, "type.properties");
SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
dbmap = new DbMapping (app, name, props);
lastUpdate = System.currentTimeMillis ();
}
@ -123,35 +117,6 @@ public class Prototype {
return null;
}
public File getCodeDir () {
return codeDir;
}
public synchronized boolean checkCodeDir () {
boolean retval = false;
String[] list = codeDir.list ();
for (int i=0; i<list.length; i++) {
if (list[i].endsWith (app.templateExtension) || list[i].endsWith (app.scriptExtension)) {
File f = new File (codeDir, list[i]);
if (f.lastModified () > lastUpdate) {
lastUpdate = System.currentTimeMillis ();
try {
app.typemgr.updatePrototype (this.name, codeDir, this);
// TypeManager.broadcaster.broadcast ("Finished update for prototype "+name+" @ "+new Date ()+"<br><hr>");
} catch (Exception x) {
app.logEvent ("Error building function protos in prototype: "+x);
// TypeManager.broadcaster.broadcast ("Error updating prototype "+name+" in application "+app.getName()+":<br>"+x.getMessage ()+"<br><hr>");
}
retval = true;
}
}
}
return retval;
}
public String getName () {
return name;
@ -159,40 +124,39 @@ public class Prototype {
public void initRequestEvaluator (RequestEvaluator reval) {
ObjectPrototype op = null;
ObjectPrototype op = null;
// get the prototype's prototype if possible and necessary
ObjectPrototype opp = null;
if (prototype != null)
opp = reval.getPrototype (prototype.getName ());
if (!"global".equalsIgnoreCase (name) &&
!"hopobject".equalsIgnoreCase (name) && opp == null)
opp = reval.esNodePrototype;
// get the prototype's prototype if possible and necessary
ObjectPrototype opp = null;
if (prototype != null)
opp = reval.getPrototype (prototype.getName ());
if (!"global".equalsIgnoreCase (name) &&
!"hopobject".equalsIgnoreCase (name) && opp == null)
opp = reval.esNodePrototype;
if ("user".equalsIgnoreCase (name)) {
op = reval.esUserPrototype;
op.setPrototype (opp);
} else if ("global".equalsIgnoreCase (name))
op = reval.global;
else if ("hopobject".equalsIgnoreCase (name))
op = reval.esNodePrototype;
else {
op = new ObjectPrototype (opp, reval.evaluator);
try {
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
} catch (EcmaScriptException ignore) {}
}
reval.putPrototype (name, op);
// Register a constructor for all types except global.
// This will first create a node and then call the actual (scripted) constructor on it.
if (!"global".equalsIgnoreCase (name)) {
try {
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
} catch (EcmaScriptException ignore) {}
}
if ("user".equalsIgnoreCase (name)) {
op = reval.esUserPrototype;
op.setPrototype (opp);
} else if ("global".equalsIgnoreCase (name))
op = reval.global;
else if ("hopobject".equalsIgnoreCase (name))
op = reval.esNodePrototype;
else {
op = new ObjectPrototype (opp, reval.evaluator);
try {
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
} catch (EcmaScriptException ignore) {}
}
reval.putPrototype (name, op);
// Register a constructor for all types except global.
// This will first create a node and then call the actual (scripted) constructor on it.
if (!"global".equalsIgnoreCase (name)) {
try {
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
} catch (EcmaScriptException ignore) {}
}
for (Iterator it = functions.values().iterator(); it.hasNext(); ) {
FunctionFile ff = (FunctionFile) it.next ();
ff.updateRequestEvaluator (reval);

View file

@ -30,6 +30,19 @@ public class SkinFile implements Updatable {
this.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;
this.skin = new Skin (body, app);
}
/**
* Tell the type manager whether we need an update. this is the case when
* the file has been modified or deleted.

View file

@ -80,7 +80,7 @@ public class TypeManager implements Runnable {
updatePrototype (list[i], fileOrDir, proto);
} else {
// create new prototype
proto = new Prototype (fileOrDir, app);
proto = new Prototype (list[i], app);
registerPrototype (list[i], fileOrDir, proto);
prototypes.put (list[i], proto);
// give logger thread a chance to tell what's going on
@ -137,11 +137,6 @@ public class TypeManager implements Runnable {
typechecker = null;
}
public Prototype getPrototype (String typename) {
return (Prototype) prototypes.get (typename);
}
public void run () {
while (Thread.currentThread () == typechecker) {
@ -163,6 +158,34 @@ public class TypeManager implements Runnable {
}
/**
* Get a prototype defined for this application
*/
public Prototype getPrototype (String typename) {
return (Prototype) prototypes.get (typename);
}
/**
* Get a prototype, creating it if id doesn't already exist
*/
public Prototype createPrototype (String typename) {
Prototype p = getPrototype (typename);
if (p == null) {
p = new Prototype (typename, app);
p.templates = new HashMap ();
p.functions = new HashMap ();
p.actions = new HashMap ();
p.skins = new HashMap ();
p.updatables = new HashMap ();
prototypes.put (typename, p);
}
return p;
}
/**
* Create a prototype from a directory containing scripts and other stuff
*/
public void registerPrototype (String name, File dir, Prototype proto) {
// app.logEvent ("registering prototype "+name);
@ -222,7 +245,12 @@ public class TypeManager implements Runnable {
}
}
updatables.put ("type.properties", proto.dbmap);
// Create and register type properties file
File propfile = new File (dir, "type.properties");
SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
DbMapping dbmap = new DbMapping (app, name, props);
updatables.put ("type.properties", dbmap);
proto.templates = ntemp;
proto.functions = nfunc;
@ -240,6 +268,9 @@ public class TypeManager implements Runnable {
}
/**
* Update a prototype based on the directory which defines it.
*/
public void updatePrototype (String name, File dir, Prototype proto) {
// app.logEvent ("updating prototype "+name);
@ -340,9 +371,7 @@ public class TypeManager implements Runnable {
app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x);
}
}
}
}

View file

@ -3,13 +3,13 @@
package helma.framework.core;
import java.util.HashMap;
import java.util.Iterator;
import java.util.*;
import java.util.zip.*;
import java.io.*;
import helma.framework.*;
import helma.util.Updatable;
import helma.objectmodel.SystemProperties;
import helma.objectmodel.DbMapping;
/**
* This represents a Zip-File which may contain other Updatables for one or more prototypes.
@ -26,7 +26,7 @@ public class ZippedAppFile implements Updatable {
public ZippedAppFile (File file, Application app) {
this.app = app;
this.file = file;
System.err.println ("CREATING ZIP FILE "+this);
// System.err.println ("CREATING ZIP FILE "+this);
}
@ -46,16 +46,83 @@ public class ZippedAppFile implements Updatable {
} else {
lastmod = file.lastModified ();
System.err.println ("UPDATING ZIP FILE "+this);
ZipFile zip = null;
try {
lastmod = file.lastModified ();
// System.err.println ("UPDATING ZIP FILE "+this);
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, "/");
if (st.countTokens () == 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);
if (fname.endsWith (".hac")) {
String name = fname.substring (0, fname.lastIndexOf ("."));
String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]");
Action act = new Action (null, name, proto);
act.update (content);
proto.actions.put (name, act);
}
else if (fname.endsWith (".hsp")) {
String name = fname.substring (0, fname.lastIndexOf ("."));
String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]");
Template tmp = new Template (null, name, proto);
tmp.update (content);
proto.templates.put (name, 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.skins.put (name, skin);
}
else if (fname.endsWith (".js")) {
String name = fname.substring (0, fname.lastIndexOf ("."));
String content = getZipEntryContent (zip, entry);
// System.err.println ("["+content+"]");
FunctionFile ff = new FunctionFile (content, name, proto);
proto.functions.put (name, ff);
}
else if ("type.properties".equalsIgnoreCase (fname)) {
String name = fname.substring (0, fname.lastIndexOf ("."));
SystemProperties props = new SystemProperties (zip.getInputStream (entry));
// DbMapping does its own registering, just construct it.
new DbMapping (app, proto.getName (), props);
}
}
}
} catch (Throwable x) {
System.err.println ("Error updating ZipFile: "+x);
} finally {
try {
zip.close ();
} catch (Exception ignore) {}
}
}
}
void remove () {
app.typemgr.zipfiles.remove (file.getName());
System.err.println ("REMOVING ZIP FILE "+this);
// System.err.println ("REMOVING ZIP FILE "+this);
}
public String getZipEntryContent (ZipFile zip, ZipEntry entry) throws IOException {
int size = (int) entry.getSize ();
char[] c = new char[size];
InputStreamReader reader = new InputStreamReader (zip.getInputStream (entry));
reader.read (c);
return new String (c);
}