org.ow2.jonas.web.base.BaseWebContainerService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jonas-web-container-base Show documentation
Show all versions of jonas-web-container-base Show documentation
Abstract Web Container used by different implementations
/**
* JOnAS: Java(TM) Open Application Server
* Copyright (C) 1999-2009 Bull S.A.S.
* Contact: [email protected]
*
* This library 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 any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: BaseWebContainerService.java 20789 2011-01-28 14:46:16Z sauthieg $
* --------------------------------------------------------------------------
*/
package org.ow2.jonas.web.base;
import static org.ow2.jonas.ws.jaxws.IJAXWSService.KEY_WEB_SERVICES_METADATAS;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.LinkRef;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContextType;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.easybeans.deployment.api.EZBInjectionHolder;
import org.ow2.easybeans.persistence.api.EZBPersistenceUnitManager;
import org.ow2.easybeans.resolver.api.EZBJNDIResolver;
import org.ow2.easybeans.resolver.api.EZBJNDIResolverException;
import org.ow2.jonas.Version;
import org.ow2.jonas.deployment.api.IEJBLocalRefDesc;
import org.ow2.jonas.deployment.api.IEJBRefDesc;
import org.ow2.jonas.deployment.api.IEnvEntryDesc;
import org.ow2.jonas.deployment.api.IMessageDestinationRefDesc;
import org.ow2.jonas.deployment.api.IResourceEnvRefDesc;
import org.ow2.jonas.deployment.api.IResourceRefDesc;
import org.ow2.jonas.deployment.api.IServiceRefDesc;
import org.ow2.jonas.deployment.common.DeploymentDescException;
import org.ow2.jonas.deployment.web.WebContainerDeploymentDesc;
import org.ow2.jonas.deployment.web.lib.WarDeployableMetadataFactoryHolder;
import org.ow2.jonas.deployment.web.lib.WebDeploymentDescManager;
import org.ow2.jonas.ejb3.IEasyBeansService;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.lib.bootstrap.LoaderManager;
import org.ow2.jonas.lib.loader.FilteringClassLoader;
import org.ow2.jonas.lib.loader.SimpleWebappClassLoader;
import org.ow2.jonas.lib.loader.WebappClassLoader;
import org.ow2.jonas.lib.naming.ComponentContext;
import org.ow2.jonas.lib.security.PermissionManagerException;
import org.ow2.jonas.lib.service.AbsServiceImpl;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.lib.work.DeployerLog;
import org.ow2.jonas.lib.work.DeployerLogException;
import org.ow2.jonas.naming.JComponentContextFactory;
import org.ow2.jonas.naming.JNamingManager;
import org.ow2.jonas.service.ServiceException;
import org.ow2.jonas.versioning.VersioningService;
import org.ow2.jonas.web.JWebContainerService;
import org.ow2.jonas.web.JWebContainerServiceException;
import org.ow2.jonas.web.base.lib.PermissionManager;
import org.ow2.jonas.web.base.proxy.HttpOnDemandProxy;
import org.ow2.jonas.web.base.proxy.HttpOnDemandProxyException;
import org.ow2.jonas.workcleaner.CleanTask;
import org.ow2.jonas.workcleaner.WorkCleanerService;
import org.ow2.jonas.ws.jaxrpc.IJAXRPCService;
import org.ow2.jonas.ws.jaxws.IJAXWSService;
import org.ow2.util.archive.api.ArchiveException;
import org.ow2.util.archive.api.IArchive;
import org.ow2.util.archive.impl.ArchiveManager;
import org.ow2.util.ee.deploy.api.deployable.EARDeployable;
import org.ow2.util.ee.deploy.api.deployable.IDeployable;
import org.ow2.util.ee.deploy.api.deployable.WARDeployable;
import org.ow2.util.ee.deploy.api.deployer.DeployerException;
import org.ow2.util.ee.deploy.api.deployer.IDeployerManager;
import org.ow2.util.ee.deploy.impl.helper.DeployableHelper;
import org.ow2.util.ee.deploy.impl.helper.UnpackDeployableHelper;
import org.ow2.util.ee.metadata.common.api.enc.IENCBinding;
import org.ow2.util.ee.metadata.common.api.enc.IENCBindingHolder;
import org.ow2.util.ee.metadata.common.api.struct.IJEjbEJB;
import org.ow2.util.ee.metadata.common.api.struct.IJavaxPersistenceContext;
import org.ow2.util.ee.metadata.common.api.struct.IJavaxPersistenceUnit;
import org.ow2.util.ee.metadata.common.api.struct.IJaxwsWebServiceRef;
import org.ow2.util.ee.metadata.war.api.IWarDeployableMetadataFactory;
import org.ow2.util.file.FileUtils;
import org.ow2.util.file.FileUtilsException;
import org.ow2.util.url.URLUtils;
/**
* This abstract class provides an implementation for a dynamic JWebContainerService service.
* @author Florent Benoit
* @author Ludovic Bert (J2EE 1.3)
* @author Nicolas Van Caneghem (exploded ear)
* @author Michel-Ange Anton (contributor)
* @author S. Ali Tokmen (versioning)
*/
public abstract class BaseWebContainerService extends AbsServiceImpl implements JWebContainerService,
BaseWebContainerServiceMBean {
/**
* The name of the JONAS_BASE directory.
*/
protected static final String JONAS_BASE = JProp.getJonasBase();
/**
* The name of the working directory.
*/
protected static final String WORK_DIR = JProp.getWorkDir();
/**
* The name of the working apps directory.
*/
protected static final String WORK_WEBAPPS_DIR = WORK_DIR + File.separator + "webapps";
/**
* The name of the property used in work directory for single webapps (not ear case).
*/
protected static final String SINGLE_WORK_WEBAPPS_DIR_SUFFIX = "single";
/**
* The name of the property used in work directory for EAR webapps (in ear case).
*/
protected static final String INEAR_WORK_WEBAPPS_DIR_SUFFIX = "ear";
/**
* Length of the extension .war.
*/
private static final int WAR_EXTENSION_LENGTH = ".war".length();
/**
* Logger for this service.
*/
private static Logger logger = Log.getLogger(Log.JONAS_WEB_PREFIX);
/**
* Reference on the NamingManager.
*/
private JNamingManager naming;
/**
* War deployer.
*/
private WARDeployer warDeployer = null;
/**
* Reference on the ComponentContextFactory.
*/
private JComponentContextFactory contextFactory;
/**
* Associates an URL of an unpacked WAR file to its classloader.
*/
private Hashtable warLoaders = new Hashtable();
/**
* Associates an URL of a deployed WAR file to its classloader.
*/
private Hashtable warBindings = new Hashtable();
/**
* JMX Service.
*/
protected JmxService jmxService = null;
/**
* List of the war deployed by the Web container Service.
*/
private List warDeployed = new Vector();
/**
* Map of the unpacked WARs.
*/
private Map unpackedWARs = new HashMap();
/**
* Name of the server (Tomcat, Jetty, ...).
*/
private String serverName = null;
/**
* Version of the web container.
*/
private String serverVersion = null;
/**
* Reference to the JAX-RPC service.
*/
private IJAXRPCService jaxrpcService = null;
/**
* External Classloader.
*/
private ClassLoader extClassLoader;
/**
* DeployerManager service.
*/
private IDeployerManager deployerManager;
/**
* Versioning service.
*/
private VersioningService versioningService;
/**
* Working directory for applications.
*/
private File workSingleWebAppsFile = null;
/**
* Reference to the {@link DeployerLog} of the Web Container service.
*/
private DeployerLog deployerLog;
/**
* Reference to the JAXWS Service.
*/
private IJAXWSService jaxwsService;
/**
* EasyBeans service.
*/
private IEasyBeansService ejb3Service = null;
/**
* On demand feature enabled ?
*/
private boolean onDemandFeatureEnabled = false;
/**
* Link to the OnDemandProxy.
*/
private HttpOnDemandProxy onDemandProxy = null;
/**
* Given port used for redirecting the requests (OnDemand proxy).
* This port will be used to launch the internal web container (tomcat, jetty, etc)
*/
private int onDemandRedirectPort = 0;
/**
* Default constructor.
*/
public BaseWebContainerService() {
this.warDeployer = new WARDeployer();
this.onDemandProxy = new HttpOnDemandProxy();
}
/**
* @param validate must we parse web.xml files with validation ?
*/
public void setParsingwithvalidation(final boolean validate) {
WebDeploymentDescManager.setParsingWithValidation(validate);
if (logger.isLoggable(BasicLevel.DEBUG)) {
if (!validate) {
logger.log(BasicLevel.DEBUG, "Web XML parsing without validation");
} else {
logger.log(BasicLevel.DEBUG, "Web XML parsing with validation");
}
}
}
/**
* Start the service.
* @throws ServiceException if the startup failed.
*/
@Override
protected void doStart() throws ServiceException {
initWorkingDirectory();
// get apps ClassLoader
try {
LoaderManager lm = LoaderManager.getInstance();
extClassLoader = lm.getExternalLoader();
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "Cannot get the Applications ClassLoader from Web Container Service: ", e);
throw new ServiceException("Cannot get the Applications ClassLoader from Web Container Service", e);
}
if (onDemandFeatureEnabled && !getServerProperties().isDevelopment()) {
logger.log(BasicLevel.INFO, "The OnDemand feature is disabled in production mode");
onDemandFeatureEnabled = false;
}
// Start the proxy if with mode onDemand ?
if (onDemandFeatureEnabled) {
// Register proxy on the deployer
warDeployer.setOnDemandProxy(onDemandProxy);
// Register ourself on the proxy
onDemandProxy.setWebContainerService(this);
onDemandProxy.setHttpPortNumber(Integer.parseInt(getDefaultHttpPort()));
// If 0, needs to send a random port
if (onDemandRedirectPort == 0) {
this.onDemandRedirectPort = getRandomPort();
}
onDemandProxy.setRedirectPortNumber(onDemandRedirectPort);
// Start the proxy port
try {
onDemandProxy.enable();
} catch (HttpOnDemandProxyException e) {
logger.log(BasicLevel.ERROR, "Cannot start the OnDemand proxy for web container: ", e);
throw new ServiceException("Cannot start the OnDemand proxy for web container", e);
}
logger.log(BasicLevel.INFO, "OnDemand Feature enabled: Listening on '" + onDemandProxy.getHttpPortNumber() + "' port (internal:" + onDemandProxy.getRedirectPortNumber() + ").");
}
// Init the deployer
warDeployer.setWebContainerService(this);
// Register the deployer
deployerManager.register(warDeployer);
// Register the MBean
registerWebServiceMBean(this, getDomainName());
}
/**
* Stop the service.
* @throws ServiceException if the stop failed.
*/
@Override
protected void doStop() throws ServiceException {
// Undeploy standalone WARs
warDeployer.stop();
if (deployerManager != null) {
// Unregister the deployer
deployerManager.unregister(warDeployer);
}
if (onDemandProxy != null) {
try {
onDemandProxy.disable();
} catch (HttpOnDemandProxyException e) {
logger.log(BasicLevel.WARN, "Cannot stop the OnDemand proxy", e);
}
}
unregisterWebServiceMBean(getDomainName());
logger.log(BasicLevel.DEBUG, "WebContainerService stopped");
}
/**
* Create the environment and delegate the operation to the implementation of the web container.
* @param ctx the context which contains the configuration in order to deploy a WAR.
* @throws JWebContainerServiceException if the registration of the WAR failed.
*/
protected abstract void doRegisterWar(Context ctx) throws JWebContainerServiceException;
/**
* Delegate the unregistration to the implementation of the web container.
* @param ctx the context which contains the configuration in order to undeploy a WAR.
* @throws JWebContainerServiceException if the unregistration failed.
*/
protected abstract void doUnRegisterWar(Context ctx) throws JWebContainerServiceException;
/**
* Starts the specific code for the web container implementation.
* This allows to start the internal container on demand (if there is an access on the http proxy port for example)
* @throws JWebContainerServiceException if container is not started
*/
public abstract void startInternalWebContainer() throws JWebContainerServiceException;
/**
* Checks if the internal web container has been started.
* @return true if it is already started
*/
public abstract boolean isInternalContainerStarted();
/**
* Return the URL where warURL has been unpacked.
* @param warURL the URL of the war
* @param earDeployable the EAR deployable (could be null)
* @return the URL where warURL has been unpacked.
* @throws JWebContainerServiceException when it is impossible to retrieve the unpacked URL.
*/
protected URL getUnpackedURL(final URL warURL, final EARDeployable earDeployable) throws JWebContainerServiceException {
String folder = WORK_WEBAPPS_DIR + File.separator + getJonasServerName() + File.separator;
// Two cases :
// war is alone --> unpack it in :
// WEBAPPS_DIR/servername/single/war_filename_timestamp/
// war come from an ear --> unpack it in :
// WEBAPPS_DIR/servername/ear/ear_filename_timestamp/war_filename__timestamp/
File warFile = URLUtils.urlToFile(warURL);
// Build destination folder name
if (earDeployable != null) {
// The destination directory is built from the filename of the unpacked ear,
// that is to say, the parent folder of the original war URL.
String earFileName = warFile.getParentFile().getName();
if (!getServerProperties().isDevelopment()) {
try {
earFileName = URLUtils.urlToFile(earDeployable.getOriginalDeployable().getArchive().getURL()).getName();
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "Cannot retrieve the original deployable");
}
}
folder += INEAR_WORK_WEBAPPS_DIR_SUFFIX + File.separator + earFileName;
} else {
folder += SINGLE_WORK_WEBAPPS_DIR_SUFFIX + File.separator;
}
// Build destination archive name
String archiveName = warFile.getName();
if (getServerProperties().isDevelopment() && earDeployable == null) {
try {
archiveName = FileUtils.lastModifiedFileName(warFile);
} catch (FileUtilsException e) {
throw new JWebContainerServiceException("Failed creating the destination name", e);
}
}
try {
IArchive archive = ArchiveManager.getInstance().getArchive(warFile);
WARDeployable warDeployable = (WARDeployable) DeployableHelper.getDeployable(archive);
UnpackDeployableHelper.unpack(warDeployable, new File(folder), archiveName, false);
return warDeployable.getUnpackedDeployable().getArchive().getURL();
} catch (Exception e) {
throw new JWebContainerServiceException("Failed unpacking the war file " + warFile, e);
}
}
/**
* Return the class loader of the given warURL. Unpack the associated war and build the loader if it's not in the cache.
* @param warURL the url of the war we want to get the loader
* @param earDeployable If the WAR is in an EAR application
* @param parentLoader the ejb class loader of the ear. May be null in non ear case.
* @return the class loader of the given warURL.
* @throws JWebContainerServiceException if the process failed.
*/
public WebappClassLoader getClassLoader(final URL warURL, final EARDeployable earDeployable, final ClassLoader parentLoader)
throws JWebContainerServiceException {
WebappClassLoader loaderForCls = null;
try {
WebLoaderHolder holder = (WebLoaderHolder) warLoaders.get(warURL);
if (holder != null) {
loaderForCls = holder.getJonasWebLoader();
}
} catch (Exception e) {
throw new JWebContainerServiceException("Error when getting '" + warURL + "' in cache", e);
}
if (loaderForCls == null) {
// the war is not already used
// Use the unpacked directory
URL unpackedWarURL = getUnpackedURL(warURL, earDeployable);
try {
if (parentLoader != null) {
// ear case.
loaderForCls = new WebappClassLoader(unpackedWarURL, parentLoader);
} else {
// Case of non-ear application : only a single war
loaderForCls = new WebappClassLoader(unpackedWarURL, extClassLoader);
}
} catch (IOException ioe) {
throw new JWebContainerServiceException("Cannot create WebAppClassLoader from '" + unpackedWarURL + "'", ioe);
}
// add the class loader in cache.
try {
WebLoaderHolder holder = new WebLoaderHolder(loaderForCls, null);
warLoaders.put(warURL, holder);
} catch (Exception e) {
throw new JWebContainerServiceException("Error when adding '" + warURL + "' in cache", e);
}
}
return loaderForCls;
}
/**
* @param warURL the URL of the webapp
* @return Returns the ClassLoader used to link a JNDI environnment to a webapp
*/
public ClassLoader getContextLinkedClassLoader(final URL warURL) {
WebLoaderHolder holder = (WebLoaderHolder) warLoaders.get(warURL);
if (holder != null) {
return holder.getEnvWebLoader();
}
return null;
}
/**
* Create the environment and delegate the operation to the implementation of the web container.
* @param ctx the context which contains the configuration in order to deploy a WAR.
* @throws JWebContainerServiceException if the registration of the WAR failed.
*/
protected void registerWar(final Context ctx) throws JWebContainerServiceException {
// There are 6 possible parameters :
// - warURL is the URL of the war to deploy (required param).
// - parentClassLoader is the parent classloader of
// the web classloader (optional param).
// - earClassLoader is the ear classloader (optional param).
// - earURL is the URL of the ear (optional parameter :
// if earURL is set it means that we are in the ear case, else it
// means that we are in the non ear case).
// - earDeployable the EARDeployable of the ear application file.
// (optional parameter, same comment as earURL).
// - altDD is the optional deployment descriptor (optional param).
// - contextRoot is the context root for the Web application
// (optional param).
// Get the URL of the ear application file in the case of an
// ear application, null otherwise.
URL earURL = null;
EARDeployable earDeployable = null;
String contextRoot = null;
String earAppName = null;
String userURI = null;
// Injection holder
EZBInjectionHolder ezbInjectionHolder = null;
try {
earURL = (URL) ctx.lookup("earURL");
earDeployable = (EARDeployable) ctx.lookup("earDeployable");
contextRoot = (String) ctx.lookup("contextRoot");
} catch (NamingException e) {
if (earURL != null || earDeployable != null || contextRoot != null) {
String err = "Error while getting parameter from context param :" + e.getMessage();
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err, e);
} // else nothing to do : non-ear case.
}
// Get EAR application name
if (earDeployable != null) {
earAppName = earDeployable.getModuleName();
}
// Get the URL of the war to deploy ...
URL warURL = null;
try {
warURL = (URL) ctx.lookup("warURL");
} catch (NamingException e) {
String err = "Error while getting parameter from context param :" + e.getMessage();
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err, e);
}
// Get injection holder
try {
ezbInjectionHolder = (EZBInjectionHolder) ctx.lookup(EZBInjectionHolder.class.getName());
} catch (NamingException e) {
logger.log(BasicLevel.DEBUG, "No injection holder");
// Create a new one if not yet existing
if (ejb3Service != null) {
ezbInjectionHolder = ejb3Service.buildInjectionHolder(null, null);
}
}
// ... and check if the war to deploy exists.
File warFile = URLUtils.urlToFile(warURL);
if (!warFile.exists()) {
String err = "registerWar: '" + warFile.getPath() + "' not found";
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err);
}
// Check if the war to deploy is not already deployed.
War war = getWar(warURL);
if (war != null) {
// The war is already deployed.
String err = "Cannot deploy war '" + warURL.getFile() + "' is already deployed."
+ " You must undeploy the war before a new deployment.";
throw new JWebContainerServiceException(err);
}
URLClassLoader parentLoader = null;
URLClassLoader earClassLoader = null;
boolean isInEar = true;
try {
parentLoader = (URLClassLoader) ctx.lookup("parentClassLoader");
earClassLoader = (URLClassLoader) ctx.lookup("earClassLoader");
} catch (NamingException ne) {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Not an ear case");
}
isInEar = false;
// exception occurs when the earClassLoader is not found.
}
// Check WsGen for webapp outside of an Ear
if (!isInEar) {
try {
applyWSGenIfNeeded(warFile.getCanonicalPath());
} catch (Exception e) {
throw new JWebContainerServiceException("Cannot apply WsGen on the file : " + warFile, e);
}
}
// Get the war class loader.
WebappClassLoader loaderForCls = getClassLoader(warURL, earDeployable, parentLoader);
// Get the URL of the unpacked WAR
URL unpackedWarURL = loaderForCls.getBaseURL();
// The file is unpacked, so log it
if (deployerLog != null && !isInEar && getServerProperties().isDevelopment()) {
try {
deployerLog.addEntry(warFile, URLUtils.urlToFile(unpackedWarURL));
} catch (Exception e) {
String err = "Error while adding the " + warFile + " entry in the log file";
logger.log(BasicLevel.ERROR, err + " : " + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
}
// Only if the JAX-RPC Service is started
// And in non EAR case
if (jaxrpcService != null && earClassLoader == null) {
try {
ComponentContext contctx = null;
try {
contctx = new ComponentContext(unpackedWarURL.getFile());
File unpackedWarFile = URLUtils.urlToFile(unpackedWarURL);
contctx.rebind(IJAXRPCService.UNPACK_DIRECTORY_CTX_PARAM, unpackedWarFile);
contctx.rebind("jarUrls", new URL[0]);
contctx.rebind("warUrls", new URL[] {warURL});
if (parentLoader != null) {
contctx.rebind("ejbClassLoader", parentLoader);
}
} catch (NamingException e) {
String err = "Can not bind params for the WebServices service, " + "Can't deploy Web Services Endpoint";
throw new JWebContainerServiceException(err, e);
}
jaxrpcService.deployWebServices(contctx);
} catch (ServiceException se) {
String err = "Error during the deployment of the WebServices of the War file '" + warURL + "'";
logger.log(BasicLevel.ERROR, err + " : " + se.getMessage());
throw new JWebContainerServiceException(err, se);
}
}
// Get the deployment descriptor from file
WebContainerDeploymentDesc webDD = null;
try {
WebDeploymentDescManager manager = WebDeploymentDescManager.getInstance();
webDD = manager.getDeploymentDesc(unpackedWarURL, warURL, loaderForCls, earClassLoader);
} catch (DeploymentDescException e) {
String err = "Cannot read the deployment descriptors '" + warURL.getFile() + "'";
logger.log(BasicLevel.ERROR, err + ": " + e);
e.printStackTrace(System.err);
throw new JWebContainerServiceException(err, e);
}
// Populate the java:comp/env (ENC) environment.
ClassLoader webClassLoader = null;
try {
FilteringClassLoader filteringClassLoader = createFilteringClassLoader(parentLoader,
unpackedWarURL);
webClassLoader = new SimpleWebappClassLoader(unpackedWarURL, filteringClassLoader);
} catch (Exception e) {
throw new JWebContainerServiceException("Unable to create classloader", e);
}
// Persistence unit entry present ?
IArchive archive = ArchiveManager.getInstance().getArchive(URLUtils.urlToFile(unpackedWarURL));
List persistenceArchives = new ArrayList();
List urlsToAddToClassLoader = new ArrayList();
// Add WEB-INF/classes for the classloader if there are persistence classes
URL urlWebInfClasses = webClassLoader.getResource("WEB-INF/classes/");
if (urlWebInfClasses != null) {
urlsToAddToClassLoader.add(urlWebInfClasses);
}
// Check entry in the war
URL persistenceXmlEntryInWarFile = webClassLoader.getResource("WEB-INF/classes/META-INF/persistence.xml");
if (persistenceXmlEntryInWarFile != null) {
// There is an entry, add the archive to be analyzed
persistenceArchives.add(archive);
}
// Check entries in each library
try {
Iterator itURLEntries = archive.getResources();
while (itURLEntries.hasNext()) {
URL urlWarEntry = itURLEntries.next();
// There are jar files
if (urlWarEntry.toExternalForm().contains("/WEB-INF/lib/") && urlWarEntry.toExternalForm().endsWith(".jar")) {
IArchive archiveLib = ArchiveManager.getInstance().getArchive(URLUtils.urlToFile(urlWarEntry));
URL persistenceXmlInLib = archiveLib.getResource("META-INF/persistence.xml");
if (persistenceXmlInLib != null) {
persistenceArchives.add(archiveLib);
}
urlsToAddToClassLoader.add(urlWarEntry);
}
}
} catch (ArchiveException e) {
throw new JWebContainerServiceException("Cannot check for persistence", e);
}
// there are archives to analyze
if (persistenceArchives.size() > 0) {
if (ejb3Service != null) {
// Add URLs to the classLoader
for (URL urlToAdd : urlsToAddToClassLoader) {
((SimpleWebappClassLoader) webClassLoader).addURL(urlToAdd);
}
// Create EasyBeans ClassLoader
webClassLoader = ejb3Service.buildByteCodeEnhancementClassLoader(new URL[0], webClassLoader);
// Analyze each persistence archive
for (IArchive persistenceArchive : persistenceArchives) {
EZBPersistenceUnitManager persistenceUnitManager = null;
try {
persistenceUnitManager = ejb3Service.getPersistenceUnitManager(persistenceArchive, webClassLoader);
} catch (org.ow2.easybeans.persistence.api.PersistenceXmlFileAnalyzerException e) {
throw new JWebContainerServiceException("Unable to analyze persistence.xml file", e);
}
EZBPersistenceUnitManager existingPersistenceUnitManager = ezbInjectionHolder.getPersistenceUnitManager();
if (existingPersistenceUnitManager == null) {
ezbInjectionHolder = ejb3Service.buildInjectionHolder(persistenceUnitManager, ezbInjectionHolder
.getJNDIResolver());
} else {
// add unit infos
existingPersistenceUnitManager.merge(persistenceUnitManager);
}
}
} else {
logger.log(BasicLevel.WARN, "Persistence archives + '" + persistenceArchives + "' found but no EJB3 service");
}
}
try {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Populating environment of the file " + warURL.getFile());
}
Context ctxParam = new ComponentContext(unpackedWarURL.getFile());
ctxParam.rebind("DeploymentDesc", webDD);
ctxParam.rebind("warName", unpackedWarURL.getFile());
if (earDeployable != null) {
ctxParam.rebind("earDeployable", earDeployable);
}
ctxParam.rebind("parentCL", webClassLoader);
// Do the populating of the java:comp/env (ENC) environment.
setWebEnvironment(ctxParam, ezbInjectionHolder, webClassLoader);
} catch (Exception e) {
// populating environment failed.
String err = "Error when populating ";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// TODO maybe to be removed ?
WebLoaderHolder holder = (WebLoaderHolder) warLoaders.get(warURL);
holder.setEnvWebLoader(webClassLoader);
contextRoot = getContextRoot(contextRoot, earClassLoader, warURL, webDD);
String versionID = null;
if (isVersioningEnabled()) {
if (earURL != null) {
versionID = versioningService.getVersionID(earDeployable);
} else {
versionID = versioningService.getVersionID(warURL);
}
// TODO: prefix for deploying MBeans inside this WAR (filters, ...)
}
if (versionID == null) {
userURI = contextRoot;
} else {
if (!contextRoot.contains(versionID)) {
userURI = contextRoot;
contextRoot += versionID;
} else {
userURI = contextRoot.replace(versionID, "");
}
if (userURI.equals("/") && contextRoot.charAt(0) == '/') {
// ensure context-root is valid (remove starting /)
contextRoot = contextRoot.substring(1);
}
}
// Set the name of the host where to deploy the war if it is
// specified in the jonas-web.xml.
String hostName = webDD.getHost();
// Check if the context to deploy is not already deployed.
List deployedWars = getWar(contextRoot);
for (Iterator itDeployed = deployedWars.iterator(); itDeployed.hasNext();) {
War deployedWar = (War) itDeployed.next();
String hostDeployed = deployedWar.getHostName();
if ((hostDeployed == null && hostName == null) || (hostDeployed != null && hostDeployed.equals(hostName))) {
// The war is already deployed.
String err = "Cannot deploy war '" + warURL.getFile() + "' is already deployed with the context '"
+ contextRoot + "'." + " You must undeploy the war before a new deployment.";
throw new JWebContainerServiceException(err);
}
}
// Context classloader must follow the java2 delegation model ?
boolean java2DelegationModel = webDD.getJava2DelegationModel();
// Create War
war = new War(warURL, earURL, hostName, contextRoot, java2DelegationModel, webDD.getXmlContent(), webDD
.getJOnASXmlContent(), webDD.getServletsName());
// Configure JACC
PermissionManager permissionManager = null;
try {
boolean removePContext = true;
// Policy context is already existing (created by ear service), no need to remove it
if (earClassLoader != null) {
removePContext = false;
}
permissionManager = new PermissionManager(webDD, war.getContextId(), removePContext);
permissionManager.translateServletDeploymentDescriptor();
// if not in ear case, commit the policy configuration, else it is done
// by EAR service after linking all policy configuration objects
if (earClassLoader == null) {
permissionManager.commit();
}
} catch (Exception e) {
e.printStackTrace();
String err = "Cannot build permission manager object for the webapp '" + unpackedWarURL + "'";
logger.log(BasicLevel.ERROR, err + ": " + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// Configure the context to give to doRegisterWar ...
Context ctxParam = null;
try {
ctxParam = new ComponentContext(unpackedWarURL.getFile());
ctxParam.rebind("warURL", warURL);
if (earURL != null) {
ctxParam.rebind("earURL", earURL);
}
ctxParam.rebind("unpackedWarURL", unpackedWarURL);
ctxParam.rebind("parentCL", webClassLoader);
if (hostName != null) {
ctxParam.rebind("hostName", hostName);
}
ctxParam.rebind("contextRoot", contextRoot);
if (earAppName != null) {
ctxParam.rebind("earAppName", earAppName);
}
// Injection holder
if (ezbInjectionHolder != null) {
ctxParam.rebind(EZBInjectionHolder.class.getName(), ezbInjectionHolder);
}
ctxParam.rebind("webDD", webDD);
ctxParam.rebind("java2DelegationModel", new Boolean(java2DelegationModel));
ctxParam.rebind("permissionManager", permissionManager);
ctxParam.rebind("userURI", userURI);
// Trasmit the @WebServices classes too
ctxParam.rebind(KEY_WEB_SERVICES_METADATAS, webDD.getWebServices());
} catch (NamingException e) {
String err = "Error when deploying the war '" + unpackedWarURL.getFile() + "'";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
war.setPermissionManager(permissionManager);
// ... and delegate the registration of the war to the wrapper.
doRegisterWar(ctxParam);
// Finaly indicates that the war is deployed.
warDeployed.add(war);
warBindings.put(warURL, webClassLoader);
unpackedWARs.put(warURL, unpackedWarURL);
// Admin code
registerWarMBean(war, getDomainName(), warURL.getFile());
// Complete the Deployment of the WebServices
// Only if the JAX-RPC Service is started
// And in non EAR case
if (jaxrpcService != null && earClassLoader == null) {
try {
ComponentContext contctx = null;
try {
contctx = new ComponentContext(unpackedWarURL.getFile());
contctx.rebind(IJAXRPCService.CLASSLOADER_CTX_PARAM, loaderForCls);
contctx.rebind(IJAXRPCService.PARENT_OBJECTNAME_CTX_PARAM, ctxParam.lookup("WebModule"));
contctx.rebind(IJAXRPCService.ISINEAR_CTX_PARAM, Boolean.FALSE);
} catch (NamingException e) {
String err = "Can not bind params for the WebServices service, "
+ "can't complete deployment of Web Services Endpoints";
throw new JWebContainerServiceException(err, e);
}
jaxrpcService.completeWSDeployment(contctx);
} catch (ServiceException se) {
String err = "Error during the deployment of the WebServices of the War file '" + warURL + "'";
logger.log(BasicLevel.ERROR, err + " : " + se.getMessage());
throw new JWebContainerServiceException(err, se);
}
}
StringBuffer txtInfo = new StringBuffer("War " + URLUtils.urlToFile(warURL).getName() + " available at the context ");
if (!contextRoot.startsWith("/")) {
txtInfo.append("/");
}
txtInfo.append(contextRoot);
if (hostName != null) {
txtInfo.append(" on the host ");
txtInfo.append(hostName);
}
txtInfo.append(".");
logger.log(BasicLevel.INFO, txtInfo.toString());
// Remove the DD cache (WebServices)
if (jaxrpcService != null && earClassLoader == null) {
jaxrpcService.removeCache(loaderForCls);
}
}
/**
* Creates a {@code FilteringClassLoader} for this WebApp.
* @param parentLoader the Ear parent's ClassLoader (may be null)
* @param unpackedWarURL The Url of the unpacked webapp (only used in non-EAR case, never null)
* @return a Filtering ClassLoader configured from {@code WEB-INF/classloader-filtering.xml} (if any).
*/
private FilteringClassLoader createFilteringClassLoader(final URLClassLoader parentLoader,
final URL unpackedWarURL) {
// Find the parent loader
ClassLoader parent;
if (parentLoader == null) {
// Standalone case, simply be a child of the common classloader
parent = extClassLoader;
} else {
// In Ear case, the filter sits between the EjbJars + Libraries loader
// and the Web Application ClassLoader (to be created as child of this loader).
parent = parentLoader;
}
// Create the child filtering loader from the parent
FilteringClassLoader filteringClassLoader = new FilteringClassLoader(parent);
// Construct the archive from the Url
// First transform the URL into File (Avoid to fall in UTIL-94)
File unpackedFile = URLUtils.urlToFile(unpackedWarURL);
IArchive archive = ArchiveManager.getInstance().getArchive(unpackedFile);
// Seek the XML definition file in the archive (if any)
try {
String name = "WEB-INF/" + FilteringClassLoader.CLASSLOADER_FILTERING_FILE;
URL definition = archive.getResource(name);
if (definition != null) {
filteringClassLoader.setDefinitionUrl(definition);
}
} catch (ArchiveException ae) {
// Ignored
if (logger.isLoggable(BasicLevel.DEBUG)) {
String message = "Cannot get classloader-filtering.xml file from the archive " + archive;
logger.log(BasicLevel.DEBUG, message, ae);
}
} finally {
archive.close();
}
filteringClassLoader.start();
return filteringClassLoader;
}
/**
* Apply WSGen on the given file if needed.
* @param path the path to use
* @return the modified file or the original file if WSGen has not been launched.
* @throws DeployerException if WSGen cannot be applied.
*/
private void applyWSGenIfNeeded(final String path) throws DeployerException {
// JAX-RPC service started ?
if (jaxrpcService == null) {
logger.log(BasicLevel.DEBUG, "The JAX-RPC service is not present, no need to call WSGen");
return;
}
// Auto WsGen enabled ?
if (!jaxrpcService.isAutoWsGenEngaged()) {
logger.log(BasicLevel.DEBUG, "Automatic WsGen is not enabled, no need to call WSGen");
return;
}
IArchive archive = ArchiveManager.getInstance().getArchive(new File(path));
// Check version in manifest
String jonasVersionWsGen = archive.getMetadata().get("WsGen-JOnAS-Version");
if (Version.getNumber().equals(jonasVersionWsGen)) {
// no changes, just continue the normal deployment process
logger.log(BasicLevel.DEBUG, "No change: no need to call WSGen");
return;
}
try {
IDeployable> deployable = DeployableHelper.getDeployable(archive);
jaxrpcService.applyWSGen(deployable);
} catch (Exception e) {
throw new DeployerException(e);
}
}
/**
* Gets the context root for a WAR.
* @param contextRoot Current context root, null if none.
* @param earClassLoader EAR classloader for the WAR, null if none.
* @param warURL War file's URL.
* @param webDD Deployment descriptor of the WAR file.
* @return Context root, checked (always begin with one slash).
*/
protected String getContextRoot(String contextRoot, final URLClassLoader earClassLoader, final URL warURL,
final WebContainerDeploymentDesc webDD) {
// Set the right context root for the web application, the priority is
// the following :
// 1 - context-root of application.xml
// 2 - context-root of jonas-web.xml
// 3 - context-root is the name of the WAR file without extension.
if (earClassLoader == null && contextRoot == null) {
String cRoot = webDD.getContextRoot();
if (cRoot == null) {
String file = new File(warURL.getFile()).getName();
if (file.toLowerCase().endsWith(".war")) {
contextRoot = file.substring(0, file.length() - WAR_EXTENSION_LENGTH);
} else {
// It's a directory which is deployed
contextRoot = file.substring(0, file.length());
}
} else {
contextRoot = cRoot;
}
}
// ensure context-root is valid (remove starting /)
if (contextRoot.startsWith("/") && !contextRoot.equals("/")) {
logger.log(BasicLevel.WARN, "Context-Root '" + contextRoot
+ "' contains invalid starting / in the name. Fixing it.");
int c = 0;
while (contextRoot.charAt(c) == '/') {
c++;
}
contextRoot = contextRoot.substring(c);
}
return contextRoot;
}
/**
* Register a WAR by delegating the operation to the registerWar() method. This is used for JMX management.
* @param fileName the name of the war to deploy.
* @throws RemoteException if rmi call failed.
* @throws JWebContainerServiceException if the registration failed.
*/
public void registerWar(final String fileName) throws RemoteException, JWebContainerServiceException {
// convert the file name to the appropriate url and check if the file
// exists.
URL warURL = checkWarFile(fileName);
// create the context to call the registerWar method.
Context ctx = null;
try {
ctx = new ComponentContext(fileName);
ctx.rebind("warURL", warURL);
} catch (NamingException e) {
String err = "Error when deploying the war '" + fileName + "'";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// call the registerWar method.
registerWar(ctx);
}
/**
* Set the environment of the web container inside the given context.
* @param ctxParam the java:comp/env/ environment where is stored the values of the web container environment.
* @param ezbInjectionHolder the easybeans injection handler.
* @param webAppClassLoader the classloader of the web application.
* @throws JWebContainerServiceException if the populating of the environment failed.
*/
protected void setWebEnvironment(final Context ctxParam, final EZBInjectionHolder ezbInjectionHolder,
final ClassLoader webAppClassLoader) throws JWebContainerServiceException {
WebContainerDeploymentDesc dd = null;
String warName = null;
ClassLoader parentClassLoader = null;
EARDeployable earDeployable = null;
/*
* get the parameters - Deployment desc of xml - Name of the war - Parent Class loader
*/
try {
dd = (WebContainerDeploymentDesc) ctxParam.lookup("DeploymentDesc");
warName = (String) ctxParam.lookup("warName");
earDeployable = (EARDeployable) ctxParam.lookup("earDeployable");
} catch (NamingException e) {
// Ignore if earDeployable not found, it's optional
if (earDeployable != null) {
String err = "Error while getting parameter from context param ";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
}
// Get the parentCL
try {
parentClassLoader = (ClassLoader) ctxParam.lookup("parentCL");
} catch (NamingException e) {
String err = "Error while getting parameter from context param ";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// Create the java:comp/env entry and bind the entries
try {
// Create a JNDI context for this war java:comp/env
Context javaCtx = contextFactory.createComponentContext(warName);
naming.setComponentContext(javaCtx, parentClassLoader);
Context envCtx = javaCtx.createSubcontext("comp/env");
// War Environment entries
IEnvEntryDesc[] envt = dd.getEnvEntryDesc();
for (int i = 0; i < envt.length; i++) {
// get information in descriptor
String name = envt[i].getName();
Object obj = envt[i].getValue();
// register object in JNDI
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, warName + ": Binding object " + name + " -> " + obj);
}
envCtx.rebind(name, obj);
}
// Resource References
IResourceRefDesc[] resref = dd.getResourceRefDesc();
for (int i = 0; i < resref.length; i++) {
// get information in descriptor
String name = resref[i].getName();
String type = resref[i].getTypeName();
String resname = resref[i].getJndiName();
// register object in JNDI
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, warName + ": Linking resource " + name + " -> " + resname);
}
if (type.equalsIgnoreCase("java.net.URL")) {
// Specify the factory to use with the right URL
Reference ref = new Reference("java.net.URL", "org.ow2.jonas.lib.naming.URLFactory", null);
StringRefAddr refAddr = new StringRefAddr("url", resname);
ref.add(refAddr);
envCtx.rebind(name, ref);
} else {
// build the LinkRef that will be registered:
// FactoryClassName = null, size = 1, refAddr = resname.
LinkRef lref = new LinkRef(resname);
envCtx.rebind(name, lref);
}
}
// Resource Environment References
IResourceEnvRefDesc[] resEnvref = dd.getResourceEnvRefDesc();
for (int i = 0; i < resEnvref.length; i++) {
// get information in descriptor
String name = resEnvref[i].getName();
String resname = resEnvref[i].getJndiName();
LinkRef lref = new LinkRef(resname);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, warName + ": Linking resource environment " + name + " -> " + resname);
}
envCtx.rebind(name, lref);
}
// EJB References
IEJBRefDesc[] ejbref = dd.getEjbRefDesc();
for (int i = 0; i < ejbref.length; i++) {
// get information in descriptor
String name = ejbref[i].getEjbRefName();
String ejbname = null;
ejbname = ejbref[i].getJndiName();
LinkRef lref = new LinkRef(ejbname);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, warName + ": Linking ejb " + name + " -> " + ejbname);
}
envCtx.rebind(name, lref);
}
// EJB Local Refs
// We use here ejb-link tag. This should be used also for
// ejb-ref when we are able to manage references to
// another jar file.
IEJBLocalRefDesc[] ejblocalref = dd.getEjbLocalRefDesc();
for (int i = 0; i < ejblocalref.length; i++) {
String name = ejblocalref[i].getEjbRefName();
String ejbname = ejblocalref[i].getJndiLocalName();
LinkRef lref = new LinkRef(ejbname);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, warName + ": Linking ejb " + name + " -> " + ejbname);
}
envCtx.rebind(name, lref);
}
// Message Destination References
IMessageDestinationRefDesc[] mdref = dd.getMessageDestinationRefDesc();
for (int i = 0; i < mdref.length; i++) {
// get information in descriptor
String name = mdref[i].getMessageDestinationRefName();
String mdname = null;
mdname = mdref[i].getJndiName();
LinkRef lref = new LinkRef(mdname);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, warName + ": Linking message-destination " + name + " -> " + mdname);
}
envCtx.rebind(name, lref);
}
// Service Ref
// We bind a Reference when full configuration is provided
// Otherwise we bind only a LinkRef in JNDI
// Only done when the JAX-RPC Service is active
if (jaxrpcService != null) {
IServiceRefDesc[] serviceRefs = dd.getServiceRefDesc();
for (int i = 0; i < serviceRefs.length; i++) {
// Create the Service from the ServiceRef description
String name = serviceRefs[i].getServiceRefName();
// create a full Reference
Reference ref = jaxrpcService.buildServiceRef(serviceRefs[i], parentClassLoader);
envCtx.rebind(name, ref);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Adding service-ref 'java:comp/env/" + name + "'");
}
}
}
// Gets the bindings
IENCBindingHolder encBindingHolder = dd.getENCBindingHolder();
// Persistence context
if (ezbInjectionHolder != null) {
EZBPersistenceUnitManager persistenceUnitManager = ezbInjectionHolder.getPersistenceUnitManager();
if (persistenceUnitManager != null) {
for (IENCBinding binding : encBindingHolder.getPersistenceContextBindings()) {
String encName = binding.getName();
String unitName = binding.getValue().getUnitName();
PersistenceContextType type = binding.getValue().getType();
EntityManager em = persistenceUnitManager.getEntityManager(unitName, type);
envCtx.rebind(encName, em);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Adding persistence-context 'java:comp/env/" + encName + "'");
}
}
}
// Persistence unit
for (IENCBinding binding : encBindingHolder.getPersistenceUnitBindings()) {
if (persistenceUnitManager != null) {
String encName = binding.getName();
String unitName = binding.getValue().getUnitName();
EntityManagerFactory emf = persistenceUnitManager.getEntityManagerFactory(unitName);
envCtx.rebind(encName, emf);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Adding persistence-unit 'java:comp/env/" + encName + "'");
}
}
}
// EJBs
EZBJNDIResolver jndiResolver = ezbInjectionHolder.getJNDIResolver();
if (jndiResolver != null) {
for (IENCBinding binding : encBindingHolder.getEJBBindings()) {
String encName = binding.getName();
IJEjbEJB jEjbEJB = binding.getValue();
String interfaceName = jEjbEJB.getBeanInterface();
String beanName = jEjbEJB.getBeanName();
String jndiName;
try {
jndiName = jndiResolver.getEJBJNDIUniqueName(interfaceName, beanName);
// Bind a link to this JNDI name
envCtx.rebind(encName, new LinkRef(jndiName));
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Adding ejb 'java:comp/env/" + encName + "' from JNDIName '"
+ jndiName + "'.");
}
} catch (EZBJNDIResolverException e) {
logger.log(BasicLevel.ERROR, "Cannot get JNDI name for enc name '" + encName + "'", e);
}
}
}
}
// If JAXWS Service is present
if (jaxwsService != null) {
for (IENCBinding binding : encBindingHolder.getWebServicesBindings()) {
// Ask the service for Reference creation
String name = binding.getName();
Reference ref = jaxwsService.createNamingReference(binding.getValue());
// Bind the reference into the JNDI Context
envCtx.rebind(name, ref);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Adding WebServiceRef 'java:comp/env/" + name + "'.");
}
}
}
// JNDI lookup prefix
if (earDeployable != null && isVersioningEnabled()) {
String jndiPrefix = versioningService.getPrefix(earDeployable);
if (jndiPrefix != null) {
envCtx.rebind("JNDILookupPrefix", jndiPrefix);
}
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Adding JNDI-lookup-prefix 'java:comp/env/JNDILookupPrefix'");
}
}
} catch (NamingException e) {
String err = "Error while populating environment of the war file " + warName;
logger.log(BasicLevel.ERROR, err + " :" + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
}
/**
* Delegate the unregistration to the implementation of the web container and delete the environment associated to the WAR
* file.
* @param ctx the context which contains the configuration in order to undeploy a WAR.
* @throws JWebContainerServiceException if the unregistration failed.
*/
protected void unRegisterWar(final Context ctx) throws JWebContainerServiceException {
// Gets the 2 parameters :
// warURL, isEarCase, hostName and contextRoot.
URL warURL = null;
boolean isEarCase = true;
try {
warURL = (URL) ctx.lookup("warURL");
isEarCase = ((Boolean) ctx.lookup("isEarCase")).booleanValue();
} catch (NamingException e) {
String err = "Error while getting parameter from context param.";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// get the file name for displaying message.
String fileName = warURL.getFile();
// Check if the war is deployed.
War war = null;
war = getWar(warURL);
if (war == null) {
String err = "Cannot undeploy war: '" + fileName + "' is not deployed.";
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err);
}
// Check if the war can be undeployed (2 case authorized) :
// - case EAR and war is in an EAR.
// - case non EAR and war isn't in an EAR.
if (isEarCase != war.isInEarCase()) {
String err = "Cannot undeploy war: '" + fileName
+ "' it is in an ear application. You must undeploy the ear associated.";
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err);
}
// Call the specific method of the implementation of the web container.
try {
String hostName = war.getHostName();
if (hostName != null) {
ctx.rebind("hostName", war.getHostName());
}
ctx.rebind("contextRoot", war.getContextRoot());
ctx.rebind("webClassLoader", warBindings.get(warURL));
} catch (NamingException e) {
String err = "Error when undeploying the war '" + fileName + "'";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// Remove permission manager
PermissionManager permissionManager = war.getPermissionManager();
try {
permissionManager.delete();
permissionManager = null;
} catch (PermissionManagerException pme) {
logger.log(BasicLevel.ERROR, "Cannot remove permission manager for file '" + fileName + "'.", pme);
}
doUnRegisterWar(ctx);
// undeploy webservices
if (jaxrpcService != null) {
jaxrpcService.undeployWebServices(ctx);
}
// Remove the context.
URLClassLoader loader = (URLClassLoader) warBindings.remove(warURL);
naming.unSetComponentContext(loader);
// Remove classloader
warLoaders.remove(warURL);
// Indicates that the war is not in the deployed war.
// (here we are sure that the war is not null and isn't in an ear).
warDeployed.remove(war);
unpackedWARs.remove(warURL);
// Admin code
unregisterWarMBean(getDomainName(), fileName);
logger.log(BasicLevel.INFO, "War " + URLUtils.urlToFile(warURL).getName() + " no longer available");
}
/**
* Unregister a WAR by delegating the operation to the unRegisterWar() method. This is used for JMX management.
* @param fileName the name of the war to undeploy.
* @throws RemoteException if rmi call failed.
* @throws JWebContainerServiceException if the unregistration failed.
*/
public void unRegisterWar(final String fileName) throws RemoteException, JWebContainerServiceException {
// Convert the given file name to an url and check if the war is
// deployed ...
URL warURL = checkWarDeployed(fileName);
// ... and do the undeployment.
Context ctx = null;
try {
ctx = new ComponentContext(fileName);
ctx.rebind("warURL", warURL);
ctx.rebind("isEarCase", new Boolean(false));
} catch (NamingException e) {
String err = "Error when undeploying the war file '" + fileName + "'";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
unRegisterWar(ctx);
}
/**
* Deploy the given wars of an ear file with the specified parent classloader (ejb classloader or ear classloader). (This
* method is only used for the ear applications, not for the web applications).
* @param ctx the context containing the configuration to deploy the wars.
* This context contains the following parameters :
* - urls the list of the urls of the wars to deploy.
* - earURL the URL of the ear application file.
* - parentClassLoader the parent classLoader of the wars.
* - earClassLoader the ear classLoader of the j2ee app.
* - altDDs the optional URI of deployment descriptor.
* - contextRoots the optional context root of the wars.
* @throws JWebContainerServiceException if an error occurs during the deployment.
*/
public void deployWars(final Context ctx) throws JWebContainerServiceException {
// Gets the parameters from the context :
// - urls the list of the urls of the wars to deploy.
// - earURL the URL of the ear application file.
// - earDeployable the EARDeployable of the ear application file.
// - parentClassLoader the parent classLoader of the wars.
// - earClassLoader the ear classLoader of the j2ee app.
// - altDDs the optional URI of deployment descriptor.
// - contextRoots the optional context root of the wars.
URL[] urls = null;
URL earURL = null;
EARDeployable earDeployable = null;
ClassLoader parentClassLoader = null;
ClassLoader earClassLoader = null;
URL[] altDDs = null;
String[] contextRoots = null;
EZBInjectionHolder ejbInjectionHolder = null;
try {
urls = (URL[]) ctx.lookup("urls");
earURL = (URL) ctx.lookup("earURL");
earDeployable = (EARDeployable) ctx.lookup("earDeployable");
parentClassLoader = (ClassLoader) ctx.lookup("parentClassLoader");
earClassLoader = (ClassLoader) ctx.lookup("earClassLoader");
altDDs = (URL[]) ctx.lookup("altDDs");
contextRoots = (String[]) ctx.lookup("contextRoots");
} catch (NamingException e) {
String err = "Error while getting parameter from context param ";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
// Get Injection holder
try {
ejbInjectionHolder = (EZBInjectionHolder) ctx.lookup(EZBInjectionHolder.class.getName());
} catch (NamingException e) {
logger.log(BasicLevel.DEBUG, "No persistence unit manager");
}
// webDDManager.setAltDD(earClassLoader, urls, altDDs);
// Deploy all the wars of the ear application.
for (int i = 0; i < urls.length; i++) {
// Get the name of a war to deploy.
String fileName = URLUtils.urlToFile(urls[i]).getPath();
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Deploy war '" + fileName + "' for the ear service");
}
// The context to give for the creation of the container
// associated to the ejb-jar.
Context contctx = null;
try {
contctx = new ComponentContext(fileName);
contctx.rebind("warURL", urls[i]);
contctx.rebind("parentClassLoader", parentClassLoader);
contctx.rebind("earClassLoader", earClassLoader);
contctx.rebind("earDeployable", earDeployable);
contctx.rebind("earURL", earURL);
if (altDDs[i] != null) {
contctx.rebind("altDD", altDDs[i]);
}
if (contextRoots[i] != null) {
contctx.rebind("contextRoot", contextRoots[i]);
}
// Injection holder
if (ejbInjectionHolder != null) {
contctx.rebind(EZBInjectionHolder.class.getName(), ejbInjectionHolder);
}
registerWar(contctx);
} catch (Exception e) {
// A war is corrupted so undeploy all the deployed war
// of the ear application.
logger.log(BasicLevel.ERROR, "Error when deploying '" + fileName + "'");
logger.log(BasicLevel.ERROR, e.getMessage());
logger.log(BasicLevel.ERROR, "Undeploy war of the ear application");
for (int j = 0; j < i; j++) {
String warFileName = urls[j].getFile();
try {
// Try to undeploy a war of the ear application.
ComponentContext context = new ComponentContext(warFileName);
context.rebind("warURL", urls[j]);
context.rebind("isEarCase", new Boolean(true));
unRegisterWar(context);
} catch (Exception ex) {
// Cannot undeploy a war of the ear application
// So there is an error message.
logger.log(BasicLevel.ERROR, "Error when undeploying '" + warFileName + "'");
logger.log(BasicLevel.ERROR, ex.getMessage());
logger.log(BasicLevel.ERROR, "Cannot undeploy war of the ear application");
}
}
throw new JWebContainerServiceException("Error during the deployment", e);
}
}
}
/**
* Undeploy the given wars of an ear file with the specified parent classloader (ejb classloader or ear classloader). (This
* method is only used for the ear applications, not for the war applications).
* @param urls the list of the urls of the wars to undeploy.
*/
public void unDeployWars(final URL[] urls) {
for (int i = 0; i < urls.length; i++) {
String warFileName = urls[i].getFile();
try {
// Try to undeploy a war of the ear application.
ComponentContext context = new ComponentContext(warFileName);
context.rebind("warURL", urls[i]);
context.rebind("isEarCase", new Boolean(true));
unRegisterWar(context);
} catch (Exception ex) {
// Cannot undeploy a war of the ear application
// So there is an error message.
logger.log(BasicLevel.ERROR, "Error when undeploying '" + warFileName + "'");
logger.log(BasicLevel.ERROR, ex.getMessage());
logger.log(BasicLevel.ERROR, "Cannot undeploy war of the ear application");
}
}
}
/**
* Get the war identified by its URL (.war).
* @param url the URL of the war to get.
* @return the war indentified by its URL, or null if the war is not found.
*/
public War getWar(final URL url) {
Iterator wars = warDeployed.iterator();
while (wars.hasNext()) {
War war = (War) wars.next();
if (war.getWarURL().equals(url)) {
return war;
}
}
return null;
}
/**
* Get a list of wars identified by their Context.
* @param pContext the context of the war to get.
* @return the list of wars indentified by their Context, or an empty list if no wars are found.
*/
protected List getWar(final String pContext) {
List checkDeployed = new ArrayList();
Iterator wars = warDeployed.iterator();
while (wars.hasNext()) {
War war = (War) wars.next();
if (war.getContextRoot().equals(pContext)) {
checkDeployed.add(war);
}
}
return checkDeployed;
}
/**
* Make a cleanup of the cache of deployment descriptor. This method must be invoked after the ear deployment by the EAR
* service.
* @param earClassLoader the ClassLoader of the ear application to remove from the cache.
*/
public void removeCache(final ClassLoader earClassLoader) {
WebDeploymentDescManager.getInstance().removeCache(earClassLoader);
}
/**
* Check if the specified file name correspond to a file which is located relatively to where the JOnAS server is launched
* or in the $JONAS_BASE/web-apps.
* @param fileName the file to check if it exists.
* @return the URL of the file found (either relatively to the JOnAS server or to the $JONAS_BASE/web-apps).
* @throws JWebContainerServiceException if the specified file does't exists.
*/
protected URL checkWarFile(final String fileName) throws JWebContainerServiceException {
File f = null;
try {
f = new File(fileName).getCanonicalFile();
if (!f.exists()) {
boolean found = false;
}
} catch (IOException e) {
String err = "Invalid war file name '" + fileName;
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err, e);
}
URL warURL = null;
try {
warURL = f.toURL();
} catch (MalformedURLException e) {
String err = "Invalid war file name '" + fileName + "'.";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
}
return warURL;
}
/**
* Check if the specified file is already deployed in the JOnAS server and return the URL of this deployed war file.
* @param fileName the name of the WAR file to check.
* @return the URL of the deployed war file.
* @throws JWebContainerServiceException if the file name doesn't correspond to a deployed war.
*/
protected URL checkWarDeployed(final String fileName) throws JWebContainerServiceException {
URL url = null;
try {
Iterator wars = warDeployed.iterator();
while (wars.hasNext()) {
War war = (War) wars.next();
url = (new File(fileName).getCanonicalFile()).toURL();
URL deployedWarURL = war.getWarURL();
String deployedWarPath = deployedWarURL.toString();
// Delete the char '/' at the end of the URL if present
// FIXME: very strange to use File.separator on an URL as it should be always / ! ??
if (deployedWarPath.endsWith(File.separator)) {
deployedWarPath = deployedWarPath.substring(0, deployedWarPath.length() - 1);
}
// For unpacked directory on Linux, the URL has a trailing / so check it also
if (deployedWarPath.equals(url.toString()) ||(deployedWarPath + "/").equals(url.toString())) {
return deployedWarURL;
}
}
String err = "Cannot undeploy war: '" + fileName + "' is not deployed.";
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err);
} catch (MalformedURLException e) {
String err = "Invalid war file name '" + fileName + "'.";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new JWebContainerServiceException(err, e);
} catch (IOException e) {
String err = "Invalid war file name '" + fileName;
logger.log(BasicLevel.ERROR, err);
throw new JWebContainerServiceException(err, e);
}
}
/**
* @return current number of wars deployed in the JOnAS server
*/
public Integer getCurrentNumberOfWars() {
return new Integer(warDeployed.size());
}
/**
* Test if the specified filename is already deployed or not.
* @param fileName the name of the war file.
* @return true if the war is deployed, else false.
*/
public boolean isWarLoaded(final String fileName) {
URL url = null;
boolean isLoaded = false;
try {
// Absolute filename
try {
url = new File(fileName).getCanonicalFile().toURL();
// Check if the war is already deployed or not
if (getWar(url) != null) {
isLoaded = true;
} else {
// Not found force to test in relative Webapps directory
url = null;
}
} catch (Exception e) {
url = null;
}
} catch (Exception e) {
String err = "Can not found if the war is deployed or not";
logger.log(BasicLevel.ERROR, err);
return false;
}
return isLoaded;
}
/**
* Return the list of all loaded web applications.
* @return The list of deployed web applications
*/
public List getDeployedWars() {
List al = new ArrayList();
for (Iterator wars = warDeployed.iterator(); wars.hasNext();) {
War war = (War) wars.next();
URL warURL = war.getWarURL();
al.add(warURL.getFile());
}
return al;
}
/**
* Gets the name of the server which is the web container.
* @return the name of the server which is the web container
*/
public String getServerName() {
if (serverName == null) {
updateServerInfos();
}
return serverName;
}
/**
* Gets the version of the server which is the web container.
* @return the version of the server which is the web container
*/
public String getServerVersion() {
if (serverVersion == null) {
updateServerInfos();
}
return serverVersion;
}
/**
* Test if the specified unpack name is already deployed or not. This method is defined in the {@link JWebContainerService}
* interface.
* @param unpackName the name of the ear file.
* @return true if the ear is deployed, else false.
*/
public boolean isWarDeployedByWorkName(final String unpackName) {
for (URL unpackedURL : unpackedWARs.values()) {
if (URLUtils.urlToFile(unpackedURL).getName().equals(unpackName)) {
return true;
}
}
return false;
}
/**
* Update info of the serverName and serverVersion.
*/
protected abstract void updateServerInfos();
/**
* Return the Default host name of the web container.
* @return the Default host name of the web container.
* @throws JWebContainerServiceException when it is impossible to get the Default Host.
*/
public abstract String getDefaultHost() throws JWebContainerServiceException;
/**
* Return the Default HTTP port number of the web container (can be null if multiple HTTP connector has been set).
* @return the Default HTTP port number of the web container.
* @throws JWebContainerServiceException when it is impossible to get the Default Http port.
*/
public abstract String getDefaultHttpPort() throws JWebContainerServiceException;
/**
* Return the Default HTTPS port number of the web container (can be null if multiple HTTPS connector has been set).
* @return the Default HTTPS port number of the web container.
* @throws JWebContainerServiceException when it is impossible to get the Default Https port.
*/
public abstract String getDefaultHttpsPort() throws JWebContainerServiceException;
/**
* @return Returns the logger.
*/
protected static Logger getLogger() {
return logger;
}
/**
* @return Returns the naming.
*/
protected JNamingManager getNaming() {
return naming;
}
/**
* @param serverName The serverName to set.
*/
protected void setServerName(final String serverName) {
this.serverName = serverName;
}
/**
* @param serverVersion The serverVersion to set.
*/
protected void setServerVersion(final String serverVersion) {
this.serverVersion = serverVersion;
}
/**
* Holds the ClassLoader used to retrieve the WebApp JNDI Context and the JOnAS Webapp ClasLoader.
* @author Guillaume Sauthier
*/
public class WebLoaderHolder {
/**
* Web ClassLoader used by JOnAS.
*/
private WebappClassLoader jonasWebLoader;
/**
* Web ClassLoader used to retrieve the JNDI Context of the webapp.
*/
private ClassLoader envWebLoader;
/**
* Constructs a WebLoaderHolder with jonas Loader and en Loader.
* @param jonas JOnAS Webapp Loader
* @param env Environnement ClassLoader
*/
public WebLoaderHolder(final WebappClassLoader jonas, final ClassLoader env) {
jonasWebLoader = jonas;
envWebLoader = env;
}
/**
* @return Returns the jonasWebLoader.
*/
public WebappClassLoader getJonasWebLoader() {
return jonasWebLoader;
}
/**
* @return Returns the envWebLoader.
*/
public ClassLoader getEnvWebLoader() {
return envWebLoader;
}
/**
* @param envWebLoader The envWebLoader to set.
*/
public void setEnvWebLoader(final ClassLoader envWebLoader) {
this.envWebLoader = envWebLoader;
}
/**
* @param jonasWebLoader The jonasWebLoader to set.
*/
public void setJonasWebLoader(final WebappClassLoader jonasWebLoader) {
this.jonasWebLoader = jonasWebLoader;
}
}
/**
* @return the {@link JComponentContextFactory}.
*/
protected JComponentContextFactory getContextFactory() {
return contextFactory;
}
// Admin code (JMX based)
// ---------------------
/**
* Register WEB Container Service MBean.
* @param service web container service to manage
* @param domainName domain name
*/
protected void registerWebServiceMBean(final Object service, final String domainName) {
ObjectName on = JonasObjectName.webContainerService(domainName);
jmxService.registerMBean(service, on);
}
/**
* Unregister WEB Container Service MBean.
* @param domainName domain name
*/
protected void unregisterWebServiceMBean(final String domainName) {
ObjectName on = JonasObjectName.webContainerService(domainName);
jmxService.unregisterMBean(on);
}
/**
* Register War MBean.
* @param war War instance to manage
* @param domainName domain name
* @param fileName the war file name
*/
protected void registerWarMBean(final War war, final String domainName, final String fileName) {
// ObjectName on = null;
try {
ObjectName on = JonasObjectName.war(domainName, fileName);
jmxService.registerMBean(war, on);
} catch (MalformedObjectNameException e) {
logger.log(BasicLevel.WARN, "Could not register War MBean", e);
}
}
/**
* Unegister War MBean.
* @param domainName domain name
* @param fileName the war file name
*/
protected void unregisterWarMBean(final String domainName, final String fileName) {
// ObjectName on = null;
try {
ObjectName on = JonasObjectName.war(domainName, fileName);
jmxService.unregisterMBean(on);
} catch (MalformedObjectNameException e) {
logger.log(BasicLevel.WARN, "Could not unregister War MBean", e);
}
}
/**
* @param jmxService the jmxService to set
*/
public void setJmxService(final JmxService jmxService) {
this.jmxService = jmxService;
}
/**
* @param jaxrpcService the jaxrpcService to set
*/
public void setJAXRPCService(final IJAXRPCService jaxrpcService) {
this.jaxrpcService = jaxrpcService;
}
/**
* @param naming the naming to set
*/
public void setNaming(final JNamingManager naming) {
this.naming = naming;
}
/**
* @param contextFactory the contextFactory to set
*/
public void setContextFactory(final JComponentContextFactory contextFactory) {
this.contextFactory = contextFactory;
}
/**
* @param deployerManager the {@link IDeployerManager} to use.
*/
public void setDeployerManager(final IDeployerManager deployerManager) {
this.deployerManager = deployerManager;
}
/**
* Create working directory for applications.
*/
protected void initWorkingDirectory() {
if (workSingleWebAppsFile == null) {
// Create $JONAS_BASE/work/webapps/single directory file
workSingleWebAppsFile = new File(WORK_WEBAPPS_DIR + File.separator + getServerProperties().getServerName()
+ File.separator + SINGLE_WORK_WEBAPPS_DIR_SUFFIX);
workSingleWebAppsFile.mkdirs();
}
}
/**
* Method called when the workCleanerService is bound to the component.
* @param workCleanerService the workCleanerService reference
*/
public void setWorkCleanerService(final WorkCleanerService workCleanerService) {
initWorkingDirectory();
File fileLog = new File(workSingleWebAppsFile.getPath() + File.separator + getServerProperties().getServerName()
+ ".log");
if (!fileLog.exists()) {
try {
// Create dirs
fileLog.getParentFile().mkdirs();
fileLog.createNewFile();
} catch (IOException e) {
logger.log(BasicLevel.ERROR, "cannot create the log file" + fileLog, e);
}
}
// Create the logger
try {
deployerLog = new DeployerLog(fileLog);
CleanTask cleanTask = new WarCleanTask(this, deployerLog);
workCleanerService.registerTask(cleanTask);
workCleanerService.executeTasks();
} catch (DeployerLogException e) {
logger.log(BasicLevel.ERROR, "Cannot register the clean task", e);
}
}
/**
* @return Associates an URL of an unpacked WAR file to its classloader.
*/
protected Hashtable getWarLoaders() {
return warLoaders;
}
/**
* @return Associates an URL of a deployed WAR file to its classloader.
*/
protected Hashtable getWarBindings() {
return warBindings;
}
/**
* @return List of the war deployed by the Web container Service.
*/
protected List getWarDeployed() {
return warDeployed;
}
/**
* @return Reference to the JAX-RPC service.
*/
protected IJAXRPCService getJAXRPCService() {
return jaxrpcService;
}
/**
* @return Application Classloader.
*/
protected ClassLoader getAppsClassLoader() {
return extClassLoader;
}
/**
* @param versioningService The versioning service to set.
*/
public void setVersioningService(final VersioningService versioningService) {
this.versioningService = versioningService;
}
/**
* Sets the versioning service to null.
*/
public void unsetVersioningService() {
this.versioningService = null;
}
/**
* @return The versioning service.
*/
public VersioningService getVersioningService() {
return this.versioningService;
}
/**
* @return Whether versioning is enabled.
*/
public boolean isVersioningEnabled() {
return (versioningService != null && versioningService.isVersioningEnabled());
}
/**
* @param warDeployableMetadataFactory the deployable metadata factory service
*/
public void setWarDeployableMetadataFactory(final IWarDeployableMetadataFactory warDeployableMetadataFactory) {
WarDeployableMetadataFactoryHolder.setWarDeployableMetadataFactory(warDeployableMetadataFactory);
}
/**
* Store the reference to the JAX-WS Service.
* @param jaxwsService jaxws Service
*/
public void bindJaxwsService(final IJAXWSService jaxwsService) {
this.jaxwsService = jaxwsService;
}
/**
* @return the jaxws service
*/
protected IJAXWSService getJAXWSService() {
return this.jaxwsService;
}
/**
* Release the reference to the JAWS Service.
* @param jaxwsService jaxws Service
*/
public void unbindJaxwsService(final IJAXWSService jaxwsService) {
this.jaxwsService = null;
}
/**
* @param service the EJB3 Service to be injected.
*/
public void setEjb3Service(final IEasyBeansService service) {
this.ejb3Service = service;
}
/**
* Unbind the {@link IEasyBeansService}.
*/
public void unsetEjb3Service() {
this.ejb3Service = null;
}
/**
* Enable or not the on demand feature.
* @param onDemandFeatureEnabled boolean true/false
*/
public void setOnDemandFeature(final boolean onDemandFeatureEnabled) {
this.onDemandFeatureEnabled = onDemandFeatureEnabled;
}
/**
* Sets the redirect port number
* @param onDemandRedirectPort the given port used for OnDemand proxy
*/
public void setOnDemandRedirectPort(final int onDemandRedirectPort) {
if (isStarted()) {
return;
}
this.onDemandRedirectPort = onDemandRedirectPort;
}
/**
* @return true if the on demand feature is enabled and in development mode.
*/
public boolean isOnDemandFeatureEnabled() {
return onDemandFeatureEnabled && getServerProperties().isDevelopment();
}
public int getOnDemandRedirectPort() {
return onDemandRedirectPort;
}
public int getRandomPort() {
Random random = new Random();
random.setSeed(System.currentTimeMillis());
int portNumber = 0;
int retry = 0;
while (portNumber == 0 && retry < 50) {
// try to use by starting at 8950 branch
int randomPort = 8950 + random.nextInt(50);
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(randomPort);
portNumber = randomPort;
} catch (IOException e) {
// invalid port number, try a new one
logger.log(BasicLevel.DEBUG, "unable to listen on the server socket", e);
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
logger.log(BasicLevel.DEBUG, "unable to close server socket", e);
}
}
}
// new try
retry++;
}
if (retry == 50) {
throw new IllegalStateException("Unable to choose a random free port");
}
return portNumber;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy