001/* 002 * (C) Copyright 2006-2017 Nuxeo (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 * George Lefter 018 * Olivier Grisel 019 * Benjamin Jalon 020 * Florent Guillaume 021 */ 022package org.nuxeo.ecm.directory; 023 024import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; 025import static org.apache.commons.lang3.StringUtils.isBlank; 026import static org.nuxeo.ecm.directory.BaseDirectoryDescriptor.DATA_LOADING_POLICY_NEVER_LOAD; 027import static org.nuxeo.ecm.directory.localconfiguration.DirectoryConfigurationConstants.DIRECTORY_CONFIGURATION_FACET; 028 029import java.time.Duration; 030import java.util.List; 031 032import org.apache.logging.log4j.LogManager; 033import org.apache.logging.log4j.Logger; 034import org.nuxeo.common.utils.DurationUtils; 035import org.nuxeo.ecm.core.api.Blob; 036import org.nuxeo.ecm.core.api.DocumentModel; 037import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 038import org.nuxeo.ecm.directory.api.DirectoryService; 039import org.nuxeo.ecm.directory.localconfiguration.DirectoryConfiguration; 040import org.nuxeo.runtime.api.Framework; 041import org.nuxeo.runtime.cluster.ClusterService; 042import org.nuxeo.runtime.model.ComponentContext; 043import org.nuxeo.runtime.model.ComponentInstance; 044import org.nuxeo.runtime.model.DefaultComponent; 045 046public class DirectoryServiceImpl extends DefaultComponent implements DirectoryService { 047 048 /** @since 11.1 */ 049 public static final String CLUSTER_START_DURATION_PROP = "org.nuxeo.directory.cluster.start.duration"; 050 051 /** @since 11.1 */ 052 public static final Duration CLUSTER_START_DURATION_DEFAULT = Duration.ofMinutes(1); 053 054 protected static final String DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX = "_"; 055 056 private static final Logger log = LogManager.getLogger(DirectoryServiceImpl.class); 057 058 protected DirectoryRegistry registry = new DirectoryRegistry(); 059 060 @Override 061 public void activate(ComponentContext context) { 062 } 063 064 @Override 065 public void deactivate(ComponentContext context) { 066 registry.shutdown(); 067 } 068 069 @Override 070 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 071 DirectoryFactoryDescriptor factoryDescriptor = (DirectoryFactoryDescriptor) contribution; 072 String factoryName = factoryDescriptor.getFactoryName(); 073 log.warn("No need to register factoryDescriptor anymore: {}", factoryName); 074 } 075 076 @Override 077 public void registerDirectoryDescriptor(BaseDirectoryDescriptor descriptor) { 078 registry.addContribution(descriptor); 079 } 080 081 @Override 082 public void unregisterDirectoryDescriptor(BaseDirectoryDescriptor descriptor) { 083 registry.removeContribution(descriptor); 084 } 085 086 @Override 087 public void loadFromCSV(String directoryName, Blob dataBlob, String dataLoadingPolicy) { 088 if (isBlank(dataLoadingPolicy) || DATA_LOADING_POLICY_NEVER_LOAD.equals(dataLoadingPolicy)) { 089 throw new DirectoryException("Illegal dataLoadingPolicy: " + dataLoadingPolicy, SC_BAD_REQUEST); 090 } 091 Directory directory = getDirectoryOrFail(directoryName); 092 directory.loadFromCSV(dataBlob, dataLoadingPolicy); 093 } 094 095 @Override 096 public int getApplicationStartedOrder() { 097 // earlier than the repository init, which has order 100, 098 // but later than the cache service, which has order 95 (100-5) 099 return 97; 100 } 101 102 @Override 103 public void start(ComponentContext context) { 104 ClusterService clusterService = Framework.getService(ClusterService.class); 105 String prop = Framework.getProperty(CLUSTER_START_DURATION_PROP); 106 Duration duration = DurationUtils.parsePositive(prop, CLUSTER_START_DURATION_DEFAULT); 107 Duration pollDelay = Duration.ofSeconds(1); 108 clusterService.runAtomically("start-directories", duration, pollDelay, this::start); 109 } 110 111 protected void start() { 112 List<Directory> directories = getDirectories(); 113 directories.forEach(Directory::initialize); 114 directories.forEach(Directory::initializeReferences); 115 directories.forEach(Directory::initializeInverseReferences); 116 } 117 118 protected DirectoryConfiguration getDirectoryConfiguration(DocumentModel documentContext) { 119 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 120 121 if (localConfigurationService == null) { 122 log.info("Local configuration not deployed, will use default configuration"); 123 return null; 124 } 125 126 return localConfigurationService.getConfiguration(DirectoryConfiguration.class, DIRECTORY_CONFIGURATION_FACET, 127 documentContext); 128 } 129 130 /** 131 * This will return the local directory name according the local configuration. If the local configuration is null 132 * or the suffix value is null or the suffix value trimmed is an empty string the returned value is the 133 * directoryName given in parameter. If not this is directoryName + DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX + 134 * suffix. if directoryName is null, return null. 135 */ 136 protected String getWaitingLocalDirectoryName(String directoryName, DirectoryConfiguration configuration) { 137 if (directoryName == null) { 138 return null; 139 } 140 141 if (configuration != null && configuration.getDirectorySuffix() != null) { 142 String suffix = configuration.getDirectorySuffix().trim(); 143 if (!"".equals(suffix)) { 144 return directoryName + DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX + suffix; 145 } 146 log.warn("The local configuration detected is an empty value, we consider it as no configuration set."); 147 log.debug("Directory Local Configuration is on : {}", configuration::getDocumentRef); 148 } 149 150 return directoryName; 151 } 152 153 @Override 154 public BaseDirectoryDescriptor getDirectoryDescriptor(String id) { 155 return registry.getDirectoryDescriptor(id); 156 } 157 158 @Override 159 public Directory getDirectory(String id) { 160 if (id == null) { 161 // TODO throw an exception 162 return null; 163 } 164 return registry.getDirectory(id); 165 } 166 167 @Override 168 public Directory getDirectory(String id, DocumentModel documentContext) { 169 if (id == null) { 170 // TODO throw an exception 171 return null; 172 } 173 String localDirectoryName = getWaitingLocalDirectoryName(id, getDirectoryConfiguration(documentContext)); 174 Directory dir = getDirectory(localDirectoryName); 175 if (dir == null && !id.equals(localDirectoryName)) { 176 log.debug("The local directory named '{}' was not found. Look for the default one named: {}", 177 localDirectoryName, id); 178 dir = getDirectory(id); 179 } 180 return dir; 181 } 182 183 protected Directory getDirectoryOrFail(String name) { 184 return getDirectoryOrFail(name, null); 185 } 186 187 protected Directory getDirectoryOrFail(String id, DocumentModel documentContext) { 188 Directory dir = getDirectory(id, documentContext); 189 if (dir == null) { 190 throw new DirectoryException("No directory registered with name: " + id); 191 } 192 return dir; 193 } 194 195 @Override 196 public List<Directory> getDirectories() { 197 return registry.getDirectories(); 198 } 199 200 @Override 201 public List<String> getDirectoryNames() { 202 return registry.getDirectoryIds(); 203 } 204 205 @Override 206 public String getDirectorySchema(String directoryName) { 207 return getDirectoryOrFail(directoryName).getSchema(); 208 } 209 210 @Override 211 public String getDirectoryIdField(String directoryName) { 212 return getDirectoryOrFail(directoryName).getIdField(); 213 } 214 215 @Override 216 public String getDirectoryPasswordField(String directoryName) { 217 return getDirectoryOrFail(directoryName).getPasswordField(); 218 } 219 220 @Override 221 public String getParentDirectoryName(String directoryName) { 222 return getDirectoryOrFail(directoryName).getParentDirectory(); 223 } 224 225 @Override 226 public Session open(String directoryName) { 227 return getDirectoryOrFail(directoryName).getSession(); 228 } 229 230 @Override 231 public Session open(String directoryName, DocumentModel documentContext) { 232 return getDirectoryOrFail(directoryName, documentContext).getSession(); 233 } 234 235}