You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@jackrabbit.apache.org by Francisco Carriedo Scher <fc...@gmail.com> on 2012/04/06 13:40:11 UTC

Re: Using nt:linkedFile's in WebDav

Hi there,

i wrote a custom IOHandler to have the nt:linkedFile nodes retrieved as the
file they link through the browser. I would like to offer it to anyone who
faces the same problem so i post it here and i will put it as answer to the
helpful link i found (see below). There are three code snippets: declaring
the nt:linkedFile as noncollection on the config.xml file, the IOHandler
Java class itself (the change needs to recompile the jackrabbit-jcr-server
project) and the line to add in the config.xml file (within
jackrabbit-webapp project, recompile it too) in order to use the brandnew
IOHandler (order matters, put the declaration on the first position). Here
it goes:

*******************************************************************************************************************
Set the nt:linkedFile as noncollection (config.xml on jackrabbit-webapp):

    [...]
    <!--
     Define nodetypes, that should never by displayed as 'collection'
    -->
    <noncollection>
        <nodetypes>
            <nodetype>nt:file</nodetype>
            *<nodetype>nt:linkedFile</nodetype>*
            <nodetype>nt:resource</nodetype>
        </nodetypes>
    </noncollection>
    [...]

*******************************************************************************************************************
LinkHandler.java (put it on
*org.apache.jackrabbit.server.io.LinkHandler*package within the
jackrabbit-jcr-server project).

package org.apache.jackrabbit.server.io;

import java.io.IOException;

import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;

