/*
* ServerConfiguration.java
*
* Created on June 12, 2007, 1:11 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.app;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.atomojo.app.admin.AdminXML;
import org.atomojo.app.auth.AuthException;
import org.atomojo.app.auth.AuthService;
import org.atomojo.app.client.Link;
import org.infoset.xml.Document;
import org.infoset.xml.DocumentLoader;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.sax.SAXDocumentLoader;
import org.restlet.data.MediaType;
/**
*
* @author alex
*/
public class ServerConfiguration
{
public static class Interface {
String address;
boolean secure;
int port;
public Interface(String addr,int port,boolean secure)
{
this.address = addr;
this.port = port;
this.secure = secure;
}
public int getPort()
{
return port;
}
public void setPort(int port)
{
this.port = port;
}
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
public boolean isSecure()
{
return secure;
}
public void setSecure(boolean secure)
{
this.secure = secure;
}
}
public static class Host {
String dbName;
String name;
String addr;
int port;
boolean allowQueries;
boolean editClient;
File hostLog;
ServerConfiguration owner;
public Host(ServerConfiguration owner,String dbName,String name) {
this.dbName = dbName;
this.name = name;
this.addr = null;
this.port = -1;
this.allowQueries = false;
this.editClient = false;
}
public Host(ServerConfiguration owner,String dbName,String name,String addr,int port,boolean allowQueries,boolean editClient,File hostLog) {
this.dbName = dbName;
this.name = name;
this.addr = addr;
this.port = port;
this.allowQueries = allowQueries;
this.editClient = editClient;
this.hostLog = hostLog;
}
public ServerConfiguration getConfiguration() {
return owner;
}
public boolean allowQueries() {
return allowQueries;
}
public boolean allowEditClient() {
return editClient;
}
public String getDatabaseName() {
return dbName;
}
public String getName() {
return name;
}
public String getAddress() {
return addr;
}
public int getPort() {
return port;
}
public File getLogFile() {
return hostLog;
}
}
public static class AdminHost extends Host {
String authName;
public AdminHost(ServerConfiguration owner,String name,String addr,int port,String authName,File logDir) {
super(owner,null,name,addr,port,false,false,logDir);
this.authName = authName;
}
public String getAuthName() {
return authName;
}
}
public static class ResourceHost extends Host {
Set<String> databases;
public ResourceHost(ServerConfiguration owner,String name,String addr,int port,boolean queries,boolean editClient,File logDir) {
super(owner,null,name,addr,port,queries,editClient,logDir);
this.databases = new TreeSet<String>();
}
public Set<String> getDatabases() {
return databases;
}
}
public static class Auth {
String name;
Class<? extends AuthService> serviceClass;
Properties props;
public Auth(String name,Class<? extends AuthService> serviceClass,Properties props) {
this.name = name;
this.serviceClass = serviceClass;
this.props = props;
}
public String getName() {
return name;
}
public Class getServiceClass() {
return serviceClass;
}
public Properties getProperties() {
return props;
}
public AuthService newInstance()
throws AuthException
{
try {
AuthService service = serviceClass.newInstance();
service.init(props);
return service;
} catch (InstantiationException ex) {
throw new AuthException("Cannot instantiate service "+serviceClass.getName(),ex);
} catch (IllegalAccessException ex) {
throw new AuthException("Cannot instantiate service "+serviceClass.getName(),ex);
}
}
}
public static class Database {
String name;
String auth;
String group;
String groupAlias;
public Database(String name,String auth)
{
this.name = name;
this.auth = auth;
this.group = null;
this.groupAlias = null;
}
public Database(String name,String auth,String group,String groupAlias)
{
this.name = name;
this.auth = auth;
this.group = group;
this.groupAlias = groupAlias;
}
public String getName() {
return name;
}
public String getAuthName() {
return auth;
}
public String getGroup() {
return group;
}
public String getGroupAlias() {
return groupAlias;
}
}
long autoconfCheck;
String storageClassName;
Map<String,AdminHost> admins;
Map<String,ResourceHost> resources;
Map<String,Host> hosts;
Map<String,Database> databases;
Map<String,Auth> authServices;
List<Interface> interfaces;
File keystoreFile;
File logDir;
String keystorePassword;
String keyPassword;
List<Link> autoconfs;
File tmpDir;
/** Creates a new instance of ServerConfiguration */
public ServerConfiguration()
{
autoconfCheck = 180*1000;
autoconfs = new ArrayList<Link>();
hosts = new TreeMap<String,Host>();
admins = new TreeMap<String,AdminHost>();
resources = new TreeMap<String,ResourceHost>();
authServices = new TreeMap<String,Auth>();
databases = new TreeMap<String,Database>();
interfaces = new ArrayList<Interface>();
tmpDir = new File(".");
}
public String getStorageClassName() {
return storageClassName;
}
public void setStorageClassName(String name)
{
storageClassName = name;
}
public long getAutoConfigurationCheckWait() {
return autoconfCheck;
}
public void setAutoConfigurationCheckWait(long value) {
autoconfCheck = value;
}
public List<Link> getAutoConfiguration() {
return autoconfs;
}
public File getKeystoreFile() {
return keystoreFile;
}
public void setKeystoreFile(File f)
{
keystoreFile = f;
}
public void setLogDirectory(File dir) {
logDir = dir;
}
public File getLogDirectory() {
return logDir;
}
public String getKeystorePassword() {
return keystorePassword;
}
public void setKeystorePassword(String password)
{
keystorePassword = password;
}
public String getKeyPassword() {
return keyPassword;
}
public void setKeyPassword(String password)
{
keyPassword = password;
}
public File getTempDirectory() {
return tmpDir;
}
public void setTempDirectory(File dir) {
tmpDir = dir;
}
public void load(URI location)
throws IOException,XMLException
{
DocumentLoader loader = new SAXDocumentLoader();
Document doc = loader.load(location);
Element top = doc.getDocumentElement();
if (!top.getName().equals(AdminXML.NM_SERVER)) {
throw new XMLException("Expecting "+AdminXML.NM_SERVER+" but found "+top.getName());
}
String value = top.getAttributeValue("autoconf-check");
if (value!=null) {
autoconfCheck = Long.parseLong(value)*1000;
}
storageClassName = top.getAttributeValue("storage-class");
value = top.getAttributeValue("logs");
if (location.getScheme().equals("file")) {
File locFile = new File(location.getSchemeSpecificPart());
File test = new File(locFile,value==null ? "logs" : value);
if (test.exists()) {
logDir = test;
} else {
logDir = new File(value==null ? "logs" : value);
}
}
value = top.getAttributeValue("temp.dir");
if (location.getScheme().equals("file")) {
File locFile = new File(location.getSchemeSpecificPart());
tmpDir = value==null ? locFile.getParentFile() : new File(locFile,value);
} else {
tmpDir = new File(".");
}
Iterator<Element> autoconfElements = top.getElementsByName(AdminXML.NM_AUTOCONF);
while (autoconfElements.hasNext()) {
Element autoconfE = autoconfElements.next();
String href = autoconfE.getAttributeValue("href");
if (href!=null) {
Link l = new Link("autoconf",MediaType.APPLICATION_ATOM_XML,autoconfE.getBaseURI().resolve(href));
l.setIdentity(autoconfE.getAttributeValue("username"),autoconfE.getAttributeValue("password"));
autoconfs.add(l);
}
}
Iterator<Element> interfaceElements = top.getElementsByName(AdminXML.NM_INTERFACE);
while (interfaceElements.hasNext()) {
Element interfaceE = interfaceElements.next();
String addr = interfaceE.getAttributeValue("address");
String portS = interfaceE.getAttributeValue("port");
boolean secure = interfaceE.getAttributeValue("secure")==null || "true".equals(interfaceE.getAttributeValue("secure"));
int port = portS==null ? (secure ? 443 : 80) : Integer.parseInt(portS);
interfaces.add(new Interface(addr,port,secure));
}
Iterator<Element> hostElements = top.getElementsByName(AdminXML.NM_HOST);
while (hostElements.hasNext()) {
Host host = createHost(hostElements.next());
String key = host.getName();
if (host.getPort()<0) {
key = key+":*";
} else {
key = key+":"+host.getPort();
}
hosts.put(key,host);
}
Iterator<Element> adminElements = top.getElementsByName(AdminXML.NM_ADMIN);
while (adminElements.hasNext()) {
AdminHost host = createAdminHost(adminElements.next());
admins.put(host.getName(),host);
}
Iterator<Element> resourceElements = top.getElementsByName(AdminXML.NM_RESOURCE);
while (resourceElements.hasNext()) {
Element spec = resourceElements.next();
String type = spec.getAttributeValue("type");
if (type==null || type.equals("database")) {
ResourceHost host = createResourceHost(spec);
resources.put(host.getName(),host);
} else {
throw new XMLException("Unrecognized resource host type "+type);
}
}
Iterator<Element> databaseElements = top.getElementsByName(AdminXML.NM_DATABASE);
while (databaseElements.hasNext()) {
Element databaseE = databaseElements.next();
String dbName = databaseE.getAttributeValue("name");
String auth = databaseE.getAttributeValue("auth");
String group = databaseE.getAttributeValue("group");
String alias = databaseE.getAttributeValue("alias");
Database database = new Database(dbName,auth,group,alias);
databases.put(dbName,database);
}
Iterator<Element> authElements = top.getElementsByName(AdminXML.NM_AUTH);
while (authElements.hasNext()) {
Element authE = authElements.next();
try {
Auth auth = createAuth(authE);
authServices.put(auth.getName(),auth);
} catch (ClassNotFoundException ex) {
throw new XMLException("Cannot load class "+authE.getAttributeValue("class")+" for auth service "+authE.getAttributeValue("name"),ex);
}
}
Element keystoreE = top.getFirstElementNamed(AdminXML.NM_KEYSTORE);
String href = keystoreE.getAttributeValue("href");
URI keystoreRef = keystoreE.getBaseURI().resolve(href);
keystoreFile = new File(keystoreRef.getSchemeSpecificPart());
keystorePassword = keystoreE.getAttributeValue("password");
keyPassword = keystorePassword;
String altPassword = keystoreE.getAttributeValue("key-password");
if (altPassword!=null) {
keyPassword = altPassword;
}
}
public Auth createAuth(Element authE)
throws ClassNotFoundException
{
String name = authE.getAttributeValue("name");
String className = authE.getAttributeValue("class");
Class<?> qClass = this.getClass().forName(className);
Class<? extends AuthService> authClass = qClass.asSubclass(AuthService.class);
Properties props = new Properties();
for (Name attName : authE.getAttributes().keySet()) {
props.put(attName.getLocalName(),authE.getAttributeValue(attName));
}
props.put("base-uri",authE.getBaseURI().toString());
Auth auth = new Auth(name,authClass,props);
return auth;
}
public Host createHost(Element hostE)
{
String dbName = hostE.getAttributeValue("database");
String name = hostE.getAttributeValue("name");
String addr = hostE.getAttributeValue("address");
String port = hostE.getAttributeValue("port");
String log = hostE.getAttributeValue("log");
File hostLog = null;
if (log!=null) {
File test = new File(logDir,log);
if (test.exists()) {
if (test.isDirectory()) {
hostLog = new File(test,"*".equals(name) ? "any.log" : name+".log");
} else {
hostLog = test;
}
} else {
hostLog = test;
}
} else {
hostLog = new File(logDir,"*".equals(name) ? "any.log" : name+".log");
}
boolean queries = "true".equals(hostE.getAttributeValue("allow-queries"));
boolean editClient = "true".equals(hostE.getAttributeValue("edit-client"));
Host host = new Host(this,dbName,name,addr,port==null ? -1 : Integer.parseInt(port),queries,editClient,hostLog);
return host;
}
public AdminHost createAdminHost(Element hostE)
{
String authName = hostE.getAttributeValue("auth");
String name = hostE.getAttributeValue("name");
String addr = hostE.getAttributeValue("address");
String port = hostE.getAttributeValue("port");
String log = hostE.getAttributeValue("log");
File hostLog = null;
if (log!=null) {
File test = new File(logDir,log);
if (test.exists()) {
if (test.isDirectory()) {
hostLog = new File(test,name+".log");
} else {
hostLog = test;
}
} else {
hostLog = test;
}
} else {
hostLog = new File(logDir,name+".log");
}
AdminHost host = new AdminHost(this,name,addr,port==null ? -1 : Integer.parseInt(port),authName,hostLog);
return host;
}
public ResourceHost createResourceHost(Element hostE)
{
String name = hostE.getAttributeValue("name");
String addr = hostE.getAttributeValue("address");
String port = hostE.getAttributeValue("port");
String log = hostE.getAttributeValue("log");
File hostLog = null;
if (log!=null) {
File test = new File(logDir,log);
if (test.exists()) {
if (test.isDirectory()) {
hostLog = new File(test,name+".log");
} else {
hostLog = test;
}
} else {
hostLog = test;
}
} else {
hostLog = new File(logDir,name+".log");
}
boolean queries = "true".equals(hostE.getAttributeValue("allow-queries"));
boolean editClient = "true".equals(hostE.getAttributeValue("edit-client"));
ResourceHost host = new ResourceHost(this,name,addr,port==null ? -1 : Integer.parseInt(port),queries,editClient,hostLog);
Iterator<Element> databases = hostE.getElementsByName(AdminXML.NM_DATABASE);
while (databases.hasNext()) {
String dname = databases.next().getAttributeValue("name");
if (dname!=null) {
dname = dname.trim();
if (dname.length()>0) {
host.getDatabases().add(dname);
}
}
}
return host;
}
public Map<String,Host> getHosts() {
return hosts;
}
public Map<String,AdminHost> getAdminHosts() {
return admins;
}
public Map<String,ResourceHost> getResourceHosts() {
return resources;
}
public List<Interface> getInterfaces() {
return interfaces;
}
public Map<String,Auth> getAuthServices() {
return authServices;
}
public Map<String,Database> getDatabases() {
return databases;
}
public void store(URI baseURI,ItemDestination dest)
throws XMLException
{
String baseURIValue = baseURI.toString();
URI baseDir = URI.create(baseURIValue.substring(0,baseURIValue.lastIndexOf('/')+1));
ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
dest.send(constructor.createDocument(baseURI));
Element top = constructor.createElement(AdminXML.NM_SERVER);
if (autoconfCheck!=((long)(180*1000))) {
top.setAttributeValue("autoconf-check",Long.toString(autoconfCheck/1000));
}
dest.send(top);
dest.send(constructor.createCharacters("\n"));
Element keystoreE = constructor.createElement(AdminXML.NM_KEYSTORE);
keystoreE.setAttributeValue("href",baseDir.relativize(keystoreFile.toURI()).toString());
keystoreE.setAttributeValue("password",keystorePassword);
if (!keystorePassword.equals(keyPassword)) {
keystoreE.setAttributeValue("key-password",keyPassword);
}
dest.send(keystoreE);
dest.send(constructor.createElementEnd(AdminXML.NM_KEYSTORE));
dest.send(constructor.createCharacters("\n"));
for (Auth auth : authServices.values()) {
Element authE = constructor.createElement(AdminXML.NM_AUTH);
for (Object nameO : auth.getProperties().keySet()) {
String name = nameO.toString();
authE.setAttributeValue(name,auth.getProperties().getProperty(name));
}
dest.send(authE);
dest.send(constructor.createElementEnd(AdminXML.NM_AUTH));
dest.send(constructor.createCharacters("\n"));
}
for (Link link : autoconfs) {
Element autoconfE = constructor.createElement(AdminXML.NM_AUTOCONF);
autoconfE.setAttributeValue("href",baseURI.relativize(link.getLink()).toString());
if (link.getUsername()!=null) {
autoconfE.setAttributeValue("username",link.getUsername());
autoconfE.setAttributeValue("password",link.getPassword());
}
dest.send(autoconfE);
dest.send(constructor.createElementEnd(AdminXML.NM_AUTOCONF));
dest.send(constructor.createCharacters("\n"));
}
for (Database database : databases.values()) {
Element databaseE = constructor.createElement(AdminXML.NM_DATABASE);
databaseE.setAttributeValue("name",database.getName());
databaseE.setAttributeValue("auth",database.getAuthName());
dest.send(databaseE);
dest.send(constructor.createElementEnd(AdminXML.NM_DATABASE));
dest.send(constructor.createCharacters("\n"));
}
for (Interface iface : interfaces) {
Element ifaceE = constructor.createElement(AdminXML.NM_INTERFACE);
ifaceE.setAttributeValue("address",iface.getAddress());
ifaceE.setAttributeValue("port",Integer.toString(iface.getPort()));
ifaceE.setAttributeValue("secure",iface.isSecure() ? "true" : "false");
dest.send(ifaceE);
dest.send(constructor.createElementEnd(AdminXML.NM_INTERFACE));
dest.send(constructor.createCharacters("\n"));
}
for (AdminHost host : admins.values()) {
Element hostE = constructor.createElement(AdminXML.NM_ADMIN);
hostE.setAttributeValue("name",host.getName());
if (host.getAddress()!=null) {
hostE.setAttributeValue("address",host.getAddress());
}
if (host.getPort()>0) {
hostE.setAttributeValue("port",Integer.toString(host.getPort()));
}
if (host.getAuthName()!=null) {
hostE.setAttributeValue("auth",host.getAuthName());
}
dest.send(hostE);
dest.send(constructor.createElementEnd(AdminXML.NM_ADMIN));
dest.send(constructor.createCharacters("\n"));
}
for (Host host : hosts.values()) {
Element hostE = constructor.createElement(AdminXML.NM_HOST);
hostE.setAttributeValue("database",host.getDatabaseName());
hostE.setAttributeValue("name",host.getName());
if (host.getAddress()!=null) {
hostE.setAttributeValue("address",host.getAddress());
}
if (host.getPort()>0) {
hostE.setAttributeValue("port",Integer.toString(host.getPort()));
}
dest.send(hostE);
dest.send(constructor.createElementEnd(AdminXML.NM_HOST));
dest.send(constructor.createCharacters("\n"));
}
dest.send(constructor.createElementEnd(AdminXML.NM_SERVER));
dest.send(constructor.createDocumentEnd());
}
}