Remove cache replication functionality including the underlying RMI networking code, make Node not serializable and Node.nmgr final, and resurrect TransientNode for use in sessions.
This commit is contained in:
parent
e1354889ec
commit
fc1d8dfb26
12 changed files with 1324 additions and 495 deletions
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.framework.core;
|
|
||||||
|
|
||||||
import helma.framework.*;
|
|
||||||
import helma.objectmodel.db.*;
|
|
||||||
import java.rmi.*;
|
|
||||||
import java.rmi.server.*;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy class for Aplication that listens to requests via RMI.
|
|
||||||
*/
|
|
||||||
public class RemoteApplication extends UnicastRemoteObject implements IRemoteApp,
|
|
||||||
IReplicationListener {
|
|
||||||
Application app;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new RemoteApplication object.
|
|
||||||
*
|
|
||||||
* @param app ...
|
|
||||||
*
|
|
||||||
* @throws RemoteException ...
|
|
||||||
*/
|
|
||||||
public RemoteApplication(Application app) throws RemoteException {
|
|
||||||
this.app = app;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ping method to let clients know if the server is reachable
|
|
||||||
*/
|
|
||||||
public void ping() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a request coming in from a web client.
|
|
||||||
*/
|
|
||||||
public ResponseTrans execute(RequestTrans req) {
|
|
||||||
return app.execute(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update HopObjects in this application's cache. This is used to replicate
|
|
||||||
* application caches in a distributed app environment
|
|
||||||
*/
|
|
||||||
public void replicateCache(Vector add, Vector delete) {
|
|
||||||
if (!"true".equalsIgnoreCase(app.getProperty("allowReplication"))) {
|
|
||||||
app.logEvent("Rejecting cache replication event: allowReplication property is not set to true");
|
|
||||||
throw new RuntimeException("Replication event rejected: setup does not allow replication.");
|
|
||||||
}
|
|
||||||
|
|
||||||
app.nmgr.replicateCache(add, delete);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -67,7 +67,7 @@ public class Session implements Serializable {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.uid = null;
|
this.uid = null;
|
||||||
this.userHandle = null;
|
this.userHandle = null;
|
||||||
cacheNode = new Node("session", null, app.getWrappedNodeManager());
|
cacheNode = new TransientNode("session");
|
||||||
onSince = System.currentTimeMillis();
|
onSince = System.currentTimeMillis();
|
||||||
lastTouched = lastModified = onSince;
|
lastTouched = lastModified = onSince;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.mortbay.jetty.servlet.ServletHandler;
|
||||||
import org.mortbay.jetty.servlet.ServletHolder;
|
import org.mortbay.jetty.servlet.ServletHolder;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.rmi.*;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import helma.util.ResourceProperties;
|
import helma.util.ResourceProperties;
|
||||||
import helma.servlet.EmbeddedServletClient;
|
import helma.servlet.EmbeddedServletClient;
|
||||||
|
@ -41,7 +40,6 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
private Hashtable descriptors;
|
private Hashtable descriptors;
|
||||||
private Hashtable applications;
|
private Hashtable applications;
|
||||||
private Hashtable xmlrpcHandlers;
|
private Hashtable xmlrpcHandlers;
|
||||||
private int rmiPort;
|
|
||||||
private ResourceProperties props;
|
private ResourceProperties props;
|
||||||
private Server server;
|
private Server server;
|
||||||
private long lastModified;
|
private long lastModified;
|
||||||
|
@ -54,23 +52,9 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
* @param props the properties defining the running apps
|
* @param props the properties defining the running apps
|
||||||
* @param server the server instance
|
* @param server the server instance
|
||||||
*/
|
*/
|
||||||
public ApplicationManager(ResourceProperties props,
|
public ApplicationManager(ResourceProperties props, Server server) {
|
||||||
Server server) {
|
|
||||||
this(props, server, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ApplicationManager object.
|
|
||||||
*
|
|
||||||
* @param props the properties defining the running apps
|
|
||||||
* @param server the server instance
|
|
||||||
* @param port The RMI port we're binding to
|
|
||||||
*/
|
|
||||||
public ApplicationManager(ResourceProperties props,
|
|
||||||
Server server, int port) {
|
|
||||||
this.props = props;
|
this.props = props;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.rmiPort = port;
|
|
||||||
descriptors = new Hashtable();
|
descriptors = new Hashtable();
|
||||||
applications = new Hashtable();
|
applications = new Hashtable();
|
||||||
xmlrpcHandlers = new Hashtable();
|
xmlrpcHandlers = new Hashtable();
|
||||||
|
@ -488,11 +472,6 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
try {
|
try {
|
||||||
getLogger().info("Binding application " + appName + " :: " + app.hashCode() + " :: " + this.hashCode());
|
getLogger().info("Binding application " + appName + " :: " + app.hashCode() + " :: " + this.hashCode());
|
||||||
|
|
||||||
// bind to RMI server
|
|
||||||
if (rmiPort > 0) {
|
|
||||||
Naming.rebind("//:" + rmiPort + "/" + appName, new RemoteApplication(app));
|
|
||||||
}
|
|
||||||
|
|
||||||
// set application URL prefix if it isn't set in app.properties
|
// set application URL prefix if it isn't set in app.properties
|
||||||
if (!app.hasExplicitBaseURI()) {
|
if (!app.hasExplicitBaseURI()) {
|
||||||
app.setBaseURI(mountpoint);
|
app.setBaseURI(mountpoint);
|
||||||
|
@ -594,11 +573,6 @@ public class ApplicationManager implements XmlRpcHandler {
|
||||||
getLogger().info("Unbinding application " + appName);
|
getLogger().info("Unbinding application " + appName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// unbind from RMI server
|
|
||||||
if (rmiPort > 0) {
|
|
||||||
Naming.unbind("//:" + rmiPort + "/" + appName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// unbind from Jetty HTTP server
|
// unbind from Jetty HTTP server
|
||||||
if (jetty != null) {
|
if (jetty != null) {
|
||||||
if (appContext != null) {
|
if (appContext != null) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class Server implements Runnable {
|
||||||
// server start time
|
// server start time
|
||||||
public final long starttime;
|
public final long starttime;
|
||||||
|
|
||||||
// if paranoid == true we only accept RMI and XML-RPC connections from
|
// if paranoid == true we only accept XML-RPC connections from
|
||||||
// explicitly listed hosts.
|
// explicitly listed hosts.
|
||||||
public boolean paranoid;
|
public boolean paranoid;
|
||||||
private ApplicationManager appManager;
|
private ApplicationManager appManager;
|
||||||
|
@ -205,14 +205,6 @@ public class Server implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.hasRmiPort() && sysProps.getProperty("rmiPort") != null) {
|
|
||||||
try {
|
|
||||||
config.setRmiPort(getInetSocketAddress(sysProps.getProperty("rmiPort")));
|
|
||||||
} catch (Exception portx) {
|
|
||||||
throw new Exception("Error parsing RMI server port property from server.properties: " + portx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.hasXmlrpcPort() && sysProps.getProperty("xmlrpcPort") != null) {
|
if (!config.hasXmlrpcPort() && sysProps.getProperty("xmlrpcPort") != null) {
|
||||||
try {
|
try {
|
||||||
config.setXmlrpcPort(getInetSocketAddress(sysProps.getProperty("xmlrpcPort")));
|
config.setXmlrpcPort(getInetSocketAddress(sysProps.getProperty("xmlrpcPort")));
|
||||||
|
@ -238,12 +230,6 @@ public class Server implements Runnable {
|
||||||
config.setPropFile(new File(args[++i]));
|
config.setPropFile(new File(args[++i]));
|
||||||
} else if (args[i].equals("-a") && ((i + 1) < args.length)) {
|
} else if (args[i].equals("-a") && ((i + 1) < args.length)) {
|
||||||
config.setApps(StringUtils.split(args[++i]));
|
config.setApps(StringUtils.split(args[++i]));
|
||||||
} else if (args[i].equals("-p") && ((i + 1) < args.length)) {
|
|
||||||
try {
|
|
||||||
config.setRmiPort(getInetSocketAddress(args[++i]));
|
|
||||||
} catch (Exception portx) {
|
|
||||||
throw new Exception("Error parsing RMI server port property: " + portx);
|
|
||||||
}
|
|
||||||
} else if (args[i].equals("-x") && ((i + 1) < args.length)) {
|
} else if (args[i].equals("-x") && ((i + 1) < args.length)) {
|
||||||
try {
|
try {
|
||||||
config.setXmlrpcPort(getInetSocketAddress(args[++i]));
|
config.setXmlrpcPort(getInetSocketAddress(args[++i]));
|
||||||
|
@ -335,7 +321,6 @@ public class Server implements Runnable {
|
||||||
System.out.println(" -w [ip:]port Specify embedded web server address/port");
|
System.out.println(" -w [ip:]port Specify embedded web server address/port");
|
||||||
System.out.println(" -x [ip:]port Specify XML-RPC address/port");
|
System.out.println(" -x [ip:]port Specify XML-RPC address/port");
|
||||||
System.out.println(" -jk [ip:]port Specify AJP13 address/port");
|
System.out.println(" -jk [ip:]port Specify AJP13 address/port");
|
||||||
System.out.println(" -p [ip:]port Specify RMI address/port");
|
|
||||||
System.out.println("");
|
System.out.println("");
|
||||||
System.out.println("Supported formats for server ports:");
|
System.out.println("Supported formats for server ports:");
|
||||||
System.out.println(" <port-number>");
|
System.out.println(" <port-number>");
|
||||||
|
@ -359,10 +344,6 @@ public class Server implements Runnable {
|
||||||
checkPort(config.getWebsrvPort());
|
checkPort(config.getWebsrvPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.hasRmiPort()) {
|
|
||||||
checkPort(config.getRmiPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.hasXmlrpcPort()) {
|
if (config.hasXmlrpcPort()) {
|
||||||
checkPort(config.getXmlrpcPort());
|
checkPort(config.getXmlrpcPort());
|
||||||
}
|
}
|
||||||
|
@ -588,34 +569,7 @@ public class Server implements Runnable {
|
||||||
logger.info("Starting XML-RPC server on port " + (xmlrpcPort));
|
logger.info("Starting XML-RPC server on port " + (xmlrpcPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.hasRmiPort()) {
|
appManager = new ApplicationManager(appsProps, this);
|
||||||
InetSocketAddress rmiPort = config.getRmiPort();
|
|
||||||
if (paranoid) {
|
|
||||||
HelmaSocketFactory factory = new HelmaSocketFactory();
|
|
||||||
String rallow = sysProps.getProperty("allowWeb");
|
|
||||||
if (rallow == null) {
|
|
||||||
rallow = sysProps.getProperty("allowRMI");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rallow != null) {
|
|
||||||
StringTokenizer st = new StringTokenizer(rallow, " ,;");
|
|
||||||
|
|
||||||
while (st.hasMoreTokens())
|
|
||||||
factory.addAddress(st.nextToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
RMISocketFactory.setSocketFactory(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Starting RMI server on port " + rmiPort);
|
|
||||||
LocateRegistry.createRegistry(rmiPort.getPort());
|
|
||||||
|
|
||||||
// create application manager which binds to the given RMI port
|
|
||||||
appManager = new ApplicationManager(appsProps, this, rmiPort.getPort());
|
|
||||||
} else {
|
|
||||||
// create application manager without RMI port
|
|
||||||
appManager = new ApplicationManager(appsProps, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xmlrpc != null) {
|
if (xmlrpc != null) {
|
||||||
xmlrpc.addHandler("$default", appManager);
|
xmlrpc.addHandler("$default", appManager);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.net.InetSocketAddress;
|
||||||
|
|
||||||
public class ServerConfig {
|
public class ServerConfig {
|
||||||
|
|
||||||
private InetSocketAddress rmiPort = null;
|
|
||||||
private InetSocketAddress xmlrpcPort = null;
|
private InetSocketAddress xmlrpcPort = null;
|
||||||
private InetSocketAddress websrvPort = null;
|
private InetSocketAddress websrvPort = null;
|
||||||
private InetSocketAddress ajp13Port = null;
|
private InetSocketAddress ajp13Port = null;
|
||||||
|
@ -46,10 +45,6 @@ public class ServerConfig {
|
||||||
return (homeDir != null);
|
return (homeDir != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRmiPort() {
|
|
||||||
return (rmiPort != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasXmlrpcPort() {
|
public boolean hasXmlrpcPort() {
|
||||||
return (xmlrpcPort != null);
|
return (xmlrpcPort != null);
|
||||||
}
|
}
|
||||||
|
@ -66,14 +61,6 @@ public class ServerConfig {
|
||||||
return (apps != null);
|
return (apps != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetSocketAddress getRmiPort() {
|
|
||||||
return rmiPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRmiPort(InetSocketAddress rmiPort) {
|
|
||||||
this.rmiPort = rmiPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InetSocketAddress getXmlrpcPort() {
|
public InetSocketAddress getXmlrpcPort() {
|
||||||
return xmlrpcPort;
|
return xmlrpcPort;
|
||||||
}
|
}
|
||||||
|
|
950
src/helma/objectmodel/TransientNode.java
Normal file
950
src/helma/objectmodel/TransientNode.java
Normal file
|
@ -0,0 +1,950 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.objectmodel;
|
||||||
|
|
||||||
|
import helma.framework.IPathElement;
|
||||||
|
import helma.objectmodel.db.DbMapping;
|
||||||
|
import helma.objectmodel.db.Relation;
|
||||||
|
import helma.objectmodel.db.Node;
|
||||||
|
import helma.util.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transient implementation of INode. An instance of this class can't be
|
||||||
|
* made persistent by reachability from a persistent node. To make a persistent-capable
|
||||||
|
* object, class helma.objectmodel.db.Node has to be used.
|
||||||
|
*/
|
||||||
|
public class TransientNode implements INode, Serializable {
|
||||||
|
private static long idgen = 0;
|
||||||
|
protected Hashtable propMap;
|
||||||
|
protected Hashtable nodeMap;
|
||||||
|
protected Vector nodes;
|
||||||
|
protected TransientNode parent;
|
||||||
|
protected Vector links; // links to this node
|
||||||
|
protected Vector proplinks; // nodes using this node as property
|
||||||
|
transient String prototype;
|
||||||
|
protected long created;
|
||||||
|
protected long lastmodified;
|
||||||
|
protected String id;
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
// is the main identity a named property or an anonymous node in a collection?
|
||||||
|
protected boolean anonymous = false;
|
||||||
|
transient DbMapping dbmap;
|
||||||
|
INode cacheNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new TransientNode object.
|
||||||
|
*/
|
||||||
|
public TransientNode() {
|
||||||
|
id = generateID();
|
||||||
|
name = id;
|
||||||
|
created = lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a new TransientNode object with a given name
|
||||||
|
*/
|
||||||
|
public TransientNode(String n) {
|
||||||
|
id = generateID();
|
||||||
|
name = ((n == null) || "".equals(n)) ? id : n;
|
||||||
|
created = lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public static String generateID() {
|
||||||
|
// make transient ids differ from persistent ones
|
||||||
|
// and are unique within on runtime session
|
||||||
|
return "t" + idgen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param dbmap ...
|
||||||
|
*/
|
||||||
|
public void setDbMapping(DbMapping dbmap) {
|
||||||
|
this.dbmap = dbmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public DbMapping getDbMapping() {
|
||||||
|
return dbmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* navigation-related
|
||||||
|
*/
|
||||||
|
public String getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean isAnonymous() {
|
||||||
|
return anonymous;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getElementName() {
|
||||||
|
return anonymous ? id : name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public int getState() {
|
||||||
|
return TRANSIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param s ...
|
||||||
|
*/
|
||||||
|
public void setState(int s) {
|
||||||
|
// state always is TRANSIENT on this kind of node
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getFullName() {
|
||||||
|
return getFullName(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param root ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getFullName(INode root) {
|
||||||
|
String divider = null;
|
||||||
|
StringBuffer b = new StringBuffer();
|
||||||
|
TransientNode p = this;
|
||||||
|
|
||||||
|
while ((p != null) && (p.parent != null) && (p != root)) {
|
||||||
|
if (divider != null) {
|
||||||
|
b.insert(0, divider);
|
||||||
|
} else {
|
||||||
|
divider = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
b.insert(0, p.getElementName());
|
||||||
|
p = p.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param name ...
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
// if (name.indexOf('/') > -1)
|
||||||
|
// throw new RuntimeException ("The name of the node must not contain \"/\".");
|
||||||
|
if ((name == null) || (name.trim().length() == 0)) {
|
||||||
|
this.name = id;
|
||||||
|
} else {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getPrototype() {
|
||||||
|
// if prototype is null, it's a vanilla HopObject.
|
||||||
|
if (prototype == null) {
|
||||||
|
return "hopobject";
|
||||||
|
}
|
||||||
|
|
||||||
|
return prototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param proto ...
|
||||||
|
*/
|
||||||
|
public void setPrototype(String proto) {
|
||||||
|
this.prototype = proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INode-related
|
||||||
|
*/
|
||||||
|
public void setSubnodeRelation(String rel) {
|
||||||
|
throw new RuntimeException("Can't set subnode relation for non-persistent Node.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getSubnodeRelation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public int numberOfNodes() {
|
||||||
|
return (nodes == null) ? 0 : nodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param elem ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode addNode(INode elem) {
|
||||||
|
return addNode(elem, numberOfNodes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param elem ...
|
||||||
|
* @param where ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode addNode(INode elem, int where) {
|
||||||
|
if ((where < 0) || (where > numberOfNodes())) {
|
||||||
|
where = numberOfNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
String n = elem.getName();
|
||||||
|
|
||||||
|
if (n.indexOf('/') > -1) {
|
||||||
|
throw new RuntimeException("The name of a node must not contain \"/\" (slash).");
|
||||||
|
}
|
||||||
|
|
||||||
|
// IServer.getLogger().log ("adding: "+node+" -- "+node.getContentLength ());
|
||||||
|
if ((nodeMap != null) && (nodeMap.get(elem.getID()) != null)) {
|
||||||
|
nodes.removeElement(elem);
|
||||||
|
where = Math.min(where, numberOfNodes());
|
||||||
|
nodes.insertElementAt(elem, where);
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeMap == null) {
|
||||||
|
nodeMap = new Hashtable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes == null) {
|
||||||
|
nodes = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeMap.put(elem.getID(), elem);
|
||||||
|
nodes.insertElementAt(elem, where);
|
||||||
|
|
||||||
|
if (elem instanceof TransientNode) {
|
||||||
|
TransientNode node = (TransientNode) elem;
|
||||||
|
|
||||||
|
if (node.parent == null) {
|
||||||
|
node.parent = this;
|
||||||
|
node.anonymous = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, node));
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode createNode() {
|
||||||
|
return createNode(null, 0); // where is ignored since this is an anonymous node
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param where ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode createNode(int where) {
|
||||||
|
return createNode(null, where);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param nm ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode createNode(String nm) {
|
||||||
|
return createNode(nm, numberOfNodes()); // where is usually ignored (if nm != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param nm ...
|
||||||
|
* @param where ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode createNode(String nm, int where) {
|
||||||
|
boolean anon = false;
|
||||||
|
|
||||||
|
if ((nm == null) || "".equals(nm.trim())) {
|
||||||
|
anon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
INode n = new TransientNode(nm);
|
||||||
|
|
||||||
|
if (anon) {
|
||||||
|
addNode(n, where);
|
||||||
|
} else {
|
||||||
|
setNode(nm, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a node that links to this node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* protected void registerLink (TransientNode from) {
|
||||||
|
if (links == null)
|
||||||
|
links = new Vector ();
|
||||||
|
if (!links.contains (from))
|
||||||
|
links.addElement (from);
|
||||||
|
} */
|
||||||
|
public IPathElement getParentElement() {
|
||||||
|
return getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param name ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public IPathElement getChildElement(String name) {
|
||||||
|
return getNode(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param name ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode getSubnode(String name) {
|
||||||
|
StringTokenizer st = new StringTokenizer(name, "/");
|
||||||
|
TransientNode retval = this;
|
||||||
|
TransientNode runner;
|
||||||
|
|
||||||
|
while (st.hasMoreTokens() && (retval != null)) {
|
||||||
|
runner = retval;
|
||||||
|
|
||||||
|
String next = st.nextToken().trim().toLowerCase();
|
||||||
|
|
||||||
|
if ("".equals(next)) {
|
||||||
|
retval = this;
|
||||||
|
} else {
|
||||||
|
retval = (runner.nodeMap == null) ? null
|
||||||
|
: (TransientNode) runner.nodeMap.get(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval == null) {
|
||||||
|
retval = (TransientNode) runner.getNode(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param index ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode getSubnodeAt(int index) {
|
||||||
|
return (nodes == null) ? null : (INode) nodes.elementAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param n ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public int contains(INode n) {
|
||||||
|
if ((n == null) || (nodes == null)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes.indexOf(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean remove() {
|
||||||
|
if (anonymous) {
|
||||||
|
parent.unset(name);
|
||||||
|
} else {
|
||||||
|
parent.removeNode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param node ...
|
||||||
|
*/
|
||||||
|
public void removeNode(INode node) {
|
||||||
|
// IServer.getLogger().log ("removing: "+ node);
|
||||||
|
releaseNode(node);
|
||||||
|
|
||||||
|
TransientNode n = (TransientNode) node;
|
||||||
|
|
||||||
|
if ((n.getParent() == this) && n.anonymous) {
|
||||||
|
int l = (n.links == null) ? 0 : n.links.size(); // notify nodes that link to n that n is going down.
|
||||||
|
|
||||||
|
for (int i = 0; i < l; i++) {
|
||||||
|
TransientNode link = (TransientNode) n.links.elementAt(i);
|
||||||
|
|
||||||
|
link.releaseNode(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.proplinks != null) {
|
||||||
|
// clean up all nodes that use n as a property
|
||||||
|
for (Enumeration e1 = n.proplinks.elements(); e1.hasMoreElements();)
|
||||||
|
try {
|
||||||
|
TransientProperty p = (TransientProperty) e1.nextElement();
|
||||||
|
|
||||||
|
p.node.propMap.remove(p.propname.toLowerCase());
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all subnodes, giving them a chance to destroy themselves.
|
||||||
|
Vector v = new Vector(); // removeElement modifies the Vector we are enumerating, so we are extra careful.
|
||||||
|
|
||||||
|
for (Enumeration e3 = n.getSubnodes(); e3.hasMoreElements();) {
|
||||||
|
v.addElement(e3.nextElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
int m = v.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
n.removeNode((TransientNode) v.elementAt(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
n.links.removeElement(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Physically" remove a subnode from the subnodes table.
|
||||||
|
* the logical stuff necessary for keeping data consistent is done elsewhere (in removeNode).
|
||||||
|
*/
|
||||||
|
protected void releaseNode(INode node) {
|
||||||
|
if ((nodes == null) || (nodeMap == null)) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int runner = nodes.indexOf(node);
|
||||||
|
|
||||||
|
// this is due to difference between .equals() and ==
|
||||||
|
while ((runner > -1) && (nodes.elementAt(runner) != node))
|
||||||
|
runner = nodes.indexOf(node, Math.min(nodes.size() - 1, runner + 1));
|
||||||
|
|
||||||
|
if (runner > -1) {
|
||||||
|
nodes.removeElementAt(runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodes.remove (node);
|
||||||
|
nodeMap.remove(node.getName().toLowerCase());
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (node, NodeEvent.NODE_REMOVED));
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_REMOVED, node));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// IServer.getLogger().log ("released node "+node +" from "+this+" oldobj = "+what);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Enumeration getSubnodes() {
|
||||||
|
return (nodes == null) ? new Vector().elements() : nodes.elements();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* property-related
|
||||||
|
*/
|
||||||
|
public Enumeration properties() {
|
||||||
|
return (propMap == null) ? new EmptyEnumeration() : propMap.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TransientProperty getProperty(String propname) {
|
||||||
|
TransientProperty prop = (propMap == null) ? null : (TransientProperty) propMap.get(propname);
|
||||||
|
|
||||||
|
// check if we have to create a virtual node
|
||||||
|
if ((prop == null) && (dbmap != null)) {
|
||||||
|
Relation rel = dbmap.getPropertyRelation(propname);
|
||||||
|
|
||||||
|
if ((rel != null) && rel.isVirtual()) {
|
||||||
|
prop = makeVirtualNode(propname, rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TransientProperty makeVirtualNode(String propname, Relation rel) {
|
||||||
|
INode node = new Node(rel.getPropName(), rel.getPrototype(),
|
||||||
|
dbmap.getWrappedNodeManager());
|
||||||
|
|
||||||
|
// node.setState (TRANSIENT);
|
||||||
|
// make a db mapping good enough that the virtual node finds its subnodes
|
||||||
|
// DbMapping dbm = new DbMapping ();
|
||||||
|
// dbm.setSubnodeRelation (rel);
|
||||||
|
// dbm.setPropertyRelation (rel);
|
||||||
|
node.setDbMapping(rel.getVirtualMapping());
|
||||||
|
setNode(propname, node);
|
||||||
|
|
||||||
|
return (TransientProperty) propMap.get(propname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public IProperty get(String propname) {
|
||||||
|
return getProperty(propname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param defaultValue ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getString(String propname, String defaultValue) {
|
||||||
|
String propValue = getString(propname);
|
||||||
|
|
||||||
|
return (propValue == null) ? defaultValue : propValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getString(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getStringValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public long getInteger(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getIntegerValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public double getFloat(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getFloatValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Date getDate(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getDateValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean getBoolean(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getBooleanValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode getNode(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getNodeValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Object getJavaObject(String propname) {
|
||||||
|
TransientProperty prop = getProperty(propname);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return prop.getJavaObjectValue();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a property if it doesn't exist for this name
|
||||||
|
private TransientProperty initProperty(String propname) {
|
||||||
|
if (propMap == null) {
|
||||||
|
propMap = new Hashtable();
|
||||||
|
}
|
||||||
|
|
||||||
|
propname = propname.trim();
|
||||||
|
TransientProperty prop = (TransientProperty) propMap.get(propname);
|
||||||
|
|
||||||
|
if (prop == null) {
|
||||||
|
prop = new TransientProperty(propname, this);
|
||||||
|
propMap.put(propname, prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setString(String propname, String value) {
|
||||||
|
// IServer.getLogger().log ("setting String prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setStringValue(value);
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setInteger(String propname, long value) {
|
||||||
|
// IServer.getLogger().log ("setting bool prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setIntegerValue(value);
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setFloat(String propname, double value) {
|
||||||
|
// IServer.getLogger().log ("setting bool prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setFloatValue(value);
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setBoolean(String propname, boolean value) {
|
||||||
|
// IServer.getLogger().log ("setting bool prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setBooleanValue(value);
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setDate(String propname, Date value) {
|
||||||
|
// IServer.getLogger().log ("setting date prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setDateValue(value);
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setJavaObject(String propname, Object value) {
|
||||||
|
// IServer.getLogger().log ("setting date prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setJavaObjectValue(value);
|
||||||
|
|
||||||
|
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setNode(String propname, INode value) {
|
||||||
|
// IServer.getLogger().log ("setting date prop");
|
||||||
|
TransientProperty prop = initProperty(propname);
|
||||||
|
|
||||||
|
prop.setNodeValue(value);
|
||||||
|
|
||||||
|
// check if the main identity of this node is as a named property
|
||||||
|
// or as an anonymous node in a collection
|
||||||
|
if (value instanceof TransientNode) {
|
||||||
|
TransientNode n = (TransientNode) value;
|
||||||
|
|
||||||
|
if (n.parent == null) {
|
||||||
|
n.name = propname;
|
||||||
|
n.parent = this;
|
||||||
|
n.anonymous = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
*/
|
||||||
|
public void unset(String propname) {
|
||||||
|
if (propMap != null && propname != null) {
|
||||||
|
propMap.remove(propname);
|
||||||
|
lastmodified = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastModified() {
|
||||||
|
return lastmodified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public long created() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "TransientNode " + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cache node for this node. This can
|
||||||
|
* be used to store transient cache data per node
|
||||||
|
* from Javascript.
|
||||||
|
*/
|
||||||
|
public synchronized INode getCacheNode() {
|
||||||
|
if (cacheNode == null) {
|
||||||
|
cacheNode = new TransientNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cacheNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the cache node for this node.
|
||||||
|
*/
|
||||||
|
public synchronized void clearCacheNode() {
|
||||||
|
cacheNode = null;
|
||||||
|
}
|
||||||
|
}
|
346
src/helma/objectmodel/TransientProperty.java
Normal file
346
src/helma/objectmodel/TransientProperty.java
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.objectmodel;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.text.*;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A property implementation for Nodes stored inside a database.
|
||||||
|
*/
|
||||||
|
public final class TransientProperty implements IProperty, Serializable {
|
||||||
|
protected String propname;
|
||||||
|
protected TransientNode node;
|
||||||
|
public String svalue;
|
||||||
|
public boolean bvalue;
|
||||||
|
public long lvalue;
|
||||||
|
public double dvalue;
|
||||||
|
public INode nvalue;
|
||||||
|
public Object jvalue;
|
||||||
|
public int type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Property object.
|
||||||
|
*
|
||||||
|
* @param node ...
|
||||||
|
*/
|
||||||
|
public TransientProperty(TransientNode node) {
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Property object.
|
||||||
|
*
|
||||||
|
* @param propname ...
|
||||||
|
* @param node ...
|
||||||
|
*/
|
||||||
|
public TransientProperty(String propname, TransientNode node) {
|
||||||
|
this.propname = propname;
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return propname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Object getValue() {
|
||||||
|
switch (type) {
|
||||||
|
case STRING:
|
||||||
|
return svalue;
|
||||||
|
|
||||||
|
case BOOLEAN:
|
||||||
|
return new Boolean(bvalue);
|
||||||
|
|
||||||
|
case INTEGER:
|
||||||
|
return new Long(lvalue);
|
||||||
|
|
||||||
|
case FLOAT:
|
||||||
|
return new Double(dvalue);
|
||||||
|
|
||||||
|
case DATE:
|
||||||
|
return new Date(lvalue);
|
||||||
|
|
||||||
|
case NODE:
|
||||||
|
return nvalue;
|
||||||
|
|
||||||
|
case JAVAOBJECT:
|
||||||
|
return jvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setStringValue(String value) {
|
||||||
|
if (type == NODE) {
|
||||||
|
this.nvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
this.jvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = STRING;
|
||||||
|
this.svalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setIntegerValue(long value) {
|
||||||
|
if (type == NODE) {
|
||||||
|
this.nvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
this.jvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = INTEGER;
|
||||||
|
this.lvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setFloatValue(double value) {
|
||||||
|
if (type == NODE) {
|
||||||
|
this.nvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
this.jvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = FLOAT;
|
||||||
|
this.dvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setDateValue(Date value) {
|
||||||
|
if (type == NODE) {
|
||||||
|
this.nvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
this.jvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = DATE;
|
||||||
|
this.lvalue = value.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setBooleanValue(boolean value) {
|
||||||
|
if (type == NODE) {
|
||||||
|
this.nvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
this.jvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = BOOLEAN;
|
||||||
|
this.bvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setNodeValue(INode value) {
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
this.jvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = NODE;
|
||||||
|
this.nvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param value ...
|
||||||
|
*/
|
||||||
|
public void setJavaObjectValue(Object value) {
|
||||||
|
if (type == NODE) {
|
||||||
|
this.nvalue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = JAVAOBJECT;
|
||||||
|
this.jvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String getStringValue() {
|
||||||
|
switch (type) {
|
||||||
|
case STRING:
|
||||||
|
return svalue;
|
||||||
|
|
||||||
|
case BOOLEAN:
|
||||||
|
return "" + bvalue;
|
||||||
|
|
||||||
|
case DATE:
|
||||||
|
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
return format.format(new Date(lvalue));
|
||||||
|
|
||||||
|
case INTEGER:
|
||||||
|
return Long.toString(lvalue);
|
||||||
|
|
||||||
|
case FLOAT:
|
||||||
|
return Double.toString(dvalue);
|
||||||
|
|
||||||
|
case NODE:
|
||||||
|
return nvalue.getName();
|
||||||
|
|
||||||
|
case JAVAOBJECT:
|
||||||
|
return (jvalue == null) ? null : jvalue.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return getStringValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public long getIntegerValue() {
|
||||||
|
if (type == INTEGER) {
|
||||||
|
return lvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public double getFloatValue() {
|
||||||
|
if (type == FLOAT) {
|
||||||
|
return dvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Date getDateValue() {
|
||||||
|
if (type == DATE) {
|
||||||
|
return new Date(lvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean getBooleanValue() {
|
||||||
|
if (type == BOOLEAN) {
|
||||||
|
return bvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public INode getNodeValue() {
|
||||||
|
if (type == NODE) {
|
||||||
|
return nvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Object getJavaObjectValue() {
|
||||||
|
if (type == JAVAOBJECT) {
|
||||||
|
return jvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,9 +117,6 @@ public final class DbMapping {
|
||||||
// timestamp of last modification of an object of this type
|
// timestamp of last modification of an object of this type
|
||||||
long lastDataChange = 0;
|
long lastDataChange = 0;
|
||||||
|
|
||||||
// evict objects of this type when received via replication
|
|
||||||
private boolean evictOnReplication;
|
|
||||||
|
|
||||||
// Set of mappings that depend on us and should be forwarded last data change events
|
// Set of mappings that depend on us and should be forwarded last data change events
|
||||||
HashSet dependentMappings = new HashSet();
|
HashSet dependentMappings = new HashSet();
|
||||||
|
|
||||||
|
@ -229,7 +226,6 @@ public final class DbMapping {
|
||||||
idField = props.getProperty("_id");
|
idField = props.getProperty("_id");
|
||||||
nameField = props.getProperty("_name");
|
nameField = props.getProperty("_name");
|
||||||
protoField = props.getProperty("_prototype");
|
protoField = props.getProperty("_prototype");
|
||||||
evictOnReplication = "true".equals(props.getProperty("_evictOnReplication"));
|
|
||||||
|
|
||||||
parentSetting = props.getProperty("_parent");
|
parentSetting = props.getProperty("_parent");
|
||||||
if (parentSetting != null) {
|
if (parentSetting != null) {
|
||||||
|
@ -594,14 +590,6 @@ public final class DbMapping {
|
||||||
return protoField;
|
return protoField;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should objects of this type be evicted/discarded/reloaded when received via
|
|
||||||
* cache replication?
|
|
||||||
*/
|
|
||||||
public boolean evictOnReplication() {
|
|
||||||
return evictOnReplication;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate a database column name to an object property name according to this mapping.
|
* Translate a database column name to an object property name according to this mapping.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.objectmodel.db;
|
|
||||||
|
|
||||||
import java.rmi.Remote;
|
|
||||||
import java.rmi.RemoteException;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RMI interface for an application. Currently only execute is used and supported.
|
|
||||||
*/
|
|
||||||
public interface IReplicationListener extends Remote {
|
|
||||||
/**
|
|
||||||
* Update HopObjects in this application's cache. This is used to replicate
|
|
||||||
* application caches in a distributed app environment
|
|
||||||
*/
|
|
||||||
public void replicateCache(Vector add, Vector delete)
|
|
||||||
throws RemoteException;
|
|
||||||
}
|
|
|
@ -34,8 +34,7 @@ import java.util.*;
|
||||||
* An implementation of INode that can be stored in the internal database or
|
* An implementation of INode that can be stored in the internal database or
|
||||||
* an external relational database.
|
* an external relational database.
|
||||||
*/
|
*/
|
||||||
public final class Node implements INode, Serializable {
|
public final class Node implements INode {
|
||||||
static final long serialVersionUID = -3740339688506633675L;
|
|
||||||
|
|
||||||
// The handle to the node's parent
|
// The handle to the node's parent
|
||||||
protected NodeHandle parentHandle;
|
protected NodeHandle parentHandle;
|
||||||
|
@ -60,7 +59,7 @@ public final class Node implements INode, Serializable {
|
||||||
private transient String prototype;
|
private transient String prototype;
|
||||||
private transient NodeHandle handle;
|
private transient NodeHandle handle;
|
||||||
private transient INode cacheNode;
|
private transient INode cacheNode;
|
||||||
transient volatile WrappedNodeManager nmgr;
|
transient final WrappedNodeManager nmgr;
|
||||||
transient DbMapping dbmap;
|
transient DbMapping dbmap;
|
||||||
transient Key primaryKey = null;
|
transient Key primaryKey = null;
|
||||||
transient String subnodeRelation = null;
|
transient String subnodeRelation = null;
|
||||||
|
@ -70,14 +69,6 @@ public final class Node implements INode, Serializable {
|
||||||
transient private volatile int state;
|
transient private volatile int state;
|
||||||
private static long idgen = 0;
|
private static long idgen = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty, uninitialized Node. The init() method must be called on the
|
|
||||||
* Node before it can do anything useful.
|
|
||||||
*/
|
|
||||||
protected Node() {
|
|
||||||
created = lastmodified = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty, uninitialized Node with the given create and modify time.
|
* Creates an empty, uninitialized Node with the given create and modify time.
|
||||||
* This is used for null-node references in the node cache.
|
* This is used for null-node references in the node cache.
|
||||||
|
@ -85,6 +76,19 @@ public final class Node implements INode, Serializable {
|
||||||
*/
|
*/
|
||||||
protected Node(long timestamp) {
|
protected Node(long timestamp) {
|
||||||
created = lastmodified = timestamp;
|
created = lastmodified = timestamp;
|
||||||
|
this.nmgr = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty, uninitialized Node. The init() method must be called on the
|
||||||
|
* Node before it can do anything useful.
|
||||||
|
*/
|
||||||
|
protected Node(WrappedNodeManager nmgr) {
|
||||||
|
if (nmgr == null) {
|
||||||
|
throw new NullPointerException("nmgr");
|
||||||
|
}
|
||||||
|
this.nmgr = nmgr;
|
||||||
|
created = lastmodified = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,10 +97,14 @@ public final class Node implements INode, Serializable {
|
||||||
* Also used by embedded database to re-create an existing Node.
|
* Also used by embedded database to re-create an existing Node.
|
||||||
*/
|
*/
|
||||||
public Node(String name, String id, String prototype, WrappedNodeManager nmgr) {
|
public Node(String name, String id, String prototype, WrappedNodeManager nmgr) {
|
||||||
|
if (nmgr == null) {
|
||||||
|
throw new NullPointerException("nmgr");
|
||||||
|
}
|
||||||
|
this.nmgr = nmgr;
|
||||||
if (prototype == null) {
|
if (prototype == null) {
|
||||||
prototype = "HopObject";
|
prototype = "HopObject";
|
||||||
}
|
}
|
||||||
init(nmgr.getDbMapping(prototype), id, name, prototype, null, nmgr);
|
init(nmgr.getDbMapping(prototype), id, name, prototype, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,12 +170,8 @@ public final class Node implements INode, Serializable {
|
||||||
/**
|
/**
|
||||||
* Initializer used for nodes being instanced from an embedded or relational database.
|
* Initializer used for nodes being instanced from an embedded or relational database.
|
||||||
*/
|
*/
|
||||||
public synchronized void init(DbMapping dbm, String id, String name, String prototype,
|
public synchronized void init(DbMapping dbm, String id, String name,
|
||||||
Hashtable propMap, WrappedNodeManager nmgr) {
|
String prototype, Hashtable propMap) {
|
||||||
if (nmgr == null) {
|
|
||||||
throw new NullPointerException("nmgr");
|
|
||||||
}
|
|
||||||
this.nmgr = nmgr;
|
|
||||||
this.dbmap = dbm;
|
this.dbmap = dbm;
|
||||||
this.prototype = prototype;
|
this.prototype = prototype;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -187,67 +191,6 @@ public final class Node implements INode, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Read this object instance from a stream. This does some smart conversion to
|
|
||||||
* update from previous serialization formats.
|
|
||||||
*/
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException {
|
|
||||||
try {
|
|
||||||
// as a general rule of thumb, if a string can be null use read/writeObject,
|
|
||||||
// if not it's save to use read/writeUTF.
|
|
||||||
// version indicates the serialization version
|
|
||||||
version = in.readShort();
|
|
||||||
|
|
||||||
if (version < 9) {
|
|
||||||
throw new IOException("Can't read pre 1.3.0 HopObject");
|
|
||||||
}
|
|
||||||
|
|
||||||
id = (String) in.readObject();
|
|
||||||
name = (String) in.readObject();
|
|
||||||
state = in.readInt();
|
|
||||||
parentHandle = (NodeHandle) in.readObject();
|
|
||||||
created = in.readLong();
|
|
||||||
lastmodified = in.readLong();
|
|
||||||
|
|
||||||
subnodes = (SubnodeList) in.readObject();
|
|
||||||
// left-over from links vector
|
|
||||||
in.readObject();
|
|
||||||
propMap = (Hashtable) in.readObject();
|
|
||||||
anonymous = in.readBoolean();
|
|
||||||
prototype = (String) in.readObject();
|
|
||||||
|
|
||||||
} catch (ClassNotFoundException x) {
|
|
||||||
throw new IOException(x.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write out this instance to a stream
|
|
||||||
*/
|
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
|
||||||
out.writeShort(9); // serialization version
|
|
||||||
out.writeObject(id);
|
|
||||||
out.writeObject(name);
|
|
||||||
out.writeInt(state);
|
|
||||||
out.writeObject(parentHandle);
|
|
||||||
out.writeLong(created);
|
|
||||||
out.writeLong(lastmodified);
|
|
||||||
|
|
||||||
DbMapping smap = (dbmap == null) ? null : dbmap.getSubnodeMapping();
|
|
||||||
|
|
||||||
if (smap != null && smap.isRelational()) {
|
|
||||||
out.writeObject(null);
|
|
||||||
} else {
|
|
||||||
out.writeObject(subnodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// left-over from links vector
|
|
||||||
out.writeObject(null);
|
|
||||||
out.writeObject(propMap);
|
|
||||||
out.writeBoolean(anonymous);
|
|
||||||
out.writeObject(prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used by Xml deserialization
|
* used by Xml deserialization
|
||||||
*/
|
*/
|
||||||
|
@ -1710,9 +1653,6 @@ public final class Node implements INode, Serializable {
|
||||||
if (n != null) {
|
if (n != null) {
|
||||||
// do set DbMapping for embedded db collection nodes
|
// do set DbMapping for embedded db collection nodes
|
||||||
n.setDbMapping(rel.getVirtualMapping());
|
n.setDbMapping(rel.getVirtualMapping());
|
||||||
// also set node manager in case this is a mountpoint node
|
|
||||||
// that came in through replication
|
|
||||||
n.nmgr = nmgr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@ public final class NodeManager {
|
||||||
protected IDGenerator idgen;
|
protected IDGenerator idgen;
|
||||||
private boolean logSql;
|
private boolean logSql;
|
||||||
private Log sqlLog = null;
|
private Log sqlLog = null;
|
||||||
protected boolean logReplication;
|
|
||||||
private ArrayList listeners = new ArrayList();
|
private ArrayList listeners = new ArrayList();
|
||||||
|
|
||||||
// a wrapper that catches some Exceptions while accessing this NM
|
// a wrapper that catches some Exceptions while accessing this NM
|
||||||
|
@ -77,19 +76,6 @@ public final class NodeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
||||||
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
|
|
||||||
|
|
||||||
String replicationUrl = props.getProperty("replicationUrl");
|
|
||||||
|
|
||||||
if (replicationUrl != null) {
|
|
||||||
if (logReplication) {
|
|
||||||
app.logEvent("Setting up replication listener at " + replicationUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
Replicator replicator = new Replicator(this);
|
|
||||||
replicator.addUrl(replicationUrl);
|
|
||||||
addNodeChangeListener(replicator);
|
|
||||||
}
|
|
||||||
|
|
||||||
db = new XmlDatabase();
|
db = new XmlDatabase();
|
||||||
db.init(dbHome, app);
|
db.init(dbHome, app);
|
||||||
|
@ -123,7 +109,6 @@ public final class NodeManager {
|
||||||
// notify the cache about the properties update
|
// notify the cache about the properties update
|
||||||
cache.updateProperties(props);
|
cache.updateProperties(props);
|
||||||
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
||||||
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1311,8 +1296,6 @@ public final class NodeManager {
|
||||||
|
|
||||||
if ((dbm == null) || !dbm.isRelational()) {
|
if ((dbm == null) || !dbm.isRelational()) {
|
||||||
node = (Node) db.getNode(txn, kstr);
|
node = (Node) db.getNode(txn, kstr);
|
||||||
node.nmgr = safe;
|
|
||||||
|
|
||||||
if ((node != null) && (dbm != null)) {
|
if ((node != null) && (dbm != null)) {
|
||||||
node.setDbMapping(dbm);
|
node.setDbMapping(dbm);
|
||||||
}
|
}
|
||||||
|
@ -1388,15 +1371,11 @@ public final class NodeManager {
|
||||||
|
|
||||||
if (node == null && (dbm == null || !dbm.isRelational())) {
|
if (node == null && (dbm == null || !dbm.isRelational())) {
|
||||||
node = (Node) db.getNode(txn, kstr);
|
node = (Node) db.getNode(txn, kstr);
|
||||||
node.nmgr = safe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
} else if (rel == null || dbm == null || !dbm.isRelational()) {
|
} else if (rel == null || dbm == null || !dbm.isRelational()) {
|
||||||
node = (Node) db.getNode(txn, kstr);
|
node = (Node) db.getNode(txn, kstr);
|
||||||
node.nmgr = safe;
|
|
||||||
node.setDbMapping(dbm);
|
node.setDbMapping(dbm);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
Statement stmt = null;
|
Statement stmt = null;
|
||||||
|
@ -1476,7 +1455,7 @@ public final class NodeManager {
|
||||||
String protoName = dbm.getTypeName();
|
String protoName = dbm.getTypeName();
|
||||||
DbMapping dbmap = dbm;
|
DbMapping dbmap = dbm;
|
||||||
|
|
||||||
Node node = new Node();
|
Node node = new Node(safe);
|
||||||
|
|
||||||
for (int i = 0; i < columns.length; i++) {
|
for (int i = 0; i < columns.length; i++) {
|
||||||
|
|
||||||
|
@ -1683,7 +1662,7 @@ public final class NodeManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.init(dbmap, id, name, protoName, propMap, safe);
|
node.init(dbmap, id, name, protoName, propMap);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1776,65 +1755,6 @@ public final class NodeManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive notification from a remote app that objects in its cache have been
|
|
||||||
* modified.
|
|
||||||
*/
|
|
||||||
public void replicateCache(Vector add, Vector delete) {
|
|
||||||
if (logReplication) {
|
|
||||||
app.logEvent("Received cache replication event: " + add.size() + " added, " +
|
|
||||||
delete.size() + " deleted");
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (cache) {
|
|
||||||
// long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
for (Enumeration en = add.elements(); en.hasMoreElements();) {
|
|
||||||
Node n = (Node) en.nextElement();
|
|
||||||
DbMapping dbm = app.getDbMapping(n.getPrototype());
|
|
||||||
|
|
||||||
if (dbm != null) {
|
|
||||||
dbm.setLastDataChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
n.setDbMapping(dbm);
|
|
||||||
n.nmgr = safe;
|
|
||||||
|
|
||||||
if (dbm != null && dbm.evictOnReplication()) {
|
|
||||||
Node oldNode = (Node) cache.get(n.getKey());
|
|
||||||
|
|
||||||
if (oldNode != null) {
|
|
||||||
evictNode(oldNode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
n.lastParentSet = -1;
|
|
||||||
cache.put(n.getKey(), n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Enumeration en = delete.elements(); en.hasMoreElements();) {
|
|
||||||
// NOTE: it would be more efficient to transfer just the keys
|
|
||||||
// of nodes that are to be deleted.
|
|
||||||
Node n = (Node) en.nextElement();
|
|
||||||
DbMapping dbm = app.getDbMapping(n.getPrototype());
|
|
||||||
|
|
||||||
if (dbm != null) {
|
|
||||||
dbm.setLastDataChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
n.setDbMapping(dbm);
|
|
||||||
n.nmgr = safe;
|
|
||||||
|
|
||||||
Node oldNode = (Node) cache.get(n.getKey());
|
|
||||||
|
|
||||||
if (oldNode != null) {
|
|
||||||
evictNode(oldNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setStatementValue(PreparedStatement stmt, int columnNumber, String value, DbColumn col)
|
private void setStatementValue(PreparedStatement stmt, int columnNumber, String value, DbColumn col)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* Helma License Notice
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Helma License
|
|
||||||
* Version 2.0 (the "License"). You may not use this file except in
|
|
||||||
* compliance with the License. A copy of the License is available at
|
|
||||||
* http://adele.helma.org/download/helma/license.txt
|
|
||||||
*
|
|
||||||
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* $RCSfile$
|
|
||||||
* $Author$
|
|
||||||
* $Revision$
|
|
||||||
* $Date$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package helma.objectmodel.db;
|
|
||||||
|
|
||||||
import java.rmi.Naming;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class replicates the updates of transactions to other applications via RMI
|
|
||||||
*/
|
|
||||||
public class Replicator implements Runnable, NodeChangeListener {
|
|
||||||
Vector urls;
|
|
||||||
Vector add;
|
|
||||||
Vector delete;
|
|
||||||
Vector currentAdd;
|
|
||||||
Vector currentDelete;
|
|
||||||
Thread runner;
|
|
||||||
NodeManager nmgr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Replicator object.
|
|
||||||
*
|
|
||||||
* @param nmgr ...
|
|
||||||
*/
|
|
||||||
public Replicator(NodeManager nmgr) {
|
|
||||||
urls = new Vector();
|
|
||||||
add = new Vector();
|
|
||||||
delete = new Vector();
|
|
||||||
this.nmgr = nmgr;
|
|
||||||
runner = new Thread(this);
|
|
||||||
runner.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param url ...
|
|
||||||
*/
|
|
||||||
public void addUrl(String url) {
|
|
||||||
urls.addElement(url);
|
|
||||||
|
|
||||||
if (nmgr.logReplication) {
|
|
||||||
nmgr.app.logEvent("Adding replication listener: " + url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
while (Thread.currentThread() == runner) {
|
|
||||||
if (prepareReplication()) {
|
|
||||||
for (int i = 0; i < urls.size(); i++) {
|
|
||||||
try {
|
|
||||||
String url = (String) urls.elementAt(i);
|
|
||||||
IReplicationListener listener = (IReplicationListener) Naming.lookup(url);
|
|
||||||
|
|
||||||
if (listener == null) {
|
|
||||||
throw new NullPointerException("Replication listener not bound for URL "+url);
|
|
||||||
}
|
|
||||||
|
|
||||||
listener.replicateCache(currentAdd, currentDelete);
|
|
||||||
|
|
||||||
if (nmgr.logReplication) {
|
|
||||||
nmgr.app.logEvent("Sent cache replication event: " +
|
|
||||||
currentAdd.size() + " added, " + currentDelete.size() +
|
|
||||||
" deleted");
|
|
||||||
}
|
|
||||||
} catch (Exception x) {
|
|
||||||
nmgr.app.logEvent("Error sending cache replication event: " + x);
|
|
||||||
if (nmgr.app.debug()) {
|
|
||||||
x.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (runner != null) {
|
|
||||||
Thread.sleep(1000L);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException ir) {
|
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a transaction is committed that has created, modified,
|
|
||||||
* deleted or changed the child collection one or more nodes.
|
|
||||||
*/
|
|
||||||
public synchronized void nodesChanged(List inserted, List updated,
|
|
||||||
List deleted, List parents) {
|
|
||||||
add.addAll(inserted);
|
|
||||||
add.addAll(updated);
|
|
||||||
delete.addAll(deleted);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private synchronized boolean prepareReplication() {
|
|
||||||
if ((add.size() == 0) && (delete.size() == 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentAdd = add;
|
|
||||||
currentDelete = delete;
|
|
||||||
add = new Vector();
|
|
||||||
delete = new Vector();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue