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 org.nuxeo.ecm.directory.localconfiguration.DirectoryConfigurationConstants.DIRECTORY_CONFIGURATION_FACET;
025
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.runtime.api.Framework;
035import org.nuxeo.runtime.model.ComponentContext;
036import org.nuxeo.runtime.model.ComponentInstance;
037import org.nuxeo.runtime.model.DefaultComponent;
038import org.nuxeo.runtime.transaction.TransactionHelper;
039
040public class DirectoryServiceImpl extends DefaultComponent implements DirectoryService {
041
042    protected static final String DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX = "_";
043
044    private static final Log log = LogFactory.getLog(DirectoryServiceImpl.class);
045
046    protected DirectoryRegistry registry = new DirectoryRegistry();
047
048    @Override
049    public void activate(ComponentContext context) {
050    }
051
052    @Override
053    public void deactivate(ComponentContext context) {
054        registry.shutdown();
055    }
056
057    @Override
058    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
059        DirectoryFactoryDescriptor factoryDescriptor = (DirectoryFactoryDescriptor) contribution;
060        String factoryName = factoryDescriptor.getFactoryName();
061        log.warn("No need to register factoryDescriptor anymore: " + factoryName);
062    }
063
064    @Override
065    public void registerDirectoryDescriptor(BaseDirectoryDescriptor descriptor) {
066        registry.addContribution(descriptor);
067    }
068
069    @Override
070    public void unregisterDirectoryDescriptor(BaseDirectoryDescriptor descriptor) {
071        registry.removeContribution(descriptor);
072    }
073
074    @Override
075    public void start(ComponentContext context) {
076        if (Framework.isTestModeSet()) {
077            // when testing, DatabaseHelper init hasn't occurred yet,
078            // so keep to lazy initialization
079            return;
080        }
081        // open all directories at application startup, so that
082        // their tables are created (outside a transaction) if needed
083        for (Directory dir : getDirectories()) {
084            // open directory to init its resources (tables for SQLDirectory)
085            try {
086                dir.getSession().close();
087            } catch (DirectoryException e) {
088                // NXP-24245 : catch potential hotreload DirectionException without breaking the whole directories start
089                log.error(e, e);
090            }
091        }
092        // commit the transaction so that tables are committed
093        if (TransactionHelper.isTransactionActiveOrMarkedRollback()) {
094            TransactionHelper.commitOrRollbackTransaction();
095            TransactionHelper.startTransaction();
096        }
097    }
098
099    protected DirectoryConfiguration getDirectoryConfiguration(DocumentModel documentContext) {
100        LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class);
101
102        if (localConfigurationService == null) {
103            log.info("Local configuration not deployed, will use default configuration");
104            return null;
105        }
106
107        return localConfigurationService.getConfiguration(DirectoryConfiguration.class, DIRECTORY_CONFIGURATION_FACET,
108                documentContext);
109    }
110
111    /**
112     * This will return the local directory name according the local configuration. If the local configuration is null
113     * or the suffix value is null or the suffix value trimmed is an empty string the returned value is the
114     * directoryName given in parameter. If not this is directoryName + DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX +
115     * suffix. if directoryName is null, return null.
116     */
117    protected String getWaitingLocalDirectoryName(String directoryName, DirectoryConfiguration configuration) {
118        if (directoryName == null) {
119            return null;
120        }
121
122        if (configuration != null && configuration.getDirectorySuffix() != null) {
123            String suffix = configuration.getDirectorySuffix().trim();
124            if (!"".equals(suffix)) {
125                return directoryName + DELIMITER_BETWEEN_DIRECTORY_NAME_AND_SUFFIX + suffix;
126            }
127            log.warn("The local configuration detected is an empty value, we consider it as no configuration set.");
128            log.debug("Directory Local Configuration is on : " + configuration.getDocumentRef());
129        }
130
131        return directoryName;
132    }
133
134    @Override
135    public BaseDirectoryDescriptor getDirectoryDescriptor(String id) {
136        return registry.getDirectoryDescriptor(id);
137    }
138
139    @Override
140    public Directory getDirectory(String id) {
141        if (id == null) {
142            // TODO throw an exception
143            return null;
144        }
145        return registry.getDirectory(id);
146    }
147
148    @Override
149    public Directory getDirectory(String id, DocumentModel documentContext) {
150        if (id == null) {
151            // TODO throw an exception
152            return null;
153        }
154        String localDirectoryName = getWaitingLocalDirectoryName(id, getDirectoryConfiguration(documentContext));
155        Directory dir = getDirectory(localDirectoryName);
156        if (dir == null && !id.equals(localDirectoryName)) {
157            log.debug(String.format(
158                    "The local directory named '%s' was" + " not found. Look for the default one named: %s",
159                    localDirectoryName, id));
160            dir = getDirectory(id);
161        }
162        return dir;
163    }
164
165    protected Directory getDirectoryOrFail(String name) throws DirectoryException {
166        return getDirectoryOrFail(name, null);
167    }
168
169    protected Directory getDirectoryOrFail(String id, DocumentModel documentContext) throws DirectoryException {
170        Directory dir = getDirectory(id, documentContext);
171        if (dir == null) {
172            throw new DirectoryException("No directory registered with name: " + id);
173        }
174        return dir;
175    }
176
177    @Override
178    public List<Directory> getDirectories() {
179        return registry.getDirectories();
180    }
181
182    @Override
183    public List<String> getDirectoryNames() {
184        return registry.getDirectoryIds();
185    }
186
187    @Override
188    public String getDirectorySchema(String directoryName) throws DirectoryException {
189        return getDirectoryOrFail(directoryName).getSchema();
190    }
191
192    @Override
193    public String getDirectoryIdField(String directoryName) throws DirectoryException {
194        return getDirectoryOrFail(directoryName).getIdField();
195    }
196
197    @Override
198    public String getDirectoryPasswordField(String directoryName) throws DirectoryException {
199        return getDirectoryOrFail(directoryName).getPasswordField();
200    }
201
202    @Override
203    public String getParentDirectoryName(String directoryName) throws DirectoryException {
204        return getDirectoryOrFail(directoryName).getParentDirectory();
205    }
206
207    @Override
208    public Session open(String directoryName) throws DirectoryException {
209        return getDirectoryOrFail(directoryName).getSession();
210    }
211
212    @Override
213    public Session open(String directoryName, DocumentModel documentContext) throws DirectoryException {
214        return getDirectoryOrFail(directoryName, documentContext).getSession();
215    }
216
217}