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 activate(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 } 088 089 @Override 090 public void applicationStarted(ComponentContext context) { 091 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 092 { // open repositories without a tx active 093 Transaction tx = TransactionHelper.suspendTransaction(); 094 try { 095 for (String name : repositoryManager.getRepositoryNames()) { 096 openRepository(name); 097 } 098 } finally { 099 TransactionHelper.resumeTransaction(tx); 100 } 101 } 102 // give up if no handler configured 103 RepositoryInitializationHandler handler = RepositoryInitializationHandler.getInstance(); 104 if (handler == null) { 105 return; 106 } 107 // invoke handler with a tx active 108 { 109 boolean started = false; 110 boolean ok = false; 111 try { 112 started = !TransactionHelper.isTransactionActive() && TransactionHelper.startTransaction(); 113 for (String name : repositoryManager.getRepositoryNames()) { 114 initializeRepository(handler, name); 115 } 116 ok = true; 117 } finally { 118 if (started) { 119 try { 120 if (!ok) { 121 TransactionHelper.setTransactionRollbackOnly(); 122 } 123 } finally { 124 TransactionHelper.commitOrRollbackTransaction(); 125 } 126 } 127 } 128 } 129 } 130 131 @Override 132 public <T> T getAdapter(Class<T> adapter) { 133 if (adapter.isAssignableFrom(getClass())) { 134 return adapter.cast(this); 135 } 136 if (adapter.isAssignableFrom(CoreSession.class)) { 137 return adapter.cast(LocalSession.createInstance()); 138 } 139 return null; 140 } 141 142 protected void openRepository(String name) { 143 new UnrestrictedSessionRunner(name) { 144 145 @Override 146 public void run() { 147 ; 148 } 149 150 }.runUnrestricted(); 151 } 152 153 protected void initializeRepository(final RepositoryInitializationHandler handler, String name) { 154 new UnrestrictedSessionRunner(name) { 155 @Override 156 public void run() { 157 handler.initializeRepository(session); 158 } 159 }.runUnrestricted(); 160 } 161 162 /** 163 * Gets a repository given its name. 164 * <p> 165 * Null is returned if no repository with that name was registered. 166 * 167 * @param repositoryName 168 * the repository name 169 * @return the repository instance or null if no repository with that name 170 * was registered 171 */ 172 public Repository getRepository(String repositoryName) { 173 synchronized (repositories) { 174 return doGetRepository(repositoryName); 175 } 176 } 177 178 /** 179 * Calls to that method should be synchronized on repositories 180 * 181 * @since 7.2 182 * @see #getRepository(String) 183 * @see #getSession(String, String) 184 */ 185 protected Repository doGetRepository(String repositoryName) { 186 Repository repository = repositories.get(repositoryName); 187 if (repository == null) { 188 RepositoryFactory factory = getFactory(repositoryName); 189 if (factory == null) { 190 return null; 191 } 192 repository = (Repository) factory.call(); 193 repositories.put(repositoryName, repository); 194 } 195 return repository; 196 } 197 198 protected RepositoryFactory getFactory(String repositoryName) { 199 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 200 if (repositoryManager == null) { 201 // tests with no high-level repository manager 202 return null; 203 } 204 org.nuxeo.ecm.core.api.repository.Repository repo = repositoryManager.getRepository(repositoryName); 205 if (repo == null) { 206 return null; 207 } 208 RepositoryFactory repositoryFactory = (RepositoryFactory) repo.getRepositoryFactory(); 209 if (repositoryFactory == null) { 210 throw new NullPointerException("Missing repositoryFactory for repository: " + repositoryName); 211 } 212 return repositoryFactory; 213 } 214 215 public List<String> getRepositoryNames() { 216 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 217 return repositoryManager.getRepositoryNames(); 218 } 219 220 /** 221 * Creates a new session with the given session id from the given 222 * repository. 223 * <p/> 224 * Locks repositories before entering the pool. That allows concurrency with 225 * shutdown. 226 * 227 * @since 7.2 228 */ 229 public Session getSession(String repositoryName) { 230 synchronized (repositories) { 231 Repository repository = doGetRepository(repositoryName); 232 if (repository == null) { 233 throw new LocalException("No such repository: " + repositoryName); 234 } 235 return repository.getSession(); 236 } 237 } 238 239}