001/* 002 * Copyright (c) 2006-2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Bogdan Stefanescu 011 * Florent Guillaume 012 */ 013package org.nuxeo.ecm.core.repository; 014 015import java.util.HashMap; 016import java.util.List; 017import java.util.Map; 018 019import javax.transaction.Transaction; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.nuxeo.ecm.core.api.CoreSession; 025import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 026import org.nuxeo.ecm.core.api.local.LocalException; 027import org.nuxeo.ecm.core.api.local.LocalSession; 028import org.nuxeo.ecm.core.api.repository.RepositoryManager; 029import org.nuxeo.ecm.core.model.Repository; 030import org.nuxeo.ecm.core.model.Session; 031import org.nuxeo.runtime.RuntimeServiceEvent; 032import org.nuxeo.runtime.RuntimeServiceListener; 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 applicationStarted(ComponentContext context) { 070 Framework.addListener(new RuntimeServiceListener() { 071 072 @Override 073 public void handleEvent(RuntimeServiceEvent event) { 074 if (event.id != RuntimeServiceEvent.RUNTIME_ABOUT_TO_STOP) { 075 return; 076 } 077 Framework.removeListener(this); 078 shutdown(); 079 } 080 }); 081 RepositoryInitializationHandler handler = RepositoryInitializationHandler.getInstance(); 082 if (handler == null) { 083 return; 084 } 085 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 086 boolean started = false; 087 boolean ok = false; 088 { // open repositories without a tx active 089 Transaction tx = TransactionHelper.suspendTransaction(); 090 try { 091 for (String name : repositoryManager.getRepositoryNames()) { 092 openRepository(name); 093 } 094 } finally { 095 TransactionHelper.resumeTransaction(tx); 096 } 097 } 098 // initialize repositories with a tx active 099 try { 100 started = !TransactionHelper.isTransactionActive() && TransactionHelper.startTransaction(); 101 for (String name : repositoryManager.getRepositoryNames()) { 102 initializeRepository(handler, name); 103 } 104 ok = true; 105 } finally { 106 if (started) { 107 try { 108 if (!ok) { 109 TransactionHelper.setTransactionRollbackOnly(); 110 } 111 } finally { 112 TransactionHelper.commitOrRollbackTransaction(); 113 } 114 } 115 } 116 } 117 118 @SuppressWarnings("unchecked") 119 @Override 120 public <T> T getAdapter(Class<T> adapter) { 121 if (adapter.isAssignableFrom(getClass())) { 122 return (T) this; 123 } 124 if (adapter.isAssignableFrom(CoreSession.class)) { 125 return (T) LocalSession.createInstance(); 126 } 127 return null; 128 } 129 130 protected void openRepository(String name) { 131 new UnrestrictedSessionRunner(name) { 132 133 @Override 134 public void run() {; 135 } 136 137 }.runUnrestricted(); 138 } 139 140 protected void initializeRepository(final RepositoryInitializationHandler handler, String name) { 141 new UnrestrictedSessionRunner(name) { 142 @Override 143 public void run() { 144 handler.initializeRepository(session); 145 } 146 }.runUnrestricted(); 147 } 148 149 /** 150 * Gets a repository given its name. 151 * <p> 152 * Null is returned if no repository with that name was registered. 153 * 154 * @param repositoryName the repository name 155 * @return the repository instance or null if no repository with that name was registered 156 */ 157 public Repository getRepository(String repositoryName) { 158 synchronized (repositories) { 159 return doGetRepository(repositoryName); 160 } 161 } 162 163 /** 164 * Calls to that method should be synchronized on repositories 165 * 166 * @since 7.2 167 * @see #getRepository(String) 168 * @see #getSession(String, String) 169 */ 170 protected Repository doGetRepository(String repositoryName) { 171 Repository repository = repositories.get(repositoryName); 172 if (repository == null) { 173 RepositoryFactory factory = getFactory(repositoryName); 174 if (factory == null) { 175 return null; 176 } 177 repository = (Repository) factory.call(); 178 repositories.put(repositoryName, repository); 179 } 180 return repository; 181 } 182 183 protected RepositoryFactory getFactory(String repositoryName) { 184 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 185 if (repositoryManager == null) { 186 // tests with no high-level repository manager 187 return null; 188 } 189 org.nuxeo.ecm.core.api.repository.Repository repo = repositoryManager.getRepository(repositoryName); 190 if (repo == null) { 191 return null; 192 } 193 RepositoryFactory repositoryFactory = (RepositoryFactory) repo.getRepositoryFactory(); 194 if (repositoryFactory == null) { 195 throw new NullPointerException("Missing repositoryFactory for repository: " + repositoryName); 196 } 197 return repositoryFactory; 198 } 199 200 public List<String> getRepositoryNames() { 201 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 202 return repositoryManager.getRepositoryNames(); 203 } 204 205 /** 206 * Creates a new session with the given session id from the given repository. 207 * <p/> 208 * Locks repositories before entering the pool. That allows concurrency with shutdown. 209 * 210 * @since 7.2 211 */ 212 public Session getSession(String repositoryName) { 213 synchronized (repositories) { 214 Repository repository = doGetRepository(repositoryName); 215 if (repository == null) { 216 throw new LocalException("No such repository: " + repositoryName); 217 } 218 return repository.getSession(); 219 } 220 } 221 222}