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 *     Bogdan Stefanescu
018 *     Florent Guillaume
019 */
020package org.nuxeo.ecm.core.repository;
021
022import java.util.List;
023import java.util.Map;
024import java.util.concurrent.ConcurrentHashMap;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
029import org.nuxeo.ecm.core.api.repository.RepositoryManager;
030import org.nuxeo.ecm.core.model.Repository;
031import org.nuxeo.runtime.api.Framework;
032import org.nuxeo.runtime.model.ComponentContext;
033import org.nuxeo.runtime.model.ComponentManager;
034import org.nuxeo.runtime.model.ComponentName;
035import org.nuxeo.runtime.model.ComponentStartOrders;
036import org.nuxeo.runtime.model.DefaultComponent;
037import org.nuxeo.runtime.transaction.TransactionHelper;
038
039/**
040 * Component and service managing low-level repository instances.
041 */
042public class RepositoryService extends DefaultComponent {
043
044    public static final ComponentName NAME = new ComponentName("org.nuxeo.ecm.core.repository.RepositoryService");
045
046    private static final Log log = LogFactory.getLog(RepositoryService.class);
047
048    public static final String XP_REPOSITORY = "repository";
049
050    private final Map<String, Repository> repositories = new ConcurrentHashMap<>();
051
052    public void shutdown() {
053        log.info("Shutting down repository manager");
054        repositories.values().forEach(Repository::shutdown);
055        repositories.clear();
056    }
057
058    @Override
059    public int getApplicationStartedOrder() {
060        return ComponentStartOrders.REPOSITORY;
061    }
062
063    @Override
064    public void start(ComponentContext context) {
065        TransactionHelper.runInTransaction(this::doCreateRepositories);
066        Framework.getRuntime().getComponentManager().addListener(new ComponentManager.Listener() {
067            @Override
068            public void afterStart(ComponentManager mgr, boolean isResume) {
069                initRepositories(); // call all RepositoryInitializationHandler
070            }
071
072            @Override
073            public void afterStop(ComponentManager mgr, boolean isStandby) {
074                Framework.getRuntime().getComponentManager().removeListener(this);
075            }
076        });
077    }
078
079    @Override
080    public void stop(ComponentContext context) {
081        TransactionHelper.runInTransaction(this::shutdown);
082    }
083
084    /**
085     * Start a tx and initialize repositories content. This method is publicly exposed since it is needed by tests to
086     * initialize repositories after cleanups (see CoreFeature).
087     *
088     * @since 8.4
089     */
090    public void initRepositories() {
091        TransactionHelper.runInTransaction(this::doInitRepositories);
092    }
093
094    /**
095     * Creates all the repositories. Requires an active transaction.
096     *
097     * @since 9.3
098     */
099    protected void doCreateRepositories() {
100        repositories.clear();
101        for (String repositoryName : getRepositoryNames()) {
102            RepositoryFactory factory = getFactory(repositoryName);
103            if (factory == null) {
104                continue;
105            }
106            Repository repository = (Repository) factory.call();
107            repositories.put(repositoryName, repository);
108        }
109    }
110
111    /**
112     * Initializes all the repositories. Requires an active transaction.
113     *
114     * @since 9.3
115     */
116    protected void doInitRepositories() {
117        // give up if no handler configured
118        RepositoryInitializationHandler handler = RepositoryInitializationHandler.getInstance();
119        if (handler == null) {
120            return;
121        }
122        // invoke handlers
123        for (String name : getRepositoryNames()) {
124            initializeRepository(handler, name);
125        }
126    }
127
128    @Override
129    public <T> T getAdapter(Class<T> adapter) {
130        if (adapter.isAssignableFrom(getClass())) {
131            return adapter.cast(this);
132        }
133        return null;
134    }
135
136    protected void initializeRepository(final RepositoryInitializationHandler handler, String name) {
137        new UnrestrictedSessionRunner(name) {
138            @Override
139            public void run() {
140                handler.initializeRepository(session);
141            }
142        }.runUnrestricted();
143    }
144
145    /**
146     * Gets a repository given its name.
147     * <p>
148     * Null is returned if no repository with that name was registered.
149     *
150     * @param repositoryName the repository name
151     * @return the repository instance or null if no repository with that name was registered
152     */
153    public Repository getRepository(String repositoryName) {
154        return repositories.get(repositoryName);
155    }
156
157    protected RepositoryFactory getFactory(String repositoryName) {
158        RepositoryManager repositoryManager = Framework.getService(RepositoryManager.class);
159        if (repositoryManager == null) {
160            // tests with no high-level repository manager
161            return null;
162        }
163        org.nuxeo.ecm.core.api.repository.Repository repo = repositoryManager.getRepository(repositoryName);
164        if (repo == null) {
165            return null;
166        }
167        RepositoryFactory repositoryFactory = (RepositoryFactory) repo.getRepositoryFactory();
168        if (repositoryFactory == null) {
169            throw new NullPointerException("Missing repositoryFactory for repository: " + repositoryName);
170        }
171        return repositoryFactory;
172    }
173
174    public List<String> getRepositoryNames() {
175        RepositoryManager repositoryManager = Framework.getService(RepositoryManager.class);
176        return repositoryManager.getRepositoryNames();
177    }
178
179}