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.HashMap; 023import java.util.List; 024import java.util.Map; 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.local.LocalException; 030import org.nuxeo.ecm.core.api.repository.RepositoryManager; 031import org.nuxeo.ecm.core.model.Repository; 032import org.nuxeo.ecm.core.model.Session; 033import org.nuxeo.runtime.api.Framework; 034import org.nuxeo.runtime.model.ComponentContext; 035import org.nuxeo.runtime.model.ComponentName; 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 // @GuardedBy("itself") 051 private final Map<String, Repository> repositories = new HashMap<>(); 052 053 public void shutdown() { 054 log.info("Shutting down repository manager"); 055 synchronized (repositories) { 056 for (Repository repository : repositories.values()) { 057 repository.shutdown(); 058 } 059 repositories.clear(); 060 } 061 } 062 063 @Override 064 public int getApplicationStartedOrder() { 065 return 100; 066 } 067 068 @Override 069 public void start(ComponentContext context) { 070 initRepositories(); 071 } 072 073 @Override 074 public void stop(ComponentContext context) { 075 TransactionHelper.runInTransaction(this::shutdown); 076 } 077 078 /** 079 * Start a tx and initialize repositories content. This method is publicly exposed since it is needed by tests to 080 * initialize repositories after cleanups (see CoreFeature). 081 * 082 * @since 8.4 083 */ 084 public void initRepositories() { 085 TransactionHelper.runInTransaction(this::doInitRepositories); 086 } 087 088 /** 089 * Initializes all repositories. Requires an active transaction. 090 * 091 * @since 9.2 092 */ 093 protected void doInitRepositories() { 094 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 095 for (String name : repositoryManager.getRepositoryNames()) { 096 openRepository(name); 097 } 098 // give up if no handler configured 099 RepositoryInitializationHandler handler = RepositoryInitializationHandler.getInstance(); 100 if (handler == null) { 101 return; 102 } 103 // invoke handlers 104 for (String name : repositoryManager.getRepositoryNames()) { 105 initializeRepository(handler, name); 106 } 107 } 108 109 @Override 110 public <T> T getAdapter(Class<T> adapter) { 111 if (adapter.isAssignableFrom(getClass())) { 112 return adapter.cast(this); 113 } 114 return null; 115 } 116 117 protected void openRepository(String name) { 118 new UnrestrictedSessionRunner(name) { 119 120 @Override 121 public void run() { 122 } 123 124 }.runUnrestricted(); 125 } 126 127 protected void initializeRepository(final RepositoryInitializationHandler handler, String name) { 128 new UnrestrictedSessionRunner(name) { 129 @Override 130 public void run() { 131 handler.initializeRepository(session); 132 } 133 }.runUnrestricted(); 134 } 135 136 /** 137 * Gets a repository given its name. 138 * <p> 139 * Null is returned if no repository with that name was registered. 140 * 141 * @param repositoryName the repository name 142 * @return the repository instance or null if no repository with that name was registered 143 */ 144 public Repository getRepository(String repositoryName) { 145 synchronized (repositories) { 146 return doGetRepository(repositoryName); 147 } 148 } 149 150 /** 151 * Calls to that method should be synchronized on repositories 152 * 153 * @since 7.2 154 * @see #getRepository(String) 155 * @see #getSession(String, String) 156 */ 157 protected Repository doGetRepository(String repositoryName) { 158 Repository repository = repositories.get(repositoryName); 159 if (repository == null) { 160 RepositoryFactory factory = getFactory(repositoryName); 161 if (factory == null) { 162 return null; 163 } 164 repository = (Repository) factory.call(); 165 repositories.put(repositoryName, repository); 166 } 167 return repository; 168 } 169 170 protected RepositoryFactory getFactory(String repositoryName) { 171 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 172 if (repositoryManager == null) { 173 // tests with no high-level repository manager 174 return null; 175 } 176 org.nuxeo.ecm.core.api.repository.Repository repo = repositoryManager.getRepository(repositoryName); 177 if (repo == null) { 178 return null; 179 } 180 RepositoryFactory repositoryFactory = (RepositoryFactory) repo.getRepositoryFactory(); 181 if (repositoryFactory == null) { 182 throw new NullPointerException("Missing repositoryFactory for repository: " + repositoryName); 183 } 184 return repositoryFactory; 185 } 186 187 public List<String> getRepositoryNames() { 188 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 189 return repositoryManager.getRepositoryNames(); 190 } 191 192 /** 193 * Creates a new session with the given session id from the given repository. 194 * <p/> 195 * Locks repositories before entering the pool. That allows concurrency with shutdown. 196 * 197 * @since 7.2 198 */ 199 public Session getSession(String repositoryName) { 200 synchronized (repositories) { 201 Repository repository = doGetRepository(repositoryName); 202 if (repository == null) { 203 throw new LocalException("No such repository: " + repositoryName); 204 } 205 return repository.getSession(); 206 } 207 } 208 209}