You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by mi...@apache.org on 2005/11/15 14:18:21 UTC

svn commit: r344363 - /lenya/branches/BRANCH_1_2_X/src/java/org/apache/lenya/cms/rc/RevisionController.java

Author: michi
Date: Tue Nov 15 05:18:15 2005
New Revision: 344363

URL: http://svn.apache.org/viewcvs?rev=344363&view=rev
Log:
Revision controller prepared such that it works with configurable content directories

Modified:
    lenya/branches/BRANCH_1_2_X/src/java/org/apache/lenya/cms/rc/RevisionController.java

Modified: lenya/branches/BRANCH_1_2_X/src/java/org/apache/lenya/cms/rc/RevisionController.java
URL: http://svn.apache.org/viewcvs/lenya/branches/BRANCH_1_2_X/src/java/org/apache/lenya/cms/rc/RevisionController.java?rev=344363&r1=344362&r2=344363&view=diff
==============================================================================
--- lenya/branches/BRANCH_1_2_X/src/java/org/apache/lenya/cms/rc/RevisionController.java (original)
+++ lenya/branches/BRANCH_1_2_X/src/java/org/apache/lenya/cms/rc/RevisionController.java Tue Nov 15 05:18:15 2005
@@ -15,7 +15,7 @@
  *
  */
 
-/* $Id: RevisionController.java,v 1.28 2004/07/16 15:43:59 edith Exp $  */
+/* $Id$  */
 
 package org.apache.lenya.cms.rc;
 
@@ -27,6 +27,8 @@
 import java.io.OutputStream;
 import java.util.Date;
 
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.Publication;
 import org.apache.lenya.util.XPSFileOutputStream;
 import org.apache.log4j.Category;
 
@@ -107,6 +109,22 @@
      * @throws IOException if an error occurs
      * @throws Exception if an error occurs
      */
+    public RCML getRCML(Document doc) throws FileNotFoundException, IOException, Exception {
+        return new RCML(rcmlDir, doc.getDocumentAreaPath(), rootDir);
+    }
+
+    /**
+     * @deprecated please use getRCML(Document doc)
+     * Get the RCML File for the file source
+     *
+     * @param source The path of the file from the publication.
+     *
+     * @return RCML The corresponding RCML file.
+     *
+     * @throws FileNotFoundException if an error occurs
+     * @throws IOException if an error occurs
+     * @throws Exception if an error occurs
+     */
     public RCML getRCML(String source) throws FileNotFoundException, IOException, Exception {
         return new RCML(rcmlDir, source, rootDir);
     }
@@ -119,6 +137,41 @@
      * @return File File to check out
      * @throws Exception if an error occurs
      */
