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:
parent
3c2e97fd20
commit
bb0d9c02fd
5 changed files with 216 additions and 101 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue