Creating File Revisions

Sample application sent by Stefan Fromm which was found in mailing-list archives (orginal post.) It shows how to create revisions for file.

import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.authenticate.SecurityToken;
import org.apache.slide.common.Domain;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenImpl;
import org.apache.slide.content.Content;
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.security.Security;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.Structure;
import org.apache.slide.structure.SubjectNode;

public class SlideVersionsTest {

     private NamespaceAccessToken namespace;
     private SlideToken token;

     private Structure structure;
     private Content content;
     private Security security;

     private static final String AUTHORS_XML =
         "<authors>" +
             "<author>" +
                 "<firstname>Stefan</firstname>" +
                 "<lastname>Fromm</lastname>" +
             "</author>" +
         "</authors>";

     public SlideVersionsTest(String slideuser) {
         namespace = Domain.accessNamespace(new SecurityToken(""), Domain.getDefaultNamespace());
         token = new SlideTokenImpl(new CredentialsToken(slideuser));
         token.setForceStoreEnlistment(true);
         structure = namespace.getStructureHelper();
         content = namespace.getContentHelper();
         security = namespace.getSecurityHelper();
     }

     private String computeEtag(String uri, NodeRevisionDescriptor nrd)
         throws Exception {
         String result =
             System.currentTimeMillis()
                 + "_"
                 + uri.hashCode()
                 + "_"
                 + nrd.getLastModified()
                 + "_"
                 + nrd.getContentLength();
         result = new String(DigestUtils.md5Hex(result));
         return result;
     }

     public void put(String uri, String data) throws Exception {
         try {
             namespace.begin();
             try {
                 byte[] dataBytes = data.getBytes();
                 ByteArrayInputStream fis = new ByteArrayInputStream(dataBytes);
                 try
                 {
                     NodeRevisionNumber lastRevision = null;
                     try {
                         structure.retrieve(token, uri);
                         lastRevision = content.retrieve(token, uri).getLatestRevision();
                         System.out.println("Found resource with latest revision number " + (lastRevision == null?"none":lastRevision.toString()));
                     }
                     catch (ObjectNotFoundException e) {
                         SubjectNode subject = new SubjectNode();
                         // create object
                         structure.create(token, subject, uri);
                     }
                     if ( lastRevision != null )
                         lastRevision = new NodeRevisionNumber(lastRevision, false);
                     else
                         lastRevision = new NodeRevisionNumber();
                     // create node revision descriptor
                     NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(lastRevision, NodeRevisionDescriptors.MAIN_BRANCH, new Vector(), new Hashtable());
                     revisionDescriptor.setResourceType("");
                     revisionDescriptor.setSource("");
                     revisionDescriptor.setContentLanguage("en");
                     revisionDescriptor.setLastModified(new Date());
                     revisionDescriptor.setETag(computeEtag(uri, revisionDescriptor));
                     revisionDescriptor.setCreationDate(new Date());
                     // Owner
                     String creator = ((SubjectNode)security.getPrincipal(token)).getPath().lastSegment();
                     revisionDescriptor.setCreationUser(creator);
                     revisionDescriptor.setOwner(creator);
                     String contentType = "text/plain";
                     revisionDescriptor.setContentType(contentType);
                     // properties
                     NodeProperty newProperty = new NodeProperty("authors", AUTHORS_XML, "stefan.fromm:");
                     revisionDescriptor.setProperty(newProperty);
                     // create content
                     NodeRevisionContent revisionContent = new NodeRevisionContent();
                     revisionContent.setContent(fis);
                     // important to create NodeRevisionDescriptors separately to be able to tell it to use versioning
                     if ( lastRevision.toString().equals("1.0") )
                         content.create(token, uri, true);
                     content.create(token, uri, revisionDescriptor, revisionContent);
                 }
                 finally
                 {
                     fis.close();
                 }
                 namespace.commit();
             }
             catch (Exception e ) {
                 namespace.rollback();
                 throw e;
             }
         }
         catch (OutOfMemoryError e)
         {
             throw new RuntimeException(e);
         }
     }

     public NodeRevisionDescriptors getVersions(String uri) throws Exception {
         namespace.begin();
         try {
             return content.retrieve(token, uri);
         }
         finally {
             namespace.rollback();
         }
     }

     public static void main(String[] args) throws Exception {
         SlideVersionsTest test = new SlideVersionsTest("root");
         test.put("/files/test.txt", "Content 1");
         test.put("/files/test.txt", "Content 2");
         test.put("/files/test.txt", "Content 3");
         NodeRevisionDescriptors revisions = test.getVersions("/files/test.txt");
         for ( Enumeration e = revisions.enumerateRevisionNumbers(); e.hasMoreElements(); ) {
             NodeRevisionNumber number = (NodeRevisionNumber)e.nextElement();
             System.out.println("number = " + number.toString());
         }
     }
}

A note on slideToken.setForceStoreEnlistment(true): the javadocs contain a caveat that this property "should be set to true only in some very specific critical sections of the code, as this would greatly decrease the ability of Slide to handle multiple concurrent requests." However, this post demonstrates the necessity of setting ForceStoreEnlistment to true. This issue is also mentioned in this thread.

Getting Properties

This example demonstrates how to access file contents and properties from the SlideAPI.

import java.util.Enumeration;

import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;

import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.authenticate.SecurityToken;
import org.apache.slide.common.Domain;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenImpl;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;

