package org.mom4j.jndi;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mom4j.api.JNDIContextHandler;
import org.mom4j.xcp.XcpConfig;
import org.mom4j.xcp.XcpException;
import org.mom4j.xcp.XcpRequest;
import org.mom4j.xcp.XcpRequestListener;
import org.mom4j.xcp.XcpServer;
import org.mom4j.xcp.XcpServerFactory;
public class NamingServer implements NamingServerMBean {
private static Log log = LogFactory.getLog(NamingServer.class);
private Map ctxHandlers;
private Map bindings;
private XcpServer server;
private int port;
private boolean startAdminServer;
public NamingServer(int p) {
this.bindings = null;
this.server = null;
this.port = p;
this.ctxHandlers = new HashMap();
}
public void start() {
this.bindings = Collections.synchronizedMap(new HashMap());
//Make sure that at least a root context is available
this.bindings.put("/", Collections.synchronizedMap(new HashMap()));
XcpConfig cfg = XcpServerFactory.createXcpConfig();
cfg.setPort(this.port);
cfg.addXcpHandler(XcpBinding.TAG_NAME, XcpBindingHandler.class);
this.server = XcpServerFactory.createXcpServer(cfg);
this.server.addXcpRequestListener(new ReqListener());
javax.management.ObjectName on = null;
try {
on = new javax.management.ObjectName("NamingServer:port=" + this.port);
XcpServerFactory.registerMBean(on, this);
} catch(javax.management.JMException ex) {
log.error("Failed registering MBean in MBeanServer", ex);
this.stop();
throw new IllegalStateException(ex.getMessage());
}
}
public void addContextHandler(JNDIContextHandler handler) {
if(handler == null) {
throw new IllegalArgumentException("handler is null!");
}
if(this.ctxHandlers.get(handler.getContextPath()) != null) {
String msg = "path '" + handler.getContextPath()
+ "' already handled!";
throw new IllegalStateException(msg);
}
if(this.bindings.get(handler.getContextPath()) != null) {
String msg = "path '" + handler.getContextPath()
+ "' already contains bindings";
throw new IllegalStateException(msg);
}
this.ctxHandlers.put(handler.getContextPath(), handler);
this.bindings.put(handler.getContextPath(),
Collections.synchronizedMap(handler.load()));
}
public void removeContextHandler(JNDIContextHandler handler) {
this.ctxHandlers.remove(handler.getContextPath());
this.bindings.remove(handler.getContextPath());
}
public String createSubcontext(String path, String name) {
if(path == null)
throw new IllegalArgumentException("path must not be null!");
if(name == null)
throw new IllegalArgumentException("name must not be null!");
String newPath = null;
if(path.endsWith("/")) {
newPath = path + name;
} else {
newPath = path + "/" + name;
}
Map map = (Map)this.bindings.get(newPath);
if(map != null) {
//new path NULL ist returned, client will throw exception
return null;
}
this.bindings.put(newPath, Collections.synchronizedMap(new HashMap()));
return newPath;
}
public void bind(String path, String name, Object obj) {
if(path == null)
throw new IllegalArgumentException("path must not be null!");
if(name == null)
throw new IllegalArgumentException("name must not be null!");
if(obj == null)
throw new IllegalArgumentException("obj must not be null!");
Map map = (Map)this.bindings.get(path);
if(map == null) {
throw new IllegalArgumentException("invalid path '" + path + "'");
}
map.put(name, obj);
JNDIContextHandler handler = (JNDIContextHandler)this.ctxHandlers.get(path);
if(handler != null) {
handler.bind(name, obj);
}
}
public void unbind(String path, String name) {
if(path == null)
throw new IllegalArgumentException("path must not be null!");
if(name == null)
throw new IllegalArgumentException("name must not be null!");
Map map = (Map)this.bindings.get(path);
if(map == null) {
throw new IllegalArgumentException("invalid path '" + path + "'");
}
map.remove(name);
JNDIContextHandler handler = (JNDIContextHandler)this.ctxHandlers.get(path);
if(handler != null) {
handler.unbind(name);
}
}
public Object lookup(String path, String name) {
if(path == null)
throw new IllegalArgumentException("path must not be null!");
if(name == null)
throw new IllegalArgumentException("name must not be null!");
String p = null;
if(path.endsWith("/")) {
p = path + name;
} else {
p = path + "/" + name;
}
Map map = (Map)this.bindings.get(p);
if(map != null) {
//ok, name is a context ...
return new CreateCtx(p);
}
map = (Map)this.bindings.get(path);
if(map == null) {
throw new IllegalArgumentException("invalid path '" + path + "'");
}
return map.get(name);
}
public Map list(String path, String name) {
if(path == null)
throw new IllegalArgumentException("path must not be null!");
if(name == null)
throw new IllegalArgumentException("name must not be null!");
Map map = (Map)this.bindings.get(path);
if(map == null) {
throw new IllegalArgumentException("invalid path '" + path + "'");
}
return map;
}
public void stop() {
this.server.shutdown();
this.bindings.clear();
this.bindings = null;
}
public String getBindings() {
return this.bindings.toString();
}
public static void main(String[] args) {
int port = 8001;
if(args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch(Exception ex) {}
}
NamingServer ns = new NamingServer(port);
ns.start();
Runtime.getRuntime().addShutdownHook(new ShutdownHook(ns));
}
class ReqListener implements XcpRequestListener {
public void requestNotify(XcpRequest req)
throws XcpException
{
XcpBinding b = (XcpBinding)req.getRootElement();
if(b.getAction().equals(XcpBinding.ACTION_BIND)) {
NamingServer.this.bind(b.getPath(), b.getName(), b.getValue());
} else if(b.getAction().equals(XcpBinding.ACTION_CREATE_CTX)) {
String newPath =
NamingServer.this.createSubcontext(b.getPath(), b.getName());
b.setValue(newPath);
OutputStream out = req.getOutputStream();
try {
b.writeTo(out);
} catch(IOException ex) {
throw new XcpException(ex.getMessage());
} finally {
try { out.close(); } catch(Exception ex) {}
}
} else if(b.getAction().equals(XcpBinding.ACTION_REBIND)) {
NamingServer.this.bind(b.getPath(), b.getName(), b.getValue());
} else if(b.getAction().equals(XcpBinding.ACTION_UNBIND)) {
NamingServer.this.unbind(b.getPath(), b.getName());
} else if(b.getAction().equals(XcpBinding.ACTION_LOOKUP)) {
Object o = (Object)NamingServer.this.lookup(b.getPath(), b.getName());
b.setValue(o);
OutputStream out = req.getOutputStream();
try {
b.writeTo(out);
} catch(IOException ex) {
throw new XcpException(ex.getMessage());
} finally {
try { out.close(); } catch(Exception ex) {}
}
} else if(b.getAction().equals(XcpBinding.ACTION_LIST)) {
Object o = NamingServer.this.list(b.getPath(), b.getName());
b.setValue(o);
OutputStream out = req.getOutputStream();
try {
b.writeTo(out);
} catch(IOException ex) {
throw new XcpException(ex.getMessage());
} finally {
try { out.close(); } catch(Exception ex) {}
}
}
}
}
static class ShutdownHook extends Thread {
NamingServer ns;
public ShutdownHook(NamingServer ns) {
super("ShutdownHook");
this.ns = ns;
}
public void run() {
ns.stop();
}
}
}