/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.deployment;
import java.io.IOException;
import java.io.InputStream;
import javax.management.ObjectName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.jboss.bootstrap.spi.util.ServerConfigUtil;
import org.jboss.mx.util.MBeanProxyExt;
import org.jboss.util.xml.DOMWriter;
import org.jboss.util.xml.JBossEntityResolver;
import org.jboss.util.xml.JBossErrorHandler;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* XSLSubDeployer
*
* @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
* @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>
* @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
* @version <tt>$Revision: 81033 $</tt>
*/
public class XSLSubDeployer extends SubDeployerSupport implements XSLSubDeployerMBean
{
protected String xslUrl;
protected String packageSuffix;
protected String ddSuffix;
protected DocumentBuilderFactory dbf;
private Templates templates;
protected ObjectName delegateName = SARDeployerMBean.OBJECT_NAME;
protected SubDeployer delegate;
/** A flag indicating if deployment descriptors should be validated */
private boolean validateDTDs;
public XSLSubDeployer()
{
}
public void setXslUrl(final String xslUrl)
{
this.xslUrl = xslUrl;
}
public String getXslUrl()
{
return xslUrl;
}
public void setPackageSuffix(final String packageSuffix)
{
this.packageSuffix = packageSuffix;
}
public String getPackageSuffix()
{
return packageSuffix;
}
public void setDdSuffix(final String ddSuffix)
{
this.ddSuffix = ddSuffix;
}
public String getDdSuffix()
{
return ddSuffix;
}
public void setDelegateName(final ObjectName delegateName)
{
this.delegateName = delegateName;
}
public ObjectName getDelegateName()
{
return delegateName;
}
public boolean getValidateDTDs()
{
return validateDTDs;
}
public void setValidateDTDs(boolean validate)
{
this.validateDTDs = validate;
}
protected void createService() throws Exception
{
super.createService();
delegate = (SubDeployer) MBeanProxyExt.create(SubDeployer.class, delegateName, server);
TransformerFactory tf = TransformerFactory.newInstance();
dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(validateDTDs);
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(xslUrl);
StreamSource ss = new StreamSource(is);
templates = tf.newTemplates(ss);
log.debug("Created templates: " + templates);
}
protected void destroyService() throws Exception
{
templates = null;
super.destroyService();
}
public boolean accepts(DeploymentInfo di)
{
String urlStr = di.url.toString();
return (packageSuffix != null && (urlStr.endsWith(packageSuffix) || urlStr.endsWith(packageSuffix + "/")))
|| (ddSuffix != null && urlStr.endsWith(ddSuffix));
}
public void init(DeploymentInfo di) throws DeploymentException
{
if (di.document == null)
findDd(di);
try
{
Transformer trans = templates.newTransformer();
String urlStr = di.url.toString();
String shortURL = ServerConfigUtil.shortUrlFromServerHome(urlStr);
trans.setErrorListener(new JBossErrorHandler(shortURL, null));
Source s = new DOMSource(di.document);
DOMResult r = new DOMResult();
setParameters(trans);
trans.transform(s, r);
di.document = (Document) r.getNode();
if (log.isDebugEnabled())
{
log.debug("transformed into doc: " + di.document);
String docStr = DOMWriter.printNode(di.document, true);
int index = docStr.toLowerCase().indexOf("password");
if (index != -1)
{
docStr = maskPasswords(docStr, index);
}
log.debug("transformed into doc: " + docStr);
}
}
catch (TransformerException ce)
{
throw new DeploymentException("Problem with xsl transformation", ce);
}
delegate.init(di);
}
public void create(DeploymentInfo di) throws DeploymentException
{
delegate.create(di);
}
public void start(DeploymentInfo di) throws DeploymentException
{
delegate.start(di);
}
public void stop(DeploymentInfo di) throws DeploymentException
{
delegate.stop(di);
}
public void destroy(DeploymentInfo di) throws DeploymentException
{
delegate.destroy(di);
}
protected void setParameters(Transformer trans) throws TransformerException
{
//override to set document names etc.
}
protected void findDd(DeploymentInfo di) throws DeploymentException
{
try
{
DocumentBuilder db = dbf.newDocumentBuilder();
String urlStr = di.url.toString();
String shortURL = ServerConfigUtil.shortUrlFromServerHome(urlStr);
JBossEntityResolver resolver = new JBossEntityResolver();
db.setEntityResolver(resolver);
db.setErrorHandler(new JBossErrorHandler(shortURL, resolver));
if (ddSuffix != null && urlStr.endsWith(ddSuffix))
di.document = db.parse(di.url.openStream());
}
catch (SAXException se)
{
throw new DeploymentException("Could not parse dd", se);
}
catch (IOException ioe)
{
throw new DeploymentException("Could not read dd", ioe);
}
catch (ParserConfigurationException pce)
{
throw new DeploymentException("Could not create document builder for dd", pce);
}
}
/**
* Masks passwords so they are not visible in the log.
*
* @param original <code>String</code> plain-text passwords
* @param index index where the password keyword was found
* @return modified <code>String</code> with masked passwords
*/
private String maskPasswords(String original, int index)
{
StringBuilder sb = new StringBuilder(original);
String modified = null;
int startPasswdStringIndex = sb.indexOf(">", index);
if (startPasswdStringIndex != -1)
{
// checks if the keyword 'password' was not in a comment
if (sb.charAt(startPasswdStringIndex - 1) != '-')
{
int endPasswdStringIndex = sb.indexOf("<", startPasswdStringIndex);
if (endPasswdStringIndex != -1) // shouldn't happen, but check anyway
{
sb.replace(startPasswdStringIndex + 1, endPasswdStringIndex, "****");
}
}
modified = sb.toString();
// unlikely event of more than one password
index = modified.toLowerCase().indexOf("password", startPasswdStringIndex);
if (index != -1)
return maskPasswords(modified, index);
return modified;
}
return original;
}
}