/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2007.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.repository.manager;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import info.aduna.io.FileUtil;
import org.openrdf.repository.DelegatingRepository;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.config.DelegatingRepositoryImplConfig;
import org.openrdf.repository.config.RepositoryConfig;
import org.openrdf.repository.config.RepositoryConfigException;
import org.openrdf.repository.config.RepositoryConfigUtil;
import org.openrdf.repository.config.RepositoryFactory;
import org.openrdf.repository.config.RepositoryImplConfig;
import org.openrdf.repository.config.RepositoryRegistry;
import org.openrdf.repository.event.base.RepositoryConnectionListenerAdapter;
/**
* An implementation of the {@link RepositoryManager} interface that operates
* directly on the repository data files in the local file system.
*
* @author Arjohn Kampman
*/
public class LocalRepositoryManager extends RepositoryManager {
/*-----------*
* Constants *
*-----------*/
public static final String REPOSITORIES_DIR = "repositories";
/*-----------*
* Variables *
*-----------*/
/**
* The base dir to resolve any relative paths against.
*/
private File baseDir;
/*--------------*
* Constructors *
*--------------*/
/**
* Creates a new RepositoryManager that operates on the specfified base
* directory.
*
* @param baseDir
* The base directory where data for repositories can be stored, among
* other things.
*/
public LocalRepositoryManager(File baseDir) {
super();
this.baseDir = baseDir;
}
/*---------*
* Methods *
*---------*/
@Override
protected SystemRepository createSystemRepository()
throws RepositoryException
{
File systemDir = getRepositoryDir(SystemRepository.ID);
SystemRepository systemRepos = new SystemRepository(systemDir);
systemRepos.initialize();
systemRepos.addRepositoryConnectionListener(new ConfigChangeListener());
return systemRepos;
}
/**
* Gets the base dir against which to resolve relative paths.
*/
public File getBaseDir() {
return baseDir;
}
/**
* Resolves the specified path against the manager's base directory.
*
* @see #getDataDir
*/
public File resolvePath(String path) {
return new File(getBaseDir(), path);
}
public File getRepositoryDir(String repositoryID) {
File repositoriesDir = resolvePath(REPOSITORIES_DIR);
return new File(repositoriesDir, repositoryID);
}
@Override
public SystemRepository getSystemRepository() {
return (SystemRepository)super.getSystemRepository();
}
@Override
protected Repository createRepository(String id)
throws RepositoryConfigException, RepositoryException
{
Repository systemRepository = getSystemRepository();
RepositoryConnection con = systemRepository.getConnection();
try {
Repository repository = null;
RepositoryConfig repConfig = RepositoryConfigUtil.getRepositoryConfig(systemRepository, id);
if (repConfig != null) {
repConfig.validate();
repository = createRepositoryStack(repConfig.getRepositoryImplConfig());
repository.setDataDir(getRepositoryDir(id));
repository.initialize();
}
return repository;
}
finally {
con.close();
}
}
/**
* Creates the stack of Repository objects for the repository represented by
* the specified <tt>repositoryImplNode</tt>.
*
* @param con
* A connection to the repository containing the repository
* configuration.
* @param repositoryImplNode
* The node representing the to-be-created repository in the
* configuration.
* @return The created repository, or <tt>null</tt> if no such repository
* exists.
* @throws RepositoryConfigException
* If no repository could be created due to invalid or incomplete
* configuration data.
*/
private Repository createRepositoryStack(RepositoryImplConfig config)
throws RepositoryConfigException
{
RepositoryFactory factory = RepositoryRegistry.getInstance().get(config.getType());
if (factory == null) {
throw new RepositoryConfigException("Unsupported repository type: " + config.getType());
}
Repository repository = factory.getRepository(config);
if (config instanceof DelegatingRepositoryImplConfig) {
RepositoryImplConfig delegateConfig = ((DelegatingRepositoryImplConfig)config).getDelegate();
Repository delegate = createRepositoryStack(delegateConfig);
try {
((DelegatingRepository)repository).setDelegate(delegate);
}
catch (ClassCastException e) {
throw new RepositoryConfigException(
"Delegate specified for repository that is not a DelegatingRepository: "
+ delegate.getClass());
}
}
return repository;
}
@Override
public RepositoryInfo getRepositoryInfo(String id)
throws RepositoryException
{
try {
RepositoryConfig config = null;
if (id.equals(SystemRepository.ID)) {
config = new RepositoryConfig(id, new SystemRepositoryConfig());
}
else {
config = getRepositoryConfig(id);
}
RepositoryInfo repInfo = new RepositoryInfo();
repInfo.setId(id);
repInfo.setDescription(config.getTitle());
try {
repInfo.setLocation(getRepositoryDir(id).toURI().toURL());
}
catch (MalformedURLException mue) {
throw new RepositoryException("Location of repository does not resolve to a valid URL", mue);
}
repInfo.setReadable(true);
repInfo.setWritable(true);
return repInfo;
}
catch (RepositoryConfigException rce) {
// FIXME: don't fetch info through config parsing
throw new RepositoryException("Unable to retrieve existing configurations", rce);
}
}
@Override
public List<RepositoryInfo> getAllRepositoryInfos(boolean skipSystemRepo)
throws RepositoryException
{
List<RepositoryInfo> result = new ArrayList<RepositoryInfo>();
for (String id : getRepositoryIDs()) {
if (!skipSystemRepo || !id.equals(SystemRepository.ID)) {
result.add(getRepositoryInfo(id));
}
}
return result;
}
class ConfigChangeListener extends RepositoryConnectionListenerAdapter {
@Override
public void commit(RepositoryConnection con) {
refresh();
}
}
@Override
protected void cleanUpRepository(String repositoryID)
throws IOException
{
File dataDir = getRepositoryDir(repositoryID);
if (dataDir.isDirectory()) {
logger.debug("Cleaning up data dir {} for repository {}", dataDir.getAbsolutePath(), repositoryID);
FileUtil.deleteDir(dataDir);
}
}
}