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