View Javadoc
1   /*
2    * Copyright (C) 2003-2008 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.ecm.webui.tree;
18  
19  import java.io.Writer;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.List;
23  
24  import javax.jcr.Node;
25  import javax.jcr.NodeIterator;
26  import javax.jcr.PathNotFoundException;
27  import javax.jcr.RepositoryException;
28  import javax.jcr.nodetype.NodeType;
29  
30  import org.exoplatform.ecm.webui.comparator.NodeTitleComparator;
31  import org.exoplatform.ecm.webui.tree.selectone.UIOneTaxonomySelector;
32  import org.exoplatform.ecm.webui.utils.Utils;
33  import org.exoplatform.portal.webui.container.UIContainer;
34  import org.exoplatform.services.cms.link.NodeFinder;
35  import org.exoplatform.services.ecm.publication.PublicationService;
36  import org.exoplatform.services.wcm.core.NodeLocation;
37  import org.exoplatform.webui.application.WebuiRequestContext;
38  import org.exoplatform.webui.config.annotation.ComponentConfig;
39  import org.exoplatform.webui.config.annotation.EventConfig;
40  import org.exoplatform.webui.core.UIBreadcumbs;
41  import org.exoplatform.webui.core.UITree;
42  import org.exoplatform.webui.core.UIBreadcumbs.LocalPath;
43  import org.exoplatform.webui.event.Event;
44  import org.exoplatform.webui.event.EventListener;
45  
46  /**
47   * Created by The eXo Platform SAS.
48   *
49   * @author : Hoa.Pham hoa.pham@exoplatform.com Jun 23, 2008
50   */
51  
52  @ComponentConfig(
53      events = @EventConfig(listeners = UITreeTaxonomyBuilder.ChangeNodeActionListener.class)
54  )
55  
56  public class UITreeTaxonomyBuilder extends UIContainer {
57    private boolean allowPublish = false;
58    private PublicationService publicationService_ = null;
59    private List<String> templates_ = null;
60  
61    private String[] acceptedNodeTypes = {};
62  
63    private String[] defaultExceptedNodeTypes = {};
64  
65    /** The root tree node. */
66    protected NodeLocation rootTreeNode;
67  
68    /** The current node. */
69    protected NodeLocation currentNode;
70  
71    public boolean isAllowPublish() {
72      return allowPublish;
73    }
74  
75    public void setAllowPublish(boolean allowPublish, PublicationService publicationService, List<String> templates) {
76      this.allowPublish = allowPublish;
77      publicationService_ = publicationService;
78      templates_ = templates;
79    }
80  
81    /**
82     * Instantiates a new uI node tree builder.
83     *
84     * @throws Exception the exception
85     */
86    public UITreeTaxonomyBuilder() throws Exception {
87      UITree tree = addChild(UINodeTree.class, null, "TaxonomyTreeBuilder") ;
88      tree.setBeanLabelField("name") ;
89      tree.setBeanIdField("path") ;
90    }
91  
92    /**
93     * Gets the root tree node.
94     *
95     * @return the root tree node
96     */
97    public Node getRootTreeNode() { 
98      return NodeLocation.getNodeByLocation(rootTreeNode); 
99    }
100 
101   /**
102    * Sets the root tree node.
103    *
104    * @param node the new root tree node
105    * @throws Exception the exception
106    */
107   public final void setRootTreeNode(Node node) throws Exception {
108     this.rootTreeNode = NodeLocation.getNodeLocationByNode(node);
109     this.currentNode = NodeLocation.getNodeLocationByNode(node);
110     UINodeTree uiNodeTree = getChild(UINodeTree.class);
111     uiNodeTree.setRootPath(node.getPath());
112     uiNodeTree.setTaxonomyLocalize(true);
113     broadcastOnChange(node,null);
114   }
115 
116   /**
117    * Gets the current node.
118    *
119    * @return the current node
120    */
121   public Node getCurrentNode() { 
122     return NodeLocation.getNodeByLocation(currentNode); 
123   }
124 
125   /**
126    * Sets the current node.
127    *
128    * @param currentNode the new current node
129    */
130   public void setCurrentNode(Node currentNode) { 
131     this.currentNode = NodeLocation.getNodeLocationByNode(currentNode); 
132   }
133 
134   /**
135    * Gets the accepted node types.
136    *
137    * @return the accepted node types
138    */
139   public String[] getAcceptedNodeTypes() { return acceptedNodeTypes; }
140 
141   /**
142    * Sets the accepted node types.
143    *
144    * @param acceptedNodeTypes the new accepted node types
145    */
146   public void setAcceptedNodeTypes(String[] acceptedNodeTypes) {
147     this.acceptedNodeTypes = acceptedNodeTypes;
148   }
149 
150   /**
151    * Gets the default excepted node types.
152    *
153    * @return the default excepted node types
154    */
155   public String[] getDefaultExceptedNodeTypes() { return defaultExceptedNodeTypes; }
156 
157   /**
158    * Sets the default excepted node types.
159    *
160    * @param defaultExceptedNodeTypes the new excepted node types
161    */
162   public void setDefaultExceptedNodeTypes(String[] defaultExceptedNodeTypes) {
163     this.defaultExceptedNodeTypes = defaultExceptedNodeTypes;
164   }
165 
166   public boolean isExceptedNodeType(Node node) throws RepositoryException {
167     if(defaultExceptedNodeTypes.length > 0) {
168       for(String nodeType: defaultExceptedNodeTypes) {
169         if(node.isNodeType(nodeType)) return true;
170       }
171     }
172     return false;
173   }
174 
175   public void buildTree() throws Exception {
176     NodeIterator sibbling = null ;
177     NodeIterator children = null ;
178     UINodeTree tree = getChild(UINodeTree.class);
179     Node selectedNode = getNodeByPathBreadcumbs();
180     if ((tree != null) && (selectedNode != null)) {
181       tree.setSelected(selectedNode);
182       if (Utils.getNodeSymLink(selectedNode).getDepth() > 0) {
183         if (!selectedNode.getPath().equals(rootTreeNode.getPath()))
184           tree.setParentSelected(selectedNode.getParent()) ;
185         sibbling = Utils.getNodeSymLink(selectedNode).getNodes() ;
186         children = Utils.getNodeSymLink(selectedNode).getNodes() ;
187       } else {
188         tree.setParentSelected(selectedNode) ;
189         sibbling = Utils.getNodeSymLink(selectedNode).getNodes() ;
190         children = null;
191       }
192       if (sibbling != null) {
193         tree.setSibbling(filfer(sibbling));
194       }
195       if (children != null) {
196         tree.setChildren(filfer(children));
197       }
198     }
199   }
200 
201   private Node getNodeByPathBreadcumbs() throws PathNotFoundException, RepositoryException {
202     UIOneTaxonomySelector uiOneTaxonomySelector = (UIOneTaxonomySelector) getParent();
203     UIBreadcumbs uiBreadcumbs = uiOneTaxonomySelector.getChildById("BreadcumbOneTaxonomy");
204     List<LocalPath> listLocalPath = uiBreadcumbs.getPath();
205     StringBuilder buffer = new StringBuilder(1024);
206     String rootPath = "";
207     if (rootTreeNode != null) rootPath = rootTreeNode.getPath();
208     for (LocalPath iterLocalPath : listLocalPath) {
209       buffer.append("/").append(iterLocalPath.getId());
210     }
211     String path = buffer.toString();
212     if (rootPath.endsWith(path)) rootPath = rootPath.substring(0, rootPath.length() - path.length());
213     path = path.replaceAll("/+", "/");
214     if (!path.startsWith(rootPath)) {
215       StringBuffer sb = new StringBuffer();
216       sb.append(rootPath).append(path);
217       path = sb.toString();
218     }
219     if (path.endsWith("/")) path = path.substring(0, path.length() - 1);
220     if (path.length() == 0) path = "/";
221     if (buffer.length() == 0) return NodeLocation.getNodeByLocation(currentNode);
222     NodeFinder nodeFinder_ = getApplicationComponent(NodeFinder.class);
223     return (Node)nodeFinder_.getItem(uiOneTaxonomySelector.getWorkspaceName(), path);
224   }
225 
226   private void addNodePublish(List<Node> listNode, Node node, PublicationService publicationService) throws Exception {
227     if (isAllowPublish()) {
228       NodeType nt = node.getPrimaryNodeType();
229       if (templates_.contains(nt.getName())) {
230         Node nodecheck = publicationService.getNodePublish(node, null);
231         if (nodecheck != null) {
232           listNode.add(nodecheck);
233         }
234       } else {
235         listNode.add(node);
236       }
237     } else {
238       listNode.add(node);
239     }
240   }
241 
242   private List<Node> filfer(final NodeIterator iterator) throws Exception{
243     List<Node> list = new ArrayList<Node>();
244     if (acceptedNodeTypes.length > 0) {
245       for(;iterator.hasNext();) {
246         Node sibbling = iterator.nextNode();
247         if(sibbling.isNodeType("exo:hiddenable")) continue;
248         for(String nodetype: acceptedNodeTypes) {
249           if(sibbling.isNodeType(nodetype)) {
250             list.add(sibbling);
251             break;
252           }
253         }
254       }
255       Collections.sort(list, new NodeTitleComparator(NodeTitleComparator.ASCENDING_ORDER));
256       List<Node> listNodeCheck = new ArrayList<Node>();
257       for (Node node : list) {
258         addNodePublish(listNodeCheck, node, publicationService_);
259       }
260       return listNodeCheck;
261     }
262     for(;iterator.hasNext();) {
263       Node sibbling = iterator.nextNode();
264       if(sibbling.isNodeType("exo:hiddenable")  || isExceptedNodeType(sibbling)) continue;
265       list.add(sibbling);
266     }
267     Collections.sort(list, new NodeTitleComparator(NodeTitleComparator.ASCENDING_ORDER));
268     List<Node> listNodeCheck = new ArrayList<Node>();
269     for (Node node : list) addNodePublish(listNodeCheck, node, publicationService_);
270     return listNodeCheck;
271   }
272 
273   /* (non-Javadoc)
274    * @see org.exoplatform.webui.core.UIComponent#processRender(org.exoplatform.webui.application.WebuiRequestContext)
275    */
276   public void processRender(WebuiRequestContext context) throws Exception {
277     Writer writer = context.getWriter() ;
278     writer.write("<div class=\"explorerTree\">") ;
279       buildTree() ;
280       super.renderChildren() ;
281     writer.write("</div>") ;
282   }
283 
284   /**
285    * When a node is change in tree. This method will be rerender the children and sibbling nodes of
286    * current node and broadcast change node event to other uicomponent
287    *
288    * @param path the path
289    * @param context the request context
290    * @throws Exception the exception
291    */
292   public void changeNode(String path, Object context) throws Exception {
293     if (path == null) return;
294     NodeFinder nodeFinder_ = getApplicationComponent(NodeFinder.class);
295     String rootPath = rootTreeNode.getPath();
296     if(rootPath.equals(path) || !path.startsWith(rootPath)) {
297       currentNode = rootTreeNode;
298     }else {
299       if (path.startsWith(rootPath)) path = path.substring(rootPath.length());
300       if (path.startsWith("/")) path = path.substring(1);
301       currentNode = NodeLocation.getNodeLocationByNode(nodeFinder_.getNode(
302                                   NodeLocation.getNodeByLocation(rootTreeNode), path));
303     }
304     broadcastOnChange(NodeLocation.getNodeByLocation(currentNode),context);
305   }
306 
307   /**
308    * Broadcast on change.
309    *
310    * @param node the node
311    * @param context the request context
312    * @throws Exception the exception
313    */
314   public void broadcastOnChange(Node node, Object context) throws Exception {
315     UIBaseNodeTreeSelector nodeTreeSelector = getAncestorOfType(UIBaseNodeTreeSelector.class);
316     nodeTreeSelector.onChange(node, context);
317   }
318 
319   /**
320    * The listener interface for receiving changeNodeAction events. The class
321    * that is interested in processing a changeNodeAction event implements this
322    * interface, and the object created with that class is registered with a
323    * component using the component's
324    * <code>addChangeNodeActionListener</code> method. When
325    * the changeNodeAction event occurs, that object's appropriate
326    * method is invoked.
327    */
328   static public class ChangeNodeActionListener extends EventListener<UITree> {
329 
330     /* (non-Javadoc)
331      * @see org.exoplatform.webui.event.EventListener#execute(org.exoplatform.webui.event.Event)
332      */
333     public void execute(Event<UITree> event) throws Exception {
334       UITreeTaxonomyBuilder builder = event.getSource().getParent();
335       String uri = event.getRequestContext().getRequestParameter(OBJECTID);
336       builder.changeNode(uri,event.getRequestContext());
337       UIBaseNodeTreeSelector nodeTreeSelector = builder.getAncestorOfType(UIBaseNodeTreeSelector.class);
338       event.getRequestContext().addUIComponentToUpdateByAjax(nodeTreeSelector);
339     }
340   }
341 }