package ca.sqlpower.sql; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.rmi.Naming; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * Implementation of the RMI interface used to get the database connection * list remotely. * * @author Dan Fraser * @version $Id$ */ public class DBConnectionSpecServerImpl extends UnicastRemoteObject implements DBConnectionSpecServer { Object fileLock = null; protected String xmlFileName = null; public DBConnectionSpecServerImpl() throws RemoteException { super(); } /** * @see ca.sqlpower.sql.DBConnectionSpecServer */ public Collection getAvailableDatabases() throws RemoteException { List databases = null; try { DBCSSource xmlSource = new XMLFileDBCSSource(xmlFileName); databases = new LinkedList(xmlSource.getDBCSList()); Collections.sort(databases); } catch (Exception e) { e.printStackTrace(); throw new RemoteException("Could not read XML File (see RMI server log)", e); // could not get the database list, not much we can do. } return databases; } /** * Basic server main. This class is executable with a command line * something like this: * * java -Djava.rmi.server.codebase="base.of.classpath" \ * -cp ".;../../../../common/lib/xerces.jar" \ * -Djava.security.policy=rmi.policy \ * -DdatabasesFile=../databases.xml \ * ca.sqlpower.sql.DBConnectionSpecServerImpl */ public static void main(String args[]) throws RemoteException{ // Create and install a security manager if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } DBConnectionSpecServerImpl obj = new DBConnectionSpecServerImpl(); obj.xmlFileName = System.getProperty("databasesFile"); if (obj.xmlFileName == null) { System.out.println( "no databases file specified. Please add -DdatabaseFile=filename to the command line."); } else { try { java.rmi.registry.LocateRegistry.createRegistry(1099); Naming.rebind("///DBConnectionSpecServer", obj); System.out.println("DBConnectionSpecServer bound in registry"); } catch (Exception e) { System.out.println( "DBConnectionSpecImpl err: " + e.getMessage()); e.printStackTrace(); } } } /** * @see ca.sqlpower.sql.DBConnectionSpecServer */ public void setAvailableDatabases(Collection dbList, String oldPass, String newPass) throws RemoteException { try { writeDBSpecsToOutputStream(dbList, oldPass, newPass); } catch (Exception e) { // not much we can do on server side throw new RemoteException("could not set databases",e); } } /** * @see ca.sqlpower.sql.DBConnectionSpecServer */ public boolean checkPassword(String argPassword) throws RemoteException { try { InputStream xmlStream = new FileInputStream(xmlFileName); DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document d = db.parse(xmlStream); NodeList list = d.getElementsByTagName("databases"); Element e = (Element) list.item(0); String password = e.getAttribute("password"); return argPassword.equals(password); } catch (Exception e) { // not much we can do on the remote side. throw new RemoteException("could not check password",e); } } /** * This uses Apache Xalan's xml-to-stream converter to build an xml * document from the list of DBConnectionSpecs in the standard * SQLPower format, and saves it to a file on the disk. * * Note, this uses xml functionality beyond what JAXP offers, so Xalan * is required, not just any JAXP parser. */ protected synchronized void writeDBSpecsToOutputStream( Collection dbspecs, String oldPassword, String newPassword) throws ParserConfigurationException, IOException { if (!checkPassword(oldPassword)) { return; } OutputStream xmlStream = new FileOutputStream(xmlFileName); DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document d = db.newDocument(); Element databases = d.createElement("databases"); if (newPassword != null) { databases.setAttribute("password",newPassword); } else { databases.setAttribute("password",oldPassword); } Iterator dbIter = dbspecs.iterator(); while (dbIter.hasNext()) { DBConnectionSpec dbcs = (DBConnectionSpec) dbIter.next(); Element dbNode = d.createElement("database"); dbNode.setAttribute("name",dbcs.getName()); dbNode.setAttribute("seqNo",Integer.toString(dbcs.getSeqNo())); dbNode.setAttribute("singleLogin",dbcs.isSingleLogin() ? "true" : "false"); if (dbcs.getDisplayName() != null) { Element displayName = d.createElement("display-name"); displayName.appendChild(d.createTextNode(dbcs.getDisplayName())); dbNode.appendChild(displayName); } if (dbcs.getDriverClass() != null) { Element driverClass = d.createElement("driver-class"); driverClass.appendChild(d.createTextNode(dbcs.getDriverClass())); dbNode.appendChild(driverClass); } if (dbcs.getUrl() != null) { Element url = d.createElement("url"); url.appendChild(d.createTextNode(dbcs.getUrl())); dbNode.appendChild(url); } if (dbcs.getUser() != null) { Element user = d.createElement("user"); user.appendChild(d.createTextNode(dbcs.getUser())); dbNode.appendChild(user); } if (dbcs.getPass() != null) { Element pass = d.createElement("pass"); pass.appendChild(d.createTextNode(dbcs.getPass())); dbNode.appendChild(pass); } databases.appendChild(dbNode); } d.appendChild(databases); OutputFormat of = new OutputFormat(); of.setIndenting(true); XMLSerializer serializer = new XMLSerializer(xmlStream, of); serializer.serialize(d); xmlStream.close(); } }