001/* 002 * (C) Copyright 2006-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 * $Id$ 017 */ 018 019package org.nuxeo.ecm.directory; 020 021import static org.nuxeo.ecm.directory.localconfiguration.DirectoryConfigurationConstants.DIRECTORY_CONFIGURATION_FACET; 022 023import java.util.ArrayList; 024import java.util.List; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028import org.nuxeo.ecm.core.api.DocumentModel; 029import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 030import org.nuxeo.ecm.directory.api.DirectoryService; 031import org.nuxeo.ecm.directory.localconfiguration.DirectoryConfiguration; 032import org.nuxeo.ecm.directory.memory.MemoryDirectoryFactory; 033import org.nuxeo.ecm.directory.registry.DirectoryFactoryMapper; 034import org.nuxeo.ecm.directory.registry.DirectoryFactoryMapperRegistry; 035import org.nuxeo.ecm.directory.registry.DirectoryFactoryRegistry; 036import org.nuxeo.runtime.api.Framework; 037import org.nuxeo.runtime.model.ComponentContext; 038import org.nuxeo.runtime.model.DefaultComponent; 039import org.nuxeo.runtime.model.Extension; 040 041public class DirectoryServiceImpl extends DefaultComponent implements DirectoryService { 042 043 protected static final String DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX = "_"; 044 045 private static final Log log = LogFactory.getLog(DirectoryServiceImpl.class); 046 047 protected DirectoryFactoryRegistry factories; 048 049 protected DirectoryFactoryMapperRegistry factoriesByDirectoryName; 050 051 @Override 052 public void applicationStarted(ComponentContext context) { 053 if (Framework.isTestModeSet()) { 054 // when testing, DatabaseHelper init hasn't occurred yet, 055 // so keep to lazy initialization 056 return; 057 } 058 // open all directories at application startup, so that 059 // their tables are created (outside a transaction) if needed 060 for (Directory dir : getDirectories()) { 061 dir.getName(); // enough to create tables for SQL directories 062 } 063 } 064 065 protected DirectoryConfiguration getDirectoryConfiguration(DocumentModel documentContext) { 066 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 067 068 if (localConfigurationService == null) { 069 log.info("Local configuration not deployed, will use default configuration"); 070 return null; 071 } 072 073 return localConfigurationService.getConfiguration(DirectoryConfiguration.class, DIRECTORY_CONFIGURATION_FACET, 074 documentContext); 075 } 076 077 /** 078 * This will return the local directory name according the local configuration. If the local configuration is null 079 * or the suffix value is null or the suffix value trimmed is an empty string the returned value is the 080 * directoryName given in parameter. If not this is directoryName + DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX + 081 * suffix. if directoryName is null, return null. 082 */ 083 protected String getWaitingLocalDirectoryName(String directoryName, DirectoryConfiguration configuration) { 084 if (directoryName == null) { 085 return null; 086 } 087 088 if (configuration != null && configuration.getDirectorySuffix() != null) { 089 String suffix = configuration.getDirectorySuffix().trim(); 090 if (!"".equals(suffix)) { 091 return directoryName + DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX + suffix; 092 } 093 log.warn("The local configuration detected is an empty value, we consider it as no configuration set."); 094 log.debug("Directory Local Configuration is on : " + configuration.getDocumentRef()); 095 } 096 097 return directoryName; 098 } 099 100 public Directory getDirectory(String directoryName) throws DirectoryException { 101 if (directoryName == null) { 102 return null; 103 } 104 List<String> factoryNames = factoriesByDirectoryName.getFactoriesForDirectory(directoryName); 105 if (factoryNames == null || factoryNames.isEmpty()) { 106 return null; 107 } 108 for (String factoryName : factoryNames) { 109 DirectoryFactory targetFactory = factories.getFactory(factoryName); 110 if (targetFactory != null) { 111 return targetFactory.getDirectory(directoryName); 112 } 113 } 114 return null; 115 } 116 117 public Directory getDirectory(String name, DocumentModel documentContext) throws DirectoryException { 118 if (name == null) { 119 return null; 120 } 121 122 String localDirectoryName = getWaitingLocalDirectoryName(name, getDirectoryConfiguration(documentContext)); 123 124 Directory directory = getDirectory(localDirectoryName); 125 126 if (directory == null && !name.equals(localDirectoryName)) { 127 log.debug(String.format("The local directory named '%s' was" 128 + " not found. Look for the default one named: %s", localDirectoryName, name)); 129 directory = getDirectory(name); 130 } 131 132 return directory; 133 } 134 135 private Directory getDirectoryOrFail(String name) throws DirectoryException { 136 return getDirectoryOrFail(name, null); 137 } 138 139 private Directory getDirectoryOrFail(String name, DocumentModel documentContext) throws DirectoryException { 140 141 Directory dir = getDirectory(name, documentContext); 142 if (null == dir) { 143 throw new DirectoryException(String.format("no directory registered with name '%s'", name)); 144 } 145 return dir; 146 } 147 148 public List<Directory> getDirectories() throws DirectoryException { 149 List<Directory> directoryList = new ArrayList<Directory>(); 150 for (DirectoryFactory factory : factories.getFactories()) { 151 List<Directory> list = factory.getDirectories(); 152 directoryList.addAll(list); 153 } 154 return directoryList; 155 } 156 157 @Override 158 public void activate(ComponentContext context) { 159 factories = new DirectoryFactoryRegistry(); 160 factoriesByDirectoryName = new DirectoryFactoryMapperRegistry(); 161 } 162 163 @Override 164 public void deactivate(ComponentContext context) { 165 for (DirectoryFactory factory : factories.getFactories()) { 166 factory.shutdown(); 167 } 168 factories = null; 169 factoriesByDirectoryName = null; 170 } 171 172 @Override 173 public void registerExtension(Extension extension) { 174 Object[] contribs = extension.getContributions(); 175 for (Object contrib : contribs) { 176 DirectoryFactoryDescriptor factoryDescriptor = (DirectoryFactoryDescriptor) contrib; 177 String factoryName = factoryDescriptor.getFactoryName(); 178 factories.addContribution(new DirectoryFactoryProxy(factoryName)); 179 log.debug("registered factory: " + factoryName); 180 } 181 } 182 183 @Override 184 public void unregisterExtension(Extension extension) { 185 Object[] contribs = extension.getContributions(); 186 for (Object contrib : contribs) { 187 DirectoryFactoryDescriptor factoryDescriptor = (DirectoryFactoryDescriptor) contrib; 188 String factoryName = factoryDescriptor.getFactoryName(); 189 DirectoryFactory factoryToRemove = factories.getFactory(factoryName); 190 if (factoryToRemove == null) { 191 log.warn(String.format("Factory '%s' was not registered", factoryName)); 192 return; 193 } 194 factoryToRemove.shutdown(); 195 // XXX: do not cleanup mappers, lookup will ignore non-registered 196 // factories anyway 197 factories.removeContribution(factoryToRemove); 198 log.debug("unregistered factory: " + factoryName); 199 } 200 } 201 202 public void registerDirectory(String directoryName, DirectoryFactory factory) { 203 // compatibility code to add otherwise missing memory factory (as it's 204 // not registered via extension points) 205 if (factory instanceof MemoryDirectoryFactory) { 206 factories.addContribution(factory); 207 } 208 DirectoryFactoryMapper contrib = new DirectoryFactoryMapper(directoryName, factory.getName()); 209 factoriesByDirectoryName.addContribution(contrib); 210 } 211 212 public void unregisterDirectory(String directoryName, DirectoryFactory factory) { 213 DirectoryFactoryMapper contrib = new DirectoryFactoryMapper(directoryName, factory.getName()); 214 factoriesByDirectoryName.removeContribution(contrib); 215 } 216 217 public List<String> getDirectoryNames() throws DirectoryException { 218 List<Directory> directories = getDirectories(); 219 List<String> directoryNames = new ArrayList<String>(); 220 for (Directory directory : directories) { 221 directoryNames.add(directory.getName()); 222 } 223 return directoryNames; 224 } 225 226 public String getDirectorySchema(String directoryName) throws DirectoryException { 227 return getDirectoryOrFail(directoryName).getSchema(); 228 } 229 230 public String getDirectoryIdField(String directoryName) throws DirectoryException { 231 return getDirectoryOrFail(directoryName).getIdField(); 232 } 233 234 public String getDirectoryPasswordField(String directoryName) throws DirectoryException { 235 return getDirectoryOrFail(directoryName).getPasswordField(); 236 } 237 238 public Session open(String directoryName) throws DirectoryException { 239 return getDirectoryOrFail(directoryName).getSession(); 240 } 241 242 public Session open(String directoryName, DocumentModel documentContext) throws DirectoryException { 243 return getDirectoryOrFail(directoryName, documentContext).getSession(); 244 } 245 246 public String getParentDirectoryName(String directoryName) throws DirectoryException { 247 return getDirectoryOrFail(directoryName).getParentDirectory(); 248 } 249 250}