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.component.explorer;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.Set;
22  
23  import javax.jcr.Node;
24  import javax.jcr.NodeIterator;
25  import javax.jcr.RepositoryException;
26  import javax.jcr.Session;
27  import javax.jcr.nodetype.NodeType;
28  import javax.jcr.nodetype.NodeTypeIterator;
29  import javax.jcr.nodetype.NodeTypeManager;
30  import javax.jcr.query.Query;
31  import javax.jcr.query.Row;
32  
33  import org.apache.commons.lang.StringUtils;
34  import org.exoplatform.commons.api.search.data.SearchResult;
35  import org.exoplatform.ecm.jcr.model.Preference;
36  import org.exoplatform.ecm.webui.utils.Utils;
37  import org.exoplatform.services.cms.documents.DocumentTypeService;
38  import org.exoplatform.services.cms.link.LinkManager;
39  import org.exoplatform.services.cms.link.NodeFinder;
40  import org.exoplatform.services.cms.link.NodeLinkAware;
41  import org.exoplatform.services.cms.templates.TemplateService;
42  import org.exoplatform.services.jcr.ext.common.SessionProvider;
43  import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
44  import org.exoplatform.services.log.ExoLogger;
45  import org.exoplatform.services.log.Log;
46  import org.exoplatform.services.security.ConversationState;
47  import org.exoplatform.services.wcm.core.NodetypeConstant;
48  import org.exoplatform.services.wcm.search.base.LazyPageList;
49  import org.exoplatform.services.wcm.search.base.PageListFactory;
50  import org.exoplatform.services.wcm.search.base.QueryData;
51  import org.exoplatform.services.wcm.search.base.SearchDataCreator;
52  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
53  
54  /**
55   * Created by The eXo Platform SARL
56   * Author : Nguyen Anh Vu
57   *          anhvurz90@gmail.com
58   * Nov 9, 2009
59   * 1:48:20 PM
60   */
61  public class DocumentProviderUtils {
62  
63    private static final String   Contents_Document_Type             = "Content";
64    
65    private static final String FAVORITE_ALIAS = "userPrivateFavorites";
66    
67    private static final Log LOG  = ExoLogger.getLogger(DocumentProviderUtils.class.getName());  
68    
69    private static final String[] prohibitedSortType = {
70                              NodetypeConstant.SORT_BY_NODESIZE,
71                              NodetypeConstant.SORT_BY_NODETYPE, 
72                              NodetypeConstant.SORT_BY_DATE, };
73    
74    private static DocumentProviderUtils docProviderUtil_ = new DocumentProviderUtils();
75    private List<String> folderTypes_;
76    
77    private DocumentProviderUtils() {
78    }
79    
80    public static DocumentProviderUtils getInstance() { return docProviderUtil_; }
81    
82    public boolean canSortType(String sortType) {
83      for (String type : prohibitedSortType) {
84        if (type.equals(sortType)) {
85          return false;
86        }
87      }
88      return true;
89    }
90    public <E> LazyPageList<E> getPageList(String ws, String path, Preference pref, 
91                                                   Set<String> allItemFilter, Set<String> allItemByTypeFilter, 
92                                                   SearchDataCreator<E> dataCreater) throws Exception{
93      String statement = getStatement(ws, path, pref, allItemFilter, allItemByTypeFilter);
94      QueryData queryData = new QueryData(statement, ws, Query.SQL, 
95                                          WCMCoreUtils.getRemoteUser().equals(WCMCoreUtils.getSuperUser()));
96      return PageListFactory.createLazyPageList(queryData, pref.getNodesPerPage(),dataCreater);
97    }
98    
99    public LazyPageList<NodeLinkAware> getPageList(String ws, String path, Preference pref, 
100                           Set<String> allItemFilter, Set<String> allItemByTypeFilter,
101                           NodeLinkAware parent) throws Exception {
102     LinkManager linkManager = WCMCoreUtils.getService(LinkManager.class);
103     NodeFinder nodeFinder = WCMCoreUtils.getService(NodeFinder.class);
104     String statement;
105     try {
106       Node node = (Node)nodeFinder.getItem(ws, path);
107       if (linkManager.isLink(node)) {
108         path = linkManager.getTarget(node).getPath();
109       }else{
110         path = node.getPath();
111       }
112       statement = getStatement(ws, path, pref, allItemFilter, allItemByTypeFilter);
113     } catch (Exception e) {
114       statement = null;
115     }
116     QueryData queryData = new QueryData(statement, ws, Query.SQL, 
117                                         WCMCoreUtils.getRemoteUser().equals(WCMCoreUtils.getSuperUser()));
118     return PageListFactory.createLazyPageList(queryData, pref.getNodesPerPage(), new NodeLinkAwareCreator(parent));
119   }
120   
121   private String getStatement(String ws, String path, Preference pref, 
122                              Set<String> allItemsFilterSet, Set<String> allItemsByTypeFilter) 
123                                  throws Exception {
124     StringBuilder buf = new StringBuilder();
125     //path
126     buf = addPathParam(buf, path);
127     //jcrEnable
128     buf = addJcrEnableParam(buf, ws, path, pref);
129     //show non document
130     buf = addShowNonDocumentType(buf, pref, allItemsByTypeFilter);
131     //show hidden node
132     buf = addShowHiddenNodeParam(buf, pref);
133     //owned by me
134     buf = addOwnedByMeParam(buf, allItemsFilterSet); 
135     //favorite
136     buf = addFavoriteParam(buf, ws, allItemsFilterSet);
137     //all items by type
138     buf = addAllItemByType(buf, allItemsByTypeFilter);
139     //sort
140     buf = addSortParam(buf, pref);
141     return (buf == null) ? null : buf.toString();
142   }
143   
144   /**
145    * add path condition to query statement
146    */
147   private StringBuilder addPathParam(StringBuilder buf, String path) {
148     buf.append("SELECT * FROM nt:base ");
149     if (path != null) {
150       if (path.endsWith("/")) {
151         path = path.substring(0, path.length() - 1);
152       }
153       buf.append("WHERE jcr:path LIKE '").append(path)
154         .append("/%' AND NOT jcr:path LIKE '").append(path).append("/%/%' ");
155     }
156     return buf;
157   }
158 
159   /**
160    * add is_jcr_enable condition to query statement
161    */
162   private StringBuilder addJcrEnableParam(StringBuilder buf, String ws, String path, Preference pref) 
163       throws Exception {
164     TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
165     SessionProvider provider = WCMCoreUtils.getUserSessionProvider();
166     Session session = provider.getSession(ws, WCMCoreUtils.getRepository());
167     Node node = (Node)session.getItem(path);
168     if(!pref.isJcrEnable() &&
169         templateService.isManagedNodeType(node.getPrimaryNodeType().getName()) && 
170         !(node.isNodeType(NodetypeConstant.NT_FOLDER) || node.isNodeType(NodetypeConstant.NT_UNSTRUCTURED) )) {
171       return null;
172     }
173     return buf;
174   }
175   
176   /**
177    * add show_non_document_type condition to query statement 
178    */
179   private StringBuilder addShowNonDocumentType(StringBuilder buf, Preference pref, Set<String> allItemsByTypeFilter) 
180       throws Exception {
181     if (buf == null) return null;
182     if (!pref.isShowNonDocumentType() || allItemsByTypeFilter.contains(Contents_Document_Type)) {
183       if (folderTypes_ == null) {
184         folderTypes_ = getFolderTypes();
185       }
186       buf.append(" AND (");
187       //nt:unstructured && nt:folder
188       buf.append("( jcr:primaryType='").append(Utils.NT_UNSTRUCTURED)
189       .append("') OR (exo:primaryType='").append(Utils.NT_UNSTRUCTURED).append("') ");
190       buf.append(" OR ( jcr:primaryType='").append(Utils.NT_FOLDER)
191       .append("') OR (exo:primaryType='").append(Utils.NT_FOLDER).append("') ");
192       //supertype of nt:unstructured or nt:folder
193       for (String fType : folderTypes_) {
194         buf.append(" OR ( jcr:primaryType='").append(fType)
195            .append("') OR (exo:primaryType='").append(fType).append("') ");
196       }
197       //all document type
198       TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
199       List<String> docTypes = templateService.getDocumentTemplates();
200       for (String docType : docTypes) {
201         buf.append(" OR ( jcr:primaryType='").append(docType)
202            .append("') OR (exo:primaryType='").append(docType).append("') ");
203       }
204       buf.append(" ) ");
205     }
206     return buf;
207   }
208 
209   private List<String> getFolderTypes() {
210     List<String> ret = new ArrayList<String>();
211     NodeTypeManager nodeTypeManager = WCMCoreUtils.getRepository().getNodeTypeManager();
212     try {
213       for (NodeTypeIterator iter = nodeTypeManager.getAllNodeTypes(); iter.hasNext();) {
214         NodeType type = iter.nextNodeType();
215         if (type.isNodeType(NodetypeConstant.NT_FOLDER) || type.isNodeType(NodetypeConstant.NT_UNSTRUCTURED)) {
216           ret.add(type.getName());
217         }
218       }
219     } catch (RepositoryException e) {
220       if (LOG.isWarnEnabled()) {
221         LOG.warn("Can not get all node types", e.getMessage());
222       }
223     }
224     return ret;
225   }
226   
227   /**
228    * add show_hidden_node condition to query statement 
229    */
230   private StringBuilder addShowHiddenNodeParam(StringBuilder buf, Preference pref) {
231     if (buf == null) return null;
232     if (!pref.isShowHiddenNode()) {
233       buf.append(" AND ( NOT jcr:mixinTypes='").append(NodetypeConstant.EXO_HIDDENABLE).append("')");
234     }
235     return buf;
236   }
237   
238   /**
239    * add owned_by_me condition to query statement 
240    */
241   private StringBuilder addOwnedByMeParam(StringBuilder buf, Set<String> allItemsFilterSet) {
242     if (buf == null) return null;
243     if (allItemsFilterSet.contains(NodetypeConstant.OWNED_BY_ME)) {
244       buf.append(" AND ( exo:owner='")
245          .append(ConversationState.getCurrent().getIdentity().getUserId())
246          .append("')");
247     }
248     return buf;
249   }
250   
251   /**
252    * add favorite condition to query statement 
253    * @throws Exception 
254    */
255   private StringBuilder addFavoriteParam(StringBuilder buf, String ws, Set<String> allItemsFilterSet) 
256       throws Exception {
257     if (buf == null) return null;
258     if (allItemsFilterSet.contains(NodetypeConstant.FAVORITE)) {
259       NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
260       Node userNode =
261           nodeHierarchyCreator.getUserNode(WCMCoreUtils.getSystemSessionProvider(),
262                                            ConversationState.getCurrent().getIdentity().getUserId());
263       String favoritePath = nodeHierarchyCreator.getJcrPath(FAVORITE_ALIAS);
264       int count = 0;
265       buf.append(" AND (");
266       for (NodeIterator iter = userNode.getNode(favoritePath).getNodes();iter.hasNext();) {
267         Node node = iter.nextNode();
268         if (node.isNodeType(NodetypeConstant.EXO_SYMLINK) &&
269             node.hasProperty(NodetypeConstant.EXO_WORKSPACE) &&
270             ws.equals(node.getProperty(NodetypeConstant.EXO_WORKSPACE).getString())) {
271           if (count ++ > 0) {
272             buf.append(" OR ");
273           }
274           buf.append(" jcr:uuid='")
275              .append(node.getProperty("exo:uuid").getString())
276              .append("'");
277         }
278       }
279       buf.append(" ) ");
280       if (count == 0) {
281         return null;
282       } 
283     }
284     return buf;
285   }
286   
287   /**
288    * add mimetype condition to query statement 
289    */
290   private StringBuilder addAllItemByType(StringBuilder buf, Set<String> allItemsByTypeFilterSet) {
291     if(allItemsByTypeFilterSet.isEmpty()) {
292       return buf;
293     }
294     DocumentTypeService documentTypeService = WCMCoreUtils.getService(DocumentTypeService.class);
295     StringBuilder buf1 = new StringBuilder(" AND (");
296     int count = 0;
297     for (String documentType : allItemsByTypeFilterSet) {
298       for (String mimeType : documentTypeService.getMimeTypes(documentType)) {
299         if (count++ > 0) {
300           buf1.append(" OR ");
301         }
302         if (mimeType.endsWith("/")) { mimeType = mimeType.substring(0, mimeType.length() - 1); }
303         buf1.append(" 'jcr:content/jcr:mimeType' like '").append(mimeType).append("/%'");
304       }
305     }
306     buf1.append(" )");
307     if (count > 0) {
308       buf.append(buf1);
309     }
310     return buf;
311   }
312 
313   /**
314    * adds 'sort by' condition to query statement
315    */
316   private StringBuilder addSortParam(StringBuilder buf, Preference pref) {
317     if (buf == null) return null;
318     String type = "";
319     if (NodetypeConstant.SORT_BY_NODENAME.equals(pref.getSortType())) { type="exo:name"; } 
320     else if (NodetypeConstant.SORT_BY_CREATED_DATE.equals(pref.getSortType())) { 
321       type = NodetypeConstant.EXO_DATE_CREATED;
322     } else if (NodetypeConstant.SORT_BY_MODIFIED_DATE.equals(pref.getSortType())) {
323       type = NodetypeConstant.EXO_LAST_MODIFIED_DATE;
324     } else { type= pref.getSortType(); }
325     buf.append(" ORDER BY ").append(type).append(" ");
326     buf.append("Ascending".equals(pref.getOrder()) ? "ASC" : "DESC");
327     return buf;
328   }
329   
330   /**
331    * Simple data creator, just creates the node result itself
332    */
333   public class NodeLinkAwareCreator implements SearchDataCreator<NodeLinkAware> {
334 
335     private NodeLinkAware parent;
336     
337     public NodeLinkAwareCreator(NodeLinkAware parent) {
338       this.parent = parent;
339     }
340     
341     @Override
342     public NodeLinkAware createData(Node node, Row row, SearchResult searchResult) {
343       try {
344         return (NodeLinkAware)parent.getNode(StringUtils.substringAfterLast(node.getPath(), "/"));
345       } catch (RepositoryException e) {
346         LOG.error("Can not create NodeLinkAware", e);
347       }
348       return null;
349     }
350   }
351 }