/*
* 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.mobicents.servlet.sip.startup.jboss;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import org.jboss.deployment.DeploymentException;
import org.jboss.deployment.DeploymentInfo;
import org.jboss.deployment.SubDeployer;
import org.jboss.metadata.WebMetaData;
import org.jboss.metadata.XmlFileLoader;
import org.jboss.mx.loading.LoaderRepositoryFactory.LoaderRepositoryConfig;
import org.jboss.mx.util.ObjectNameFactory;
import org.jboss.util.file.JarUtils;
import org.jboss.web.AbstractWebContainer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* This class extends the Abstract Web Container so that the .war hard coded value
* is not mandatory and that .sar2 can be used instead
*
* @author Jean Deruelle
*
*/
public abstract class AbstractConvergedContainer extends AbstractWebContainer {
@Override
public synchronized void init(DeploymentInfo di) throws DeploymentException {
log.debug("Begin init");
this.server = di.getServer();
try {
if (di.url.getPath().endsWith("/")) {
// the URL is a unpacked collection, watch the deployment
// descriptor
di.watch = new URL(di.url, "WEB-INF/web.xml");
} else {
// just watch the original URL
di.watch = di.url;
}
// We need to unpack the WAR if it has webservices, because we need
// to manipulate th web.xml before deploying to the web container
boolean unpackWebservice = di.localCl
.findResource("WEB-INF/webservices.xml") != null;
// With JSR-181 annotated JSE endpoints we need to do it as well
// even if there is no webservices.xml
unpackWebservice |= server.isRegistered(ObjectNameFactory
.create("jboss.ws:service=ServiceEndpointManager"));
// Make sure the war is unpacked if unpackWars is true
File warFile = new File(di.localUrl.getFile());
if (warFile.isDirectory() == false
&& (unpackWars || unpackWebservice)) {
// After findResource we cannot rename the WAR anymore, because
// some systems keep an open reference to the file :(
String prefix = warFile.getCanonicalPath();
int prefixIndex = prefix.lastIndexOf(".");
String extension = "war";
if(prefixIndex < 0) {
prefix = prefix.substring(0, prefixIndex);
extension = prefix.substring(prefixIndex + 1, prefix.length());
}
File expWarFile = new File(prefix + "-exp." + extension);
if (expWarFile.mkdir() == false)
throw new DeploymentException("Was unable to mkdir: "
+ expWarFile);
log.debug("Unpacking " + extension + " to: " + expWarFile);
FileInputStream fis = new FileInputStream(warFile);
JarUtils.unjar(fis, expWarFile);
fis.close();
log.debug("Replaced " + extension + " with unpacked contents");
if (warFile.delete() == false)
log.debug("Was unable to delete " + extension + " file");
else
log.debug("Deleted " + extension + " archive");
// Reset the localUrl to end in a '/'
di.localUrl = expWarFile.toURL();
// Reset the localCl to point to the file
URL[] localCl = new URL[] { di.localUrl };
di.localCl = new URLClassLoader(localCl);
}
WebMetaData metaData = new WebMetaData();
metaData.setResourceClassLoader(di.localCl);
metaData
.setJava2ClassLoadingCompliance(this.java2ClassLoadingCompliance);
di.metaData = metaData;
String webContext = di.webContext;
if (webContext != null) {
if (webContext.length() > 0 && webContext.charAt(0) != '/')
webContext = "/" + webContext;
}
// Get the war URL
URL warURL = di.localUrl != null ? di.localUrl : di.url;
log.debug("webContext: " + webContext);
log.debug("warURL: " + warURL);
// Parse the web.xml and jboss-web.xml descriptors
parseMetaData(webContext, warURL, di.shortName, metaData);
// Check for a loader-repository
LoaderRepositoryConfig config = metaData.getLoaderConfig();
if (config != null)
di.setRepositoryInfo(config);
// Generate an event for the initialization
processNestedDeployments(di);
emitNotification(SubDeployer.INIT_NOTIFICATION, di);
} catch (DeploymentException e) {
log.debug("Problem in init ", e);
throw e;
} catch (Exception e) {
log.error("Problem in init ", e);
throw new DeploymentException(e);
}
log.debug("End init");
}
/**
* This method creates a context-root string from either the
* WEB-INF/jboss-web.xml context-root element is one exists, or the filename
* portion of the warURL. It is called if the DeploymentInfo webContext
* value is null which indicates a standalone war deployment. A war name of
* ROOT.war is handled as a special case of a war that should be installed
* as the default web context.
*/
protected void parseMetaData(String ctxPath, URL warURL, String warName,
WebMetaData metaData) throws DeploymentException {
InputStream jbossWebIS = null;
InputStream webIS = null;
// Parse the war deployment descriptors, web.xml and jboss-web.xml
try {
// See if the warUrl is a directory
File warDir = new File(warURL.getFile());
if (warURL.getProtocol().equals("file")
&& warDir.isDirectory() == true) {
File webDD = new File(warDir, "WEB-INF/web.xml");
if (webDD.exists() == true)
webIS = new FileInputStream(webDD);
File jbossWebDD = new File(warDir, "WEB-INF/jboss-web.xml");
if (jbossWebDD.exists() == true)
jbossWebIS = new FileInputStream(jbossWebDD);
} else {
// First check for a WEB-INF/web.xml and a WEB-INF/jboss-web.xml
InputStream warIS = warURL.openStream();
java.util.zip.ZipInputStream zipIS = new java.util.zip.ZipInputStream(
warIS);
java.util.zip.ZipEntry entry;
byte[] buffer = new byte[512];
int bytes;
while ((entry = zipIS.getNextEntry()) != null) {
if (entry.getName().equals("WEB-INF/web.xml")) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((bytes = zipIS.read(buffer)) > 0) {
baos.write(buffer, 0, bytes);
}
webIS = new ByteArrayInputStream(baos.toByteArray());
} else if (entry.getName().equals("WEB-INF/jboss-web.xml")) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((bytes = zipIS.read(buffer)) > 0) {
baos.write(buffer, 0, bytes);
}
jbossWebIS = new ByteArrayInputStream(baos
.toByteArray());
}
}
zipIS.close();
}
XmlFileLoader xmlLoader = new XmlFileLoader();
String warURI = warURL.toExternalForm();
try {
if (webIS != null) {
Document webDoc = xmlLoader.getDocument(webIS, warURI
+ "/WEB-INF/web.xml");
Element web = webDoc.getDocumentElement();
metaData.importXml(web);
}
} catch (Exception e) {
throw new DeploymentException(
"Failed to parse WEB-INF/web.xml", e);
}
try {
if (jbossWebIS != null) {
Document jbossWebDoc = xmlLoader.getDocument(jbossWebIS,
warURI + "/WEB-INF/jboss-web.xml");
Element jbossWeb = jbossWebDoc.getDocumentElement();
metaData.importXml(jbossWeb);
}
} catch (Exception e) {
throw new DeploymentException(
"Failed to parse WEB-INF/jboss-web.xml", e);
}
} catch (DeploymentException e) {
throw e;
} catch (Exception e) {
log.warn("Failed to parse descriptors for war(" + warURL + ")", e);
}
// Build a war root context from the war name if one was not specified
String webContext = ctxPath;
if (webContext == null)
webContext = metaData.getContextRoot();
if (webContext == null) {
// Build the context from the war name, strip the .war suffix
webContext = warName;
webContext = webContext.replace('\\', '/');
if (webContext.endsWith("/"))
webContext = webContext.substring(0, webContext.length() - 1);
int prefix = webContext.lastIndexOf('/');
if (prefix > 0)
webContext = webContext.substring(prefix + 1);
int suffix = webContext.lastIndexOf(".");
if (suffix > 0)
webContext = webContext.substring(0, suffix);
// Strip any '<int-value>.' prefix
int index = 0;
for (; index < webContext.length(); index++) {
char c = webContext.charAt(index);
if (Character.isDigit(c) == false && c != '.')
break;
}
webContext = webContext.substring(index);
}
// Servlet containers are anal about the web context starting with '/'
if (webContext.length() > 0 && webContext.charAt(0) != '/')
webContext = "/" + webContext;
// And also the default root context must be an empty string, not '/'
else if (webContext.equals("/"))
webContext = "";
metaData.setContextRoot(webContext);
}
}