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;
|
Prototype prototype;
|
||||||
Application app;
|
Application app;
|
||||||
File file;
|
File file;
|
||||||
|
String content;
|
||||||
long lastmod;
|
long lastmod;
|
||||||
|
|
||||||
// a set of funcion names defined by this file. We keep this to be able to
|
// 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 ();
|
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
|
* Tell the type manager whether we need an update. this is the case when
|
||||||
|
@ -66,7 +93,9 @@ public class FunctionFile implements Updatable {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
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) {}
|
} catch (Exception ignore) {}
|
||||||
}
|
}
|
||||||
|
@ -74,10 +103,22 @@ public class FunctionFile implements Updatable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
|
|
||||||
|
|
||||||
|
public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
|
||||||
|
if (file != null) {
|
||||||
|
try {
|
||||||
|
FileReader fr = new FileReader (file);
|
||||||
EvaluationSource es = new FileEvaluationSource (file.getPath (), null);
|
EvaluationSource es = new FileEvaluationSource (file.getPath (), null);
|
||||||
FileReader fr = 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;
|
HashMap priorProps = null;
|
||||||
HashSet newProps = null;
|
HashSet newProps = null;
|
||||||
|
@ -100,8 +141,7 @@ public class FunctionFile implements Updatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// do the update, evaluating the file
|
// do the update, evaluating the file
|
||||||
fr = new FileReader(file);
|
reval.evaluator.evaluate(reader, op, source, false);
|
||||||
reval.evaluator.evaluate(fr, op, es, false);
|
|
||||||
|
|
||||||
// check what's new
|
// check what's new
|
||||||
if (declaredPropsTimestamp != lastmod) try {
|
if (declaredPropsTimestamp != lastmod) try {
|
||||||
|
@ -113,14 +153,13 @@ public class FunctionFile implements Updatable {
|
||||||
}
|
}
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
// app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
||||||
} catch (EcmaScriptException e) {
|
app.logEvent ("Error parsing function file "+source+": "+e);
|
||||||
app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (fr!=null) {
|
if (reader != null) {
|
||||||
try {
|
try {
|
||||||
fr.close();
|
reader.close();
|
||||||
} catch (IOException ignore) {}
|
} catch (IOException ignore) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +222,9 @@ public class FunctionFile implements Updatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString () {
|
public String toString () {
|
||||||
|
if (file == null)
|
||||||
|
return "[Zipped script file]";
|
||||||
|
else
|
||||||
return prototype.getName()+"/"+file.getName();
|
return prototype.getName()+"/"+file.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,25 +26,19 @@ public class Prototype {
|
||||||
String name;
|
String name;
|
||||||
Application app;
|
Application app;
|
||||||
HashMap templates, functions, actions, skins, updatables;
|
HashMap templates, functions, actions, skins, updatables;
|
||||||
File codeDir;
|
|
||||||
long lastUpdate;
|
long lastUpdate;
|
||||||
|
|
||||||
DbMapping dbmap;
|
// DbMapping dbmap;
|
||||||
|
|
||||||
Prototype prototype;
|
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.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 ();
|
lastUpdate = System.currentTimeMillis ();
|
||||||
|
|
||||||
|
@ -123,35 +117,6 @@ public class Prototype {
|
||||||
return null;
|
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 () {
|
public String getName () {
|
||||||
return name;
|
return name;
|
||||||
|
@ -192,7 +157,6 @@ public class Prototype {
|
||||||
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
|
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
|
||||||
} catch (EcmaScriptException ignore) {}
|
} catch (EcmaScriptException ignore) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator it = functions.values().iterator(); it.hasNext(); ) {
|
for (Iterator it = functions.values().iterator(); it.hasNext(); ) {
|
||||||
FunctionFile ff = (FunctionFile) it.next ();
|
FunctionFile ff = (FunctionFile) it.next ();
|
||||||
ff.updateRequestEvaluator (reval);
|
ff.updateRequestEvaluator (reval);
|
||||||
|
|
|
@ -30,6 +30,19 @@ public class SkinFile implements Updatable {
|
||||||
this.skin = null;
|
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
|
* Tell the type manager whether we need an update. this is the case when
|
||||||
* the file has been modified or deleted.
|
* the file has been modified or deleted.
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class TypeManager implements Runnable {
|
||||||
updatePrototype (list[i], fileOrDir, proto);
|
updatePrototype (list[i], fileOrDir, proto);
|
||||||
} else {
|
} else {
|
||||||
// create new prototype
|
// create new prototype
|
||||||
proto = new Prototype (fileOrDir, app);
|
proto = new Prototype (list[i], app);
|
||||||
registerPrototype (list[i], fileOrDir, proto);
|
registerPrototype (list[i], fileOrDir, proto);
|
||||||
prototypes.put (list[i], proto);
|
prototypes.put (list[i], proto);
|
||||||
// give logger thread a chance to tell what's going on
|
// give logger thread a chance to tell what's going on
|
||||||
|
@ -137,11 +137,6 @@ public class TypeManager implements Runnable {
|
||||||
typechecker = null;
|
typechecker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prototype getPrototype (String typename) {
|
|
||||||
return (Prototype) prototypes.get (typename);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void run () {
|
public void run () {
|
||||||
|
|
||||||
while (Thread.currentThread () == typechecker) {
|
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) {
|
public void registerPrototype (String name, File dir, Prototype proto) {
|
||||||
// app.logEvent ("registering prototype "+name);
|
// 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.templates = ntemp;
|
||||||
proto.functions = nfunc;
|
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) {
|
public void updatePrototype (String name, File dir, Prototype proto) {
|
||||||
// app.logEvent ("updating prototype "+name);
|
// app.logEvent ("updating prototype "+name);
|
||||||
|
|
||||||
|
@ -340,9 +371,7 @@ public class TypeManager implements Runnable {
|
||||||
app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x);
|
app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
|
|
||||||
package helma.framework.core;
|
package helma.framework.core;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
import java.util.zip.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
import helma.util.Updatable;
|
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.
|
* 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) {
|
public ZippedAppFile (File file, Application app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.file = file;
|
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 {
|
} else {
|
||||||
|
|
||||||
|
ZipFile zip = null;
|
||||||
|
try {
|
||||||
lastmod = file.lastModified ();
|
lastmod = file.lastModified ();
|
||||||
System.err.println ("UPDATING ZIP FILE "+this);
|
// 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 () {
|
void remove () {
|
||||||
app.typemgr.zipfiles.remove (file.getName());
|
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