import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.webdav.DavResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LinkHandler implements IOHandler {

    private static Logger log = LoggerFactory.getLogger(LinkHandler.class);

    private IOManager ioManager;

    public IOManager getIOManager() {
        return this.ioManager;
    }

    public void setIOManager(IOManager ioManager) {
        this.ioManager = ioManager;

    }

    public String getName() {
        return getClass().getName();
    }

    public boolean canImport(ImportContext context, boolean isCollection) {
        // As we do not want this handler to manage the links on their
income
        // because they are properly managed by the existing handlers
        return false;
    }

    public boolean canImport(ImportContext context, DavResource resource) {
        // As we do not want this handler to manage the links on their
income
        // because they are properly managed by the existing handlers
        return false;
    }

    public boolean importContent(ImportContext context, boolean
isCollection) throws IOException {
        // TODO Auto-generated method stub
        return false;
    }

    public boolean importContent(ImportContext context, DavResource
resource) throws IOException {
        // TODO Auto-generated method stub
        return false;
    }

    public boolean canExport(ExportContext context, boolean isCollection) {
        // Error controlling i supose...
        if (context == null)
            return false;

        Item item;
        Node node;
        boolean itemIsNotNull;
        boolean isNode;
        boolean isLink;
        boolean result = false;


        item = context.getExportRoot();
        node = (Node) item;

        itemIsNotNull = (item != null);
        isNode = (item.isNode());
        try {
            // There is no content but a reference to content
            isLink = (node.getProperty("jcr:content") != null);
            // Everything right? Then true
            result = itemIsNotNull && isNode && isLink && (!isCollection);
        } catch (PathNotFoundException e) {
            e.printStackTrace();
        } catch (RepositoryException e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean canExport(ExportContext context, DavResource resource) {
        if (resource == null) {
            return false;
        }
        return canExport(context, resource.isCollection());
    }

    public boolean exportContent(ExportContext context, boolean
isCollection) throws IOException {

        if (!canExport(context,isCollection))
            throw new IOException(getName() + ": Cannot export " +
context.getExportRoot());

        try {
            Node linkedFile = (Node) context.getExportRoot();
            Node contentNode =
linkedFile.getProperty("jcr:content").getNode();
            System.out.println("LinkedFile: " + linkedFile.getName());
            if (context.hasStream()) {
                exportData(context,isCollection, contentNode);
            }
            return true;
        } catch (RepositoryException e) {

        }
        return false;
    }

    public boolean exportContent(ExportContext context, DavResource
resource) throws IOException {
        if (!canExport(context, resource)) {
            throw new IOException(getName() + ": Cannot export " +
context.getExportRoot());
        }
        return exportContent(context, resource.isCollection());
    }


    /**
     * Checks if the given content node contains a jcr:data property
     * and spools its value to the output stream of the export context.<br>
     * Please note, that subclasses that define a different structure of the
     * content node should create their own
     * {@link  #exportData(ExportContext, boolean, Node) exportData} method.
     *
     * @param context export context
     * @param isCollection <code>true</code> if collection
     * @param contentNode the content node
     * @throws IOException if an I/O error occurs
     */
    protected void exportData(ExportContext context, boolean isCollection,
Node contentNode) throws IOException, RepositoryException {
        if (contentNode.hasProperty(JcrConstants.JCR_DATA)) {
            Property p = contentNode.getProperty(JcrConstants.JCR_DATA);
            IOUtil.spool(p.getStream(), context.getOutputStream());
        } // else: stream undefined -> content length was not set
    }

}


*******************************************************************************************************************
Declare the IOHandler:

    [...]
     <class name="org.apache.jackrabbit.server.io.IOManagerImpl" />
        *<iohandler>**
            **<class name="org.apache.jackrabbit.server.io.LinkHandler" />**
        **</iohandler>*
        <iohandler>
            <class name="org.apache.jackrabbit.server.io.VersionHandler" />
        </iohandler>
        <iohandler>
            <class
name="org.apache.jackrabbit.server.io.VersionHistoryHandler" />
        </iohandler>
     [...]


******************************************************************************************************
END
******************************************************************************************************

Just to recall it, tips about the behaviour of the garbage collector and
links? (asked on previous posts).


Thanks for your attention!

Re: Using nt:linkedFile's in WebDav

Posted by Angela Schreiber <an...@adobe.com>.
hi francisco

would it be possible that you contribute this extension
to the source of the jackrabbit project?

in this case it would be helpful if you could create a
jira issue and attach the patch and mark it as
contribution (there is an option to indicate whether
you grant it for inclusion in the project or not.

kind regards
angela



On 4/6/12 1:40 PM, Francisco Carriedo Scher wrote:
> Hi there,
>
> i wrote a custom IOHandler to have the nt:linkedFile nodes retrieved as the
> file they link through the browser. I would like to offer it to anyone who
> faces the same problem so i post it here and i will put it as answer to the
> helpful link i found (see below). There are three code snippets: declaring
> the nt:linkedFile as noncollection on the config.xml file, the IOHandler
> Java class itself (the change needs to recompile the jackrabbit-jcr-server
> project) and the line to add in the config.xml file (within
> jackrabbit-webapp project, recompile it too) in order to use the brandnew
> IOHandler (order matters, put the declaration on the first position). Here
> it goes:
>
> *******************************************************************************************************************
> Set the nt:linkedFile as noncollection (config.xml on jackrabbit-webapp):
>
>      [...]
>      <!--
>       Define nodetypes, that should never by displayed as 'collection'
>      -->
>      <noncollection>
>          <nodetypes>
>              <nodetype>nt:file</nodetype>
>              *<nodetype>nt:linkedFile</nodetype>*
>              <nodetype>nt:resource</nodetype>
>          </nodetypes>
>      </noncollection>
>      [...]
>
> *******************************************************************************************************************
> LinkHandler.java (put it on
> *org.apache.jackrabbit.server.io.LinkHandler*package within the
> jackrabbit-jcr-server project).
>
> package org.apache.jackrabbit.server.io;
>
> import java.io.IOException;
>
> import javax.jcr.Item;
> import javax.jcr.Node;
> import javax.jcr.PathNotFoundException;
> import javax.jcr.Property;
> import javax.jcr.RepositoryException;
>
> import org.apache.jackrabbit.JcrConstants;
> import org.apache.jackrabbit.webdav.DavResource;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
>
> public class LinkHandler implements IOHandler {
>
>      private static Logger log = LoggerFactory.getLogger(LinkHandler.class);
>
>      private IOManager ioManager;
>
>      public IOManager getIOManager() {
>          return this.ioManager;
>      }
>
>      public void setIOManager(IOManager ioManager) {
>          this.ioManager = ioManager;
>
>      }
>
>      public String getName() {
>          return getClass().getName();
>      }
>
>      public boolean canImport(ImportContext context, boolean isCollection) {
>          // As we do not want this handler to manage the links on their
> income
>          // because they are properly managed by the existing handlers
>          return false;
>      }
>
>      public boolean canImport(ImportContext context, DavResource resource) {
>          // As we do not want this handler to manage the links on their
> income
>          // because they are properly managed by the existing handlers
>          return false;
>      }
>
>      public boolean importContent(ImportContext context, boolean
> isCollection) throws IOException {
>          // TODO Auto-generated method stub
>          return false;
>      }
>
>      public boolean importContent(ImportContext context, DavResource
> resource) throws IOException {
>          // TODO Auto-generated method stub
>          return false;
>      }
>
>      public boolean canExport(ExportContext context, boolean isCollection) {
>          // Error controlling i supose...
>          if (context == null)
>              return false;
>
>          Item item;
>          Node node;
>          boolean itemIsNotNull;
>          boolean isNode;
>          boolean isLink;
>          boolean result = false;
>
>
>          item = context.getExportRoot();
>          node = (Node) item;
>
>          itemIsNotNull = (item != null);
>          isNode = (item.isNode());
>          try {
>              // There is no content but a reference to content
>              isLink = (node.getProperty("jcr:content") != null);
>              // Everything right? Then true
>              result = itemIsNotNull&&  isNode&&  isLink&&  (!isCollection);
>          } catch (PathNotFoundException e) {
>              e.printStackTrace();
>          } catch (RepositoryException e) {
>              e.printStackTrace();
>          }
>          return result;
>      }
>
>      public boolean canExport(ExportContext context, DavResource resource) {
>          if (resource == null) {
>              return false;
>          }
>          return canExport(context, resource.isCollection());
>      }
>
>      public boolean exportContent(ExportContext context, boolean
> isCollection) throws IOException {
>
>          if (!canExport(context,isCollection))
>              throw new IOException(getName() + ": Cannot export " +
> context.getExportRoot());
>
>          try {
>              Node linkedFile = (Node) context.getExportRoot();
>              Node contentNode =
> linkedFile.getProperty("jcr:content").getNode();
>              System.out.println("LinkedFile: " + linkedFile.getName());
>              if (context.hasStream()) {
>                  exportData(context,isCollection, contentNode);
>              }
>              return true;
>          } catch (RepositoryException e) {
>
>          }
>          return false;
>      }
>
>      public boolean exportContent(ExportContext context, DavResource
> resource) throws IOException {
>          if (!canExport(context, resource)) {
>              throw new IOException(getName() + ": Cannot export " +
> context.getExportRoot());
>          }
>          return exportContent(context, resource.isCollection());
>      }
>
>
>      /**
>       * Checks if the given content node contains a jcr:data property
>       * and spools its value to the output stream of the export context.<br>
>       * Please note, that subclasses that define a different structure of the
>       * content node should create their own
>       * {@link  #exportData(ExportContext, boolean, Node) exportData} method.
>       *
>       * @param context export context
>       * @param isCollection<code>true</code>  if collection
>       * @param contentNode the content node
>       * @throws IOException if an I/O error occurs
>       */
>      protected void exportData(ExportContext context, boolean isCollection,
> Node contentNode) throws IOException, RepositoryException {
>          if (contentNode.hasProperty(JcrConstants.JCR_DATA)) {
>              Property p = contentNode.getProperty(JcrConstants.JCR_DATA);
>              IOUtil.spool(p.getStream(), context.getOutputStream());
>          } // else: stream undefined ->  content length was not set
>      }
>
> }
>
>
> *******************************************************************************************************************
> Declare the IOHandler:
>
>      [...]
>       <class name="org.apache.jackrabbit.server.io.IOManagerImpl" />
>          *<iohandler>**
>              **<class name="org.apache.jackrabbit.server.io.LinkHandler" />**
>          **</iohandler>*
>          <iohandler>
>              <class name="org.apache.jackrabbit.server.io.VersionHandler" />
>          </iohandler>
>          <iohandler>
>              <class
> name="org.apache.jackrabbit.server.io.VersionHistoryHandler" />
>          </iohandler>
>       [...]
>
>
> ******************************************************************************************************
> END
> ******************************************************************************************************
>
> Just to recall it, tips about the behaviour of the garbage collector and
> links? (asked on previous posts).
>
>
> Thanks for your attention!