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