/* Copyright (2012) Schibsted ASA
* This file is part of Possom.
*
* Possom is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Possom 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Possom. If not, see <http://www.gnu.org/licenses/>.
*
* SiteClassLoaderFactory.java
*/
package no.sesat.search.site.config;
import no.sesat.search.site.Site;
import no.sesat.search.site.SiteContext;
import no.sesat.search.site.SiteKeyedFactory;
import org.apache.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* This provides class loaders capable of loading classes from the skins.
*
*
* @version $Id$
*/
public final class SiteClassLoaderFactory implements SiteKeyedFactory {
/** The context needed. */
public interface Context extends BytecodeContext, SiteContext, SpiContext {}
private static final String CREATING_CLASS_LOADER = "Creating new class loader for ";
private static final String CLASS_LOADER_REMOVED = "Class loader removed for: ";
private static final String CLASS_LOADER_WANTED = "Looking for an existing class loader for ";
private static final Map<Site, Map<Spi, SiteClassLoaderFactory>> INSTANCES
= new HashMap<Site, Map<Spi, SiteClassLoaderFactory>>();
private static final ReentrantReadWriteLock INSTANCES_LOCK = new ReentrantReadWriteLock();
private static final Logger LOG = Logger.getLogger(SiteClassLoaderFactory.class);
/** The actual class loader for the (site, SPI)-pair */
private final ClassLoader classLoader;
private SiteClassLoaderFactory(final Context context) {
final SpiClassLoader.Context classLoaderContext = new SpiClassLoader.Context() {
public BytecodeLoader newBytecodeLoader(final SiteContext siteCxt, final String cName, final String jar) {
return context.newBytecodeLoader(siteCxt, cName, jar);
}
public Site getSite() {
return context.getSite();
}
public Spi getSpi() {
return context.getSpi();
}
};
classLoader = new SpiClassLoader(classLoaderContext);
}
/**
* Returns a class loader factory for a site.
*
* @param context The site and bytecode loader.
* @return a class loader factory for the site.
*/
public static SiteClassLoaderFactory instanceOf(final Context context) {
final Site site = context.getSite();
LOG.trace(CLASS_LOADER_WANTED + site);
try {
INSTANCES_LOCK.readLock().lock();
if (null == INSTANCES.get(site) || null == INSTANCES.get(site).get(context.getSpi())) {
try {
INSTANCES_LOCK.readLock().unlock();
INSTANCES_LOCK.writeLock().lock();
if (null == INSTANCES.get(site)) {
LOG.info(CREATING_CLASS_LOADER + site);
final Map<Spi, SiteClassLoaderFactory> spis = new HashMap<Spi, SiteClassLoaderFactory>();
INSTANCES.put(site, spis);
}
INSTANCES.get(site).put(context.getSpi(), new SiteClassLoaderFactory(context));
} finally {
INSTANCES_LOCK.readLock().lock();
INSTANCES_LOCK.writeLock().unlock();
}
}
return INSTANCES.get(site).get(context.getSpi());
} finally {
INSTANCES_LOCK.readLock().unlock();
}
}
/**
* Returns a class loader for the site.
*
* @return a classloader for the site.
*/
public ClassLoader getClassLoader() {
return classLoader;
}
/**
* {@inheritDoc}
*/
public boolean remove(final Site site) {
try {
INSTANCES_LOCK.writeLock().lock();
return null != INSTANCES.remove(site);
} finally {
INSTANCES_LOCK.writeLock().unlock();
LOG.info(CLASS_LOADER_REMOVED);
}
}
}