/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.core.storage.sql.coremodel;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.nuxeo.ecm.core.api.repository.Repository;
import org.nuxeo.ecm.core.api.repository.RepositoryManager;
import org.nuxeo.ecm.core.repository.RepositoryFactory;
import org.nuxeo.ecm.core.repository.RepositoryService;
import org.nuxeo.ecm.core.storage.FulltextConfiguration;
import org.nuxeo.ecm.core.storage.FulltextParser;
import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor;
import org.nuxeo.ecm.core.storage.sql.RepositoryImpl;
import org.nuxeo.ecm.core.storage.sql.RepositoryManagement;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.model.ComponentContext;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.DefaultComponent;
import org.nuxeo.runtime.model.SimpleContributionRegistry;
/**
* Service holding the configuration for VCS repositories.
*
* @since 5.9.3
*/
public class SQLRepositoryService extends DefaultComponent {
private static final String XP_REPOSITORY = "repository";
protected static final String CONNECTIONFACTORYIMPL_CLASS = "org.nuxeo.ecm.core.storage.sql.ra.ConnectionFactoryImpl";
protected RepositoryDescriptorRegistry registry = new RepositoryDescriptorRegistry();
protected static class RepositoryDescriptorRegistry extends
SimpleContributionRegistry<RepositoryDescriptor> {
@Override
public String getContributionId(RepositoryDescriptor contrib) {
return contrib.name;
}
@Override
public RepositoryDescriptor clone(RepositoryDescriptor orig) {
return new RepositoryDescriptor(orig);
}
@Override
public void merge(RepositoryDescriptor src, RepositoryDescriptor dst) {
dst.merge(src);
}
@Override
public boolean isSupportingMerge() {
return true;
}
public void clear() {
currentContribs.clear();
}
public RepositoryDescriptor getRepositoryDescriptor(String id) {
return getCurrentContribution(id);
}
public List<String> getRepositoryIds() {
return new ArrayList<>(currentContribs.keySet());
}
}
@Override
public void activate(ComponentContext context) throws Exception {
registry.clear();
}
@Override
public void deactivate(ComponentContext context) throws Exception {
registry.clear();
}
@Override
public void registerContribution(Object contrib, String xpoint,
ComponentInstance contributor) {
if (XP_REPOSITORY.equals(xpoint)) {
addContribution((RepositoryDescriptor) contrib);
} else {
throw new RuntimeException("Unknown extension point: " + xpoint);
}
}
@Override
public void unregisterContribution(Object contrib, String xpoint,
ComponentInstance contributor) throws Exception {
if (XP_REPOSITORY.equals(xpoint)) {
removeContribution((RepositoryDescriptor) contrib);
} else {
throw new RuntimeException("Unknown extension point: " + xpoint);
}
}
protected void addContribution(RepositoryDescriptor descriptor) {
registry.addContribution(descriptor);
updateRegistration(descriptor.name);
}
protected void removeContribution(RepositoryDescriptor descriptor) {
registry.removeContribution(descriptor);
updateRegistration(descriptor.name);
}
/**
* Update repository registration in high-level repository service.
*/
protected void updateRegistration(String repositoryName) {
RepositoryManager repositoryManager = Framework.getLocalService(RepositoryManager.class);
RepositoryDescriptor descriptor = registry.getRepositoryDescriptor(repositoryName);
if (descriptor == null) {
// last contribution removed
repositoryManager.removeRepository(repositoryName);
return;
}
// extract label, isDefault and factory
// and pass it to high-level registry
Class<? extends RepositoryFactory> repositoryFactoryClass = descriptor.getRepositoryFactoryClass();
if (repositoryFactoryClass == null) {
// not the main contribution, just an override with
// much less info
repositoryManager.removeRepository(repositoryName);
return;
}
RepositoryFactory repositoryFactory;
try {
repositoryFactory = repositoryFactoryClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Cannot instantiate repository: "
+ repositoryName, e);
}
repositoryFactory.init(repositoryName);
Repository repository = new Repository(repositoryName,
descriptor.label, descriptor.isDefault(), repositoryFactory);
repositoryManager.addRepository(repository);
}
public RepositoryDescriptor getRepositoryDescriptor(String name) {
return registry.getRepositoryDescriptor(name);
}
/**
* Gets the list of SQL repository names.
*
* @return the list of SQL repository names
* @since 5.9.5
*/
public List<String> getRepositoryNames() {
return registry.getRepositoryIds();
}
protected final Map<String, RepositoryImpl> testRepositories = new HashMap<String, RepositoryImpl>();
public void registerTestRepository(RepositoryImpl repository) {
testRepositories.put(repository.getName(), repository);
}
/**
* Gets the low-level SQL Repository of the given name.
*
* @param repositoryName the repository name
* @return the repository
* @since 5.9.5
*/
public RepositoryManagement getRepository(String repositoryName) {
RepositoryService repositoryService = Framework.getLocalService(RepositoryService.class);
org.nuxeo.ecm.core.model.Repository repository = repositoryService.getRepository(repositoryName);
if (repository == null) {
RepositoryImpl repo = testRepositories.get(repositoryName);
if (repo != null) {
return repo;
}
}
if (repository == null) {
throw new RuntimeException("Unknown repository: " + repositoryName);
}
if (repository instanceof org.nuxeo.ecm.core.storage.sql.Repository) {
// (JCA) ConnectionFactoryImpl already implements Repository
return (org.nuxeo.ecm.core.storage.sql.Repository) repository;
} else if (repository instanceof SQLRepository) {
// (LocalSession not pooled) SQLRepository
// from SQLRepositoryFactory called by descriptor at registration
return ((SQLRepository) repository).repository;
} else {
throw new RuntimeException("Unknown repository class: "
+ repository.getClass().getName());
}
}
public RepositoryImpl getRepositoryImpl(String repositoryName) {
RepositoryManagement repository = getRepository(repositoryName);
if (repository instanceof RepositoryImpl) {
return (RepositoryImpl) repository;
}
if (!CONNECTIONFACTORYIMPL_CLASS.equals(repository.getClass().getName())) {
throw new RuntimeException("Unknown repository class: "
+ repository.getClass());
}
try {
Field f1 = repository.getClass().getDeclaredField(
"managedConnectionFactory");
f1.setAccessible(true);
Object factory = f1.get(repository);
Field f2 = factory.getClass().getDeclaredField("repository");
f2.setAccessible(true);
return (RepositoryImpl) f2.get(factory);
} catch (SecurityException | NoSuchFieldException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Gets the repositories as a list of {@link RepositoryManagement} objects.
*
* @since 5.9.5
* @return a list of {@link RepositoryManagement}
*/
public List<RepositoryManagement> getRepositories() {
List<RepositoryManagement> repositories = new ArrayList<RepositoryManagement>();
for (String repositoryName : getRepositoryNames()) {
repositories.add(getRepository(repositoryName));
}
return repositories;
}
public Class<? extends FulltextParser> getFulltextParserClass(
String repositoryName) {
return getRepositoryImpl(repositoryName).getFulltextParserClass();
}
public FulltextConfiguration getFulltextConfiguration(String repositoryName) {
return getRepositoryImpl(repositoryName).getModel().getFulltextConfiguration();
}
/**
* Returns the datasource definition for the given repository and fills the
* properties map with the datasource configuration.
*
* @param repositoryName the repository name
* @param properties a return map of properties
* @return the XA datasource name, or null if single datasource is
* configured
* @since 5.9.5
*/
public String getRepositoryDataSourceAndProperties(String repositoryName,
Map<String, String> properties) {
RepositoryDescriptor desc = getRepositoryImpl(repositoryName).getRepositoryDescriptor();
if (desc.properties != null) {
properties.putAll(desc.properties);
}
return desc.xaDataSourceName;
}
}