Many changes and fixes in Prototype skin management:

- Use an ordered TreeSet for prototype's repositories so we
	  know the resources we get are already in the right order.
	- Use SkinMap again for intetracking mapping the prototype's skins
	  internally after cleaning the code up a bit.
	- Add new ScriptableSkinMap object that wraps a skinmap, exposes it as
	  native JavaScript object by extending WrappedMap, and does the
	  Resource to String conversion in get().
	- Move code that loads additional skins from skinpath from
	  SkinManager.getSkinFiles() to SkinMap.loadSkinFiles()
	- Inline addSkinResource() and addCodeResource() methods into
	  checkForUpdates().
	- Make lastUpdate kind of fields volatile.
This commit is contained in:
hns 2005-06-02 12:06:57 +00:00
parent 1c9bdff6af
commit 43b1b5edd8
3 changed files with 113 additions and 143 deletions

View file

@ -23,7 +23,6 @@ import helma.util.WrappedMap;
import java.io.File;
import java.io.Serializable;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -443,7 +442,7 @@ public class ApplicationBean implements Serializable {
for (Iterator it = app.getPrototypes().iterator(); it.hasNext();) {
Prototype p = (Prototype) it.next();
Object skinmap = p.getSkinMap();
Object skinmap = p.getScriptableSkinMap();
skinz.put(p.getName(), skinmap);
skinz.put(p.getLowerCaseName(), skinmap);
}
@ -464,7 +463,7 @@ public class ApplicationBean implements Serializable {
for (Iterator it = app.getPrototypes().iterator(); it.hasNext();) {
Prototype p = (Prototype) it.next();
Object skinmap = p.getSkinMap(skinpath);
Object skinmap = p.getScriptableSkinMap(skinpath);
skinz.put(p.getName(), skinmap);
skinz.put(p.getLowerCaseName(), skinmap);
}

View file

@ -17,11 +17,12 @@
package helma.framework.core;
import helma.objectmodel.db.DbMapping;
import helma.util.SystemMap;
import helma.util.ResourceProperties;
import helma.util.WrappedMap;
import helma.framework.repository.Resource;
import helma.framework.repository.Repository;
import helma.framework.repository.ResourceTracker;
import helma.framework.repository.FileResource;
import java.io.*;
import java.util.*;
@ -47,18 +48,18 @@ public final class Prototype {
long lastChecksum = -1;
// the time at which any of the prototype's files were found updated the last time
long lastCodeUpdate = 0;
volatile long lastCodeUpdate = 0;
TreeSet code;
TreeSet skins;
HashMap trackers;
HashSet repositories;
TreeSet repositories;
// a map of this prototype's skins as raw strings
// used for exposing skins to application (script) code (via app.skinfiles).
HashMap skinMap;
SkinMap skinMap;
DbMapping dbmap;
@ -81,7 +82,7 @@ public final class Prototype {
// app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
this.app = app;
this.name = name;
repositories = new HashSet();
repositories = new TreeSet(app.getResourceComparator());
if (repository != null) {
repositories.add(repository);
}
@ -102,7 +103,7 @@ public final class Prototype {
trackers = new HashMap();
skinMap = new HashMap();
skinMap = new SkinMap();
isJavaPrototype = app.isJavaPrototype(name);
}
@ -170,10 +171,11 @@ public final class Prototype {
name.endsWith(TypeManager.skinExtension)) {
updatedResources = true;
if (name.endsWith(TypeManager.skinExtension)) {
addSkinResource(resources[i]);
skins.add(resources[i]);
} else {
addCodeResource(resources[i]);
code.add(resources[i]);
}
trackers.put(resources[i].getName(), new ResourceTracker(resources[i]));
}
}
}
@ -306,28 +308,13 @@ public final class Prototype {
return dbmap;
}
/**
* Get a Skinfile for this prototype. This only works for skins
* residing in the prototype directory, not for skin files in
* other locations or database stored skins.
*/
public Resource getSkinResource(String sname) {
return (Resource) skinMap.get(sname);
}
/**
* Get a skin for this prototype. This only works for skins
* residing in the prototype directory, not for skins files in
* other locations or database stored skins.
*/
public Skin getSkin(String sname) throws IOException {
Resource res = getSkinResource(sname);
if (res != null) {
return Skin.getSkin(res, app);
} else {
return null;
}
return skinMap.getSkin(name);
}
/**
@ -373,28 +360,6 @@ public final class Prototype {
return code.iterator();
}
/**
* Add a code resource to this prototype
*
* @param res a code resource
*/
public synchronized void addCodeResource(Resource res) {
code.add(res);
trackers.put(res.getName(), new ResourceTracker(res));
}
/**
* Add a skin resource to this prototype
*
* @param res a skin resource
*/
public synchronized void addSkinResource(Resource res) {
skins.add(res);
skinMap.put(res.getBaseName(), res);
trackers.put(res.getName(), new ResourceTracker(res));
}
/**
* Return a string representing this prototype.
*/
@ -403,68 +368,39 @@ public final class Prototype {
}
/**
* Get a map containing this prototype's skins as strings
*
*
* @return ...
* @return
*/
public SkinMap getSkinMap() {
return new SkinMap();
public Map getScriptableSkinMap() {
return new ScriptableSkinMap(new SkinMap());
}
// not yet implemented
public SkinMap getSkinMap(Object[] skinpath) {
return new SkinMap(skinpath);
/**
* Get a map containing this prototype's skins as strings, overloaded by the
* skins found in the given skinpath.
*
* @return
*/
public Map getScriptableSkinMap(Object[] skinpath) {
return new ScriptableSkinMap(new SkinMap(skinpath));
}
// a map that dynamically expands to all skins in this prototype
final class SkinMap extends SystemMap {
long lastSkinmapLoad = -1;
Object[] skinpath;
/**
* A map of this prototype's skins that acts as a native JavaScript object in
* rhino and returns the skins as strings. This is used to expose the skins
* to JavaScript in app.skinfiles[prototypeName][skinName].
*/
class ScriptableSkinMap extends WrappedMap {
SkinMap() {
super();
skinpath = null;
}
SkinMap(Object[] path) {
super();
skinpath = path;
}
public boolean containsKey(Object key) {
checkForUpdates();
return super.containsKey(key);
}
public boolean containsValue(Object value) {
checkForUpdates();
return super.containsValue(value);
}
public Set entrySet() {
checkForUpdates();
return super.entrySet();
}
public boolean equals(Object obj) {
checkForUpdates();
return super.equals(obj);
public ScriptableSkinMap(Map wrapped) {
super(wrapped);
}
public Object get(Object key) {
if (key == null) {
return null;
}
checkForUpdates();
Resource res = (Resource) super.get(key);
if (res == null) {
if (res == null || !res.exists()) {
return null;
}
@ -474,22 +410,70 @@ public final class Prototype {
return null;
}
}
}
/**
* A Map that dynamically expands to all skins in this prototype.
*/
class SkinMap extends HashMap {
volatile long lastSkinmapLoad = -1;
Object[] skinpath;
SkinMap() {
skinpath = null;
}
SkinMap(Object[] path) {
skinpath = path;
}
public boolean containsKey(Object key) {
checkForUpdates();
return super.containsKey(key);
}
public boolean containsValue(Object value) {
checkForUpdates();
return super.containsValue(value);
}
public Set entrySet() {
checkForUpdates();
return super.entrySet();
}
public boolean equals(Object obj) {
checkForUpdates();
return super.equals(obj);
}
public Skin getSkin(Object key) throws IOException {
Resource res = (Resource) super.get(key);
if (res != null) {
return Skin.getSkin(res, app);
} else {
return null;
}
}
public Object get(Object key) {
checkForUpdates();
return super.get(key);
}
public int hashCode() {
checkForUpdates();
return super.hashCode();
}
public boolean isEmpty() {
checkForUpdates();
return super.isEmpty();
}
public Set keySet() {
checkForUpdates();
return super.keySet();
}
@ -505,19 +489,16 @@ public final class Prototype {
public Object remove(Object key) {
checkForUpdates();
return super.remove(key);
}
public int size() {
checkForUpdates();
return super.size();
}
public Collection values() {
checkForUpdates();
return super.values();
}
@ -527,11 +508,11 @@ public final class Prototype {
// if prototype resources haven't been checked yet, check them now
Prototype.this.checkForUpdates();
}
load();
loadSkins();
}
}
private synchronized void load() {
private synchronized void loadSkins() {
if (lastCodeUpdate == lastSkinmapLoad) {
return;
}
@ -541,7 +522,6 @@ public final class Prototype {
// load Skins
for (Iterator i = skins.iterator(); i.hasNext();) {
Resource res = (Resource) i.next();
super.put(res.getBaseName(), res);
}
@ -549,12 +529,7 @@ public final class Prototype {
if (skinpath != null) {
for (int i = skinpath.length - 1; i >= 0; i--) {
if ((skinpath[i] != null) && skinpath[i] instanceof String) {
Map m = app.skinmgr.getSkinFiles((String) skinpath[i],
Prototype.this);
if (m != null) {
super.putAll(m);
}
loadSkinFiles((String) skinpath[i]);
}
}
}
@ -562,6 +537,31 @@ public final class Prototype {
lastSkinmapLoad = lastCodeUpdate;
}
private void loadSkinFiles(String skinDir) {
File dir = new File(skinDir.toString(), Prototype.this.getName());
// if directory does not exist use lower case property name
if (!dir.isDirectory()) {
dir = new File(skinDir.toString(), Prototype.this.getLowerCaseName());
if (!dir.isDirectory()) {
return;
}
}
String[] skinNames = dir.list(app.skinmgr);
if ((skinNames == null) || (skinNames.length == 0)) {
return;
}
for (int i = 0; i < skinNames.length; i++) {
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
File file = new File(dir, skinNames[i]);
super.put(name, (new FileResource(file)));
}
}
public String toString() {
return "[SkinMap " + name + "]";
}

View file

@ -20,7 +20,6 @@ import helma.objectmodel.INode;
import helma.framework.repository.FileResource;
import java.io.*;
import java.util.*;
/**
* Manages skins for a Helma application
@ -121,34 +120,6 @@ public final class SkinManager implements FilenameFilter {
return null;
}
protected Map getSkinFiles(String skinDir, Prototype proto) {
File dir = new File(skinDir.toString(), proto.getName());
// if directory does not exist use lower case property name
if (!dir.isDirectory()) {
dir = new File(skinDir.toString(), proto.getLowerCaseName());
if (!dir.isDirectory()) {
return null;
}
}
String[] skinNames = dir.list(this);
if ((skinNames == null) || (skinNames.length == 0)) {
return null;
}
HashMap map = new HashMap();
for (int i = 0; i < skinNames.length; i++) {
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
File file = new File(dir, skinNames[i]);
map.put(name, (new FileResource(file)));
}
return map;
}
/**
* Implements java.io.FilenameFilter.accept()
*/