/**
 * An example the Slide API that demonstrates fetching the properties
 * enumeration from a NodeRevisionDescriptor. This example assumes the existance
 * of "/files/test.txt" in the store (this file can be generated by the
 * SlideVersionsTest in the example above.)
 * 
 * @author James Kelly
 */
public class SlideTest2 {

    /**
     * Prints the contents and properties for "/files/test.txt"
     * 
     * @param args
     */
    public static void main(String[] args) {
        SlideTest2 client = new SlideTest2();
        try {
            client.printContent("/files/test.txt");
            client.printProperties("/files/test.txt");
        } catch (NotSupportedException e) {

            e.printStackTrace();
        } catch (SystemException e) {
            e.printStackTrace();
        }
    }

    /** Default Namespace */
    private NamespaceAccessToken namespace;

    /** Security Token */
    private SlideToken token;

    /**
     * Loads the default namespace and creates a new security token for "root"
     */
    public SlideTest2() {
        this.namespace = Domain.accessNamespace(new SecurityToken(""), Domain
                .getDefaultNamespace());
        this.token = new SlideTokenImpl(new CredentialsToken("root"));
        this.token.setForceStoreEnlistment(true);
    }

    /**
     * Fetches a file from the store and prints its content to STOUT.
     * 
     * @param path
     *            the path to the file
     * @throws NotSupportedException
     * @throws SystemException
     */
    public void printContent(String path) throws NotSupportedException,
            SystemException {
        this.namespace.begin();
        try {
            Content c = this.namespace.getContentHelper();
            NodeRevisionDescriptors revs = c.retrieve(this.token, path);
            NodeRevisionDescriptor rev = c.retrieve(this.token, revs, revs
                    .getLatestRevision());
            NodeRevisionContent nrc = c.retrieve(this.token, path, rev);
            System.out.print(nrc.getContent());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.namespace.rollback();
        }
    }

    /**
     * Fetches and prints the properties enumeration to STDOUT.
     * 
     * @param path
     *            the file URI
     * @throws IllegalStateException
     * @throws SecurityException
     * @throws SystemException
     * @throws NotSupportedException
     */
    @SuppressWarnings("unchecked")
    public void printProperties(String path) throws IllegalStateException,
            SecurityException, SystemException, NotSupportedException {
        this.namespace.begin();
        try {
            Content c = this.namespace.getContentHelper();
            NodeRevisionDescriptors revs = c.retrieve(this.token, path);
            NodeRevisionDescriptor rev = c.retrieve(this.token, revs, revs
                    .getLatestRevision());
            Enumeration e = rev.enumerateProperties();
            while (e.hasMoreElements()) {
                NodeProperty p = (NodeProperty) e.nextElement();
                System.out.println(String.format("%s = %s", p.getName(), p
                        .getValue()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.namespace.rollback();
        }
    }
}

Creating GroupNodes and LinkNodes

From Michael Plomer's post to the Slide-Users mailing list on 2003-05-24

First, you'll need to obtain a NamespaceAccessToken:

        // prepare the namespace access token (assuming you want the default namespace)
        String namespace = Domain.getDefaultNamespace();
        NamespaceAccessToken nat = Domain.accessNamespace(new SecurityToken(this), namespace);
        // "this" is a HttpServlet in my case, but could be almost anything (or so I think...)

Next, you need a SlideToken, which you could construct, for instance, from the credentials in your servlets request (that is, assuming you are writing a servlet...).

        // prepare the slide token Principal principal = request.getUserPrincipal();
        CredentialsToken credentials;
        if (principal == null)
                credentials = new CredentialsToken("");
        else
                credentials = new CredentialsToken(principal);
        SlideToken st = new SlideTokenImpl(credentials);

Creating a group node is pretty straightforward, most of the code deals with exception handling:

        // prepare the structure helper
        Structure structureHelper = nat.getStructureHelper();

        try {
                try {
                        // start namespace tansaction
                        nat.begin();
                        // create the node in the structure
                        ObjectNode object = new GroupNode();
                    structureHelper.create(st, object,"/users/testgroup");
                    // commit the transaction
                    nat.commit();
                } catch (AccessDeniedException ex) {
                        ... // handle exception
                    throw ex;
                } catch (ObjectAlreadyExistsException ex) {
                        ... // handle exception
                    throw ex;
                } catch (Exception ex) {
                        ... // handle exception
                    throw ex;
                }
                // ... SUCCESS ...
        } catch (Exception ex) {
                try {
                        nat.rollback();
                } catch (SystemException sysex) { // catch silently }
        }

Linking users into the group should be done like this:

        // prepare the structure helper
        Structure structureHelper = nat.getStructureHelper();

        try {
                try {
                        // start namespace tansaction
                        nat.begin();
                        // retrieve the node to be linked
                        ObjectNode object = structureHelper.retrieve(st,"/users/testuser");
                        // create the link node
                        structureHelper.createLink(st, new LinkNode(),"/users/testgroup/testuser", object);
                    // commit the transaction
                    nat.commit();
                } catch (AccessDeniedException ex) {
                        ... // handle exception
                    throw ex;
                } catch (ObjectAlreadyExistsException ex) {
                        ... // handle exception
                    throw ex;
                } catch (Exception ex) {
                        ... // handle exception
                    throw ex;
                }
                // ... SUCCESS ...
        } catch (Exception ex) {
                try {
                        nat.rollback();
                } catch (SystemException sysex) { // catch silently }
        }

Hope this helps. Keep in mind that while this code is from a servlet
I wrote and actually works, I might have edited in some errors when
writing this mail...

Sample_API_application (last edited 2009-09-20 22:02:32 by localhost)