Package org.apache.abdera.protocol.server.adapters.jcr

Source Code of org.apache.abdera.protocol.server.adapters.jcr.JcrCollectionAdapter

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  The ASF licenses this file to You
* under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.  For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.abdera.protocol.server.adapters.jcr;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.activation.MimeType;
import javax.jcr.Credentials;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.Workspace;

import org.apache.abdera.Abdera;
import org.apache.abdera.factory.Factory;
import org.apache.abdera.i18n.iri.IRI;
import org.apache.abdera.i18n.text.Sanitizer;
import org.apache.abdera.model.Content;
import org.apache.abdera.model.Element;
import org.apache.abdera.model.Person;
import org.apache.abdera.model.Text;
import org.apache.abdera.model.Content.Type;
import org.apache.abdera.protocol.server.RequestContext;
import org.apache.abdera.protocol.server.ResponseContext;
import org.apache.abdera.protocol.server.RequestContext.Scope;
import org.apache.abdera.protocol.server.context.EmptyResponseContext;
import org.apache.abdera.protocol.server.context.ResponseContextException;
import org.apache.abdera.protocol.server.impl.AbstractEntityCollectionAdapter;
import org.apache.abdera.protocol.util.PoolManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.api.JackrabbitNodeTypeManager;

/**
* Adapter implementation that uses a JCR Repository to store Atompub collection
* entries.  The adapter is intended to be used with the DefaultProvider implementation.
*/
public class JcrCollectionAdapter
  extends AbstractEntityCollectionAdapter<Node> {

  private final static Log log = LogFactory.getLog(JcrCollectionAdapter.class);
 
  private static final String TITLE = "title";

  private static final String SUMMARY = "summary";

  private static final String UPDATED = "updated";

  private static final String AUTHOR = "author";

  private static final String AUTHOR_EMAIL = "author.email";

  private static final String AUTHOR_LANGUAGE = "author.language";

  private static final String AUTHOR_NAME = "author.name";

  private static final String CONTENT = "content";

  private static final String SESSION_KEY = "jcrSession";

  private static final String MEDIA = "media";

  private static final String CONTENT_TYPE = "contentType";

  private static final String NAMESPACE = "http://abdera.apache.org";

  private String collectionNodePath;

  private String id;

  private String title;

  private String author;

  private String collectionNodeId;

  private Repository repository;

  private Credentials credentials;
 
  private int maxActiveSessions = 100;
 
  private PoolManager<Session> sessionPool;
 
  public void setCollectionNodePath(String collectionNodePath) {
    this.collectionNodePath = collectionNodePath;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public void setAuthor(String author) {
    this.author = author;
  }

  /**
   * Logs into the repository and posts a node for the collection if one does not exist. Also,
   * this will set up the session pool.
   * @throws RepositoryException
   */
  public void initialize() throws Exception {
    Session session = repository.login(credentials);

    Node collectionNode = null;
    try {
      collectionNode = session.getRootNode().getNode(collectionNodePath);
    } catch (PathNotFoundException e) {
      collectionNode = session.getRootNode().addNode(collectionNodePath);
      collectionNode.addMixin("mix:referenceable");
      session.save();
    }
   
    this.collectionNodeId = collectionNode.getUUID();
    this.id = "urn:" + collectionNodeId;

    Workspace workspace = session.getWorkspace();

    // Get the NodeTypeManager from the Workspace.
    // Note that it must be cast from the generic JCR NodeTypeManager to the
    // Jackrabbit-specific implementation.
    JackrabbitNodeTypeManager jntmgr = (JackrabbitNodeTypeManager) workspace.getNodeTypeManager();
    if (!jntmgr.hasNodeType("abdera:entry")) {
      InputStream in = getClass().getResourceAsStream("/org/apache/abdera/jcr/nodeTypes.xml");
      try {
        // register the node types and any referenced namespaces
        jntmgr.registerNodeTypes(in, JackrabbitNodeTypeManager.TEXT_XML);
      } finally {
        in.close();
      }
    }
   
    session.logout();
   
    sessionPool = new SessionPoolManager(maxActiveSessions, repository, credentials);
  }

  @Override
  public void start(RequestContext request) throws ResponseContextException {
    try {
      Session session = (Session) sessionPool.get(request);

      request.setAttribute(Scope.REQUEST, SESSION_KEY, session);
    } catch (Exception e) {
      throw new ResponseContextException(500, e);
    }
  }

  @Override
  public void end(RequestContext request, ResponseContext response) {
    // Logout of the JCR session
    Session session = getSession(request);
    if (session != null) {
      try {
        sessionPool.release(session);
      } catch (Exception e) {
        log.warn("Could not return Session to pool!", e);
      }
    }
  }


  @Override
  public String getContentType(Node entry) {
    try {
      return getStringOrNull(entry, CONTENT_TYPE);
    } catch (ResponseContextException e) {
      throw new UnsupportedOperationException();
    }
  }

  @Override
  public boolean isMediaEntry(Node entry) throws ResponseContextException {
    try {
      return entry.hasProperty(MEDIA);
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  @Override
  public Node postMedia(MimeType mimeType, String slug,
                               InputStream inputStream, RequestContext request)
    throws ResponseContextException {
    if (slug == null) {
      throw new ResponseContextException("A slug header must be supplied.", 500);
    }
    Node n = postEntry(slug, null, null, new Date(), null, null, request);
   
    try {
      n.setProperty(MEDIA, inputStream);
      n.setProperty(CONTENT_TYPE, mimeType.toString());

      String summary = postSummaryForEntry(n);
      if (summary != null) {
        n.setProperty(SUMMARY, summary);
      }

      getSession(request).save();
     
      return n;
    } catch (RepositoryException e) {
      try {
        getSession(request).refresh(false);
      } catch (Throwable t) {
        log.warn(t);
      }
      throw new ResponseContextException(500, e);
    }
  }
 
  /**
   * post a summary for an entry. Used when a media entry is postd
   * so you have the chance to post a meaningful summary for consumers
   * of the feed.
   *
   * @param n
   * @return
   */
  protected String postSummaryForEntry(Node n) {
    return null;
  }

  @Override
  public Node postEntry(String title, IRI id, String summary, Date updated, List<Person> authors,
                          Content content, RequestContext request) throws ResponseContextException {
    Session session = getSession(request);
    try {

      Node collectionNode = session.getNodeByUUID(collectionNodeId);
      String resourceName = Sanitizer.sanitize(title, "-");
      return postEntry(title, summary, updated, authors,
                          content, session, collectionNode,
                          resourceName, 0);
    } catch (RepositoryException e) {
      try {
        session.refresh(false);
      } catch (Throwable t) {
        log.warn(t);
      }     
      throw new ResponseContextException(500, e);
    }
  }

  protected Node postEntry(String title, String summary,
                             Date updated, List<Person> authors,
                             Content content, Session session,
                             Node collectionNode, String resourceName, int num)
    throws ResponseContextException, RepositoryException {
    try {
      String name = resourceName;
      if (num > 0) {
        name = name + "_" + num;
      }
      Node entry = collectionNode.addNode(name, "abdera:entry");
     
      entry.addMixin("mix:referenceable");

      mapEntryToNode(entry, title, summary, updated, authors, content, session);
     
      session.save();
     
      return entry;
    }
    catch (ItemExistsException e)
    {
      return postEntry(title, summary, updated, authors, content, session, collectionNode, resourceName, ++num);
    }
  }

  protected Node mapEntryToNode(Node entry, String title, String summary, Date updated, List<Person> authors,
                              Content content, Session session)
    throws ResponseContextException, RepositoryException {
    if (title == null) {
      EmptyResponseContext ctx = new EmptyResponseContext(500);
      ctx.setStatusText("Entry title cannot be empty.");
      throw new ResponseContextException(ctx);
    }

    entry.setProperty(TITLE, title);

    if (summary != null) {
      entry.setProperty(SUMMARY, summary);
    }
   
    Calendar upCal = Calendar.getInstance();
    upCal.setTime(updated);
    entry.setProperty(UPDATED, upCal);

    if (authors != null) {
      for (Person p : authors) {
        Node addNode = entry.addNode(AUTHOR);
        addNode.setProperty(AUTHOR_EMAIL, p.getEmail());
        addNode.setProperty(AUTHOR_LANGUAGE, p.getLanguage());
        addNode.setProperty(AUTHOR_NAME, p.getName());
      }
    }

    if (content != null) {
      switch(content.getContentType()) {
      case TEXT:
  entry.setProperty(CONTENT, content.getText());
  entry.setProperty(CONTENT_TYPE, Type.TEXT.toString());
  break;
      case XHTML:
  entry.setProperty(CONTENT, asString(content));
  entry.setProperty(CONTENT_TYPE, Type.XHTML.toString());
  break;
      default:
  throw new ResponseContextException("Invalid content element type.", 500);
      }
    }

    if (summary != null) {
      entry.setProperty(SUMMARY, summary);
    }
   
    return entry;
  }

  private String asString(Content content2) throws ResponseContextException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
  content2.<Element>getFirstChild().writeTo(bos);
    } catch (IOException e) {
      throw new ResponseContextException(500, e);
    }
    return new String(bos.toByteArray());
  }

  protected Session getSession(RequestContext request) {
    return (Session)request.getAttribute(Scope.REQUEST, SESSION_KEY);
  }

  @Override
  public void deleteEntry(String resourceName, RequestContext request) throws ResponseContextException {
    Session session = getSession(request);
    try {
      getNode(session, resourceName).remove();
      session.save();
    } catch (RepositoryException e) {
      try {
        session.refresh(false);
      } catch (Throwable t) {
        log.warn(t);
      }           
      throw new ResponseContextException(500, e);
    }
  }

  private Node getNode(Session session, String resourceName) throws ResponseContextException,
    RepositoryException {
    try {
      return session.getNodeByUUID(collectionNodeId).getNode(resourceName);
    } catch (PathNotFoundException e) {
      throw new ResponseContextException(404);
    }
  }

  /** Recursively outputs the contents of the given node. */
  public static void dump(Node node) throws RepositoryException {
      // First output the node path
      System.out.println(node.getPath());
      // Skip the virtual (and large!) jcr:system subtree
      if (node.getName().equals("jcr:system")) {
          return;
      }

      // Then output the properties
      PropertyIterator properties = node.getProperties();
      while (properties.hasNext()) {
          Property property = properties.nextProperty();
          if (property.getDefinition().isMultiple()) {
              // A multi-valued property, print all values
              Value[] values = property.getValues();
              for (int i = 0; i < values.length; i++) {
                  System.out.println(
                      property.getPath() + " = " + values[i].getString());
              }
          } else {
              // A single-valued property
              System.out.println(
                  property.getPath() + " = " + property.getString());
          }
      }

      // Finally output all the child nodes recursively
      NodeIterator nodes = node.getNodes();
      while (nodes.hasNext()) {
          dump(nodes.nextNode());
      }
  }

  @Override
  public String getAuthor(RequestContext request) throws ResponseContextException {
    return author;
  }

  @Override
  public List<Person> getAuthors(Node entry, RequestContext request) throws ResponseContextException {
    try {
      ArrayList<Person> authors = new ArrayList<Person>();
      for (NodeIterator nodes = entry.getNodes(); nodes.hasNext();) {
        Node n = nodes.nextNode();
       
        if (n.getName().equals(AUTHOR)) {
          Person author = request.getAbdera().getFactory().newAuthor();
          author.setName(getStringOrNull(entry, AUTHOR_NAME));
          author.setEmail(getStringOrNull(entry, AUTHOR_EMAIL));
          author.setLanguage(getStringOrNull(entry, AUTHOR_LANGUAGE));
          authors.add(author);
        }
      }
      return authors;
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  @Override
  public Object getContent(Node entry, RequestContext request) throws ResponseContextException {
   
    String typeStr = getStringOrNull(entry, CONTENT_TYPE);
    Factory factory = Abdera.getInstance().getFactory();
    String textContent = getStringOrNull(entry, CONTENT);
    Type type = Type.valueOf(typeStr);
    Content content = factory.newContent(type);
    switch (type) {
      case TEXT:
        content.setValue(textContent);
        return content;
      case XHTML:
        content.setWrappedValue(textContent);
        return content;
      default
    }
    return null;
  }

  @Override
  public Iterable<Node> getEntries(RequestContext request) throws ResponseContextException {
    ArrayList<Node> entries = new ArrayList<Node>();

    Session session = getSession(request);
    try {
      Node n = session.getNodeByUUID(collectionNodeId);
      for (NodeIterator nodes = n.getNodes(); nodes.hasNext();) {
        entries.add(nodes.nextNode());
      }
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }

    return entries;
  }

  @Override
  public Node getEntry(String resourceName, RequestContext request) throws ResponseContextException {
    try {
      return getNode(getSession(request), resourceName);
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  @Override
  public String getId(RequestContext request) {
    return id;
  }

  @Override
  public String getId(Node entry) throws ResponseContextException {
    try {
      return "urn:" + entry.getUUID();
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }
 
  public String getMediaName(Node entry) throws ResponseContextException {
    return getName(entry);
  }

  public InputStream getMediaStream(Node entry) throws ResponseContextException {
    try {
      Value value = getValueOrNull(entry, MEDIA);
      return (value != null) ? value.getStream() : null;
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
   
  }
 
  @Override
  public String getName(Node entry) throws ResponseContextException {
    try {
      return entry.getName();
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  @Override
  public Text getSummary(Node entry, RequestContext request) throws ResponseContextException {
    Text summary = request.getAbdera().getFactory().newSummary();
    summary.setText(getStringOrNull(entry, SUMMARY));
    return summary;
  }

  public String getTitle(RequestContext request) {
    return title;
  }

  @Override
  public String getTitle(Node entry) throws ResponseContextException {
    return getStringOrNull(entry, TITLE);
  }

  @Override
  public Date getUpdated(Node entry) throws ResponseContextException {
    Calendar updated = getDateOrNull(entry, UPDATED);
    return (updated != null) ? updated.getTime() : null;
  }

  @Override
  public void putEntry(Node entry, String title, Date updated,
                          List<Person> authors, String summary,
                          Content content, RequestContext request) throws ResponseContextException {
    Session session = getSession(request);
    try {
      mapEntryToNode(entry, title, summary, updated, authors, content, session);
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  public static String getStringOrNull(Node node, String propName) throws ResponseContextException  {
    try {
      Value v = getValueOrNull(node, propName);
      return (v != null) ? v.getString() : null;
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  public ResponseContext getCategories(RequestContext request) {
    return null;
  }

  public static Calendar getDateOrNull(Node node, String propName) throws ResponseContextException {
    try {
      Value v = getValueOrNull(node, propName);
      return (v != null) ? v.getDate() : null;
    } catch (RepositoryException e) {
      throw new ResponseContextException(500, e);
    }
  }

  public static Value getValueOrNull(Node node, String propName) throws RepositoryException {
    return node.hasProperty(propName)
      ? node.getProperty(propName).getValue() : null;
  }

  public void setRepository(Repository repository) {
    this.repository = repository;
  }

  public void setCredentials(Credentials credentials) {
    this.credentials = credentials;
  }

  public void setMaxActiveSessions(int maxActiveSessions) {
    this.maxActiveSessions = maxActiveSessions;
  }

}
TOP

Related Classes of org.apache.abdera.protocol.server.adapters.jcr.JcrCollectionAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.