cmlenz 2002/08/19 00:45:55 Added: src/stores/org/apache/slide/store/impl/rdbms JDBCStore.java Log: Merge JDBCDescriptorsStore and JDBCContentStore so that they share the JDBC connection and thus the transaction. Revision Changes Path 1.1 jakarta-slide/src/stores/org/apache/slide/store/impl/rdbms/JDBCStore.java Index: JDBCStore.java =================================================================== /* * $Header: $ * $Revision: $ * $Date: $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Slide", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.slide.store.impl.rdbms; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import javax.transaction.xa.XAException; import javax.transaction.xa.Xid; import org.apache.slide.common.AbstractSimpleService; import org.apache.slide.common.NamespaceAccessToken; import org.apache.slide.common.ServiceAccessException; import org.apache.slide.common.ServiceConnectionFailedException; import org.apache.slide.common.ServiceDisconnectionFailedException; import org.apache.slide.common.ServiceInitializationFailedException; import org.apache.slide.common.ServiceParameterErrorException; import org.apache.slide.common.ServiceParameterMissingException; import org.apache.slide.common.ServiceResetFailedException; import org.apache.slide.common.Uri; import org.apache.slide.content.NodeProperty; import org.apache.slide.content.NodeRevisionContent; import org.apache.slide.content.NodeRevisionDescriptor; import org.apache.slide.content.NodeRevisionDescriptors; import org.apache.slide.content.NodeRevisionNumber; import org.apache.slide.content.RevisionAlreadyExistException; import org.apache.slide.content.RevisionDescriptorNotFoundException; import org.apache.slide.content.RevisionNotFoundException; import org.apache.slide.lock.LockTokenNotFoundException; import org.apache.slide.lock.NodeLock; import org.apache.slide.security.NodePermission; import org.apache.slide.store.ContentStore; import org.apache.slide.store.LockStore; import org.apache.slide.store.NodeStore; import org.apache.slide.store.RevisionDescriptorStore; import org.apache.slide.store.RevisionDescriptorsStore; import org.apache.slide.store.SecurityStore; import org.apache.slide.structure.LinkNode; import org.apache.slide.structure.ObjectAlreadyExistsException; import org.apache.slide.structure.ObjectNode; import org.apache.slide.structure.ObjectNotFoundException; import org.apache.slide.util.logger.Logger; /** * Store implementation that is able to store all information (like structure, * locks and content) in a JDBC-aware relational database system. As this * implementation only uses a single connection to the database, it does not * work properly in production environments that require simultaneous access by * multiple clients. * * @author <a href="mailto:[EMAIL PROTECTED]">Remy Maucherat</a> * @author Dirk Verbeeck * @author <a href="mailto:[EMAIL PROTECTED]">Christopher Lenz</a> * @version $Revision: $ */ public class JDBCStore extends AbstractSimpleService implements LockStore, NodeStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore, ContentStore { // -------------------------------------------------------------- Constants // Column numbers // Structure descriptors private static final int OBJECTS_URI = 1; private static final int OBJECTS_CLASS = 2; private static final int CHILDREN_URI = 1; private static final int CHILDREN_CHILDURI = 2; private static final int LINKS_LINK = 1; private static final int LINKS_LINKTO = 2; // Security descriptors private static final int PERMISSIONS_OBJECT = 1; private static final int PERMISSIONS_REVISION_NUMBER = 2; private static final int PERMISSIONS_SUBJECT = 3; private static final int PERMISSIONS_ACTION = 4; private static final int PERMISSIONS_INHERITABLE = 5; private static final int PERMISSIONS_NEGATIVE = 6; // Lock descriptors private static final int LOCKS_ID = 1; private static final int LOCKS_OBJECT = 2; private static final int LOCKS_SUBJECT = 3; private static final int LOCKS_TYPE = 4; private static final int LOCKS_EXPIRATIONDATE = 5; private static final int LOCKS_INHERITABLE = 6; private static final int LOCKS_EXCLUSIVE = 7; // Content descriptors private static final int REVISIONS_URI = 1; private static final int REVISIONS_ISVERSIONED = 2; private static final int REVISIONS_INITIALREVISION = 3; private static final int WORKINGREVISION_URI = 1; private static final int WORKINGREVISION_BASEREVISION = 2; private static final int WORKINGREVISION_NUMBER = 3; private static final int LATESTREVISIONS_URI = 1; private static final int LATESTREVISIONS_BRANCHNAME = 2; private static final int LATESTREVISIONS_NUMBER = 3; private static final int BRANCHES_URI = 1; private static final int BRANCHES_NUMBER = 2; private static final int BRANCHES_CHILDNUMBER = 3; private static final int REVISION_URI = 1; private static final int REVISION_NUMBER = 2; private static final int REVISION_BRANCHNAME = 3; private static final int LABEL_URI = 1; private static final int LABEL_NUMBER = 2; private static final int LABEL_LABEL = 3; private static final int PROPERTY_URI = 1; private static final int PROPERTY_NUMBER = 2; private static final int PROPERTY_NAME = 3; private static final int PROPERTY_VALUE = 4; private static final int PROPERTY_NAMESPACE = 5; private static final int PROPERTY_TYPE = 6; private static final int PROPERTY_PROTECTED = 7; //private static final int REVISION_URI = 1; //private static final int REVISION_NUMBER = 2; private static final int REVISION_CONTENT = 3; public static final int BUFFER_SIZE = 2048; // ----------------------------------------------------- Instance Variables /** * Database connection. */ private Connection connection; /** * Driver class name. */ private String driver; /** * Connection URL. */ private String url; /** * User name. */ private String user; /** * Password. */ private String password; /** * JDBC Version to use. */ private int jdbcVersion; /** * This store doesn't handle nested transactions, this variable keeps track * if the store is already enlisted to a transaction. */ private boolean alreadyEnlisted=false; // -------------------------------------------------------- Service Methods /** * Initializes the data source with a set of parameters. * * @param parameters Hashtable containing the parameters' name * and associated value * @exception ServiceParameterErrorException Incorrect service parameter * @exception ServiceParameterMissingException Service parameter missing */ public void setParameters(Hashtable parameters) throws ServiceParameterErrorException, ServiceParameterMissingException { // Driver classname driver = (String) parameters.get("driver"); // Connection url url = (String) parameters.get("url"); // FIXME: before slide 1.0.12 the database url was passed // without "jdbc:" this compatibility code sould be removed in the // future code changed 18 jul 2001 if (!url.startsWith("jdbc:")) url="jdbc:" + url; // end compatibility code // User name user = (String) parameters.get("user"); if (user == null) { user = new String(); } // Password password = (String) parameters.get("password"); if (password == null) { password = new String(); } // JDBC version to use jdbcVersion = 1; String version = (String) parameters.get("jdbcversion"); if (version != null) { jdbcVersion = (new Integer(version)).intValue(); } } /** * Connects to JDBC and creates the basic table structure. * * @exception ServiceConnectionFailedException Connection to the * database failed */ public synchronized void connect() throws ServiceConnectionFailedException { getLogger().log("Connecting to \"" + url + "\" as user \"" + user + "\"",LOG_CHANNEL, Logger.INFO); try { connection = DriverManager.getConnection (url, user, password); } catch (SQLException e) { getLogger().log("Connecting to \"" + url + "\" as user \"" + user + "\" failed",LOG_CHANNEL, Logger.ERROR); getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceConnectionFailedException(this, e); } // all updates must be done inside a transaction, no auto commits try { connection.setAutoCommit(false); } catch (SQLException e) { } Statement statement = null; try { statement = connection.createStatement(); String[] statements = getDatabaseCreateStatements(); for (int i=0; i<statements.length ; i++ ) { statement.execute(statements[i]); } // Cloudscape needs a commit on DDL statements (create,...) connection.commit(); } catch (SQLException e) { try { connection.rollback(); } catch (SQLException ex) { } } finally { closeStatement(statement); } // we are just connected and are not enlisted alreadyEnlisted=false; } /** * Disconnects from data source. * * @exception ServiceDisconnectionFailedException Disconnection * from database failed */ public void disconnect() throws ServiceDisconnectionFailedException { getLogger().log("Disconnecting from \"" + url + "\" as user \"" + user + "\"",LOG_CHANNEL, Logger.INFO); try { if (connection != null) connection.close(); connection = null; } catch (SQLException e) { getLogger().log("Disconnecting from \"" + url + "\" as user \"" + user + "\" failed",LOG_CHANNEL, Logger.ERROR); getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceDisconnectionFailedException(this, e); } } /** * Tries to reconnect if needed but doesn't report failure. */ private synchronized void connectIfNeededAndPossible() { try { connectIfNeeded(); } catch (Throwable ex) { // ignore } } /** * Initializes data source. * <p/> * Occurs in four steps : * <li>Driver class is loaded</li> * <li>Driver is intantiated</li> * <li>Driver registration in the driver manager</li> * <li>Creation of the basic tables, if they didn't exist before</li> * * @exception ServiceInitializationFailedException Throws an exception * if the data source has already been initialized before */ public synchronized void initialize(NamespaceAccessToken token) throws ServiceInitializationFailedException { try { // Loading and registering driver token.getLogger().log("Loading and registering driver: " + driver,LOG_CHANNEL, Logger.INFO); Class driverClass = Class.forName(driver); Driver databaseDriver = (Driver) driverClass.newInstance(); DriverManager.registerDriver(databaseDriver); } catch (ClassNotFoundException e) { token.getLogger().log("Loading and registering driver " + driver + " failed",LOG_CHANNEL, Logger.ERROR); token.getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceInitializationFailedException(this, e.getMessage()); } catch (InstantiationException e) { token.getLogger().log("Loading and registering driver " + driver + " failed",LOG_CHANNEL, Logger.ERROR); token.getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceInitializationFailedException(this, e.getMessage()); } catch (IllegalAccessException e) { token.getLogger().log("Loading and registering driver " + driver + " failed",LOG_CHANNEL, Logger.ERROR); token.getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceInitializationFailedException(this, e.getMessage()); } catch (SQLException e) { token.getLogger().log("Loading and registering driver " + driver + " failed",LOG_CHANNEL, Logger.ERROR); token.getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceInitializationFailedException(this, e.getMessage()); } catch (ClassCastException e) { token.getLogger().log("Loading and registering driver " + driver + " failed",LOG_CHANNEL, Logger.ERROR); token.getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceInitializationFailedException(this, e.getMessage()); } catch (Exception e) { token.getLogger().log("Loading and registering driver " + driver + " failed",LOG_CHANNEL, Logger.ERROR); token.getLogger().log(e.toString(),LOG_CHANNEL, Logger.ERROR); throw new ServiceInitializationFailedException(this, e.getMessage()); } } /** * Deletes data source. Should remove stored data if possible. * * @exception ServiceResetFailedException Reset failed */ public synchronized void reset() throws ServiceResetFailedException { Statement statement = null; try { connectIfNeeded(); statement = connection.createStatement(); String s = null; s = "drop table objects"; statement.execute(s); s = "drop table children"; statement.execute(s); s = "drop table links"; statement.execute(s); s = "drop table permissions"; statement.execute(s); s = "drop table locks"; statement.execute(s); s = "drop table revisions"; statement.execute(s); s = "drop table workingrevision"; statement.execute(s); s = "drop table latestrevisions"; statement.execute(s); s = "drop table branches"; statement.execute(s); s = "drop table revision"; statement.execute(s); s = "drop table label"; statement.execute(s); s = "drop table property"; statement.execute(s); s = "drop table revisioncontent"; statement.execute(s); statement.close(); disconnect(); } catch (SQLException e) { throw new ServiceResetFailedException(this, e.getMessage()); } catch (ServiceAccessException e) { throw new ServiceResetFailedException(this, e.getMessage()); } catch (ServiceConnectionFailedException e) { throw new ServiceResetFailedException(this, e.getMessage()); } catch (ServiceDisconnectionFailedException e) { throw new ServiceResetFailedException(this, e.getMessage()); } finally { closeStatement(statement); } } /** * This function tells whether or not the data source is connected. * * @return boolean true if we are connected * @exception ServiceAccessException Error accessing DataSource */ public boolean isConnected() throws ServiceAccessException { try { if ((connection == null) || (connection.isClosed())) { return false; } PreparedStatement statement = connection.prepareStatement(getDatabaseConnectionTestStatement()); statement.executeQuery(); statement.close(); // testStatement executed without throwing an exception return true; } catch (SQLException e) { throw new ServiceAccessException(this, e); } } // ----------------------------------------------------- XAResource Methods /** * Commit the global transaction specified by xid. */ public void commit(Xid xid, boolean onePhase) throws XAException { super.commit(xid, onePhase); try { // getLogger().log("commit",LOG_CHANNEL, Logger.DEBUG); connection.commit(); } catch (SQLException e) { throw new XAException(XAException.XA_RBCOMMFAIL); } alreadyEnlisted=false; } /** * Inform the resource manager to roll back work done on behalf of a * transaction branch. */ public void rollback(Xid xid) throws XAException { super.rollback(xid); try { // getLogger().log("rollback",LOG_CHANNEL, Logger.DEBUG); connection.rollback(); } catch (SQLException e) { throw new XAException(XAException.XA_HEURCOM); } alreadyEnlisted=false; } /** * Start work on behalf of a transaction branch specified in xid. */ public void start(Xid xid, int flags) throws XAException { super.start(xid, flags); if (!alreadyEnlisted) { try { // getLogger().log("start",LOG_CHANNEL, Logger.DEBUG); // test connection connectIfNeeded(); // discard changes made outside a tranaction connection.rollback(); } catch (Exception e) { throw new XAException(XAException.XAER_RMERR); } alreadyEnlisted=true; } } // ----------------------------------------------- DescriptorsStore Methods /** * Retrive an object. * * @param uri Uri of the object we want to retrieve * @exception ServiceAccessException Error accessing the Service * @exception ObjectNotFoundException The object to retrieve was not found */ public ObjectNode retrieveObject(Uri uri) throws ServiceAccessException, ObjectNotFoundException { ObjectNode result = null; PreparedStatement statement = null; try { statement = connection.prepareStatement ("select * from objects where uri= ?"); statement.setString(1, uri.toString()); ResultSet res = statement.executeQuery(); // Parsing result set String className; if (res.next()) { // Retrieving and loading the object className = res.getString(OBJECTS_CLASS); } else { // Object was not found ... throw new ObjectNotFoundException(uri); } closeStatement(statement); // Then, retrieve the children statement = connection.prepareStatement ("select * from children where uri= ?"); statement.setString(1,uri.toString()); res = statement.executeQuery(); Vector childrenVector = new Vector(); // Parse result set while (res.next()) { // Load each permission childrenVector.addElement(res.getString(CHILDREN_CHILDURI)); } closeStatement(statement); statement = connection.prepareStatement ("select * from links where linkto= ?"); statement.setString(1,uri.toString()); res = statement.executeQuery(); Vector linksVector = new Vector(); // Parse result set while (res.next()) { // Load each permission linksVector.addElement(res.getString(LINKS_LINKTO)); } closeStatement(statement); if (className.equals("org.apache.slide.structure.LinkNode")) { String linkTo = new String(); statement = connection.prepareStatement ("select * from links where link= ?"); statement.setString(1,uri.toString()); res = statement.executeQuery(); if(res.next()) linkTo = res.getString(LINKS_LINKTO); closeStatement(statement); result = new LinkNode(uri.toString(), childrenVector, linksVector, linkTo); } else { try { Class objclass = Class.forName(className); Class[] argClasses = { Class.forName("java.lang.String"), Class.forName("java.util.Vector"), Class.forName("java.util.Vector") }; Object[] arguments = { uri.toString(), childrenVector, linksVector }; Constructor constructor = objclass.getConstructor(argClasses); result = (ObjectNode)constructor.newInstance(arguments); } catch(Exception e) { // ClassNotFoundException, NoSuchMethodException, etc. throw new ServiceAccessException(this, e); } } } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } return result; } /** * Update an object. * * @param object Object to update * @exception ServiceAccessException Error accessing the Service * @exception ObjectNotFoundException The object to update was not found */ public void storeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { PreparedStatement statement = null; try { statement = connection.prepareStatement ("select * from objects where uri= ?"); statement.setString(1, uri.toString()); ResultSet res = statement.executeQuery(); // Parsing result set if (!res.next()) { throw new ObjectNotFoundException(uri); } closeStatement(statement); // Updating children statement = connection.prepareStatement ("delete from children where uri= ?"); statement.setString(1, object.getUri()); statement.execute(); closeStatement(statement); statement = null; Enumeration children = object.enumerateChildren(); while (children.hasMoreElements()) { if (statement == null){ statement = connection.prepareStatement ("insert into children values(?, ?)"); } statement.setString(1, object.getUri()); statement.setString(2, (String)children.nextElement()); statement.execute(); } closeStatement(statement); // Updating inbound links /* s = "delete from links where linkto='" + object.getUri() + "'"; statement.execute(s); Enumeration links = object.enumerateLinks(); while (children.hasMoreElements()) { s = "insert into links values('" + (String) links.nextElement() + "', '" + object.getUri() + "')"; statement.execute(s); } */ // Updating links statement = connection.prepareStatement ("delete from links where link= ?"); statement.setString(1, object.getUri()); statement.execute(); closeStatement(statement); if (object instanceof LinkNode) { statement = connection.prepareStatement ("insert into links values(?,?)"); statement.setString(1, object.getUri()); statement.setString(2, ((LinkNode) object).getLinkedUri()); statement.execute(); closeStatement(statement); } } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Create a new object. * * @param object ObjectNode * @param uri Uri of the object we want to create * @exception ServiceAccessException Error accessing the Service * @exception ObjectAlreadyExistsException An object already exists * at this Uri */ public void createObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectAlreadyExistsException { PreparedStatement statement = null; try { String className = object.getClass().getName(); statement = connection.prepareStatement ("select * from objects where uri= ?"); statement.setString(1, uri.toString()); ResultSet res = statement.executeQuery(); // Parsing result set if (res.next()) { throw new ObjectAlreadyExistsException(uri.toString()); } closeStatement(statement); statement = connection.prepareStatement ("insert into objects values(?,?)"); statement.setString(1, uri.toString()); statement.setString(2, className ); statement.execute(); closeStatement(statement); statement = null; // Inserting children Enumeration children = object.enumerateChildren(); while (children.hasMoreElements()) { if (statement == null){ statement = connection.prepareStatement ("insert into children values(?,?)"); } statement.setString(1, uri.toString()); statement.setString(2, (String) children.nextElement()); statement.execute(); } closeStatement(statement); // Updating inbound links /* Enumeration links = object.enumerateLinks(); while (children.hasMoreElements()) { s = "insert into links values('" + (String) links.nextElement() + "', '" + object.getUri() + "')"; statement.execute(s); } */ // If the object is a link, also store the link information if (object instanceof LinkNode) { statement = connection.prepareStatement ("insert into links values(?,?)"); statement.setString(1, uri.toString()); statement.setString(2, ((LinkNode) object).getLinkedUri()); statement.execute(); closeStatement(statement); } } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Remove an object. * * @param object Object to remove * @exception ServiceAccessException Error accessing the Service * @exception ObjectNotFoundException The object to remove was not found */ public void removeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { PreparedStatement statement = null; try { // Removing object statement = connection.prepareStatement ("delete from objects where uri= ?"); statement.setString(1,object.getUri()); statement.execute(); closeStatement(statement); // Removing children statement = connection.prepareStatement ("delete from children where uri=?"); statement.setString(1, object.getUri()); statement.execute(); closeStatement(statement); // Removing inbound links /* s = "delete from links where linkto='" + object.getUri() + "'"; statement.execute(s); */ // Removing links statement = connection.prepareStatement ("delete from links where link= ?"); statement.setString(1, object.getUri()); statement.execute(); closeStatement(statement); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } } /** * Grant a new permission. * * @param permission Permission we want to create * @exception ServiceAccessException Error accessing the Service */ public void grantPermission(Uri uri, NodePermission permission) throws ServiceAccessException { PreparedStatement statement = null; try { int inheritable = 0; if (permission.isInheritable()) { inheritable = 1; } int negative = 0; if (permission.isNegative()) { negative = 1; } NodeRevisionNumber revisionNumber = permission.getRevisionNumber(); String revisionNumberStr = (revisionNumber == null) ? null : revisionNumber.toString(); statement = connection.prepareStatement ("insert into permissions values(?,?,?,?,?,?)"); statement.setString(1, permission.getObjectUri()); statement.setString(2, revisionNumberStr); statement.setString(3, permission.getSubjectUri()); statement.setString(4, permission.getActionUri()); statement.setInt(5, inheritable); statement.setInt(6, negative); statement.execute(); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Revoke a permission. * * @param permission Permission we want to create * @exception ServiceAccessException Error accessing the Service */ public void revokePermission(Uri uri, NodePermission permission) throws ServiceAccessException { /* Warning changes to this method should also be done to CloudscapeDescriptorsStore */ PreparedStatement statement = null; try { NodeRevisionNumber revisionNumber = permission.getRevisionNumber(); if(revisionNumber != null) { statement = connection.prepareStatement ("delete from permissions where object= ? and subject = ? and action = ? and revisionnumber = ? "); statement.setString(4, revisionNumber.toString()); } else { statement = connection.prepareStatement ("delete from permissions where object = ? and subject = ? and action = ? and revisionnumber is NULL"); } statement.setString(1, permission.getObjectUri()); statement.setString(2, permission.getSubjectUri()); statement.setString(3, permission.getActionUri()); statement.execute(); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Revoke all the permissions on an object. * * @param permission Permission we want to create * @exception ServiceAccessException Error accessing the Service */ public void revokePermissions(Uri uri) throws ServiceAccessException { PreparedStatement statement = null; try { statement = connection.prepareStatement ("delete from permissions where object= ?"); statement.setString(1, uri.toString()); statement.execute(); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Enumerate permissions on an object. * * @param permission Permission we want to create * @exception ServiceAccessException Error accessing the Service */ public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException { Vector permissionVector = new Vector(); PreparedStatement statement = null; try { statement = connection.prepareStatement ("select * from permissions where object= ?"); statement.setString(1, uri.toString()); ResultSet res = statement.executeQuery(); while (res.next()) { String object = res.getString(PERMISSIONS_OBJECT); String revision = res.getString(PERMISSIONS_REVISION_NUMBER); String subject = res.getString(PERMISSIONS_SUBJECT); String action = res.getString(PERMISSIONS_ACTION); boolean inheritable = false; if (res.getInt(PERMISSIONS_INHERITABLE) == 1) { inheritable = true; } boolean negative = false; if (res.getInt(PERMISSIONS_NEGATIVE) == 1) { negative = true; } NodePermission permission = new NodePermission(object,revision,subject, action,inheritable,negative); permissionVector.addElement(permission); } } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } return permissionVector.elements(); } /** * Create a new lock. * * @param lock Lock token * @exception ServiceAccessException Service access error */ public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException { PreparedStatement statement = null; try { int inheritable = 0; if (lock.isInheritable()) { inheritable = 1; } int exclusive = 0; if (lock.isExclusive()) { exclusive = 1; } statement = connection.prepareStatement ("insert into locks values(?,?,?,?,?,?,?)"); statement.setString(1, lock.getLockId()); statement.setString(2, lock.getObjectUri()); statement.setString(3, lock.getSubjectUri()); statement.setString(4, lock.getTypeUri()); statement.setString (5, String.valueOf(lock.getExpirationDate().getTime())); statement.setInt(6,inheritable); statement.setInt(7, exclusive); statement.execute(); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Renew a lock. * * @param lock Token to renew * @exception ServiceAccessException Service access error * @exception LockTokenNotFoundException Lock token was not found */ public void renewLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { PreparedStatement statement = null; try { int inheritable = 0; if (lock.isInheritable()) { inheritable = 1; } int exclusive = 0; if (lock.isExclusive()) { exclusive = 1; } statement = connection.prepareStatement ("delete from locks where id=?"); statement.setString(1, lock.getLockId()); statement.execute(); closeStatement(statement); statement = connection.prepareStatement ("insert into locks values(?,?,?,?,?,?,?)"); statement.setString(1, lock.getLockId()); statement.setString(2, lock.getObjectUri()); statement.setString(3, lock.getSubjectUri()); statement.setString(4, lock.getTypeUri()); statement.setString (5, String.valueOf(lock.getExpirationDate().getTime())); statement.setInt(6, inheritable); statement.setInt(7, exclusive); statement.execute(); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Unlock. * * @param lock Token to remove * @exception ServiceAccessException Service access error * @exception LockTokenNotFoundException Lock token was not found */ public void removeLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { Statement statement = null; try { statement = connection.createStatement(); int inheritable = 0; if (lock.isInheritable()) { inheritable = 1; } String s = null; s = "delete from locks where id='" + lock.getLockId() + "'"; statement.execute(s); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Kill a lock. * * @param lock Token to remove * @exception ServiceAccessException Service access error * @exception LockTokenNotFoundException Lock token was not found */ public void killLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { removeLock(uri, lock); } /** * Enumerate locks on an object. * * @param subject Subject * @return Enumeration List of locks which have been put on the subject * @exception ServiceAccessException Service access error */ public Enumeration enumerateLocks(Uri uri) throws ServiceAccessException { Vector lockVector = new Vector(); PreparedStatement statement = null; try { statement = connection.prepareStatement ("select * from locks where object= ?"); statement.setString(1, uri.toString()); statement.execute(); ResultSet res = statement.getResultSet(); while (res.next()) { Date expirationDate = null; try { Long timeValue = new Long(res.getString (LOCKS_EXPIRATIONDATE)); expirationDate = new Date(timeValue.longValue()); } catch (NumberFormatException e) { expirationDate = new Date(); } NodeLock lock = new NodeLock(res.getString(LOCKS_ID), res.getString(LOCKS_OBJECT), res.getString(LOCKS_SUBJECT), res.getString(LOCKS_TYPE), expirationDate, (res.getInt(LOCKS_INHERITABLE) == 1), (res.getInt(LOCKS_EXCLUSIVE) == 1)); lockVector.addElement(lock); } } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } return lockVector.elements(); } /** * Retrieve the revisions informations of an object. * * @param uri Uri * @exception ServiceAccessException Service access error * @exception RevisionDescriptorNotFoundException Revision descriptor * was not found */ public NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri) throws ServiceAccessException, RevisionDescriptorNotFoundException { NodeRevisionDescriptors revisionDescriptors = null; PreparedStatement statement = null; PreparedStatement statement2 = null; try { ResultSet res = null; NodeRevisionNumber initialRevision = new NodeRevisionNumber(); Hashtable workingRevisions = new Hashtable(); Hashtable latestRevisionNumbers = new Hashtable(); Hashtable branches = new Hashtable(); boolean isVersioned = false; statement = connection.prepareStatement ("select * from revisions where uri= ?"); statement.setString(1, uri.toString()); res = statement.executeQuery(); if (res.next()) { int isVersionedInt = res.getInt(REVISIONS_ISVERSIONED); if (isVersionedInt == 1) { isVersioned = true; } } else { throw new RevisionDescriptorNotFoundException(uri.toString()); } closeStatement(statement); statement = connection.prepareStatement ("select * from workingrevision where uri= ?"); statement.setString(1, uri.toString()); res = statement.executeQuery(); while(res.next()) { // TODO : Parse each working revision definition } closeStatement(statement); statement = connection.prepareStatement ("select * from latestrevisions where uri=?"); statement.setString(1, uri.toString()); res = statement.executeQuery(); while(res.next()) { latestRevisionNumbers .put(res.getString(LATESTREVISIONS_BRANCHNAME), new NodeRevisionNumber (res.getString(LATESTREVISIONS_NUMBER))); } closeStatement(statement); statement = connection.prepareStatement ("select * from revision where uri= ?"); statement.setString(1, uri.toString()); res = statement.executeQuery(); while(res.next()) { String currentRevisionNumber = res.getString(REVISION_NUMBER); // We parse the revision list of the object if (statement2 == null){ statement2 = connection.prepareStatement ("select * from branches where uri = ? and xnumber = ?"); } statement2.setString(1, uri.toString()); statement2.setString(2, currentRevisionNumber); ResultSet res2 = statement2.executeQuery(); Vector childList = new Vector(); while (res2.next()) { childList.addElement(new NodeRevisionNumber (res2.getString(BRANCHES_CHILDNUMBER))); } branches.put(new NodeRevisionNumber(currentRevisionNumber), childList); res2.close(); } closeStatement(statement2); revisionDescriptors = new NodeRevisionDescriptors (uri.toString(), initialRevision, workingRevisions, latestRevisionNumbers, branches, isVersioned); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); closeStatement(statement2); } return revisionDescriptors; } /** * Create a new revision information object. * * @param uri Uri * @param revisionDescriptors Node revision descriptors * @exception ServiceAccessException Service access error */ public void createRevisionDescriptors (Uri uri, NodeRevisionDescriptors revisionDescriptors) throws ServiceAccessException { // TODO : Here, we have the option of "cleaning up" before // creating the new records in the database. PreparedStatement statement = null; try { ResultSet res = null; // Creating record in revisions tables int isVersioned = 0; if (revisionDescriptors.isVersioned()) { isVersioned = 1; } statement = connection.prepareStatement ("insert into revisions values(?,?,?)"); statement.setString(1,uri.toString()); statement.setInt(2, isVersioned); statement.setString (3, revisionDescriptors.getInitialRevision().toString()); statement.execute(); closeStatement(statement); // Creating records in working revisions table // ... TODO (working revisions are not used for now) // Creating records in latest revisions table // For now, only the latest revision from the main branch is stored if (revisionDescriptors.getLatestRevision() != null) { statement = connection.prepareStatement ("insert into latestrevisions values(?,?,?)"); statement.setString(1, uri.toString()); statement.setString (2, NodeRevisionDescriptors.MAIN_BRANCH.toString()); statement.setString (3, revisionDescriptors.getLatestRevision().toString()); statement.execute(); closeStatement(statement); } // Creating records in the branches table // TODO } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Update revision information. * * @param uri Uri * @param revisionDescriptors Node revision descriptors * @exception ServiceAccessException Service access error * @exception RevisionDescriptorNotFoundException Revision descriptor * was not found */ public void storeRevisionDescriptors (Uri uri, NodeRevisionDescriptors revisionDescriptors) throws ServiceAccessException, RevisionDescriptorNotFoundException { removeRevisionDescriptors(uri); createRevisionDescriptors(uri, revisionDescriptors); } /** * Remove revision information. * * @param uri Uri * @exception ServiceAccessException Service access error */ public void removeRevisionDescriptors(Uri uri) throws ServiceAccessException { PreparedStatement statement = null; try { statement = connection.prepareStatement ("delete from revisions where uri= ?"); statement.setString(1, uri.toString()); statement.execute(); closeStatement(statement); statement = connection.prepareStatement ("delete from workingrevision where uri= ?"); statement.setString(1, uri.toString()); statement.execute(); closeStatement(statement); statement = connection.prepareStatement ("delete from latestrevisions where uri= ?"); statement.setString(1, uri.toString()); statement.execute(); closeStatement(statement); statement = connection.prepareStatement ("delete from branches where uri= ?"); statement.setString(1, uri.toString()); statement.execute(); closeStatement(statement); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Retrieve an individual object's revision descriptor. * * @param Uri uri * @param revisionNumber Node revision number */ public NodeRevisionDescriptor retrieveRevisionDescriptor (Uri uri, NodeRevisionNumber revisionNumber) throws ServiceAccessException, RevisionDescriptorNotFoundException { NodeRevisionDescriptor revisionDescriptor = null; PreparedStatement statement = null; if(revisionNumber == null) throw new RevisionDescriptorNotFoundException(uri.toString()); try { ResultSet res = null; String branchName = null; Vector labels = new Vector(); Hashtable properties = new Hashtable(); // Retrieving branch name (and also check that revision // does indeed exist) statement = connection.prepareStatement ("select * from revision where uri= ? and xnumber = ?"); statement.setString(1, uri.toString()); statement.setString(2, revisionNumber.toString()); res = statement.executeQuery(); if (res.next()) { branchName = res.getString(REVISION_BRANCHNAME); } else { throw new RevisionDescriptorNotFoundException(uri.toString()); } closeStatement(statement); // Retrieve labels statement = connection.prepareStatement ("select * from label where uri= ? and xnumber = ?"); statement.setString(1, uri.toString()); statement.setString(2, revisionNumber.toString()); res = statement.executeQuery(); while (res.next()) { labels.addElement(res.getString(LABEL_LABEL)); } closeStatement(statement); // Retrieve properties statement = connection.prepareStatement ("select * from property where uri= ? and xnumber = ?"); statement.setString(1, uri.toString()); statement.setString(2, revisionNumber.toString()); res = statement.executeQuery(); while (res.next()) { String propertyName = res.getString(PROPERTY_NAME); String propertyNamespace = res.getString(PROPERTY_NAMESPACE); NodeProperty property = new NodeProperty(propertyName, res.getString(PROPERTY_VALUE), propertyNamespace, res.getString(PROPERTY_TYPE), (res.getInt(PROPERTY_PROTECTED) == 1)); properties.put(propertyNamespace + propertyName, property); } revisionDescriptor = new NodeRevisionDescriptor(revisionNumber, branchName, labels, properties); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } return revisionDescriptor; } /** * Create a new revision descriptor. * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @exception ServiceAccessException Service access error */ public void createRevisionDescriptor (Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException { PreparedStatement statement = null; try { ResultSet res = null; statement = connection.prepareStatement ("insert into revision values(?, ?, ?)"); statement.setString(1, uri.toString()); statement.setString (2, revisionDescriptor.getRevisionNumber().toString()); statement.setString(3, revisionDescriptor.getBranchName()); statement.execute(); closeStatement(statement); // Creating revision labels statement = null; Enumeration labels = revisionDescriptor.enumerateLabels(); while (labels.hasMoreElements()) { if (statement == null){ statement = connection.prepareStatement ("insert into label values(?,?,?)"); } statement.setString(1, uri.toString()); statement.setString (2, revisionDescriptor.getRevisionNumber().toString()); statement.setString(3, (String)labels.nextElement()); statement.execute(); } closeStatement(statement); // Creating associated properties statement = null; Enumeration properties = revisionDescriptor.enumerateProperties(); while (properties.hasMoreElements()) { NodeProperty property = (NodeProperty) properties.nextElement(); int protectedProperty = 0; if (property.isProtected()) { protectedProperty = 1; } if (statement == null){ statement = connection.prepareStatement ("insert into property values(?,?,?,?,?,?,?)"); } statement.setString(1, uri.toString()); statement.setString (2, revisionDescriptor.getRevisionNumber().toString()); statement.setString(3, property.getName()); statement.setString(4, property.getValue().toString()); statement.setString(5, property.getNamespace()); statement.setString(6, property.getType()); statement.setInt(7, protectedProperty); statement.execute(); } closeStatement(statement); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } /** * Update a revision descriptor. * * @param uri Uri * @param revisionDescriptors Node revision descriptor * @exception ServiceAccessException Service access error * @exception RevisionDescriptorNotFoundException Revision descriptor * was not found */ public void storeRevisionDescriptor (Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException, RevisionDescriptorNotFoundException { removeRevisionDescriptor(uri, revisionDescriptor.getRevisionNumber()); createRevisionDescriptor(uri, revisionDescriptor); } /** * Remove a revision descriptor. * * @param uri Uri * @param revisionNumber Revision number * @exception ServiceAccessException Service access error */ public void removeRevisionDescriptor(Uri uri, NodeRevisionNumber number) throws ServiceAccessException { PreparedStatement statement = null; try { statement = connection.prepareStatement ("delete from revision where uri= ? and xnumber = ?"); statement.setString(1, uri.toString()); statement.setString(2, number.toString()); statement.execute(); closeStatement(statement); // Removing revision labels statement = connection.prepareStatement ("delete from label where uri= ? and xnumber = ?"); statement.setString(1, uri.toString()); statement.setString(2, number.toString()); statement.execute(); closeStatement(statement); // Removing associated properties statement = connection.prepareStatement ("delete from property where uri= ? and xnumber = ?"); statement.setString(1, uri.toString()); statement.setString(2, number.toString()); statement.execute(); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e); } finally { closeStatement(statement); } } // --------------------------------------------------- ContentStore Methods /** * Retrive revision content. * * @param uri Uri * @param revisionNumber Node revision number */ public NodeRevisionContent retrieveRevisionContent (Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException, RevisionNotFoundException { NodeRevisionContent result = null; String revisionUri = uri.toString(); String revisionNumber = revisionDescriptor.getRevisionNumber().toString(); try { PreparedStatement selectStatement = connection.prepareStatement ("select * from revisioncontent where uri = ? and " + "xnumber = ?"); selectStatement.setString(1, revisionUri); selectStatement.setString(2, revisionNumber); ResultSet rs = selectStatement.executeQuery(); if (!rs.next()) { rs.close(); selectStatement.close(); throw new RevisionNotFoundException (uri.toString(), revisionDescriptor.getRevisionNumber()); } InputStream is = rs.getBinaryStream(REVISION_CONTENT); if (is == null) { throw new RevisionNotFoundException (uri.toString(), revisionDescriptor.getRevisionNumber()); } result = new NodeRevisionContent(); result.setContent(is); // this input stream passes on the closure of itself onto the // jdbc statement and resultSet result.setContent( new JDBCAwareInputStream(is,selectStatement) ); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } catch (RevisionNotFoundException e) { getLogger().log("RevisionNotFoundException encountered for " + revisionUri + " revision " + revisionNumber, LOG_CHANNEL, Logger.WARNING); throw e; // we do NOT want this caught by next clause. } catch (Exception e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } return result; } /** * Create a new revision * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @param revisionContent Node revision content */ public void createRevisionContent (Uri uri, NodeRevisionDescriptor revisionDescriptor, NodeRevisionContent revisionContent) throws ServiceAccessException, RevisionAlreadyExistException { String revisionUri = uri.toString(); String revisionNumber = revisionDescriptor.getRevisionNumber().toString(); long contentLength = revisionDescriptor.getContentLength(); PreparedStatement selectStatement = null; try { selectStatement = connection.prepareStatement ("select 1 from revisioncontent where uri = ? and " + "xnumber = ?"); selectStatement.setString(1, revisionUri); selectStatement.setString(2, revisionNumber); ResultSet rs = selectStatement.executeQuery(); if (rs.next()) { rs.close(); throw new RevisionAlreadyExistException (uri.toString(), revisionDescriptor.getRevisionNumber()); } rs.close(); storeContent(revisionUri, revisionNumber, revisionDescriptor, revisionContent); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } catch (IOException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } catch(RevisionAlreadyExistException e) { getLogger().log("RevisionNotFoundException encountered for " + revisionUri + " revision " + revisionNumber, LOG_CHANNEL, Logger.WARNING); throw e; // we do NOT want this caught by next clause. } catch (Exception e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } finally { closeStatement(selectStatement); } } /** * Modify the latest revision of an object. * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @param revisionContent Node revision content */ public void storeRevisionContent (Uri uri, NodeRevisionDescriptor revisionDescriptor, NodeRevisionContent revisionContent) throws ServiceAccessException, RevisionNotFoundException { String revisionUri = uri.toString(); String revisionNumber = revisionDescriptor.getRevisionNumber().toString(); PreparedStatement selectStatement = null; try { selectStatement = connection.prepareStatement ("select 1 from revisioncontent where uri = ? and " + "xnumber = ?"); selectStatement.setString(1, revisionUri); selectStatement.setString(2, revisionNumber); ResultSet rs = selectStatement.executeQuery(); if (!rs.next()) { rs.close(); selectStatement.close(); throw new RevisionNotFoundException (uri.toString(), revisionDescriptor.getRevisionNumber()); } rs.close(); removeContent(revisionUri, revisionNumber); storeContent(revisionUri, revisionNumber, revisionDescriptor, revisionContent); } catch (SQLException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } catch (IOException e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } catch(RevisionNotFoundException e) { getLogger().log("RevisionNotFoundException encountered for " + revisionUri + " revision " + revisionNumber, LOG_CHANNEL, Logger.WARNING); throw e; // we do NOT want this caught by next clause. } catch (Exception e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } finally { closeStatement(selectStatement); } } /** * Remove revision. * * @param uri Uri * @param revisionNumber Node revision number */ public void removeRevisionContent (Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException { String revisionUri = uri.toString(); String revisionNumber = revisionDescriptor.getRevisionNumber().toString(); try { removeContent(revisionUri, revisionNumber); } catch (Exception e) { getLogger().log(e,LOG_CHANNEL, Logger.ERROR); connectIfNeededAndPossible(); throw new ServiceAccessException(this, e.getMessage()); } } // -------------------------------------------------------- Private Methods /** * Close specified statement. */ private void closeStatement(Statement statement) { if (statement != null) { try { statement.close(); } catch (SQLException e) { connectIfNeededAndPossible(); } } } /** * Store a revision. */ private void storeContent(String revisionUri, String revisionNumber, NodeRevisionDescriptor revisionDescriptor, NodeRevisionContent revisionContent) throws IOException, SQLException { PreparedStatement insertStatement = connection.prepareStatement ("insert into revisioncontent values(?, ?, ?)"); insertStatement.setString(1, revisionUri); insertStatement.setString(2, revisionNumber); InputStream is = revisionContent.streamContent(); if (is != null) { OutputStream os = null; // We copy 8 ko with each read byte[] buffer = new byte[BUFFER_SIZE]; long position = 0; long contentLength = revisionDescriptor.getContentLength(); File tempFile = null; String tempFileName = null; if (contentLength == -1) { // If content length is unspecified, we have to buffer // to a temp file. try { tempFileName = revisionUri + "-" + revisionNumber; tempFileName = tempFileName.replace('/', '.'); int tempFileNameLength = tempFileName.length(); if (tempFileNameLength > 200) tempFileName = tempFileName.substring (tempFileNameLength - 200, tempFileNameLength); tempFile = File.createTempFile(tempFileName, null); FileOutputStream fos = new FileOutputStream(tempFile); while (true) { int nChar = is.read(buffer); if (nChar == -1) { break; } fos.write(buffer, 0, nChar); position = position + nChar; } fos.close(); is = new FileInputStream(tempFile); contentLength = tempFile.length(); } catch (IOException ex) { getLogger().log(ex.toString() + " during the calculation of the content length.",LOG_CHANNEL, Logger.ERROR); getLogger().log("tempFileName: " + tempFileName,LOG_CHANNEL, Logger.ERROR); getLogger().log("tempFile: " + tempFile.getAbsolutePath(),LOG_CHANNEL, Logger.ERROR); throw ex; } } // FIXME ? Cast from long to int won't allow files > 4GB. insertStatement.setBinaryStream(3, is, (int) contentLength); insertStatement.executeUpdate(); revisionDescriptor.setContentLength(contentLength); if (tempFile != null) { is.close(); tempFile.delete(); } } insertStatement.close(); } /** * Remove content. */ private void removeContent(String revisionUri, String revisionNumber) throws SQLException { PreparedStatement deleteStatement = connection.prepareStatement ("delete from revisioncontent where uri = ? and xnumber = ?"); deleteStatement.setString(1, revisionUri); deleteStatement.setString(2, revisionNumber); deleteStatement.executeUpdate(); deleteStatement.close(); } /** * Returns the sql statements to create the database objects. */ private String[] getDatabaseCreateStatements() { String[] statements = { "create table objects(uri varchar(65536) primary key," + " classname varchar(4096))", "create table children(uri varchar(65536), " + " childuri varchar(65536))", "create table links(link varchar(65536), " + " linkto varchar(65536))", "create table permissions(object varchar(65536)," + " revisionnumber varchar(20), " + " subject varchar(65536), action varchar(65536), " + " inheritable int, negative int)", "create table locks(id varchar(65536), object varchar(4096)," + " subject varchar(4096), type varchar(4096), " + " expirationdate varchar(15), inheritable int, " + " xexclusive int)", "create table revisions(uri varchar(65536) primary key, " + " isversioned int, initialrevision varchar(10))", "create table workingrevision(uri varchar(65536), " + " baserevision varchar(20), xnumber varchar(20))", "create table latestrevisions(uri varchar(65536), " + " branchname varchar(4096), xnumber varchar(20))", "create table branches(uri varchar(65536), xnumber varchar(20)," + " childnumber varchar(20))", "create table revision(uri varchar(65536), xnumber varchar(20)," + " branchname varchar(4096))", "create table label(uri varchar(65536), xnumber varchar(20)," + " label varchar(4096))", "create table property(uri varchar(65536), xnumber varchar(20)," + " name varchar(4096), value varchar(65536), " + " namespace varchar(4096), type varchar(100), private int)", "create table revisioncontent(uri varchar(65536), " + " xnumber varchar(20), content LONGVARBINARY)"}; return statements; } private String getDatabaseConnectionTestStatement() { return "select 1 from objects where uri is null"; } }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
