001/* 002 * (C) Copyright 2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id: DirectoryTreeManagerBean.java 28950 2008-01-11 13:35:06Z tdelprat $ 018 */ 019package org.nuxeo.ecm.webapp.directory; 020 021import static org.jboss.seam.ScopeType.CONVERSATION; 022import static org.nuxeo.ecm.webapp.directory.DirectoryTreeNode.PARENT_FIELD_ID; 023 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.LinkedList; 027import java.util.List; 028import java.util.Map; 029 030import org.apache.commons.lang.StringUtils; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.jboss.seam.annotations.In; 034import org.jboss.seam.annotations.Name; 035import org.jboss.seam.annotations.Scope; 036import org.nuxeo.ecm.core.api.CoreSession; 037import org.nuxeo.ecm.core.schema.SchemaManager; 038import org.nuxeo.ecm.core.schema.types.Schema; 039import org.nuxeo.ecm.directory.Directory; 040import org.nuxeo.ecm.directory.DirectoryException; 041import org.nuxeo.ecm.directory.api.DirectoryService; 042import org.nuxeo.ecm.platform.ui.web.directory.DirectoryHelper; 043import org.nuxeo.ecm.webapp.seam.NuxeoSeamHotReloader; 044import org.nuxeo.runtime.api.Framework; 045 046/** 047 * Manage trees defined by xvocabulary directories. Update the associated QueryModel when a node is selected and return 048 * a parameterized faces navigation case. 049 * 050 * @author <a href="mailto:ogrisel@nuxeo.com">Olivier Grisel</a> 051 */ 052@Scope(CONVERSATION) 053@Name("directoryTreeManager") 054public class DirectoryTreeManagerBean implements DirectoryTreeManager { 055 056 private static final long serialVersionUID = -5250556791009032616L; 057 058 private static final Log log = LogFactory.getLog(DirectoryTreeManagerBean.class); 059 060 public static final String NODE_SELECTED_MARKER = DirectoryTreeManagerBean.class.getName() 061 + "_NODE_SELECTED_MARKER"; 062 063 @In(create = true, required = false) 064 protected transient CoreSession documentManager; 065 066 @In(create = true) 067 protected NuxeoSeamHotReloader seamReload; 068 069 @In(create = true) 070 protected Map<String, String> messages; 071 072 protected transient Map<String, DirectoryTreeNode> treeModels; 073 074 protected Long treeModelsTimestamp; 075 076 protected transient DirectoryTreeService directoryTreeService; 077 078 protected String selectedTree; 079 080 private transient List<DirectoryTreeNode> directoryTrees; 081 082 /* 083 * The directoryTrees need a working core session in order to perform search actions. 084 */ 085 public boolean isInitialized() { 086 return documentManager != null; 087 } 088 089 public DirectoryTreeNode get(String treeName) { 090 DirectoryTreeService dirTreeService = getDirectoryTreeService(); 091 if (seamReload.isDevModeSet() && seamReload.shouldResetCache(dirTreeService, treeModelsTimestamp)) { 092 treeModels = null; 093 } 094 if (treeModels == null) { 095 treeModels = new HashMap<String, DirectoryTreeNode>(); 096 treeModelsTimestamp = dirTreeService.getLastModified(); 097 } 098 // lazy loading of tree models 099 DirectoryTreeNode treeModel = treeModels.get(treeName); 100 if (treeModel != null) { 101 // return cached model 102 return treeModel; 103 } 104 DirectoryTreeDescriptor config = dirTreeService.getDirectoryTreeDescriptor(treeName); 105 if (config == null) { 106 log.error("no DirectoryTreeDescriptor registered as " + treeName); 107 return null; 108 } 109 110 // check that each required directory exists and has the xvocabulary 111 // schema 112 String[] directories = config.getDirectories(); 113 DirectoryService directoryService = DirectoryHelper.getDirectoryService(); 114 SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class); 115 try { 116 boolean isFirst = true; 117 for (String directoryName : directories) { 118 Directory directory = directoryService.getDirectory(directoryName); 119 if (directory == null) { 120 throw new DirectoryException(directoryName + " is not a registered directory"); 121 } 122 if (!isFirst) { 123 Schema schema = schemaManager.getSchema(directory.getSchema()); 124 if (!schema.hasField(PARENT_FIELD_ID)) { 125 throw new DirectoryException(directoryName + "does not have the required field: " 126 + PARENT_FIELD_ID); 127 } 128 } 129 isFirst = false; 130 } 131 } catch (DirectoryException e) { 132 throw new RuntimeException(e); 133 } 134 135 treeModel = new DirectoryTreeNode(0, config, config.getName(), config.getLabel(), "", null); 136 137 // store the build tree to reuse it the next time in the same state 138 treeModels.put(treeName, treeModel); 139 return treeModel; 140 } 141 142 public List<String> getDirectoryTreeNames() { 143 return getDirectoryTreeService().getDirectoryTrees(); 144 } 145 146 public List<DirectoryTreeNode> getDirectoryTrees() { 147 if (directoryTrees == null) { 148 directoryTrees = new LinkedList<DirectoryTreeNode>(); 149 for (String treeName : getDirectoryTreeNames()) { 150 directoryTrees.add(get(treeName)); 151 } 152 } 153 return directoryTrees; 154 } 155 156 public String getSelectedTreeName() { 157 if (selectedTree == null) { 158 List<String> names = getDirectoryTreeNames(); 159 if (!names.isEmpty()) { 160 selectedTree = names.get(0); 161 } 162 } 163 return selectedTree; 164 } 165 166 public void setSelectedTreeName(String treeName) { 167 selectedTree = treeName; 168 } 169 170 public List<DirectoryTreeNode> getSelectedTreeAsList() { 171 List<DirectoryTreeNode> res = new ArrayList<>(); 172 DirectoryTreeNode selected = getSelectedTree(); 173 if (selected != null) { 174 res.add(selected); 175 } 176 return res; 177 } 178 179 public DirectoryTreeNode getSelectedTree() { 180 return get(getSelectedTreeName()); 181 } 182 183 protected DirectoryTreeService getDirectoryTreeService() { 184 if (directoryTreeService != null) { 185 return directoryTreeService; 186 } 187 directoryTreeService = (DirectoryTreeService) Framework.getRuntime().getComponent(DirectoryTreeService.NAME); 188 return directoryTreeService; 189 } 190 191 public String getLabelFor(String directoryTreeName, String fullPath) { 192 return getLabelFor(directoryTreeName, fullPath, false); 193 } 194 195 public String getLabelFor(String directoryTreeName, String fullPath, boolean includeDirectoryTreeLabel) { 196 DirectoryTreeNode rootNode = get(directoryTreeName); 197 List<String> labels = new ArrayList<String>(); 198 computeLabels(labels, rootNode, fullPath, includeDirectoryTreeLabel); 199 List<String> translatedLabels = translateLabels(labels); 200 return StringUtils.join(translatedLabels, "/"); 201 } 202 203 protected void computeLabels(List<String> labels, DirectoryTreeNode node, String fullPath, 204 boolean includeDirectoryTreeLabel) { 205 // add label for the root path only if specified 206 if (!node.getPath().isEmpty() || (node.getPath().isEmpty() && includeDirectoryTreeLabel)) { 207 labels.add(node.getDescription()); 208 } 209 if (fullPath.equals(node.getPath())) { 210 return; 211 } 212 for (DirectoryTreeNode treeNode : node.getChildren()) { 213 if (fullPath.startsWith(treeNode.getPath())) { 214 computeLabels(labels, treeNode, fullPath, includeDirectoryTreeLabel); 215 } 216 } 217 } 218 219 protected List<String> translateLabels(List<String> labels) { 220 List<String> translatedLabels = new ArrayList<String>(labels.size()); 221 for (String label : labels) { 222 translatedLabels.add(messages.get(label)); 223 } 224 return translatedLabels; 225 } 226 227 public void resetCurrentTree() { 228 if (treeModels != null && selectedTree != null) { 229 treeModels.remove(selectedTree); 230 } 231 } 232 233}