[jboss-cvs] jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node ...

Christian Bauer christian.bauer at jboss.com
Thu Feb 1 02:08:26 EST 2007


  User: cbauer  
  Date: 07/02/01 02:08:26

  Added:       examples/wiki/src/org/jboss/seam/wiki/core/node         
                        DocumentHome.java Menu.java Document.java
                        WikiRoot.java DirectoryHome.java UIBindings.java
                        Node.java Directory.java NodeBrowser.java
  Log:
  Committed first (broken) wiki implementation
  
  Revision  Changes    Path
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/DocumentHome.java
  
  Index: DocumentHome.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import static javax.faces.application.FacesMessage.SEVERITY_ERROR;
  import javax.persistence.Query;
  
  import org.jboss.seam.framework.EntityHome;
  import org.jboss.seam.annotations.*;
  import org.jboss.seam.wiki.core.links.WikiLinkResolver;
  import org.jboss.seam.core.FacesMessages;
  import org.jboss.seam.ScopeType;
  
  import java.util.List;
  
  @Name("documentHome")
  public class DocumentHome extends EntityHome<Document> {
  
      @RequestParameter
      private Long docId;
  
      @RequestParameter
      private Long parentDirId;
  
      // Pages need this for rendering
      @Out(required = true, scope = ScopeType.CONVERSATION, value = "currentDirectory")
      Directory parentDirectory;
  
      @In(create=true)
      private FacesMessages facesMessages;
  
      @In(create=true)
      private WikiLinkResolver wikiLinkResolver;
  
      private String formContent;
      boolean enabledPreview = false;
  
      @Override
      public Object getId() {
  
          if (docId == null) {
              return super.getId();
          } else {
              return docId;
          }
      }
  
      @Begin(flushMode = FlushModeType.MANUAL)
      @Transactional
      public void create() {
          super.create();
  
          // Load the parent directory
          getEntityManager().joinTransaction();
          parentDirectory = getEntityManager().find(Directory.class, parentDirId);
      }
  
      public String persist() {
  
          // Validate
          if (!isUniqueWikinameInDirectory(null) ||
              !isUniqueWikinameInArea()) return null;
  
          // Link the document with a directory
          parentDirectory.addChild(getInstance());
  
          // Set its area number
          getInstance().setAreaNumber(parentDirectory.getAreaNumber());
  
          // Convert and set form content onto entity instance
          getInstance().setContent(
              wikiLinkResolver.convertToWikiLinks(parentDirectory, getFormContent())
          );
  
          return super.persist();
      }
  
  
      public String update() {
  
          // Validate
          if (!isUniqueWikinameInDirectory(getInstance()) ||
              !isUniqueWikinameInArea()) return null;
  
          // Convert and set form content onto entity instance
          getInstance().setContent(
              wikiLinkResolver.convertToWikiLinks(parentDirectory, getFormContent())
          );
  
          return super.update();
      }
  
      public String remove() {
  
          // Unlink the document from its directory
          getInstance().getParent().removeChild(getInstance());
  
          return super.remove();
      }
  
      public String getFormContent() {
          // Load the document content and resolve links
          if (formContent == null)
              formContent = wikiLinkResolver.convertFromWikiLinks(getInstance().getContent());
          return formContent;
      }
  
      public void setFormContent(String formContent) {
          this.formContent = formContent;
      }
  
      public boolean isEnabledPreview() {
          return enabledPreview;
      }
  
      public void setEnabledPreview(boolean enabledPreview) {
          this.enabledPreview = enabledPreview;
          // Convert and set form content onto entity instance
          getInstance().setContent(
              wikiLinkResolver.convertToWikiLinks(parentDirectory, getFormContent())
          );
      }
  
      // Validation rules for persist(), update(), and remove();
  
      @Transactional
      private boolean isUniqueWikinameInDirectory(Document ignore) {
          getEntityManager().joinTransaction();
  
          String queryString = "select n from Node n where n.parent = :parent and n.wikiname = :wikiname";
          if (ignore != null)  queryString = queryString + " and not n = :ignore";
  
          Query q = getEntityManager().createQuery(queryString);
          if (ignore != null) q.setParameter("ignore", ignore);
  
          // Unique directory name within parent
          List existingChildren = q
                  .setParameter("parent", parentDirectory)
                  .setParameter("wikiname", getInstance().getWikiname())
                  .getResultList();
          if (existingChildren.size() >0) {
              facesMessages.addFromResourceBundle(
                  "name",
                  SEVERITY_ERROR,
                  getMessageKeyPrefix() + "duplicateName",
                  "Directory or document with that name already exists."
              );
              return false;
          }
          return true;
      }
  
      @Transactional
      private boolean isUniqueWikinameInArea() {
          getEntityManager().joinTransaction();
          // Unique document name within area
          Document foundDocument = wikiLinkResolver.findDocumentInArea(parentDirectory, getInstance().getWikiname());
          if ( foundDocument != null && foundDocument != getInstance()) {
              facesMessages.addFromResourceBundle(
                  "name",
                  SEVERITY_ERROR,
                  getMessageKeyPrefix() + "duplicateNameInArea",
                  "Document with that name already exists in this area."
              );
              return false;
          }
          return true;
      }
  
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/Menu.java
  
  Index: Menu.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import org.jboss.seam.annotations.*;
  import org.jboss.seam.ScopeType;
  
  import javax.persistence.EntityManager;
  import java.util.List;
  import java.util.ArrayList;
  
  @Name("menu")
  @Scope(ScopeType.CONVERSATION)
  public class Menu {
  
      @In(create = true)
      protected EntityManager entityManager;
  
      @In(create = true)
      private Directory wikiRoot;
  
      private List<MenuItem> items;
      public List<MenuItem> getItems() {
          if (items == null) refreshMenuItems();
          return items;
      }
  
      /** 
       * This is very inefficient. There really is no better way if we want recursively have
       * all documents and directories with isMenuItem() in the main menu. Not even a direct
       * SQL query would help (multicolumn ordering would require by PK, not good). If this
       * can't be made performant with caching, we need to replace it with a simple one
       * or two level menu item search. Currently optimizing with batch fetching, future
       * implementation might use a nested set approach (we need one anyway for recursive
       * deletion of subtrees).
       */
      @Observer("Nodes.directoryStructureModified")
      @Transactional
      public void refreshMenuItems() {
          items = new ArrayList<MenuItem>();
          entityManager.joinTransaction();
          for(Node area : wikiRoot.getChildren())
              addNodesToMenuTree(items, 0, area);
      }
  
      // Recursive
      private void addNodesToMenuTree(List<MenuItem> menuItems, int i, Node node) {
          MenuItem menuItem = new MenuItem(node);
          menuItem.setLevel(i);
          if (node.isMenuItem()) menuItems.add(menuItem); // Check flag in-memory
          if (node.getChildren() != null && node.getChildren().size() > 0) {
              i++;
              for (Node child : node.getChildren()) {
                  if (i > 1)
                      // Flatten the menu tree into two levels (simple display)
                      addNodesToMenuTree(menuItems, i, child);
                  else
                      addNodesToMenuTree(menuItem.getSubItems(), i, child);
              }
          }
      }
  
      public class MenuItem{
          private Node node;
          private int level;
          private List<MenuItem> subItems = new ArrayList<MenuItem>();
  
          public MenuItem(Node node) { this.node = node; }
  
          public Node getNode() { return node; }
          public void setNode(Node node) { this.node = node; }
  
          public int getLevel() { return level; }
          public void setLevel(int level) { this.level = level; }
  
          public List<MenuItem> getSubItems() { return subItems; }
          public void setSubItems(List<MenuItem> subItems) { this.subItems = subItems; }
      }
  
      
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/Document.java
  
  Index: Document.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import org.hibernate.validator.Length;
  
  import javax.persistence.*;
  
  @Entity
  @DiscriminatorValue("DOCUMENT")
  public class Document extends Node {
  
      @Column(name = "CONTENT")
      @Length(min = 1, max = 32768)
      private String content;
  
      public Document() { super(); }
  
      public Document(String name) {
          super(name);
      }
  
      // Mutable properties
  
      public String getContent() {
          return content;
      }
      public void setContent(String content) {
          this.content = content;
          makeDirty();
      }
  
      public Directory getParent() {
          return (Directory)super.getParent();
      }
  
      public void addChild(Node child) {
          throw new UnsupportedOperationException("Documents can't have children");
      }
  
      public void removeChild(Node child) {
          throw new UnsupportedOperationException("Documents can't have children");
      }
  
  
      public String toString() {
          return getName();
      }
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/WikiRoot.java
  
  Index: WikiRoot.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import org.jboss.seam.annotations.*;
  import org.jboss.seam.ScopeType;
  
  import javax.persistence.EntityManager;
  
  @Name("wikiRoot")
  @Scope(ScopeType.CONVERSATION)
  public class WikiRoot {
  
      @In(create = true)
      protected EntityManager entityManager;
  
      protected Directory wikiRoot;
  
      @Unwrap
      public Directory getWikiRoot() {
          if (wikiRoot == null) loadWikiRoot();
          return wikiRoot;
      }
  
      @Transactional
      private void loadWikiRoot() {
          try {
              wikiRoot =(Directory)entityManager
                      .createQuery("select d from Directory d where d.parent is null")
                      .getSingleResult();
          } catch (RuntimeException ex) {
              throw new RuntimeException("You need to INSERT at least one parentless directory into the database", ex);
          }
      }
  
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/DirectoryHome.java
  
  Index: DirectoryHome.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import static javax.faces.application.FacesMessage.SEVERITY_ERROR;
  import static javax.faces.application.FacesMessage.SEVERITY_INFO;
  import javax.faces.application.FacesMessage;
  import javax.faces.context.FacesContext;
  
  import org.jboss.seam.annotations.*;
  import org.jboss.seam.annotations.datamodel.DataModel;
  import org.jboss.seam.annotations.datamodel.DataModelSelection;
  import org.jboss.seam.framework.EntityHome;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.wiki.core.links.WikiLinkResolver;
  import org.jboss.seam.core.FacesMessages;
  import org.jboss.seam.core.Events;
  
  import javax.persistence.Query;
  import java.util.List;
  import java.util.Collections;
  
  @Name("directoryHome")
  public class DirectoryHome extends EntityHome<Directory> {
  
      @RequestParameter
      Long dirId;
  
      @RequestParameter
      Long parentDirectoryId;
  
      Directory parentDirectory;
  
      @In(required = false)
      @Out(required = false, scope = ScopeType.CONVERSATION) // Propagate it through the conversation
      Directory currentDirectory;
  
      @In(create=true)
      private FacesMessages facesMessages;
  
      @In(create=true)
      private WikiLinkResolver wikiLinkResolver;
  
      @Override
      public Object getId() {
  
          if (dirId == null) {
              return super.getId();
          } else {
              return dirId;
          }
      }
  
      @Override
      @Begin(flushMode = FlushModeType.MANUAL)
      @Transactional
      public void create() {
          super.create();
  
          currentDirectory = getInstance(); // Prepare for outjection
  
          getEntityManager().joinTransaction();
          if (parentDirectoryId != null) {
              parentDirectory = getEntityManager().find(Directory.class, parentDirectoryId);
          } else {
              parentDirectory = getInstance().getParent();
          }
  
          // Fill the datamodel for outjection
          refreshChildNodes();
      }
  
      public String persist() {
  
          // Validate
          if (!isUniqueWikinameInDirectory(null) ||
              !isUniqueWikinameInArea()) return null;
  
          // Link the directory with its parent
          parentDirectory.addChild(getInstance());
  
          if (parentDirectory.getParent() != null) {
              // This is a subdirectory in an area
              getInstance().setAreaNumber(parentDirectory.getAreaNumber());
              return super.persist();
          } else {
              // This is a logical area
  
              // Satisfy NOT NULL constraint
              getInstance().setAreaNumber(Long.MAX_VALUE);
  
              // Do the persist() first, we need the identifier after this
              String outcome = super.persist();
  
              getInstance().setAreaNumber(getInstance().getId());
  
              // And flush() again...
              getEntityManager().flush();
              return outcome;
          }
      }
  
  
      public String update() {
  
          // Validate
          if (!isUniqueWikinameInDirectory(getInstance()) ||
              !isUniqueWikinameInArea()) return null;
  
          Events.instance().raiseEvent("Nodes.directoryStructureModified");
  
  // TODO: What the superclass.update() is doing breaks the menu preview http://jira.jboss.com/jira/browse/JBSEAM-713
  //        FacesMessages.instance().add("Updated object");
  //        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Updated Object"));
  
          return super.update();
      }
  
      public String remove() {
  
          // Unlink the document from its parent directory
          parentDirectory.removeChild(getInstance());
  
          // Null the outjected value
          currentDirectory = null;
  
          return super.remove();
      }
  
  
      public Directory getParentDirectory() {
          return parentDirectory;
      }
  
      public void setParentDirectory(Directory parentDirectory) {
          this.parentDirectory = parentDirectory;
      }
  
  
      public String getUpdatedMessage() {
          return super.getUpdatedMessage() + ": '" + getInstance().getName() + "'";
      }
  
  
      public String getDeletedMessage() {
          return super.getDeletedMessage() + ": '" + getInstance().getName() + "'";
      }
  
  
      public String getCreatedMessage() {
          return super.getCreatedMessage() + ": '" + getInstance().getName() + "'";
      }
  
      @DataModel
      List<Node> childNodes;
  
      @DataModelSelection
      Node selectedChildNode;
  
      public void moveNodeUpInList() {
          int position = getInstance().getChildren().indexOf(selectedChildNode);
          Collections.rotate(getInstance().getChildren().subList(position-1, position+1), 1);
          refreshChildNodes();
      }
  
      public void moveNodeDownInList() {
          int position = getInstance().getChildren().indexOf(selectedChildNode);
          Collections.rotate(getInstance().getChildren().subList(position, position+2), 1);
          refreshChildNodes();
      }
  
      public void selectDefaultDocument() {
          getInstance().setDefaultDocument((Document)selectedChildNode);
          refreshChildNodes();
      }
  
      private void refreshChildNodes() {
          childNodes = getInstance().getChildren();
      }
  
      public void previewMenuItems() {
          Events.instance().raiseEvent("Nodes.directoryStructureModified");
      }
  
      // Validation rules for persist(), update(), and remove();
  
      @Transactional
      private boolean isUniqueWikinameInDirectory(Directory ignore) {
          getEntityManager().joinTransaction();
  
          String queryString = "select n from Node n where n.parent = :parent and n.wikiname = :wikiname";
          if (ignore != null)  queryString = queryString + " and not n = :ignore";
  
          Query q = getEntityManager().createQuery(queryString);
          if (ignore != null) q.setParameter("ignore", ignore);
  
          // Unique directory name within parent
          List existingChildren = q
                  .setParameter("parent", parentDirectory)
                  .setParameter("wikiname", getInstance().getWikiname())
                  .getResultList();
          if (existingChildren.size() >0) {
              facesMessages.addFromResourceBundle(
                  "name",
                  SEVERITY_ERROR,
                  getMessageKeyPrefix() + "duplicateName",
                  "Directory or document with that name already exists."
              );
              return false;
          }
          return true;
      }
  
      /**
       * This is used to check for duplicate directory names in area. We could allow duplicate
       * directory names from a logical/automatic linking perspective, but the database constraint
       * would require a custom trigger. If we don't allow duplicate directory names in a logical
       * area, we can apply a simple multicolumn UNIQUE constraint, that is a lot easier.
       *
       * @return boolean True if the current instances WikiName already exists in the parents area
       */
      @Transactional
      private boolean isUniqueWikinameInArea() {
          if (parentDirectory == null) return true;
          getEntityManager().joinTransaction();
          // Unique directory name within area
          Directory foundDirectory =
                  wikiLinkResolver.findDirectoryInArea(parentDirectory, getInstance().getWikiname());
          if (foundDirectory != null && foundDirectory != getInstance()) {
              facesMessages.addFromResourceBundle(
                  "name",
                  SEVERITY_ERROR,
                  getMessageKeyPrefix() + "duplicateNameInArea",
                  "Directory with that name already exists in this area."
              );
              return false;
          }
          return true;
      }
  
  
  
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/UIBindings.java
  
  Index: UIBindings.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import org.jboss.seam.annotations.Name;
  
  import javax.faces.component.UIData;
  
  /**
   * Can't use conversational components for UI binding in Seam... and @In(#{uiComponents['id']}) doesn't work
   * for some reason... and JSF stinks.
   */
  @Name("uiBindings")
  public class UIBindings {
  
      private UIData childNodeTable;
      public UIData getChildNodeTable() { return childNodeTable; }
      public void setChildNodeTable(UIData childNodeTable) { this.childNodeTable = childNodeTable; }
  
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/Node.java
  
  Index: Node.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import org.hibernate.validator.Length;
  import org.jboss.seam.wiki.core.links.WikiLinkResolver;
  
  import javax.persistence.*;
  import java.util.List;
  import java.util.ArrayList;
  import java.util.Date;
  import java.io.Serializable;
  
  @Entity
  @Table(
      name = "NODE",
      uniqueConstraints = {
          // Siblings in a directory can't have the same name
          @UniqueConstraint(columnNames = {"PARENT_NODE_ID", "WIKINAME"}),
          // Wikiname of a document needs to be unique within an area
          @UniqueConstraint(columnNames = {"NODE_TYPE", "AREA_NR", "WIKINAME"})
      }
  )
  @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
  @DiscriminatorColumn(
      name = "NODE_TYPE",
      length = 255
  )
  @org.hibernate.annotations.FilterDef(
      name = "Node.onlyMenuItems",
      defaultCondition = "MENU_ITEM = 'true'"
  )
  public abstract class Node implements Serializable {
  
      @Id
      @GeneratedValue
      @Column(name = "NODE_ID")
      protected Long id;
  
      @Version
      @Column(name = "OBJ_VERSION")
      protected Integer version;
  
      @Column(name = "NAME", length = 255, nullable = false)
      @Length(min = 3, max = 255)
      protected String name;
  
      @Column(name = "WIKINAME", length = 255, nullable = false)
      protected String wikiname;
  
      @Column(name = "MENU_ITEM", nullable = false)
      protected boolean menuItem;
  
      @Column(name = "CREATED_ON", nullable = false)
      private Date createdOn;
  
      @Column(name = "LAST_MODIFIED_ON")
      private Date lastModifiedOn;
  
      @Column(name = "AREA_NR", nullable = false)
      private Long areaNumber;
  
      @ManyToOne
      @JoinColumn(name = "PARENT_NODE_ID", nullable = true, insertable = false, updatable = false)
      protected Node parent;
  
      @OneToMany(cascade = CascadeType.PERSIST)
      @JoinColumn(name = "PARENT_NODE_ID", nullable = true)
      @org.hibernate.annotations.IndexColumn(name = "NODE_POSITION")
      @org.hibernate.annotations.Filter(name = "Node.onlyMenuItems")
      @org.hibernate.annotations.BatchSize(size = 5)
      private List<Node> children = new ArrayList<Node>();
  
      public Node() {
          this.createdOn = new Date();
      }
  
      public Node(String name) {
          this.name = name;
      }
  
      // Immutable properties
  
      public Long getId() { return id; }
      public String getIdAsString() {
          // JSF is stupid
          return getId().toString();
      }
      public Integer getVersion() { return version; }
      public Date getCreatedOn() { return createdOn; }
  
      // Mutable properties
  
      public String getName() {
           return name;
      }
      public void setName(String name) {
          this.name = name;
          this.wikiname = WikiLinkResolver.convertToWikiName(name);
          makeDirty();
      }
  
      public String getWikiname() {
          return wikiname;
      }
  
      public boolean isMenuItem() {
          return menuItem;
      }
  
      public void setMenuItem(boolean menuItem) {
          this.menuItem = menuItem;
      }
  
      public Date getLastModifiedOn() {
          return lastModifiedOn;
      }
  
      public void setLastModifiedOn(Date lastModifiedOn) {
          this.lastModifiedOn = lastModifiedOn;
      }
  
      public Long getAreaNumber() {
          return areaNumber;
      }
  
      public void setAreaNumber(Long areaNumber) {
          this.areaNumber = areaNumber;
      }
  
      public Node getParent() {
          return parent;
      }
  
      public void setParent(Node parent) {
          this.parent = parent;
      }
  
      public List<Node> getChildren() {
          // Unfortunately, it needs to be modifiable for the virtual root logic...
          //return Collections.unmodifiableList(children);
          return children;
      }
  
      public void addChild(Node child) {
          if (child.getParent() != null) child.getParent().getChildren().remove(child);
          child.setParent(this);
          this.getChildren().add(child);
      }
  
      public void removeChild(Node child) {
          child.setParent(null);
          this.getChildren().remove(child);
      }
  
      protected void makeDirty() {
          setLastModifiedOn(new Date());
      }
  
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/Directory.java
  
  Index: Directory.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  
  import javax.persistence.*;
  
  @Entity
  @DiscriminatorValue("DIRECTORY")
  public class Directory extends Node {
  
      @ManyToOne(fetch = FetchType.EAGER) // Lazy would break UI logic that relies on classnames (proxy doesn't work)
      @JoinColumn(name = "DEFAULT_DOCUMENT_ID", nullable = true)
      private Document defaultDocument;
  
      public Directory() { super(); }
  
      public Directory(String name) {
          super(name);
      }
  
      // Mutable properties
  
      public Document getDefaultDocument() {
          return defaultDocument;
      }
  
      public void setDefaultDocument(Document defaultDocument) {
          this.defaultDocument = defaultDocument;
          makeDirty();
      }
  
      public String toString() {
          return getName();
      }
  
      public Directory getParent() {
          return (Directory)super.getParent();
      }
  }
  
  
  
  1.1      date: 2007/02/01 07:08:26;  author: cbauer;  state: Exp;jboss-seam/examples/wiki/src/org/jboss/seam/wiki/core/node/NodeBrowser.java
  
  Index: NodeBrowser.java
  ===================================================================
  package org.jboss.seam.wiki.core.node;
  
  import org.jboss.seam.annotations.*;
  import org.jboss.seam.ScopeType;
  
  import javax.persistence.EntityManager;
  import javax.persistence.EntityNotFoundException;
  import java.util.*;
  
  /**
   * Resolves <tt>currentDocument</tt> and <tt>currentDirectory</tt> objects for given request parameters.
   * <p>
   * URLs typically mapped and resolved with these classes:
   * <p>
   * <pre>
   * http://host/         -- rewrite filter --> http://host/docDisplay.seam (DONE)
   * http://host/123.html -- rewrite filter --> http://host/docDisplay.seam?nodeId=123 (DONE)
   * http://host/Foo      -- rewrite filter --> http://host/docDisplay.seam?dirName=Foo (PLANNED)
   * http://host/Foo/Bar  -- rewrite filter --> http://host/docDisplay.seam?dirName=Foo&docName=Bar (PLANNED)
   * </pre>
   * 'Foo' is a WikiName of a directory with a parentless parent (ROOT), we call this a logical area.
   * 'Bar' is a WikiName of a document in that logical area, unique within that directory subtree.
   * <p>
   * We _never_ have URLs like <tt>http://host/Foo/Baz/Bar</tt> because 'Baz' would be a subdirectory
   * we don't need. An area name and a document name is enough, the document name is unique within
   * a subtree. We also never have <tt>http://host/Bar</tt>, a document name alone is not enough to
   * identify a document, we also need the area name. In that case, 'Bar' would be treated like an
   * area name and the default document of that area would be shown.
   *
   * @author Christian Bauer
   */
  @Name("browser")
  public class NodeBrowser {
  
  
      @RequestParameter
      protected String dirName;
  
      @RequestParameter
      protected String docName;
  
      protected Long nodeId;
      public Long getNodeId() { return nodeId; }
      public void setNodeId(Long nodeId) { this.nodeId = nodeId; }
  
      @In(create = true)
      protected EntityManager entityManager;
  
      @In
      protected org.jboss.seam.core.Redirect redirect;
  
      @In(create = true)
      protected Directory wikiRoot;
  
      // These are only EVENT scoped, we don't want them to jump from DocumentBrowser to
      // DirectoryBrowser over redirects
      @In(required=false) @Out(scope = ScopeType.EVENT, required = false)
      protected Document currentDocument;
  
      @In(required=false) @Out(scope = ScopeType.EVENT, required = false)
      protected Directory currentDirectory;
  
      @Out(scope = ScopeType.EVENT)
      protected  List<Node> currentDirectoryPath = new ArrayList<Node>();
  
  
      /**
       * Executes a redirect to the last view-id that was prepare()ed.
       * <p>
       * Usually called after ending a conversation. Assumes that the caller of the method does not want to propagate
       * the current (ended) conversation across that redirect. Also removes any stored <tt>actionOutcome</tt>,
       * <tt>actionMethod</tt> or <tt>cid</tt> request parameter before redirecting, we don't want to redirect to
       * a prepare()ed page that was in a long-running conversation (temporary doesn't matter) or that was last
       * called with an action (that action would probably send us straight back into the conversation we are trying
       * to redirect out of).
       */
      public void redirectToLastBrowsedPage() {
  /*
          // We don't want to redirect to an action, so if the last browsed page was called with an action, remove it
          redirect.getParameters().remove("actionOutcome");
          redirect.getParameters().remove("actionMethod");
  
          // If the last browsed page had a conversation identifier (we assume of a temporary conversation), remove it
          redirect.getParameters().remove("cid");
  
          // We also don't want to redirect the long-running conversation, the caller has ended it already
          redirect.setConversationPropagationEnabled(false);
  */
          redirect.execute();
      }
  
      // Just a convenience method for recursive calling
      protected void addDirectoryToPath(List<Node> path, Node directory) {
          path.add(directory);
          if (directory.getParent() != null )
              addDirectoryToPath(path, directory.getParent());
      }
  
      public String prepareAndCapture() {
          // Store the view-id that called this method (as a page action) for return (exit of a later conversation)
          redirect.captureCurrentRequest();
          return prepare();
      }
  
      @Transactional
      public String prepare() {
  
          // Have we been called with a nodeId request parameter, could be document or directory
          if (nodeId != null) {
  
              entityManager.joinTransaction();
  
              // Try to find a document
              try {
                  currentDocument = entityManager.find(Document.class, nodeId);
              } catch (EntityNotFoundException ex) {}
  
              // Document not found, see if it is a directory
              if (currentDocument == null) {
                  try {
                      currentDirectory = entityManager.find(Directory.class, nodeId);
                  } catch (EntityNotFoundException ex) {}
  
                  // Try to get a default document of that directory
                  if (currentDirectory != null) {
                      currentDocument = currentDirectory.getDefaultDocument();
                  } else {
                  }
              } else {
                  // Document found, take its directory
                  currentDirectory = currentDocument.getParent();
              }
          }
  
          // Fall back to wiki root
          if (currentDirectory== null) currentDirectory = wikiRoot;
  
          // Prepare directory path for breadcrumb
          addDirectoryToPath(currentDirectoryPath, currentDirectory);
          Collections.reverse(currentDirectoryPath);
  
          // This handles the wiki names in dirName and docName request parameters.
          // The logic here is the same as the code that will resolve wiki URLs during rendering of
          // pages, so we need to do that later...
          if (dirName != null) {
              System.out.println("#### NEED TO RESOLVE DIR NAME: " + dirName);
          }
          if (docName != null) {
              System.out.println("#### NEED TO RESOLVE DOC NAME: " + docName);
          }
  
          // Return not-null outcome so we can navigate from here
          return "prepared";
      }
  
  
  }
  
  
  



More information about the jboss-cvs-commits mailing list