Adapted to other classes moving to the helma.scripting packages
This commit is contained in:
parent
6353177656
commit
dd3cbc45e9
6 changed files with 172 additions and 86 deletions
|
@ -8,6 +8,7 @@ import java.lang.reflect.*;
|
|||
import java.rmi.*;
|
||||
import java.rmi.server.*;
|
||||
import helma.framework.*;
|
||||
import helma.scripting.fesi.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import helma.xmlrpc.*;
|
||||
|
@ -34,7 +35,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
|
||||
private String baseURI;
|
||||
|
||||
TypeManager typemgr;
|
||||
public TypeManager typemgr;
|
||||
|
||||
RequestEvaluator eval;
|
||||
protected Stack freeThreads;
|
||||
|
@ -43,8 +44,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
boolean stopped = false;
|
||||
boolean debug;
|
||||
|
||||
Hashtable sessions;
|
||||
Hashtable activeUsers;
|
||||
public Hashtable sessions;
|
||||
public Hashtable activeUsers;
|
||||
Hashtable dbMappings;
|
||||
Hashtable dbSources;
|
||||
|
||||
|
@ -181,8 +182,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
activeRequests = new Hashtable ();
|
||||
|
||||
typemgr = new TypeManager (this);
|
||||
typemgr.check ();
|
||||
logEvent ("Started type manager for "+name);
|
||||
typemgr.createPrototypes ();
|
||||
// logEvent ("Started type manager for "+name);
|
||||
|
||||
rootMapping = getDbMapping ("root");
|
||||
userMapping = getDbMapping ("user");
|
||||
|
@ -196,16 +197,16 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
|
||||
nmgr = new NodeManager (this, dbDir.getAbsolutePath (), props);
|
||||
|
||||
worker = new Thread (this, "Worker-"+name);
|
||||
worker.setPriority (Thread.NORM_PRIORITY+2);
|
||||
worker.start ();
|
||||
// worker = new Thread (this, "Worker-"+name);
|
||||
// worker.setPriority (Thread.NORM_PRIORITY+2);
|
||||
// worker.start ();
|
||||
// logEvent ("session cleanup and scheduler thread started");
|
||||
|
||||
String xmlrpcHandlerName = props.getProperty ("xmlrpcHandlerName", this.name);
|
||||
if (xmlrpc != null)
|
||||
xmlrpc.addHandler (xmlrpcHandlerName, new XmlRpcInvoker (this));
|
||||
|
||||
typemgr.start ();
|
||||
// typemgr.start ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -264,7 +265,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
* This can be used to set the maximum number of evaluators which will be allocated.
|
||||
* If evaluators are required beyound this number, an error will be thrown.
|
||||
*/
|
||||
protected boolean setNumberOfEvaluators (int n) {
|
||||
public boolean setNumberOfEvaluators (int n) {
|
||||
if (n < 2 || n > 511)
|
||||
return false;
|
||||
int current = allThreads.size();
|
||||
|
@ -293,13 +294,20 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of currently active threads
|
||||
*/
|
||||
public int getActiveThreads () {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a request coming in from a web client.
|
||||
*/
|
||||
public ResponseTrans execute (RequestTrans req) {
|
||||
|
||||
requestCount += 1;
|
||||
|
||||
// long reqstart = System.currentTimeMillis ();
|
||||
User u = getUser (req.session);
|
||||
|
||||
ResponseTrans res = null;
|
||||
|
@ -342,7 +350,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
res.waitForClose ();
|
||||
}
|
||||
}
|
||||
|
||||
// System.err.println ("********************** ABSOLUTE TIME: "+(System.currentTimeMillis() - reqstart));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -697,7 +705,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
Hashtable cloned = (Hashtable) sessions.clone ();
|
||||
for (Enumeration e = cloned.elements (); e.hasMoreElements (); ) {
|
||||
User u = (User) e.nextElement ();
|
||||
if (now - u.touched () > sessionTimeout * 60000) {
|
||||
if (now - u.lastTouched () > sessionTimeout * 60000) {
|
||||
if (u.uid != null) {
|
||||
try {
|
||||
eval.invokeFunction (u, "onLogout", new ESValue[0]);
|
||||
|
@ -766,11 +774,11 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
String protoname = m.getExtends ();
|
||||
if (protoname == null)
|
||||
protoname = "hopobject";
|
||||
Prototype protoProto = (Prototype) typemgr.prototypes.get (protoname);
|
||||
if (protoProto == null)
|
||||
protoProto = (Prototype) typemgr.prototypes.get ("hopobject");
|
||||
if (protoProto != null)
|
||||
proto.setPrototype (protoProto);
|
||||
Prototype parentProto = (Prototype) typemgr.prototypes.get (protoname);
|
||||
if (parentProto == null)
|
||||
parentProto = (Prototype) typemgr.prototypes.get ("hopobject");
|
||||
if (parentProto != null)
|
||||
proto.setParentPrototype (parentProto);
|
||||
}
|
||||
}
|
||||
} catch (Exception x) {
|
||||
|
@ -822,6 +830,13 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
|
|||
dbMappings.put (typename, dbmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method to get a property from the applications properties.
|
||||
*/
|
||||
public String getProperty (String propname, String defvalue) {
|
||||
return props.getProperty (propname, defvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically called to log thread stats for this application
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,10 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.scripting.*;
|
||||
import helma.scripting.fesi.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.Updatable;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.EcmaScriptException;
|
||||
|
||||
|
@ -25,12 +28,10 @@ public class Prototype {
|
|||
String id;
|
||||
String name;
|
||||
Application app;
|
||||
HashMap templates, functions, actions, skins, updatables;
|
||||
public HashMap templates, functions, actions, skins, updatables;
|
||||
long lastUpdate;
|
||||
|
||||
// DbMapping dbmap;
|
||||
|
||||
Prototype prototype;
|
||||
Prototype parent;
|
||||
|
||||
|
||||
public Prototype (String name, Application app) {
|
||||
|
@ -40,11 +41,20 @@ public class Prototype {
|
|||
this.app = app;
|
||||
this.name = name;
|
||||
|
||||
lastUpdate = System.currentTimeMillis ();
|
||||
lastUpdate = 0; // System.currentTimeMillis ();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the application this prototype is a part of
|
||||
*/
|
||||
public Application getApplication () {
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an action defined for this prototype
|
||||
*/
|
||||
public Action getActionOrTemplate (String aname) {
|
||||
|
||||
Action retval = null;
|
||||
|
@ -56,21 +66,24 @@ public class Prototype {
|
|||
if (retval == null && "true".equalsIgnoreCase (app.props.getProperty ("exposetemplates")))
|
||||
retval = (Action) templates.get (aname);
|
||||
// if still not found, check if the action is defined for the generic node prototype
|
||||
if (retval == null && prototype != null)
|
||||
retval = prototype.getActionOrTemplate (aname);
|
||||
if (retval == null && parent != null)
|
||||
retval = parent.getActionOrTemplate (aname);
|
||||
return retval;
|
||||
}
|
||||
|
||||
public void setPrototype (Prototype prototype) {
|
||||
/**
|
||||
* Set the parent prototype of this prototype, i.e. the prototype this one inherits from.
|
||||
*/
|
||||
public void setParentPrototype (Prototype parent) {
|
||||
// this is not allowed for the hopobject and global prototypes
|
||||
if ("hopobject".equalsIgnoreCase (name) || "global".equalsIgnoreCase (name))
|
||||
return;
|
||||
|
||||
Prototype old = this.prototype;
|
||||
this.prototype = prototype;
|
||||
Prototype old = this.parent;
|
||||
this.parent = parent;
|
||||
|
||||
// if prototype has changed, update ES-prototypes in request evaluators
|
||||
if (prototype != old) {
|
||||
// if parent has changed, update ES-prototypes in request evaluators
|
||||
if (parent != old) {
|
||||
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
try {
|
||||
|
@ -78,8 +91,8 @@ public class Prototype {
|
|||
ObjectPrototype op = reval.getPrototype (getName());
|
||||
// use hopobject (node) as prototype even if prototype is null -
|
||||
// this is the case if no hopobject directory exists
|
||||
ObjectPrototype opp = prototype == null ?
|
||||
reval.esNodePrototype : reval.getPrototype (prototype.getName ());
|
||||
ObjectPrototype opp = parent == null ?
|
||||
reval.esNodePrototype : reval.getPrototype (parent.getName ());
|
||||
// don't think this is possible, but check anyway
|
||||
if (opp == null)
|
||||
opp = reval.esNodePrototype;
|
||||
|
@ -90,8 +103,8 @@ public class Prototype {
|
|||
}
|
||||
}
|
||||
|
||||
public Prototype getPrototype () {
|
||||
return prototype;
|
||||
public Prototype getParentPrototype () {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Template getTemplate (String tmpname) {
|
||||
|
@ -123,6 +136,18 @@ public class Prototype {
|
|||
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;
|
||||
|
||||
}
|
||||
|
||||
public void initRequestEvaluator (RequestEvaluator reval) {
|
||||
// see if we already registered with this evaluator
|
||||
|
@ -133,12 +158,12 @@ public class Prototype {
|
|||
|
||||
// get the prototype's prototype if possible and necessary
|
||||
ObjectPrototype opp = null;
|
||||
if (prototype != null) {
|
||||
if (parent != null) {
|
||||
// see if parent prototype is already registered. if not, register it
|
||||
opp = reval.getPrototype (prototype.getName ());
|
||||
opp = reval.getPrototype (parent.getName ());
|
||||
if (opp == null) {
|
||||
prototype.initRequestEvaluator (reval);
|
||||
opp = reval.getPrototype (prototype.getName ());
|
||||
parent.initRequestEvaluator (reval);
|
||||
opp = reval.getPrototype (parent.getName ());
|
||||
}
|
||||
}
|
||||
if (!"global".equalsIgnoreCase (name) && !"hopobject".equalsIgnoreCase (name) && opp == null) {
|
||||
|
|
|
@ -6,7 +6,9 @@ package helma.framework.core;
|
|||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import helma.framework.*;
|
||||
import helma.framework.extensions.*;
|
||||
import helma.scripting.*;
|
||||
import helma.scripting.fesi.*;
|
||||
import helma.scripting.fesi.extensions.*;
|
||||
import helma.xmlrpc.fesi.*;
|
||||
import helma.util.*;
|
||||
import java.util.*;
|
||||
|
@ -27,11 +29,11 @@ import FESI.Exceptions.*;
|
|||
public class RequestEvaluator implements Runnable {
|
||||
|
||||
|
||||
Application app;
|
||||
public Application app;
|
||||
protected boolean initialized;
|
||||
|
||||
RequestTrans req;
|
||||
ResponseTrans res;
|
||||
public RequestTrans req;
|
||||
public ResponseTrans res;
|
||||
|
||||
volatile Transactor rtx;
|
||||
|
||||
|
@ -46,16 +48,16 @@ public class RequestEvaluator implements Runnable {
|
|||
protected ArrayPrototype reqPath;
|
||||
private ESRequestData reqData;
|
||||
|
||||
// vars for FESI EcmaScript support
|
||||
public Evaluator evaluator;
|
||||
public ObjectPrototype esNodePrototype;
|
||||
public ObjectPrototype esUserPrototype;
|
||||
|
||||
public LruHashtable objectcache;
|
||||
Hashtable prototypes;
|
||||
// Used to cache skins within one request evaluation
|
||||
HashMap skincache;
|
||||
|
||||
// vars for FESI EcmaScript support
|
||||
protected Evaluator evaluator;
|
||||
protected ObjectPrototype esNodePrototype;
|
||||
protected ObjectPrototype esUserPrototype;
|
||||
protected LruHashtable objectcache;
|
||||
protected Hashtable prototypes;
|
||||
|
||||
GlobalObject global;
|
||||
HopExtension hopx;
|
||||
MailExtension mailx;
|
||||
|
@ -65,8 +67,8 @@ public class RequestEvaluator implements Runnable {
|
|||
"FESI.Extensions.BasicIO",
|
||||
"FESI.Extensions.FileIO",
|
||||
"helma.xmlrpc.fesi.FesiRpcExtension",
|
||||
"helma.framework.extensions.ImageExtension",
|
||||
"helma.framework.extensions.FtpExtension",
|
||||
"helma.scripting.fesi.extensions.ImageExtension",
|
||||
"helma.scripting.fesi.extensions.FtpExtension",
|
||||
"FESI.Extensions.JavaAccess",
|
||||
"FESI.Extensions.OptionalRegExp"};
|
||||
|
||||
|
@ -106,9 +108,9 @@ public class RequestEvaluator implements Runnable {
|
|||
evaluator.addExtension (extensions[i]);
|
||||
hopx = new HopExtension ();
|
||||
hopx.initializeExtension (this);
|
||||
mailx = (MailExtension) evaluator.addExtension ("helma.framework.extensions.MailExtension");
|
||||
mailx = (MailExtension) evaluator.addExtension ("helma.scripting.fesi.extensions.MailExtension");
|
||||
mailx.setProperties (this.app.props);
|
||||
Database dbx = (Database) evaluator.addExtension ("helma.framework.extensions.Database");
|
||||
Database dbx = (Database) evaluator.addExtension ("helma.scripting.fesi.extensions.Database");
|
||||
dbx.setApplication (this.app);
|
||||
|
||||
// fake a cache member like the one found in ESNodes
|
||||
|
@ -142,6 +144,7 @@ public class RequestEvaluator implements Runnable {
|
|||
try {
|
||||
do {
|
||||
|
||||
app.typemgr.checkPrototypes ();
|
||||
IPathElement root, currentElement;
|
||||
// reset skinManager
|
||||
skinmanagers = null;
|
||||
|
@ -751,7 +754,7 @@ public class RequestEvaluator implements Runnable {
|
|||
if (proto == null)
|
||||
return null;
|
||||
// First check if the skin has been already used within the execution of this request
|
||||
CompositeKey key = new CompositeKey (proto.getName(), skinname);
|
||||
SkinKey key = new SkinKey (proto.getName(), skinname);
|
||||
Skin skin = (Skin) skincache.get (key);
|
||||
if (skin != null) {
|
||||
return skin;
|
||||
|
@ -775,7 +778,7 @@ public class RequestEvaluator implements Runnable {
|
|||
return skin;
|
||||
}
|
||||
// still not found. See if there is a parent prototype which might define the skin
|
||||
proto = proto.getPrototype ();
|
||||
proto = proto.getParentPrototype ();
|
||||
} while (proto != null);
|
||||
// looked every where, nothing to be found
|
||||
return null;
|
||||
|
@ -932,18 +935,18 @@ public class RequestEvaluator implements Runnable {
|
|||
prototypes.put (protoName, op);
|
||||
}
|
||||
|
||||
final class CompositeKey {
|
||||
final class SkinKey {
|
||||
|
||||
final String first, second;
|
||||
|
||||
public CompositeKey (String first, String second) {
|
||||
public SkinKey (String first, String second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public boolean equals (Object other) {
|
||||
try {
|
||||
CompositeKey key = (CompositeKey) other;
|
||||
SkinKey key = (SkinKey) other;
|
||||
return first.equals (key.first) && second.equals (key.second);
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
package helma.framework.core;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.*;
|
||||
import helma.framework.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.*;
|
||||
import helma.scripting.*;
|
||||
import helma.scripting.fesi.*;
|
||||
import helma.objectmodel.INode;
|
||||
import helma.objectmodel.ConcurrencyException;
|
||||
import helma.util.HtmlEncoder;
|
||||
|
@ -24,13 +25,19 @@ public class Skin {
|
|||
Object[] parts;
|
||||
Application app;
|
||||
String source;
|
||||
ESObject sandbox;
|
||||
HashSet sandbox;
|
||||
|
||||
/**
|
||||
* Create a skin without any restrictions on which macros are allowed to be called from it
|
||||
*/
|
||||
public Skin (String content, Application app) {
|
||||
this (content, app, null);
|
||||
}
|
||||
|
||||
public Skin (String content, Application app, ESObject sandbox) {
|
||||
/**
|
||||
* Create a skin with a sandbox which contains the names of macros allowed to be called
|
||||
*/
|
||||
public Skin (String content, Application app, HashSet sandbox) {
|
||||
this.app = app;
|
||||
this.sandbox = sandbox;
|
||||
parse (content);
|
||||
|
@ -110,18 +117,23 @@ public class Skin {
|
|||
for (int i=0; i<parts.length; i++) {
|
||||
if (parts[i] instanceof Macro) {
|
||||
Macro m = (Macro) parts[i];
|
||||
String mname = null;
|
||||
if (m.handler == null)
|
||||
mname = m.name;
|
||||
else
|
||||
mname = m.handler+"."+m.name;
|
||||
if (macroname.equals (mname))
|
||||
if (macroname.equals (m.getFullName ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a macro to the list of allowed macros. The macro is in handler.name notation.
|
||||
*/
|
||||
public void allowMacro (String macroname) {
|
||||
if (sandbox == null) {
|
||||
sandbox = new HashSet ();
|
||||
}
|
||||
sandbox.add (macroname);
|
||||
}
|
||||
|
||||
static final int HANDLER = 0;
|
||||
static final int MACRO = 1;
|
||||
static final int PARAMNAME = 2;
|
||||
|
@ -131,8 +143,8 @@ public class Skin {
|
|||
|
||||
String handler;
|
||||
String name;
|
||||
String fullname;
|
||||
Hashtable parameters;
|
||||
boolean notallowed = false;
|
||||
|
||||
public Macro (String str) {
|
||||
|
||||
|
@ -219,24 +231,17 @@ public class Skin {
|
|||
else if (state <= MACRO)
|
||||
name = b.toString().trim();
|
||||
}
|
||||
if (sandbox != null && name != null) try {
|
||||
ESValue allow = handler == null ?
|
||||
sandbox.getProperty ("global", "global".hashCode ()) :
|
||||
sandbox.getProperty (handler, handler.hashCode ());
|
||||
allow = ((ESObject) allow).getProperty (name, name.hashCode ());
|
||||
if (allow == null || allow == ESUndefined.theUndefined)
|
||||
notallowed = true;
|
||||
} catch (Exception x) {
|
||||
notallowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the macro given a handler object
|
||||
*/
|
||||
public void render (RequestEvaluator reval, ESObject thisObject, IPathElement elem, ESObject paramObject) throws RedirectException {
|
||||
|
||||
if (notallowed) {
|
||||
if (sandbox != null && sandbox.contains (getFullName ())) {
|
||||
String h = handler == null ? "global" : handler;
|
||||
reval.res.write ("[Macro "+h+"."+name+" not allowed in sandbox]");
|
||||
reval.res.write ("[Macro "+getFullName()+" not allowed in sandbox]");
|
||||
return;
|
||||
} else if ("response".equalsIgnoreCase (handler)) {
|
||||
renderFromResponse (reval);
|
||||
|
@ -305,7 +310,7 @@ public class Skin {
|
|||
if (v != ESUndefined.theUndefined && v != ESNull.theNull)
|
||||
reval.res.write (v);
|
||||
} else {
|
||||
String msg = "[HopMacro unhandled: "+handler+"."+name+"]";
|
||||
String msg = "[HopMacro unhandled: "+getFullName()+"]";
|
||||
reval.res.write (" "+msg+" ");
|
||||
app.logEvent (msg);
|
||||
}
|
||||
|
@ -352,6 +357,10 @@ public class Skin {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for performing different kind of character encodings on the
|
||||
* macro output.
|
||||
*/
|
||||
public String encode (String text, String encoding) {
|
||||
if (encoding == null || text == null)
|
||||
return text;
|
||||
|
@ -367,8 +376,22 @@ public class Skin {
|
|||
}
|
||||
|
||||
public String toString () {
|
||||
return "[HopMacro: "+handler+","+name+"]";
|
||||
return "[HopMacro: "+getFullName()+"]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full name of the macro in handler.name notation
|
||||
*/
|
||||
public String getFullName () {
|
||||
if (fullname == null) {
|
||||
if (handler == null)
|
||||
fullname = name;
|
||||
else
|
||||
fullname = handler+"."+name;
|
||||
}
|
||||
return fullname;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -74,10 +74,29 @@ public class User implements Serializable {
|
|||
lastTouched = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
public long touched () {
|
||||
public long lastTouched () {
|
||||
return lastTouched;
|
||||
}
|
||||
|
||||
|
||||
public long onSince () {
|
||||
return onSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persistent user id of a registered user. This is usually the user name, or
|
||||
* null if the user is not logged in.
|
||||
*/
|
||||
public String getUID () {
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transient cache node for this user.
|
||||
*/
|
||||
public INode getCache () {
|
||||
return cache;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.*;
|
|||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.scripting.*;
|
||||
import helma.util.Updatable;
|
||||
import helma.util.SystemProperties;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
|
@ -35,7 +36,7 @@ public class ZippedAppFile implements Updatable {
|
|||
* the file has been modified or deleted.
|
||||
*/
|
||||
public boolean needsUpdate () {
|
||||
return lastmod != file.lastModified () || !file.exists ();
|
||||
return lastmod != file.lastModified ();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue