/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Principal;
import java.security.acl.Group;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.jackrabbit.test.NotExecutableException;
import org.apache.jackrabbit.test.RepositoryStub;
import org.apache.jackrabbit.test.RepositoryStubException;
/**
* RepositoryStub implementation for Apache Jackrabbit.
*
* @since Apache Jackrabbit 1.6
*/
public class JackrabbitRepositoryStub extends RepositoryStub {
/**
* Property for the repository configuration file. Defaults to
* <repository home>/repository.xml if not specified.
*/
public static final String PROP_REPOSITORY_CONFIG =
"org.apache.jackrabbit.repository.config";
/**
* Property for the repository home directory. Defaults to
* target/repository for convenience in Maven builds.
*/
public static final String PROP_REPOSITORY_HOME =
"org.apache.jackrabbit.repository.home";
/**
* Repository settings.
*/
private final Properties settings;
/**
* Map of repository instances. Key = repository home, value = repository
* instance.
*/
private static final Map<String, Repository> REPOSITORY_INSTANCES = new HashMap<String, Repository>();
static {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
synchronized (REPOSITORY_INSTANCES) {
for (Repository repo : REPOSITORY_INSTANCES.values()) {
if (repo instanceof RepositoryImpl) {
((RepositoryImpl) repo).shutdown();
}
}
}
}
}));
}
private static Properties getStaticProperties() {
Properties properties = new Properties();
try {
InputStream stream =
getResource("JackrabbitRepositoryStub.properties");
try {
properties.load(stream);
} finally {
stream.close();
}
} catch (IOException e) {
// TODO: Log warning
}
return properties;
}
private static InputStream getResource(String name) {
return JackrabbitRepositoryStub.class.getResourceAsStream(name);
}
/**
* Constructor as required by the JCR TCK.
*
* @param settings repository settings
*/
public JackrabbitRepositoryStub(Properties settings) {
super(getStaticProperties());
// set some attributes on the sessions
superuser.setAttribute("jackrabbit", "jackrabbit");
readwrite.setAttribute("jackrabbit", "jackrabbit");
readonly.setAttribute("jackrabbit", "jackrabbit");
// Repository settings
this.settings = settings;
}
/**
* Returns the configured repository instance.
*
* @return the configured repository instance.
* @throws RepositoryStubException if an error occurs while
* obtaining the repository instance.
*/
public synchronized Repository getRepository()
throws RepositoryStubException {
try {
String dir = settings.getProperty(PROP_REPOSITORY_HOME);
if (dir == null) {
dir = new File("target", "repository").getAbsolutePath();
} else {
dir = new File(dir).getAbsolutePath();
}
String xml = settings.getProperty(PROP_REPOSITORY_CONFIG);
if (xml == null) {
xml = new File(dir, "repository.xml").getPath();
}
return getOrCreateRepository(dir, xml);
} catch (Exception e) {
RepositoryStubException exception =
new RepositoryStubException("Failed to start repository");
exception.initCause(e);
throw exception;
}
}
protected Repository createRepository(String dir, String xml)
throws Exception {
new File(dir).mkdirs();
if (!new File(xml).exists()) {
InputStream input = getResource("repository.xml");
try {
OutputStream output = new FileOutputStream(xml);
try {
IOUtils.copy(input, output);
} finally {
output.close();
}
} finally {
input.close();
}
}
RepositoryConfig config = RepositoryConfig.create(xml, dir);
return RepositoryImpl.create(config);
}
protected Repository getOrCreateRepository(String dir, String xml)
throws Exception {
synchronized (REPOSITORY_INSTANCES) {
Repository repo = REPOSITORY_INSTANCES.get(dir);
if (repo == null) {
repo = createRepository(dir, xml);
Session session = repo.login(superuser);
try {
TestContentLoader loader = new TestContentLoader();
loader.loadTestContent(session);
} finally {
session.logout();
}
REPOSITORY_INSTANCES.put(dir, repo);
}
return repo;
}
}
@Override
public Principal getKnownPrincipal(Session session) throws RepositoryException {
Principal knownPrincipal = null;
if (session instanceof SessionImpl) {
for (Principal p : ((SessionImpl)session).getSubject().getPrincipals()) {
if (! (p instanceof Group)) {
knownPrincipal = p;
}
}
}
if (knownPrincipal != null) {
return knownPrincipal;
}
else {
throw new RepositoryException("no applicable principal found");
}
}
private static Principal UNKNOWN_PRINCIPAL = new Principal() {
public String getName() {
return "an_unknown_user";
}
};
@Override
public Principal getUnknownPrincipal(Session session) throws RepositoryException, NotExecutableException {
return UNKNOWN_PRINCIPAL;
}
}