001/* 002 * (C) Copyright 2006-2015 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 * 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 javax.transaction.Transaction; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.ecm.core.api.CoreSession; 031import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 032import org.nuxeo.ecm.core.api.local.LocalException; 033import org.nuxeo.ecm.core.api.local.LocalSession; 034import org.nuxeo.ecm.core.api.repository.RepositoryManager; 035import org.nuxeo.ecm.core.model.Repository; 036import org.nuxeo.ecm.core.model.Session; 037import org.nuxeo.runtime.RuntimeServiceEvent; 038import org.nuxeo.runtime.RuntimeServiceListener; 039import org.nuxeo.runtime.api.Framework; 040import org.nuxeo.runtime.model.ComponentContext; 041import org.nuxeo.runtime.model.ComponentName; 042import org.nuxeo.runtime.model.DefaultComponent; 043import org.nuxeo.runtime.transaction.TransactionHelper; 044 045/** 046 * Component and service managing low-level repository instances. 047 */ 048public class RepositoryService extends DefaultComponent { 049 050 public static final ComponentName NAME = new ComponentName("org.nuxeo.ecm.core.repository.RepositoryService"); 051 052 private static final Log log = LogFactory.getLog(RepositoryService.class); 053 054 public static final String XP_REPOSITORY = "repository"; 055 056 // @GuardedBy("itself") 057 private final Map<String, Repository> repositories = new HashMap<>(); 058 059 public void shutdown() { 060 log.info("Shutting down repository manager"); 061 synchronized (repositories) { 062 for (Repository repository : repositories.values()) { 063 repository.shutdown(); 064 } 065 repositories.clear(); 066 } 067 } 068 069 @Override 070 public int getApplicationStartedOrder() { 071 return 100; 072 } 073 074 @Override 075 public void applicationStarted(ComponentContext context) { 076 Framework.addListener(new RuntimeServiceListener() { 077 078 @Override 079 public void handleEvent(RuntimeServiceEvent event) { 080 if (event.id != RuntimeServiceEvent.RUNTIME_ABOUT_TO_STOP) { 081 return; 082 } 083 Framework.removeListener(this); 084 shutdown(); 085 } 086 }); 087 RepositoryInitializationHandler handler = RepositoryInitializationHandler.getInstance(); 088 if (handler == null) { 089 return; 090 } 091 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 092 boolean started = false; 093 boolean ok = false; 094 { // open repositories without a tx active 095 Transaction tx = TransactionHelper.suspendTransaction(); 096 try { 097 for (String name : repositoryManager.getRepositoryNames()) { 098 openRepository(name); 099 } 100 } finally { 101 TransactionHelper.resumeTransaction(tx); 102 } 103 } 104 // initialize repositories with a tx active 105 try { 106 started = !TransactionHelper.isTransactionActive() && TransactionHelper.startTransaction(); 107 for (String name : repositoryManager.getRepositoryNames()) { 108 initializeRepository(handler, name); 109 } 110 ok = true; 111 } finally { 112 if (started) { 113 try { 114 if (!ok) { 115 TransactionHelper.setTransactionRollbackOnly(); 116 } 117 } finally { 118 TransactionHelper.commitOrRollbackTransaction(); 119 } 120 } 121 } 122 } 123 124 @Override 125 public <T> T getAdapter(Class<T> adapter) { 126 if (adapter.isAssignableFrom(getClass())) { 127 return adapter.cast(this); 128 } 129 if (adapter.isAssignableFrom(CoreSession.class)) { 130 return adapter.cast(LocalSession.createInstance()); 131 } 132 return null; 133 } 134 135 protected void openRepository(String name) { 136 new UnrestrictedSessionRunner(name) { 137 138 @Override 139 public void run() {; 140 } 141 142 }.runUnrestricted(); 143 } 144 145 protected void initializeRepository(final RepositoryInitializationHandler handler, String name) { 146 new UnrestrictedSessionRunner(name) { 147 @Override 148 public void run() { 149 handler.initializeRepository(session); 150 } 151 }.runUnrestricted(); 152 } 153 154 /** 155 * Gets a repository given its name. 156 * <p> 157 * Null is returned if no repository with that name was registered. 158 * 159 * @param repositoryName the repository name 160 * @return the repository instance or null if no repository with that name was registered 161 */ 162 public Repository getRepository(String repositoryName) { 163 synchronized (repositories) { 164 return doGetRepository(repositoryName); 165 } 166 } 167 168 /** 169 * Calls to that method should be synchronized on repositories 170 * 171 * @since 7.2 172 * @see #getRepository(String) 173 * @see #getSession(String, String) 174 */ 175 protected Repository doGetRepository(String repositoryName) { 176 Repository repository = repositories.get(repositoryName); 177 if (repository == null) { 178 RepositoryFactory factory = getFactory(repositoryName); 179 if (factory == null) { 180 return null; 181 } 182 repository = (Repository) factory.call(); 183 repositories.put(repositoryName, repository); 184 } 185 return repository; 186 } 187 188 protected RepositoryFactory getFactory(String repositoryName) { 189 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 190 if (repositoryManager == null) { 191 // tests with no high-level repository manager 192 return null; 193 } 194 org.nuxeo.ecm.core.api.repository.Repository repo = repositoryManager.getRepository(repositoryName); 195 if (repo == null) { 196 return null; 197 } 198 RepositoryFactory repositoryFactory = (RepositoryFactory) repo.getRepositoryFactory(); 199 if (repositoryFactory == null) { 200 throw new NullPointerException("Missing repositoryFactory for repository: " + repositoryName); 201 } 202 return repositoryFactory; 203 } 204 205 public List<String> getRepositoryNames() { 206 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 207 return repositoryManager.getRepositoryNames(); 208 } 209 210 /** 211 * Creates a new session with the given session id from the given repository. 212 * <p/> 213 * Locks repositories before entering the pool. That allows concurrency with shutdown. 214 * 215 * @since 7.2 216 */ 217 public Session getSession(String repositoryName) { 218 synchronized (repositories) { 219 Repository repository = doGetRepository(repositoryName); 220 if (repository == null) { 221 throw new LocalException("No such repository: " + repositoryName); 222 } 223 return repository.getSession(); 224 } 225 } 226 227}