org.apache.sling.jcr.base.util.RepositoryAccessor Maven / Gradle / Ivy
/*
* 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.sling.jcr.base.util;
import java.util.Hashtable;
import javax.jcr.Repository;
import javax.naming.InitialContext;
import org.apache.jackrabbit.rmi.client.ClientAdapterFactory;
import org.apache.jackrabbit.rmi.client.ClientRepositoryFactory;
import org.apache.jackrabbit.rmi.client.LocalAdapterFactory;
import org.apache.jackrabbit.rmi.remote.RemoteRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Access a Repository via JNDI or RMI. */
public class RepositoryAccessor {
private final Logger log = LoggerFactory.getLogger(getClass());
/** Prefix for RMI Repository URLs */
public static final String RMI_PREFIX = "rmi://";
/** Prefix for JNDI Repository URLs */
public static final String JNDI_PREFIX = "jndi://";
/**
* Name of the property that the jcr client and server bundles to override
* their default configuration settings and connect to the specified
* repository instead (SLING-254 and SLING-260)
*/
public static final String REPOSITORY_URL_OVERRIDE_PROPERTY = "sling.repository.url";
/**
* First try to access the Repository via JNDI (unless jndiContext is null),
* and if not successful try RMI.
*
* @param repositoryName JNDI name or RMI URL (must start with "rmi://") of
* the Repository
* @param jndiContext if null, JNDI is not tried
* @return a Repository, or null if not found
*/
public Repository getRepository(String repositoryName,
Hashtable jndiContext) {
Repository result = null;
String tried = "";
if (jndiContext == null || jndiContext.size() == 0) {
log.info("jndiContext is null or empty, not trying JNDI");
} else {
log.debug("Trying to acquire Repository '" + repositoryName
+ "' via JNDI, context=" + jndiContext);
tried += "JNDI ";
final ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(
this.getClass().getClassLoader());
InitialContext initialContext = new InitialContext(jndiContext);
Object repoObject = initialContext.lookup(repositoryName);
if (repoObject instanceof Repository) {
result = (Repository) repoObject;
log.info("Acquired Repository '" + repositoryName
+ "' via JNDI");
} else if (repoObject instanceof RemoteRepository) {
RemoteRepository remoteRepo = (RemoteRepository) repoObject;
LocalAdapterFactory laf = getLocalAdapterFactory();
result = laf.getRepository(remoteRepo);
log.info("Acquired RemoteRepository '" + repositoryName
+ "' via JNDI");
} else {
log.info("Repository '" + repositoryName
+ "' acquired via JDNI "
+ "does not implement the required interfaces, class="
+ repoObject.getClass().getName());
}
} catch (Throwable t) {
log.info("Unable to acquire Repository '" + repositoryName
+ "' via JNDI, context=" + jndiContext, t);
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
if (result == null) {
if (repositoryName == null
|| !repositoryName.startsWith(RMI_PREFIX)) {
log.info("Repository name does not start with '" + RMI_PREFIX
+ "', not trying RMI");
} else {
try {
tried += "RMI ";
log.debug("Trying to acquire Repository '" + repositoryName
+ "' via RMI");
ClientRepositoryFactory crf = getClientRepositoryFactory();
result = crf.getRepository(repositoryName);
log.info("Acquired Repository '" + repositoryName
+ "' via RMI");
} catch (Throwable t) {
log.info("Unable to acquire Repository '" + repositoryName
+ "' via RMI", t);
}
}
}
if (result == null) {
log.info("Unable to acquire Repository '" + repositoryName
+ "', tried " + tried);
}
return result;
}
/**
* Acquire a Repository from the given URL
*
* @param url for RMI, an RMI URL. For JNDI, "jndi://", followed by the JNDI
* repository name, followed by a colon and a comma-separated
* list of JNDI context values, for example:
*
*
* jndi://jackrabbit:java.naming.factory.initial=org.SomeClass,java.naming.provider.url=http://foo.com
*
*
* @throws NullPointerException If url
is null
.
*/
public Repository getRepositoryFromURL(String url) {
if (url == null) {
throw new NullPointerException("url");
}
if (url.startsWith(JNDI_PREFIX)) {
// Parse JNDI URL to extract repository name and context
String name = null;
final Hashtable jndiContext = new Hashtable();
final String urlNoPrefix = url.substring(JNDI_PREFIX.length());
final int colonPos = urlNoPrefix.indexOf(':');
if (colonPos < 0) {
name = urlNoPrefix;
} else {
name = urlNoPrefix.substring(0, colonPos);
for (String entryStr : urlNoPrefix.substring(colonPos + 1).split(
",")) {
final String[] entry = entryStr.split("=");
if (entry.length == 2) {
jndiContext.put(entry[0], entry[1]);
}
}
}
return getRepository(name, jndiContext);
}
// Use URL as is
return getRepository(url, null);
}
/**
* Returns the LocalAdapterFactory
used to convert Jackrabbit
* JCR RMI remote objects to local JCR API objects.
*
* This method returns an instance of the
* JackrabbitClientAdapterFactory
which allows accessing
* Jackrabbit (or Jackrabbit-based) repositories over RMI. Extensions of
* this class may overwrite this method to use a different implementation.
*/
protected LocalAdapterFactory getLocalAdapterFactory() {
return new ClientAdapterFactory();
}
/**
* Returns the ClientRepositoryFactory
to access the remote
* JCR repository over RMI.
*
* This method creates an instance of the
* ClientRepositoryFactory
class initialized with the
* LocalAdapterFactory
returned from the
* {@link #getLocalAdapterFactory()} method. Extensions may overwrite this
* method to return an extension of the Jackrabbit JCR RMI
* ClientRepositoryFactory
class.
*/
protected ClientRepositoryFactory getClientRepositoryFactory() {
return new ClientRepositoryFactory(getLocalAdapterFactory());
}
}