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