/*
 * JBoss, the OpenSource WebOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.deployment;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;

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.mx.util.MBeanProxy;
import org.jboss.system.server.ServerConfigUtil;
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: 1.17.4.4 $</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) MBeanProxy.get(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();
         log.debug("transformed into doc: " + di.document);
         if (log.isDebugEnabled())
         {
            StringWriter sw = new StringWriter();
            DOMWriter w = new DOMWriter(sw, false);
            w.print(di.document, true);
            log.debug("transformed into doc: " + sw.getBuffer().toString());
         }
      }
      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);
      }
   }
}
