001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Florent Guillaume 016 */ 017package org.nuxeo.ecm.core.storage.sql.coremodel; 018 019import java.lang.reflect.Field; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025import org.nuxeo.ecm.core.api.repository.Repository; 026import org.nuxeo.ecm.core.api.repository.RepositoryManager; 027import org.nuxeo.ecm.core.repository.RepositoryFactory; 028import org.nuxeo.ecm.core.repository.RepositoryService; 029import org.nuxeo.ecm.core.storage.FulltextConfiguration; 030import org.nuxeo.ecm.core.storage.FulltextParser; 031import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor; 032import org.nuxeo.ecm.core.storage.sql.RepositoryImpl; 033import org.nuxeo.ecm.core.storage.sql.RepositoryManagement; 034import org.nuxeo.runtime.api.Framework; 035import org.nuxeo.runtime.model.ComponentContext; 036import org.nuxeo.runtime.model.ComponentInstance; 037import org.nuxeo.runtime.model.DefaultComponent; 038import org.nuxeo.runtime.model.SimpleContributionRegistry; 039 040/** 041 * Service holding the configuration for VCS repositories. 042 * 043 * @since 5.9.3 044 */ 045public class SQLRepositoryService extends DefaultComponent { 046 047 private static final String XP_REPOSITORY = "repository"; 048 049 protected static final String CONNECTIONFACTORYIMPL_CLASS = "org.nuxeo.ecm.core.storage.sql.ra.ConnectionFactoryImpl"; 050 051 protected RepositoryDescriptorRegistry registry = new RepositoryDescriptorRegistry(); 052 053 protected static class RepositoryDescriptorRegistry extends SimpleContributionRegistry<RepositoryDescriptor> { 054 055 @Override 056 public String getContributionId(RepositoryDescriptor contrib) { 057 return contrib.name; 058 } 059 060 @Override 061 public RepositoryDescriptor clone(RepositoryDescriptor orig) { 062 return new RepositoryDescriptor(orig); 063 } 064 065 @Override 066 public void merge(RepositoryDescriptor src, RepositoryDescriptor dst) { 067 dst.merge(src); 068 } 069 070 @Override 071 public boolean isSupportingMerge() { 072 return true; 073 } 074 075 public void clear() { 076 currentContribs.clear(); 077 } 078 079 public RepositoryDescriptor getRepositoryDescriptor(String id) { 080 return getCurrentContribution(id); 081 } 082 083 public List<String> getRepositoryIds() { 084 return new ArrayList<>(currentContribs.keySet()); 085 } 086 } 087 088 @Override 089 public void activate(ComponentContext context) { 090 registry.clear(); 091 } 092 093 @Override 094 public void deactivate(ComponentContext context) { 095 registry.clear(); 096 } 097 098 @Override 099 public void registerContribution(Object contrib, String xpoint, ComponentInstance contributor) { 100 if (XP_REPOSITORY.equals(xpoint)) { 101 addContribution((RepositoryDescriptor) contrib); 102 } else { 103 throw new RuntimeException("Unknown extension point: " + xpoint); 104 } 105 } 106 107 @Override 108 public void unregisterContribution(Object contrib, String xpoint, ComponentInstance contributor) { 109 if (XP_REPOSITORY.equals(xpoint)) { 110 removeContribution((RepositoryDescriptor) contrib); 111 } else { 112 throw new RuntimeException("Unknown extension point: " + xpoint); 113 } 114 } 115 116 protected void addContribution(RepositoryDescriptor descriptor) { 117 registry.addContribution(descriptor); 118 updateRegistration(descriptor.name); 119 } 120 121 protected void removeContribution(RepositoryDescriptor descriptor) { 122 registry.removeContribution(descriptor); 123 updateRegistration(descriptor.name); 124 } 125 126 /** 127 * Update repository registration in high-level repository service. 128 */ 129 protected void updateRegistration(String repositoryName) { 130 RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class); 131 RepositoryDescriptor descriptor = registry.getRepositoryDescriptor(repositoryName); 132 if (descriptor == null) { 133 // last contribution removed 134 repositoryManager.removeRepository(repositoryName); 135 return; 136 } 137 // extract label, isDefault and factory 138 // and pass it to high-level registry 139 Class<? extends RepositoryFactory> repositoryFactoryClass = descriptor.getRepositoryFactoryClass(); 140 if (repositoryFactoryClass == null) { 141 // not the main contribution, just an override with 142 // much less info 143 repositoryManager.removeRepository(repositoryName); 144 return; 145 } 146 RepositoryFactory repositoryFactory; 147 try { 148 repositoryFactory = repositoryFactoryClass.newInstance(); 149 } catch (InstantiationException | IllegalAccessException e) { 150 throw new RuntimeException("Cannot instantiate repository: " + repositoryName, e); 151 } 152 repositoryFactory.init(repositoryName); 153 Repository repository = new Repository(repositoryName, descriptor.label, descriptor.isDefault(), 154 repositoryFactory); 155 repositoryManager.addRepository(repository); 156 } 157 158 public RepositoryDescriptor getRepositoryDescriptor(String name) { 159 return registry.getRepositoryDescriptor(name); 160 } 161 162 /** 163 * Gets the list of SQL repository names. 164 * 165 * @return the list of SQL repository names 166 * @since 5.9.5 167 */ 168 public List<String> getRepositoryNames() { 169 return registry.getRepositoryIds(); 170 } 171 172 protected final Map<String, RepositoryImpl> testRepositories = new HashMap<String, RepositoryImpl>(); 173 174 public void registerTestRepository(RepositoryImpl repository) { 175 testRepositories.put(repository.getName(), repository); 176 } 177 178 /** 179 * Gets the low-level SQL Repository of the given name. 180 * 181 * @param repositoryName the repository name 182 * @return the repository 183 * @since 5.9.5 184 */ 185 public RepositoryManagement getRepository(String repositoryName) { 186 RepositoryService repositoryService = Framework.getLocalService(RepositoryService.class); 187 org.nuxeo.ecm.core.model.Repository repository = repositoryService.getRepository(repositoryName); 188 if (repository == null) { 189 RepositoryImpl repo = testRepositories.get(repositoryName); 190 if (repo != null) { 191 return repo; 192 } 193 } 194 if (repository == null) { 195 throw new RuntimeException("Unknown repository: " + repositoryName); 196 } 197 if (repository instanceof org.nuxeo.ecm.core.storage.sql.Repository) { 198 // (JCA) ConnectionFactoryImpl already implements Repository 199 return (org.nuxeo.ecm.core.storage.sql.Repository) repository; 200 } else if (repository instanceof SQLRepository) { 201 // (LocalSession not pooled) SQLRepository 202 // from SQLRepositoryFactory called by descriptor at registration 203 return ((SQLRepository) repository).repository; 204 } else { 205 throw new RuntimeException("Unknown repository class: " + repository.getClass().getName()); 206 } 207 } 208 209 public RepositoryImpl getRepositoryImpl(String repositoryName) { 210 RepositoryManagement repository = getRepository(repositoryName); 211 if (repository instanceof RepositoryImpl) { 212 return (RepositoryImpl) repository; 213 } 214 if (!CONNECTIONFACTORYIMPL_CLASS.equals(repository.getClass().getName())) { 215 throw new RuntimeException("Unknown repository class: " + repository.getClass()); 216 } 217 try { 218 Field f1 = repository.getClass().getDeclaredField("managedConnectionFactory"); 219 f1.setAccessible(true); 220 Object factory = f1.get(repository); 221 Field f2 = factory.getClass().getDeclaredField("repository"); 222 f2.setAccessible(true); 223 return (RepositoryImpl) f2.get(factory); 224 } catch (SecurityException | NoSuchFieldException | IllegalAccessException e) { 225 throw new RuntimeException(e); 226 } 227 } 228 229 /** 230 * Gets the repositories as a list of {@link RepositoryManagement} objects. 231 * 232 * @since 5.9.5 233 * @return a list of {@link RepositoryManagement} 234 */ 235 public List<RepositoryManagement> getRepositories() { 236 List<RepositoryManagement> repositories = new ArrayList<RepositoryManagement>(); 237 for (String repositoryName : getRepositoryNames()) { 238 repositories.add(getRepository(repositoryName)); 239 } 240 return repositories; 241 } 242 243 public Class<? extends FulltextParser> getFulltextParserClass(String repositoryName) { 244 return getRepositoryImpl(repositoryName).getFulltextParserClass(); 245 } 246 247 public FulltextConfiguration getFulltextConfiguration(String repositoryName) { 248 return getRepositoryImpl(repositoryName).getModel().getFulltextConfiguration(); 249 } 250 251 /** 252 * Returns the datasource definition for the given repository and fills the properties map with the datasource 253 * configuration. 254 * 255 * @param repositoryName the repository name 256 * @param properties a return map of properties 257 * @return the XA datasource name, or null if single datasource is configured 258 * @since 5.9.5 259 */ 260 public String getRepositoryDataSourceAndProperties(String repositoryName, Map<String, String> properties) { 261 RepositoryDescriptor desc = getRepositoryImpl(repositoryName).getRepositoryDescriptor(); 262 if (desc.properties != null) { 263 properties.putAll(desc.properties); 264 } 265 return desc.xaDataSourceName; 266 } 267 268}