+    public File reservedCheckOut(Document doc, String identity) throws Exception {
+
+        RCML rcml = new RCML(rcmlDir, doc.getDocumentAreaPath(), rootDir);
+
+        RCMLEntry entry = rcml.getLatestEntry();
+
+        // The same user is allowed to check out repeatedly without
+        // having to check back in first.
+        //
+        if (entry != null) {
+            log.debug("entry: " + entry);
+            log.debug("entry.type:" + entry.getType());
+            log.debug("entry.identity" + entry.getIdentity());
+        }
+
+        if ((entry != null)
+            && (entry.getType() != RCML.ci)
+            && !entry.getIdentity().equals(identity)) {
+            throw new FileReservedCheckOutException(rootDir + doc.getDocumentAreaPath(), rcml);
+        }
+
+        rcml.checkOutIn(RCML.co, identity, new Date().getTime(), false);
+
+        return doc.getFile();
+    }
+
+    /**
+     * @deprecated reservedCheckOut(Document, String)
+     * Try to make a reserved check out of the file source for a user with identity
+     *
+     * @param source The filename of the file to check out
+     * @param identity The identity of the user
+     * @return File File to check out
+     * @throws Exception if an error occurs
+     */
     public File reservedCheckOut(String source, String identity) throws Exception {
         
         File file = new File(rootDir + source);
@@ -159,6 +212,35 @@
      * @return A boolean value.
      * @throws Exception when something went wrong.
      */
+    public boolean canCheckOut(Document doc, String identity) throws Exception {
+                
+        RCML rcml = new RCML(rcmlDir, doc.getDocumentAreaPath(), rootDir);
+
+        RCMLEntry entry = rcml.getLatestEntry();
+
+        // The same user is allowed to check out repeatedly without
+        // having to check back in first.
+        //
+        if (entry != null) {
+            log.debug("entry: " + entry);
+            log.debug("entry.type:" + entry.getType());
+            log.debug("entry.identity" + entry.getIdentity());
+        }
+
+        boolean checkedOutByOther =
+            entry != null && entry.getType() != RCML.ci && !entry.getIdentity().equals(identity);
+
+        return !checkedOutByOther;
+    }
+
+    /**
+     * @deprecated please use canCheckOut(Document, String)
+     * Checks if a source can be checked out.
+     * @param source The source.
+     * @param identity The identity who requests checking out.
+     * @return A boolean value.
+     * @throws Exception when something went wrong.
+     */
     public boolean canCheckOut(String source, String identity) throws Exception {
         RCML rcml = new RCML(rcmlDir, source, rootDir);
 
@@ -193,6 +275,116 @@
      *            because it is already checked out by someone other ...)
      * @exception Exception if other problems occur
      */
+    public long reservedCheckIn(Document doc, String identity, boolean backup)
+        throws FileReservedCheckInException, Exception {
+        
+        RCML rcml = new RCML(rcmlDir, doc.getDocumentAreaPath(), rootDir);
+
+        CheckOutEntry coe = rcml.getLatestCheckOutEntry();
+        CheckInEntry cie = rcml.getLatestCheckInEntry();
+
+        // If there has never been a checkout for this object
+        // *or* if the user attempting the checkin right now
+        // is the system itself, we will skip any checks and proceed
+        // right away to the actual checkin.
+        // In all other cases we enforce the revision control
+        // rules inside this if clause:
+        //
+        if (!((coe == null) || identity.equals(RevisionController.systemUsername))) {
+            /*
+             * Possible cases and rules:
+             *
+             * 1.) we were able to read the latest checkin and it is later than latest checkout
+             *     (i.e. there is no open checkout to match this checkin, an unusual case)
+             *     1.1.) identity of latest checkin is equal to current user
+             *           -> checkin allowed, same user may check in repeatedly
+             *     1.2.) identity of latest checkin is not equal to current user
+             *           -> checkin rejected, may not overwrite the revision which
+             *              another user checked in previously
+             * 2.) there was no checkin or the latest checkout is later than latest checkin
+             *     (i.e. there is an open checkout)
+             *     2.1.) identity of latest checkout is equal to current user
+             *           -> checkin allowed, user checked out and may check in again
+             *              (the most common case)
+             *     2.2.) identity of latest checkout is not equal to current user
+             *           -> checkin rejected, may not check in while another
+             *              user is working on this document
+             *
+             */
+            if ((cie != null) && (cie.getTime() > coe.getTime())) {
+                // We have case 1
+                if (!cie.getIdentity().equals(identity)) {
+                    // Case 1.2., abort...
+                    //
+                    throw new FileReservedCheckInException(rootDir + doc.getDocumentAreaPath(), rcml);
+                }
+            } else {
+                // Case 2
+                if (!coe.getIdentity().equals(identity)) {
+                    // Case 2.2., abort...
+                    //
+                    throw new FileReservedCheckInException(rootDir + doc.getDocumentAreaPath(), rcml);
+                }
+            }
+        }
+
+        File originalFile = doc.getFile();
+        long time = new Date().getTime();
+
+        if (backup && originalFile.isFile()) {
+            File backupFile = new File(backupDir, doc.getDocumentAreaPath() + ".bak." + time);
+            File parent = new File(backupFile.getParent());
+
+            if (!parent.isDirectory()) {
+                parent.mkdirs();
+            }
+
+            log.info(
+                "Backup: copy "
+                    + originalFile.getAbsolutePath()
+                    + " to "
+                    + backupFile.getAbsolutePath());
+
+            InputStream in = new FileInputStream(originalFile.getAbsolutePath());
+
+            OutputStream out = new XPSFileOutputStream(backupFile.getAbsolutePath());
+            byte[] buffer = new byte[512];
+            int length;
+
+            while ((length = in.read(buffer)) != -1) {
+                out.write(buffer, 0, length);
+            }
+
+            out.close();
+        }
+
+        rcml.checkOutIn(RCML.ci, identity, time, backup);
+        rcml.pruneEntries(backupDir);
+        rcml.write();
+
+        // FIXME: If we reuse the observer pattern as implemented in
+        // xps this would be the place to notify the observers,
+        // e.g. like so:
+        // 	StatusChangeSignalHandler.emitSignal("file:" + originalFile.getAbsolutePath(),
+        // 					     "reservedCheckIn");
+        return time;
+    }
+
+    /**
+     * @deprecated please use reservedCheckIn(Document, String, boolean)
+     * Try to make a reserved check in of the file destination for a user with identity. A backup
+     * copy can be made.
+     *
+     * @param destination The file we want to check in
+     * @param identity The identity of the user
+     * @param backup if true, a backup will be created, else no backup will be made.
+     *
+     * @return long The time.
+     *
+     * @exception FileReservedCheckInException if the document couldn't be checked in (for instance
+     *            because it is already checked out by someone other ...)
+     * @exception Exception if other problems occur
+     */
     public long reservedCheckIn(String destination, String identity, boolean backup)
         throws FileReservedCheckInException, Exception {
         RCML rcml = new RCML(rcmlDir, destination, rootDir);
@@ -309,6 +501,20 @@
      *
      * @return File The file of the backup version
      */
+    public File getBackupFile(long time, Document doc) {        
+        File backup = new File(backupDir, doc.getDocumentAreaPath() + ".bak." + time);
+        return backup;
+    }
+
+    /**
+     * @deprecated getBackupFile(long, Document)
+     * Get the file of a backup version  
+     *
+     * @param time The time of the backup 
+     * @param filename The path of the file from the {publication}
+     *
+     * @return File The file of the backup version
+     */
     public File getBackupFile(long time, String filename) {
         File backup = new File(backupDir, filename + ".bak." + time);
 
@@ -330,6 +536,69 @@
      * @exception FileNotFoundException if a file couldn't be found
      * @exception Exception if another problem occurs
      */
+    public long rollback(Document doc, String identity, boolean backupFlag, long time)
+        throws
+            FileReservedCheckInException,
+            FileReservedCheckOutException,
+            FileNotFoundException,
+            Exception {
+        
+        // Make sure the old version exists
+        //
+        File backup = new File(backupDir, doc.getDocumentAreaPath() + ".bak." + time);
+        File current = doc.getFile();
+
+        if (!backup.isFile()) {
+            throw new FileNotFoundException(backup.getAbsolutePath());
+        }
+
+        if (!current.isFile()) {
+            throw new FileNotFoundException(current.getAbsolutePath());
+        }
+
+        // Try to check out current version
+        //
+        reservedCheckOut(doc, identity);
+
+        // Now roll back to the old state
+        //
+        FileInputStream in = new FileInputStream(backup.getAbsolutePath());
+
+        XPSFileOutputStream out = new XPSFileOutputStream(current.getAbsolutePath());
+        byte[] buffer = new byte[512];
+        int length;
+
+        while ((length = in.read(buffer)) != -1) {
+            out.write(buffer, 0, length);
+        }
+
+        out.close();
+
+        // Try to check back in, this might cause
+        // a backup of the current version to be created if
+        // desired by the user.
+        //
+        long newtime = reservedCheckIn(doc, identity, backupFlag);
+
+        return newtime;
+    }
+
+    /**
+     * @deprecated please use rollback(Document, String, boolean, long)
+     * Rolls back to the given point in time.  
+     *
+     * @param destination File which will be rolled back
+     * @param identity The identity of the user
+     * @param backupFlag If true, a backup of the current version will be made before the rollback
+     * @param time The time point of the desired version
+     *
+     * @return long The time of the version to roll back to.
+     *
+     * @exception FileReservedCheckInException if the current version couldn't be checked in again
+     * @exception FileReservedCheckOutException if the current version couldn't be checked out
+     * @exception FileNotFoundException if a file couldn't be found
+     * @exception Exception if another problem occurs
+     */
     public long rollback(String destination, String identity, boolean backupFlag, long time)
         throws
             FileReservedCheckInException,
@@ -417,6 +686,37 @@
 
     /**
      * delete the revisions
+     * @param filename of the document
+     * @throws RevisionControlException when somthing went wrong
+     */
+    public void deleteRevisions(Document doc) throws RevisionControlException{
+        try {
+            RCML rcml = this.getRCML(doc);
+            String[] times = rcml.getBackupsTime();
+            for (int i=0; i < times.length; i++) {
+                long time = new Long(times[i]).longValue();
+                File backup = this.getBackupFile(time, doc);
+                File parentDirectory = null; 
+                parentDirectory = backup.getParentFile(); 
+                boolean deleted = backup.delete();
+                if (!deleted) {
+                    throw new RevisionControlException("The backup file, "+backup.getCanonicalPath()+" could not be deleted!");
+                }
+                if (parentDirectory != null 
+                    && parentDirectory.exists()
+                    && parentDirectory.isDirectory()
+                    && parentDirectory.listFiles().length == 0) {
+                        parentDirectory.delete();
+                }
+            }
+		} catch (Exception e) {
+            throw new RevisionControlException(e);
+		}
+    }
+
+    /**
+     * @deprecated please use deleteRevisions(Document)
+     * delete the revisions
 	 * @param filename of the document
 	 * @throws RevisionControlException when somthing went wrong
 	 */
@@ -446,6 +746,24 @@
     }
     
     /**
+     * delete the rcml file
+     * @param filename of the document
+     * @throws RevisionControlException if something went wrong
+     */
+    public void deleteRCML(Document doc) throws RevisionControlException{
+        try {
+            RCML rcml = this.getRCML(doc);
+            boolean deleted = rcml.delete();
+            if (!deleted) {
+                throw new RevisionControlException("The rcml file could not be deleted!");
+            }
+        } catch (Exception e) {
+            throw new RevisionControlException(e);
+        }
+    }
+    
+    /**
+     * @deprecated please use deleteRCML(Document)
      * delete the rcml file
 	 * @param filename of the document
 	 * @throws RevisionControlException if something went wrong



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org