/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* SipArchiveDeployer.java
*
* This class is an implementation of the ArchiveDeployer intereface and
* extends the WebArchiveDeployer. The main function of this class is to
* handle the processing of a SIP/Converged HTTP+SIP archive by
* 1. expanding the archive
* 2. Processing the SIP Deployment descriptors
* 3. Processing all the Web Application supported deployment descriptors
* 4. Adding these processed descriptors in a SipBundleDescriptor
* In addition this class also supports undeployment and clean up operations
* for a SIP/Converged HTTP+SIP application
* Created on February 27, 2007, 3:10 PM
*
*/
package org.jvnet.glassfish.comms.deployment.backend;
import com.ericsson.ssa.container.auth.DescriptorProcessor;
import com.sun.enterprise.deployment.util.ApplicationValidator;
import com.sun.enterprise.deployment.util.WebBundleVisitor;
import com.sun.enterprise.security.util.IASSecurityException;
import com.sun.enterprise.util.io.FileUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import javax.enterprise.deploy.shared.ModuleType;
import org.xml.sax.SAXParseException;
import org.jvnet.glassfish.comms.deployment.backend.SipApplicationBase;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.DeploymentException;
import com.sun.enterprise.deployment.Descriptor;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.annotation.AnnotatedElementHandler;
import com.sun.enterprise.deployment.annotation.AnnotationProcessor;
import com.sun.enterprise.deployment.annotation.ProcessingContext;
import com.sun.enterprise.deployment.annotation.factory.AnnotatedElementHandlerFactory;
import com.sun.enterprise.deployment.backend.IASDeploymentException;
import com.sun.enterprise.deployment.backend.WebArchiveDeployer;
import com.sun.enterprise.deployment.deploy.shared.AbstractArchive;
import com.sun.enterprise.deployment.deploy.shared.FileArchive;
import com.sun.enterprise.deployment.interfaces.pluggable.ArchiveDeployer;
import com.sun.enterprise.deployment.interfaces.pluggable.ArchiveDescriptor;
import com.sun.enterprise.deployment.io.DeploymentDescriptorFile;
import com.sun.enterprise.deployment.io.WebDeploymentDescriptorFile;
import com.sun.enterprise.deployment.io.runtime.WebRuntimeDDFile;
import com.sun.enterprise.deployment.pluggable.PluggableDeploymentInfo;
import com.sun.enterprise.deployment.util.DOLLoadingContextFactory;
import com.sun.enterprise.deployment.util.XModuleType;
import com.sun.enterprise.loader.ClassLoaderUtils;
import com.sun.enterprise.loader.EJBClassLoader;
import com.sun.enterprise.security.SecurityUtil;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.web.security.WebSecurityManager;
import org.xml.sax.SAXParseException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.deploy.shared.ModuleType;
import org.jvnet.glassfish.comms.deployment.backend.SipApplication;
import org.jvnet.glassfish.comms.deployment.annotations.factory.SipHandlerFactory;
import org.jvnet.glassfish.comms.deployment.annotations.scanners.SarScanner;
import org.jvnet.glassfish.comms.deployment.io.runtime.SipRuntimeDDFile;
import org.jvnet.glassfish.comms.deployment.io.SipDeploymentDescriptorFile;
import org.jvnet.glassfish.comms.extensions.Extension;
import org.jvnet.glassfish.comms.security.auth.impl.SipSecurityManager;
/**
*
* @author Prasad Subramanian
*/
public class SipArchiveDeployer extends WebArchiveDeployer
implements ArchiveDeployer {
private static StringManager newLocalStrings = StringManager.getManager(SipArchiveDeployer.class);
// Member variables
/* Private variables */
private String SIP_JAR_ENTRY = "WEB-INF/sip.xml";
private String WEB_JAR_ENTRY = "WEB-INF" + File.separator + "web.xml";
private ModuleType moduleType = XModuleType.getModuleType(this.getClass()
.getName());
private boolean isJ2eeApplication = false;
/* Protected variables */
protected SipBundleDescriptor sbd = null;
protected DeploymentDescriptorFile standardDD = new WebDeploymentDescriptorFile();
protected ClassLoader classLoader = null;
//protected ExtensionModuleConfigManager emConfigMgr = null;
// need this for representing the BundleDescriptor
protected WebBundleDescriptor descriptor = null;
//Public methods
public boolean load(ArchiveDescriptor descriptor) {
return true;
}
public boolean unload(ArchiveDescriptor descriptor) {
return true;
}
/**
* This method does the following
* a. Parse the sip.xml
* b. Process the web related bundle descriptors
* c. add the web bundle descriptor to SipBundleDescriptor
* d. During startup of the Application server reads the deployment
* except sip.xml from the generated folder.
* e. Process annotations defined by the SIP Servlet API (code to be added)
*
* @param moduleRootDirectory the directory where the archive is exploded
* @param moduleScratchDirectory the directory where the generated artifacts * are stored
* @param parentClassLoader the parent class loader for this application
* @param isStartup a boolean that indicates if this is a deployment time
* operation or startup time
*/
public ArchiveDescriptor prepare(File moduleRootDirectory,
File moduleScratchDirectory, ClassLoader parentClassLoader,
boolean isStartup) throws Exception {
classLoader = parentClassLoader;
String moduleDir = moduleRootDirectory.getAbsolutePath();
String moduleName = moduleDir.substring(moduleDir.lastIndexOf(File.separator) + 1,
moduleDir.length());
// This is the initial moduleDir
// sailfin/domains/domain1/applications/j2ee-apps/DeployTest/DeployTest-war_war
// This is the moduleDir at reDeployment
// sailfin/domains/domain1/generated/xml/j2ee-apps/DeployTest/DeployTest-war_war
String sarScanDir = moduleDir;
try {
if ((moduleDir.indexOf("generated") >= 0) &&
(moduleDir.indexOf("xml") >= 0)) {
if (getJ2eeApplication()) {
//
String earName = moduleRootDirectory.getParentFile()
.getName();
String appType = moduleRootDirectory.getParentFile()
.getParentFile()
.getName();
File domainDir = moduleRootDirectory.getParentFile()
.getParentFile()
.getParentFile()
.getParentFile()
.getParentFile();
File scanDir = new File(domainDir,
"applications" + File.separatorChar + appType +
File.separatorChar + earName + File.separatorChar +
moduleRootDirectory.getName());
sarScanDir = scanDir.getAbsolutePath();
} else {
//
String appType = moduleRootDirectory.getParentFile()
.getName();
File domainDir = moduleRootDirectory.getParentFile()
.getParentFile()
.getParentFile()
.getParentFile();
File scanDir = new File(domainDir,
"applications" + File.separatorChar + appType +
File.separatorChar + moduleRootDirectory.getName());
sarScanDir = scanDir.getAbsolutePath();
}
}
} catch (NullPointerException e) {
logger.log(Level.WARNING, e.toString());
}
//parse the web and SIP DDs
Application application = null;
WebBundleDescriptor wbd = null;
// check if this is a converged app. The rule is the presence of a
// web.xml
if (hasDDXML(moduleRootDirectory, WEB_JAR_ENTRY)) {
setConverged(true);
} else {
setConverged(false);
}
// now check is this a sub-module of an Enterprise Application
if (getJ2eeApplication()) {
// we know that its a sub-module in a EAR
wbd = (WebBundleDescriptor) getBundleDescriptor(moduleDir,
parentClassLoader);
//((SipBundleDescriptor)wbd).setConverged(isConverged());
} else if (!isStartup && (moduleDir.indexOf("nodeagents") < 0)) {
// deployment operation
//set the module type to be WAR
this.setModuleType(ModuleType.WAR);
processWebArchive();
application = getApplication();
//set the module type back to the archive deployer type
this.setModuleType(XModuleType.getModuleType(
this.getClass().getName()));
if (application != null) {
wbd = (WebBundleDescriptor) application.getStandaloneBundleDescriptor();
}
} else {
//this.setModuleType(ModuleType.WAR);
// loading application during AS startup
// Obtain the application object
application = getApplication(moduleName, moduleRootDirectory,
moduleScratchDirectory, moduleType);
//set the module type back to the archive deployer type
//this.setModuleType(XModuleType.getModuleType(
// this.getClass().getName()));
if (application != null) {
wbd = (WebBundleDescriptor) application.getStandaloneBundleDescriptor();
}
}
// check if we have sip.xml or its a DD-less archive
// If there is a DD we read it, else we initialize the DD objects for annotation
// processing.
if (hasDDXML(moduleRootDirectory, SIP_JAR_ENTRY)) {
readSipDeploymentDescriptors(moduleRootDirectory);
} else {
sbd = new SipBundleDescriptor();
SipApplication sipApplication = new SipApplication();
sbd.setSipApplication(sipApplication);
}
// set the module name
sbd.getSipApplication().setModuleName(moduleName);
//set the Referring Decsriptor
sbd.getSipApplication().setReferringDescriptor(sbd);
sbd.setConverged(isConverged());
// copy the web bundle descriptor contents to sbd.
if (wbd != null) {
if( wbd.getServletDescriptors().size() > 2 ) {
sbd.setContainsHTTPServlets(true);
}
sbd.copyWebBundleDescriptor(wbd);
sbd.setApplication(application);
}
logger.log(Level.FINE, "Version ="+sbd.getSipApplication().getApplicationVersion());
// Now process the runtime DDs
readRuntimeDeploymentDescriptors(moduleRootDirectory, sbd);
if(!isStartup && (moduleDir.indexOf("nodeagents") < 0) ) {
//runSipVerifier();
}
prepareAnnotations(sarScanDir);
if (!getJ2eeApplication()) {
if (!isStartup && (moduleDir.indexOf("nodeagents") < 0)) {
generateSipPolicy((ArchiveDescriptor)sbd);
}
}
return sbd;
}
/** Utility method to determine if this is directory deploy case or not
* The presence of a WEB-INF directory is checked to determine if this
* archive needs to be sniffed for sip annotations
* @param archiveURI
* @return boolean
*/
private boolean isDirectoryDeploy(String archiveURI) {
File directoryRoot = new File(archiveURI);
File webInfDir = new File(directoryRoot, "WEB-INF");
if(webInfDir.exists() && webInfDir.isDirectory()) {
return true;
} else {
return false;
}
}
private void prepareAnnotations(String sarScanDir)
throws DeploymentException , Exception{
if ( sbd.getSipApplication().getDeploymentErrorInfo() != null ){
Exception e = new Exception (sbd.getSipApplication().getDeploymentErrorInfo());
throw e;
}
//Create an Annotation processor here
try {
AnnotatedElementHandler aeHandler = AnnotatedElementHandlerFactory.createAnnotatedElementHandler(sbd);
SarScanner scanner = new SarScanner();
scanner.initScanRepository(new File(sarScanDir),
(WebBundleDescriptor) sbd, classLoader);
if (!scanner.getElements().isEmpty()) {
AnnotationProcessor ap = SipHandlerFactory.getAnnotationProcessor();
ProcessingContext ctx = ap.createContext();
ctx.setProcessingInput(scanner);
ctx.pushHandler(aeHandler);
ap.process(ctx);
postProcessAnnotations();
}
} catch (DeploymentException e) {
throw e;
}
catch (Exception ioe) {
ioe.printStackTrace();
logger.log(Level.SEVERE, ioe.toString());
}
}
@Override
public void removePolicy() throws IASDeploymentException {
try {
super.removePolicy();
String requestName = request.getName();
cleanSecurityContext(requestName);
String[] ctxIds = SipSecurityManager.getContextsForApp(requestName, true);
if (ctxIds != null) {
for (String pid : ctxIds) {
SecurityUtil.removePolicy(pid);
}
}
} catch (IASSecurityException ex) {
Logger.getLogger(SipArchiveDeployer.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void cleanSecurityContext(String appName) {
// String[] ctxIds = SipSecurityManager.getContextsForApp(appName, false);
// if(ctxIds != null){
// for (String pid : ctxIds) {
// try {
// SecurityUtil.removePolicy(pid);
// } catch (IASSecurityException ex) {
// ex.printStackTrace();
// Logger.getLogger(ConvergedContextConfig.class.getName()).log(Level.SEVERE, null, ex);
// }
// }
// }
ArrayList<SipSecurityManager> managers =
SipSecurityManager.getManagersForApp(appName, false);
for (int i = 0; managers != null && i < managers.size(); i++) {
try {
managers.get(i).destroy();
} catch (javax.security.jacc.PolicyContextException pce) {
pce.printStackTrace();
// log it and continue
//_logger.log(Level.WARNING,
// "Unable to destroy WebSecurityManager",
// pce);
}
}
}
public void generateSipPolicy(ArchiveDescriptor desc) throws Exception {
super.generatePolicy();
SipBundleDescriptor sipDesc = (org.jvnet.glassfish.comms.deployment.backend.SipBundleDescriptor) desc;
SipApplication sipApplication = (SipApplication) sipDesc.getSipApplication();
SipSecurityManager manager = SipSecurityManager.createManager(sipDesc, true);
String pContextId = manager.getContextID();
if (!manager.inService()) {
new DescriptorProcessor().process(pContextId, sipApplication);
}
}
public void removePolicy(String appName) throws Exception {
try {
cleanSecurityContext(appName);
String[] ctxIds = SipSecurityManager.getContextsForApp(appName, true);
if (ctxIds != null) {
for (String pid : ctxIds) {
SecurityUtil.removePolicy(pid);
}
}
ArrayList<WebSecurityManager> managers =
WebSecurityManager.getManagersForApp(appName, false);
for (int i = 0; managers != null && i < managers.size(); i++) {
try {
managers.get(i).destroy();
} catch (javax.security.jacc.PolicyContextException pce) {
// log it and continue
logger.log(Level.WARNING,
"Unable to destroy WebSecurityManager",
pce);
}
}
ctxIds = WebSecurityManager.getContextsForApp(appName, true);
if (ctxIds != null && ctxIds.length > 0 && ctxIds[0] != null) {
SecurityUtil.removePolicy(ctxIds[0]);
}
} catch (IASSecurityException ex) {
throw new IASDeploymentException( ex);
}
}
public void generatePolicy(ArchiveDescriptor desc) throws Exception {
SipBundleDescriptor sipDesc = (org.jvnet.glassfish.comms.deployment.backend.SipBundleDescriptor) desc;
SipApplication sipApplication = (SipApplication) sipDesc.getSipApplication();
SipSecurityManager manager = SipSecurityManager.createManager(sipDesc, true);
String pContextId = manager.getContextID();
if (!manager.inService()) {
new DescriptorProcessor().process(pContextId, sipApplication);
}
}
private void postProcessAnnotations() throws Exception {
postProcessServletAnnotations();
postProcessListenerAnnotations();
postProcessSipApplicationKeyAnnotations();
}
/**
* Post process the listener annotations. The matching listeners
* will be added to the listener list.
*
* @throws DeploymentException
*/
private void postProcessListenerAnnotations() throws DeploymentException {
SipApplication sipApplication = (SipApplication) sbd.getSipApplication();
Collection<SipListener> listeners = sipApplication.getAnnotatedListeners();
ApplicationMatcher matcher = new ApplicationMatcher(sipApplication);
for (SipListener listener : listeners) {
/// XXX: Commenting out for now.
/*if (matcher.match(listener.getPackageName(),
listener.getApplicationName())) { */
sipApplication.addListener(listener.getListenerClass());
}
}
/**
* Post process SipApplicationKey annotations.
* There may only be one matching such per application.
*
* @throws DeploymentException
*/
private void postProcessSipApplicationKeyAnnotations()
throws DeploymentException {
SipApplication sipApplication = (SipApplication) sbd.getSipApplication();
/**
* Fetch the candidates.
*/
Collection<SipApplicationKey> sipApplicationKeyAnnotationCandidates = sipApplication.getAnnotatedSipApplicationKeys();
ApplicationMatcher matcher = new ApplicationMatcher(sipApplication);
/**
* Create temporary object that stores all application name matching such
*/
ArrayList<SipApplicationKey> matchingSipApplicationKeyAnnotations = new ArrayList<SipApplicationKey>();
/**
* Match.
*/
for (SipApplicationKey listener : sipApplicationKeyAnnotationCandidates) {
/* if (matcher.match(listener.getPackageName(),
listener.getApplicationName())) { */
matchingSipApplicationKeyAnnotations.add(listener);
/* } */
}
/**
* There may be at most one matching @SipApplicationKey
*/
if (matchingSipApplicationKeyAnnotations.size() > 1) {
// Several sipApplicationKey methods
String errMsg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.duplicatesak.found",
sipApplication.getModuleID());
logger.log(Level.SEVERE, errMsg );
String exMsg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.cannot.have.dupsak");
throw new DeploymentException(exMsg);
}
if (matchingSipApplicationKeyAnnotations.size() == 1) {
sipApplication.setSipApplicationKey(matchingSipApplicationKeyAnnotations.get(
0).getApplicationKeyMethod());
}
}
private void postProcessServletAnnotations() throws Exception {
// Rules for adding annotated SipServlets
// 1. If only one annotated SipServlet exists, then the SipApplication
// annotation is optional.
// Otherwise a logging error
SipApplication sipApplication = (SipApplication) sbd
.getSipApplication();
String ApplicationName = sipApplication.getAppName();
String mainServletName = sipApplication.getMainservletName();
Map<String, Servlet> annotatedServlets = sipApplication.getAnnotatedServlets();
if (annotatedServlets == null || annotatedServlets.isEmpty()) {
Extension.getInstance().processAnnotations(sipApplication);
}
// Find the number of annotated servlets
int noAnnotatedServlets = annotatedServlets.size();
// Find the number of servlets defined in the DD.
int declarativeDefinedServlets = sipApplication.getServlets().size();
// If multiple annotated servlets exists, then a main servlet has to be
// defined in the SipApplication annotation.
// If a servlet-mapping mechanism is used, then we do not need the
// main-servlet
if (mainServletName == null &&
noAnnotatedServlets > 1 &&
sipApplication.getServletMappings() == null) {
logger.log(Level.SEVERE,
"No main servlet defined in a SAR archive " +
"with multiple annotated servlets");
throw new DeploymentException(
"No main servlet defined in a SAR archive " +
"with multiple annotated servlets");
}
if ( mainServletName != null ) {
ExistsOperand existsOperand = new ExistsOperand();
existsOperand.setVariable("request.method");
Pattern pattern = new Pattern();
pattern.addCondition(existsOperand);
ServletMapping servletMapping = new ServletMapping();
servletMapping.setServletName(mainServletName);
servletMapping.setPattern(pattern);
// applicable if main servlet is annotated
Servlet servlet = annotatedServlets.remove(mainServletName);
if ( servlet != null ) {
sipApplication.addServlet(servlet);
}
sipApplication.addServletMapping(servletMapping);
}
for (String servletName : annotatedServlets.keySet()) {
Servlet servlet = annotatedServlets.get(servletName);
// Check that the servlet belongs to the same application, by bening
// defined in same package
// Check that this servlet name is not defined in sip.xml
// then ignore it.
Map<String, Servlet> servlets = sipApplication.getServlets();
// Servlets defined in sip.xml overrides annotations
if (servlets.get(servletName) != null) {
// Servlet specified in sip.xml
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO,
"Annotated servlet found with same name " +
"as servlet defined in sip.xml name = " + servletName);
logger.log(Level.INFO, "Annotated servlet discarded");
}
continue;
}
// check if the same servlet class has been defined twice using annotations and sip.xml
boolean isDuplicateClass = false;
Iterator servletNameIter = sipApplication.getServletNames();
while( servletNameIter.hasNext()) {
String servletNameinDD = (String) servletNameIter.next();
if(sipApplication.getServlet(servletNameinDD).getServletClass().equals(
servlet.getServletClass())) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.same.servlet.class.used",
servlet.getServletName());
logger.log(Level.WARNING, msg);
isDuplicateClass = true;
break;
}
}
if(isDuplicateClass) continue;
/*
* Check that the Servlet belongs to the same Application, That is
* 1. Same Package as the package-info.java package annotation, or
* 2. Same Application Name
*
*/
String servletPackage = servlet.getPackageName();
String anotatedServletApplication = servlet.getApplicationName();
/// XXX: Fix me later
/*
if (!new ApplicationMatcher(sipApplication).match(servletPackage,
anotatedServletApplication)) {
// Not in same application, discharge his servlet
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO,
"Annotated servlet found " + servletName +
" Servlet not defined as part of Sip Application " +
sipApplication.getAppName() + "and discharged");
}
continue;
} else {
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO,
"Deploying " + servletName +
" as belonging to application " +
sipApplication.getAppName());
}
}
*/
ExistsOperand existsOperand = new ExistsOperand();
// If only one annotated servlet exist, this is regarded as main
// servlet
if (servletName.equals(mainServletName) ||
(noAnnotatedServlets == 1)) {
// Create a match all Pattern
existsOperand.setVariable("request.method");
} else {
// Create a match nothing Pattern
// This is not part of Operand.getAttributeValue()
existsOperand.setVariable("NeverMatchMe");
}
sipApplication.addServlet(servlet);
if(sipApplication.getServletMappings(servletName) == null ) {
Pattern pattern = new Pattern();
pattern.addCondition(existsOperand);
ServletMapping servletMapping = new ServletMapping();
servletMapping.setServletName(servletName);
servletMapping.setPattern(pattern);
sipApplication.addServletMapping(servletMapping);
}
}
}
/**
* Expands the archive to be deployed. Delegates to the super class.
* @param archivePath the path to the archive
* @param moduleRootDirectory the directory where the contents of the
* archive would need to be copied after
* exploded
*/
public void expand(File archivePath, File moduleRootDirectory)
throws Exception {
super.expand(archivePath, moduleRootDirectory);
}
/**
* Determines if this is the correct ArchiveDeployer to process this archive
* @param archive the archive being processed
* @return boolean true if this the ArchiveDeployer implementation to
* process this archive
*/
public boolean handles(AbstractArchive archive) throws IOException {
// Need to check the case when there is no sip.xml
return hasSipXML(archive) || hasSipAnnotations(archive);
}
/**
* Main method that deals with undeployment of the SIP/Converged Applications
* @param archive the location of the archive that is being undeployed
*/
public void cleanup(File archive) {
//set the module type to be WAR
this.setModuleType(ModuleType.WAR);
processWebArchive();
cleanup_internal();
//set the module type back to the archive deployer type
this.setModuleType(XModuleType.getModuleType(this.getClass().getName()));
}
/**
* Method that returns a description for this extension module
* @return the description for this module
*/
public String getModuleDescription() {
return "SIP Application";
}
/**
* Method that returns the standard deployment descriptor
* @return the class that represents a standard deployment descriptor
* file
*/
public DeploymentDescriptorFile getStandardDDFile() {
return standardDD;
}
/**
* Returns the runtime deployment descriptor sun-web.xml in this case
* @return the class that represenst the runtime web descriptor
*/
public DeploymentDescriptorFile getConfigurationDDFile() {
return new WebRuntimeDDFile();
}
/**
* Returns the default web.xml representation
* @return the class the represents the default-web.xml
*/
public Descriptor getDefaultBundleDescriptor() {
WebBundleDescriptor webBundleDesc = DOLLoadingContextFactory.getDefaultWebBundleDescriptor();
return webBundleDesc;
}
protected boolean hasDDXML(File moduleRootDirectory, String JAR_ENTRY) {
try {
File webXML = new File(moduleRootDirectory, JAR_ENTRY);
if (!webXML.exists()) {
return false;
}
FileInputStream fis = new FileInputStream(webXML);
if (fis.read() > 0) {
fis.close();
return true;
} else {
fis.close();
return false;
}
} catch (IOException ioe) {
logger.log(Level.SEVERE, ioe.toString());
return false;
}
}
/**
* This method checks if the archive being processed has a WEB-INF/sip.xml
* or not. This is used to deteremine if this class can process this archive * or not
* @return true if there is a WEB-INF/sip.xml in the archive
*/
protected boolean hasSipXML(AbstractArchive archive)
throws IOException {
InputStream is = null;
try {
is = archive.getEntry(SIP_JAR_ENTRY);
if (is != null) {
return true;
} else {
return false;
}
} catch (IOException ioe) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.ioexception") +
ioe.getMessage();
IOException e = new IOException(msg);
e.initCause(ioe);
throw e;
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException ioexception) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.ioexception") +
ioexception.getMessage();
IOException e = new IOException(msg);
e.initCause(ioexception);
throw e;
}
}
}
/**
* This method reads the sip.xml contents into a byteArryInputStream. This
* method tries to replicate what the ServletContext.getResourceAsStream
* does
*
* @param moduleRootDirectory the directory where the module is exploded
* @param sipXmlPath the path to the sip.xml with the application
* @return InputStream
*/
protected InputStream getSipXml(File moduleRootDirectory, String sipXmlPath)
throws Exception {
File sipXmlFile = new File(moduleRootDirectory, sipXmlPath);
try {
// create a FileInputStream
FileInputStream fis = new FileInputStream(sipXmlFile);
byte[] sipXmlBytes = new byte[(int) sipXmlFile.length()];
// read the file into the byte array
int offset = 0;
int numRead = 0;
while ((offset < sipXmlBytes.length) &&
((numRead = fis.read(sipXmlBytes, offset,
sipXmlBytes.length - offset)) >= 0)) {
offset = +numRead;
}
// now create a ByteArrayInputStream
return new ByteArrayInputStream(sipXmlBytes);
} catch (FileNotFoundException fnfe) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.filenotfound") +
fnfe.getMessage();
Exception e = new Exception(msg);
e.initCause(fnfe);
throw e;
} catch (IOException ioe) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.ioexception") +
ioe.getMessage();
Exception e = new Exception(msg);
e.initCause(ioe);
throw e;
}
}
/**
* Returns the moduleType of the application being processed
* @return the ModuleType object that represents the module type of the
* application being processed
*/
public ModuleType getModuleType() {
return moduleType;
}
/**
* Sets the module type for the application being processed
* @param mType the ModuleType object representing the module type
*/
public void setModuleType(ModuleType mType) {
moduleType = mType;
}
public void setDescriptor(Descriptor descriptor) {
if (descriptor instanceof WebBundleDescriptor) {
this.descriptor = (WebBundleDescriptor) descriptor;
} else {
if (descriptor instanceof Application) {
// this is acceptable if the application actually represents
// a standalone module
java.util.Set webBundles = ((Application) descriptor).getWebBundleDescriptors();
if (webBundles.size() > 0) {
this.descriptor = (WebBundleDescriptor) webBundles.iterator()
.next();
if (this.descriptor.getModuleDescriptor().isStandalone()) {
return;
} else {
this.descriptor = null;
}
}
}
throw new RuntimeException("Error setting descriptor " +
descriptor + " in " + this);
}
}
/**
* Returns the descriptor object for the module being processed
* @return the descriptor object for the module being processed
*/
public BundleDescriptor getDescriptor() {
return descriptor;
}
/**
* This method parses the sun-sip.xml
* @param moduleRootDirectory
* @param sbd
* @throws java.lang.Exception
*/
public void readRuntimeDeploymentDescriptors(File moduleRootDirectory,
SipBundleDescriptor sbd) throws Exception {
FileArchive archive = new FileArchive();
try {
archive.open(moduleRootDirectory.getAbsolutePath());
} catch (IOException io) {
throw new Exception(io.getCause());
}
String ddFileEntryName = getRuntimeDeploymentDescriptorPath();
if (ddFileEntryName == null) {
return;
}
InputStream is = null;
try {
// apply the runtime settings if any
is = archive.getEntry(ddFileEntryName);
DeploymentDescriptorFile confDD = new SipRuntimeDDFile();
if (archive.getArchiveUri() != null) {
confDD.setErrorReportingString(archive.getArchiveUri());
}
if ((is != null) && (confDD != null)) {
confDD.setXMLValidation(super.getRuntimeXMLValidation());
confDD.setXMLValidationLevel(super.getRuntimeXMLValidationLevel());
confDD.read(sbd, is);
}
} catch (SAXParseException spe) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.saxparseexception") +
spe.getMessage();
Exception e = new Exception(msg);
e.initCause(spe);
throw e;
} catch (IOException ioe) {
String msg = newLocalStrings.getString(
"enterprise.deployment.backend.sip.ioexception") +
ioe.getMessage();
Exception e = new Exception(msg);
e.initCause(ioe);
throw e;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
throw new Exception(ioe.getCause());
}
}
}
}
public String getRuntimeDeploymentDescriptorPath() {
return new SipRuntimeDDFile().getDeploymentDescriptorPath();
}
@Override
public void runVerifier() throws IASDeploymentException {
/**
* Verification process should be deferred until the
* SipApplication is available. Hence, deliberate NO-OP here.
*/
}
private void runSipVerifier() throws Exception {
/**
* Set sbd in the ModuleDescriptor so that
* application.getModules().next() returns the newly created
* SipModule instead of WebModule.
*/
BundleDescriptor prev = sbd.getModuleDescriptor().getDescriptor();
sbd.getModuleDescriptor().setDescriptor(sbd);
super.runVerifier();
sbd.getModuleDescriptor().setDescriptor(prev);
}
/**
* Method to read the sip.xml in an archive and add a SipApplication object
* to the SipBundledescriptor passed in
* @param moduleRootDirectory the path where the archive is exploded
* @param sbd the SipBundleDescriptor object for the entire bundle
*/
public void readSipDeploymentDescriptors(File moduleRootDirectory)
throws Exception {
FileArchive archive = new FileArchive();
try {
archive.open(moduleRootDirectory.getAbsolutePath());
} catch (IOException io) {
String msg =
newLocalStrings.getString("enterprise.deployment.backend.sip.ioexception")
+ io.getMessage();
Exception e = new Exception(msg);
e.initCause(io);
throw e;
}
String ddFileEntryName = getSipDeploymentDescriptorPath();
if (ddFileEntryName == null) {
return;
}
InputStream is = null;
try {
// apply the runtime settings if any
is = archive.getEntry(ddFileEntryName);
DeploymentDescriptorFile confDD = new SipDeploymentDescriptorFile();
if (archive.getArchiveUri() != null) {
confDD.setErrorReportingString(archive.getArchiveUri());
}
if ((is != null) && (confDD != null)) {
confDD.setXMLValidation(super.getRuntimeXMLValidation());
confDD.setXMLValidationLevel(super.getRuntimeXMLValidationLevel());
SipApplication sipApplication = (SipApplication) confDD.read(is);
this.sbd = (SipBundleDescriptor) sipApplication.getReferringDescriptor();
}
} catch (SAXParseException spe) {
String msg =
newLocalStrings.getString("enterprise.deployment.backend.sip.saxparseexception")
+ spe.getMessage();
Exception e = new Exception(msg);
e.initCause(spe);
throw e;
} catch (IOException ioe) {
String msg =
newLocalStrings.getString("enterprise.deployment.backend.sip.ioexception")
+ ioe.getMessage();
Exception e = new Exception(msg);
e.initCause(ioe);
throw e;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
String msg =
newLocalStrings.getString("enterprise.deployment.backend.sip.ioexception")
+ ioe.getMessage();
Exception e = new Exception(msg);
e.initCause(ioe);
throw e;
}
}
}
}
/**
* Method to return the Deployment Descriptor path in a archive
* @return String the relative path of the DD within the archive
*/
public String getSipDeploymentDescriptorPath() {
return new SipDeploymentDescriptorFile().getDeploymentDescriptorPath();
}
public void setJ2eeApplication(boolean isJ2ee) {
this.isJ2eeApplication = isJ2ee;
}
public boolean getJ2eeApplication() {
return isJ2eeApplication;
}
/**
* This method scans the archive for annotations defined by Sip Servlet API 1.1
* @param archive
* @return boolean
* @throws java.io.IOException
*/
public boolean hasSipAnnotations(AbstractArchive archive) {
if(System.getProperty("com.sun.aas.comms.sipDDMandated") != null ) {
return false;
}
if (Extension.getInstance().isConverged(archive)) {
return true;
}
// We create a dummy descriptor for checkin for annotations in the handles() method.
SipBundleDescriptor dummySbd = new SipBundleDescriptor();
// create a new dummy SipApplication object and add it to the dummySbd
SipApplication dummySipApp = new SipApplication();
dummySbd.setSipApplication(dummySipApp);
File destForArchive = null;
boolean isDirectoryDeploy = false;
//Create an Annotation processor here
try {
// get the destination to expand this
String archiveURI = archive.getArchiveUri();
isDirectoryDeploy = isDirectoryDeploy(archiveURI);
destForArchive = new File(archiveURI.replace(".", "_"));
// It has to be a .war or .sar to have annotations defined by
// JSR289. If the extension is not either of them, we return a
// false and do not process the archive.
if(archiveURI.endsWith(".war") || archiveURI.endsWith(".sar")) {
super.expand(new File(archiveURI), destForArchive);
} else if(!isDirectoryDeploy) {
return false;
}
System.out.println("CL ::"+getClassLoader().toString());
AnnotatedElementHandler aeHandler = AnnotatedElementHandlerFactory.createAnnotatedElementHandler(dummySbd);
SarScanner scanner = new SarScanner();
scanner.initScanRepository(destForArchive,
(WebBundleDescriptor) dummySbd, getClassLoader());
if (!scanner.getElements().isEmpty()) {
AnnotationProcessor ap = SipHandlerFactory.getAnnotationProcessor();
ProcessingContext ctx = ap.createContext();
ctx.setProcessingInput(scanner);
ctx.pushHandler(aeHandler);
ap.process(ctx);
// Check if there are Servlets or Listeners. XXX: Should the check for Servlets alone be not
// enough?
if ((!dummySbd.getSipApplication().getAnnotatedServlets().isEmpty()) ||
(!dummySbd.getSipApplication().getAnnotatedListeners().isEmpty())){
dummySbd = null;
if(!isDirectoryDeploy) whackExpandedArchive(destForArchive);
return true;
} else {
dummySbd = null;
if(!isDirectoryDeploy) whackExpandedArchive(destForArchive);
return false;
}
}
} catch (Exception ex ) {
if(!isDirectoryDeploy) whackExpandedArchive(destForArchive);
logger.log(Level.WARNING, "Exception thrown in " + this.getClass() +
"while scanning for annotations");
}
if(!isDirectoryDeploy) whackExpandedArchive(destForArchive);
dummySbd = null;
return false;
}
private void whackExpandedArchive(File archiveToBeWhacked) {
if( archiveToBeWhacked != null &&
archiveToBeWhacked.exists() &&
archiveToBeWhacked.isDirectory() ) {
FileUtils.whack(archiveToBeWhacked);
}
}
/**
* Class ApplicationMatcher
*
* An ApplicationMatcher matches appName settings in an annotated object (SipServlet or SipListener) against
* name of application.
*
*
* @author qmaghes
*/
class ApplicationMatcher {
/**
* SipApplication to match against.
*/
SipApplication sipApplication;
public ApplicationMatcher(SipApplication application) {
this.sipApplication = application;
}
/**
* match application name against SipApplication
* There are three possible outcomes.
* 1. Returns true if this object belongs to application and should be deployed
* 2. Returns false if this object belongs to another application and should not be deployed.
* 3. Throws DeploymentException if the settings are invalid and JSR289 mandates deployment error.
*
* @param objectPackageName
* @param objectAnnotatedApplicationName
* @return
* @throws DeploymentException
*/
public boolean match(String objectPackageName,
String objectAnnotatedApplicationName) {
if (noApplicationNameSet()) {
logger.log(Level.WARNING,
"Application name is not specified, though it is mandatory for sipservlet 1.1 applications");
return false;
//throw new DeploymentException(
// "Application name is not specified, though it is mandatory for sipservlet 1.1 applications");
}
if (hasSpecifiedApplicationName(objectAnnotatedApplicationName)) {
return sameApplicationName(objectAnnotatedApplicationName);
} else {
// has not specified application
// There are three possibilities
// since we have already checked that
// appname is set somehow.
//
// 1. Appname set in DD => OK
// 2. Appname set in same package => OK
// 3. Appname set in other package => Deployment error
if (isApplicationNameSpecifiedInDD()) {
return true;
} else {
if (belongsToPackage(objectPackageName)) {
return true;
} else {
logger.log(Level.WARNING, "Application \'" +
sipApplication.getAppName() +
"\' not deployed since some SipListeners or SipServlets has not specified appName in annotation");
return false;
//throw new DeploymentException("Application \'" +
// sipApplication.getAppName() +
// "\' not deployed since some SipListeners or SipServlets has not specified appName in annotation");
}
}
}
}
private boolean noApplicationNameSet() {
return sipApplication.getAppName() == null;
}
/**
*
* @return
*/
private boolean isApplicationNameSpecifiedInDD() {
return sipApplication.isAppNameFromDD();
}
private boolean sameApplicationName(String annotatedListenerApplication) {
return annotatedListenerApplication.equals(sipApplication.getAppName());
}
private boolean belongsToPackage(String listenerPackage) {
String packageInfoPackage = sipApplication.getPackageName();
return (packageInfoPackage != null) && (listenerPackage != null) &&
listenerPackage.equals(packageInfoPackage);
}
private boolean hasSpecifiedApplicationName(
String annotatedListenerApplication) {
return !"".equals(annotatedListenerApplication);
}
}
}