/* Copyright (2006-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/>.
*/
/*
* UrlRewriterContainerFactory.java
*
* Created on 19. april 2006, 20:48
*/
package no.sesat.search.http.urlrewrite;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import no.sesat.commons.ioc.BaseContext;
import no.sesat.search.site.config.DocumentLoader;
import no.sesat.search.site.Site;
import no.sesat.search.site.SiteContext;
import no.sesat.search.site.SiteKeyedFactory;
import no.sesat.search.site.config.DocumentContext;
import org.apache.log4j.Logger;
import org.tuckey.web.filters.urlrewrite.Conf;
import org.tuckey.web.filters.urlrewrite.UrlRewriter;
import org.w3c.dom.Document;
/** Provides a SiteKeyedFactory around urlrewrite.xml configurations instead of tuckey's default
* of only loading WEB-INF/urlrewrite.xml
*
*
* @version $Id$
*/
public final class UrlRewriterContainerFactory /*extends AbstractDocumentFactory*/ implements SiteKeyedFactory{
/**
* The context any SearchTabFactory must work against.
*/
public interface Context extends BaseContext, DocumentContext, SiteContext {
ServletContext getServletContext();
}
// Constants -----------------------------------------------------
private static final Map<Site, UrlRewriterContainerFactory> INSTANCES
= new HashMap<Site,UrlRewriterContainerFactory>();
private static final ReentrantReadWriteLock INSTANCES_LOCK = new ReentrantReadWriteLock();
/**
* The name of the skin's configuration file.
*/
public static final String URLREWRITE_XMLFILE = "urlrewrite.xml";
private static final String EMPTY_RULES = "<urlrewrite></urlrewrite>";
private static final Logger LOG = Logger.getLogger(UrlRewriterContainerFactory.class);
private static final String ERR_DOC_BUILDER_CREATION
= "Failed to DocumentBuilderFactory.newInstance().newDocumentBuilder()";
// Attributes ----------------------------------------------------
private final UrlRewriter urlRewriter;
private final DocumentLoader loader;
private final Context context;
// Static --------------------------------------------------------
/** Return the factory in use for the skin defined within the context. *
* @param cxt
* @return
*/
public static UrlRewriterContainerFactory instanceOf(final Context cxt) {
final Site site = cxt.getSite();
assert null != site;
UrlRewriterContainerFactory instance;
try{
INSTANCES_LOCK.readLock().lock();
instance = INSTANCES.get(site);
}finally{
INSTANCES_LOCK.readLock().unlock();
}
if (instance == null) {
try {
instance = new UrlRewriterContainerFactory(cxt);
} catch (ParserConfigurationException ex) {
LOG.error(ERR_DOC_BUILDER_CREATION,ex);
}
}
return instance;
}
/** Remove the factory in use for the skin defined within the context. **/
public boolean remove(final Site site){
try{
INSTANCES_LOCK.writeLock().lock();
urlRewriter.destroy();
return null != INSTANCES.remove(site);
}finally{
INSTANCES_LOCK.writeLock().unlock();
}
}
// Constructors --------------------------------------------------
/** Creates a new instance of ViewFactory */
private UrlRewriterContainerFactory(final Context cxt) throws ParserConfigurationException {
LOG.trace("UrlRewriterContainerFactory(cxt)");
try{
INSTANCES_LOCK.writeLock().lock();
context = cxt;
// configuration files
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
final DocumentBuilder builder = factory.newDocumentBuilder();
loader = context.newDocumentLoader(cxt, URLREWRITE_XMLFILE, builder);
// start initialisation
urlRewriter = initUrlRewriter();
// update the store of factories
INSTANCES.put(context.getSite(), this);
}finally{
INSTANCES_LOCK.writeLock().unlock();
}
}
// Public --------------------------------------------------------
/**
* @return
*/
public UrlRewriter getUrlRewriter(){
LOG.trace("getUrlRewriter()");
return urlRewriter;
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
private UrlRewriter initUrlRewriter() {
loader.abut();
LOG.info("Parsing " + URLREWRITE_XMLFILE + " started");
final Document doc = loader.getDocument();
final String output = transformDocumentToString(doc).getBuffer().toString();
// finished
LOG.info("Parsing " + URLREWRITE_XMLFILE + " finished");
byte[] byteArr = 0 < output.trim().length()
? output.getBytes()
: EMPTY_RULES.getBytes();
return new UrlRewriter(new Conf(
context.getServletContext(),
new ByteArrayInputStream(byteArr),
URLREWRITE_XMLFILE,
""));
}
private static StringWriter transformDocumentToString(final Document xml){
final StringWriter writer = new StringWriter();
try{
final Result res = new StreamResult(writer);
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "no" );
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform( new DOMSource(xml), res );
}catch(TransformerException te){
LOG.error(te.getMessage(), te);
}
return writer;
}
// Inner classes -------------------------------------------------
}