/**
* JOnAS: Java(TM) Open Application Server
* Copyright (C) 1999-2005 Bull S.A.
* Contact: jonas-team@objectweb.org
*
* 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: ResourceServiceImpl.java 9708 2006-10-10 06:12:37Z ehardesty $
* --------------------------------------------------------------------------
*/
package org.objectweb.jonas.resource;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBean;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkManager;
import org.apache.commons.modeler.ManagedBean;
import org.objectweb.jonas.common.JModule;
import org.objectweb.jonas.common.JProp;
import org.objectweb.jonas.common.Log;
import org.objectweb.jonas.container.EJBService;
import org.objectweb.jonas.jmx.J2eeObjectName;
import org.objectweb.jonas.jmx.JmxService;
import org.objectweb.jonas.jmx.JonasObjectName;
import org.objectweb.jonas.jtm.TransactionService;
import org.objectweb.jonas.management.JonasMBeanTools;
import org.objectweb.jonas.naming.CompNamingContext;
import org.objectweb.jonas.server.LoaderManager;
import org.objectweb.jonas.service.AbsServiceImpl;
import org.objectweb.jonas.service.ServiceException;
import org.objectweb.jonas.service.ServiceManager;
import org.objectweb.jonas_lib.JWorkManager;
import org.objectweb.jonas_rar.deployment.lib.wrapper.RarManagerWrapper;
import org.objectweb.transaction.jta.TransactionManager;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
/**
* JCA resource service implmentation
* @author Philippe Coq
* Contributor(s):
* JOnAS 2.4 Sebastien Chassande-Barrioz (sebastien.chassande@inrialpes.fr)
* JOnAS 3.0 Eric Hardesty (Eric.Hardesty@bull.com)
* JOnAS 4.0 Adriana Danes (JSR 77 + use of Jakarta Modeler Component : http://jakarta.apache.org/commons/modeler)
* Eric Hardesty (J2CA 1.5)
*
*/
public class ResourceServiceImpl extends AbsServiceImpl implements
ResourceService,
ResourceServiceImplMBean {
// Loggers used in the ResourceService
/**
* Main logger
*/
private static Logger logger = null;
/**
* Pool infomation logger
*/
private static Logger poolLogger = null;
/**
* Config property setter logger
*/
private static Logger setterLogger = null;
/**
* Management logger
*/
private static Logger manageLogger = null;
// Properties for inits
// JCA resource service configuration parameters
/**
* Autoload directory property name
*/
public static final String AUTOLOADDIR = "jonas.service.resource.autoloaddir";
/**
* Service class property name
*/
public static final String CLASS = "jonas.service.resource.class";
/**
* Jndiname property name
*/
public static final String JNDI_NAME = "jndiname";
/**
* Rar object property name
*/
public static final String RAR_OBJNAME = "rarobjname";
/**
* Factory offset property name
*/
public static final String FACTORY_OFFSET = "factoryoffset";
/**
* Factory type property name
*/
public static final String FACTORY_TYPE = "factorytype";
/**
* Rar filename property name
*/
public static final String RAR_FILENAME = "rarfilename";
/**
* Jndiname link property name
*/
public static final String LNK_JNDI_NAME = "lnkjndiname";
/**
* Link Rar filename property name
*/
public static final String LNK_RAR_FILENAME = "lnkrarfilename";
/**
* Jonas ra.xml property name
*/
public static final String JONAS_RA_XML = "jonasraxml";
/**
* ra.xml property name
*/
public static final String RA_XML = "raxml";
/**
* Parsing validation property name
*/
public static final String PARSINGWITHVALIDATION = "jonas.service.resource.parsingwithvalidation";
/**
* Resources list property name
*/
public static final String RESOURCE_LIST = "jonas.service.resource.resources";
/**
* Thread timeout
*/
public static final String THREADWAITTIMEOUT = "jonas.service.resource.threadwaittimeout";
/**
* Minimum number of work threads property name
*/
public static final String MINWORKTHREADS = "jonas.service.resource.minworkthreads";
/**
* Maximum number of work threads property name
*/
public static final String MAXWORKTHREADS = "jonas.service.resource.maxworkthreads";
/**
* Work max execution timeout property name
*/
public static final String EXECTIMEOUT = "jonas.service.resource.worktimeout";
/**
* Default work thread timeout
*/
public static final int DEF_WRK_THREADWAITTIMEOUT = 60;
/**
* Default number of work threads
*/
public static final int DEF_WRK_THREADS = 5;
/**
* Default max number of work threads
*/
public static final int DEF_MAX_WRK_THREADS = 80;
/**
* Maximum work execution timeout (0 is unlimited)
*/
public static final int DEF_EXEC_TIME = 0;
/**
* Hashtable mapping a jndiname to an RAR object
*/
// private static Hashtable jndiName2RA = new Hashtable();
/**
* Hashtable mapping a filename to an RAR object
*/
// private static Hashtable fileName2RA = new Hashtable();
/**
* Hashtable mapping a jndiname to an "external" factory
*/
// private static Hashtable jndiName2Factory = new Hashtable();
/**
* This vector is list of RAR files that will be deployed after all
* other RAR files have been deployed. The problem is that these RAR
* files are associated with another RAR file that has not been processed.
*/
private Vector delayedRAs = new Vector();
/**
* boolean to determine if processing of delayed Rars has begun
*/
private boolean processingDelayed = false;
/**
* The transaction service for this server
*/
private TransactionService ts = null;
/**
* The transaction manager for this server
*/
private TransactionManager tm = null;
/**
* Reference to a MBean server.
*/
private MBeanServer mbeanServer = null;
/**
* Autoload directory names
*/
private Vector autoNames = null;
/**
* List of resource names
*/
private Vector resourceNames = null;
// J2EE CA 1.5 objects
/**
* Work Manager for the Resource service
*/
private WorkManager workMgr = null;
/**
* BootstrapContext for the Resource service
*/
private ResourceBootstrapContext bootCtx = null;
/**
* The name of the JONAS_BASE directory
*/
public static final String JONAS_BASE = JProp.getJonasBase();
/**
* The name of the working apps directory.
*/
public static final String WORK_RARS_DIR = JProp.getWorkDir() + File.separator + "rars";
/**
* The name of the rars directory
*/
public static final String RARSDIR = JProp.getJonasBase() + File.separator + "rars";
/**
* Application parent classloader
*/
private ClassLoader appsClassLoader;
/**
* Default construtor for ResourceService
*/
public ResourceServiceImpl() {
}
//IMPLEMENTATION OF 'AbsServiceImpl' ABSTRACT CLASS
/**
* - Get the loggers
* - Get the global jndi context
* - Get the list of the resource adapters. The list is reachable in the
* - context parameter under the name RESOURCE_LIST.
* - Get the transaction manager into the jndi
* - Set the XML validation property
* @param ctx Context
*/
public void doInit(Context ctx) {
if (logger == null) {
logger = Log.getLogger(Log.JONAS_JCA_PREFIX + ".process");
}
if (poolLogger == null) {
poolLogger = Log.getLogger(Log.JONAS_JCA_PREFIX + ".pool");
}
if (setterLogger == null) {
setterLogger = Log.getLogger(Log.JONAS_JCA_PREFIX + ".setters");
}
if (manageLogger == null) {
manageLogger = Log.getLogger(Log.JONAS_JCA_PREFIX + ".management");
}
try {
LoaderManager lm = LoaderManager.getInstance();
appsClassLoader = lm.getAppsLoader();
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "Cannot get the Applications ClassLoader from RAR Container Service: " + e);
throw new ServiceException("Cannot get the Applications ClassLoader from RAR Container Service", e);
}
resourceNames = new Vector();
autoNames = new Vector();
// Add the rars of the jonas.service.resource.autoloaddir property
String dirValue = null;
try {
dirValue = (String) ctx.lookup(AUTOLOADDIR);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "autoloaddir= " + dirValue);
}
} catch (NamingException e) {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "No autoloaddir value specified in context, usually for client container");
}
}
if (dirValue != null) {
StringTokenizer st = new StringTokenizer(dirValue, ",");
String dirName = null;
while (st.hasMoreTokens()) {
dirName = normalizePath(st.nextToken().trim());
addRars(dirName);
}
}
// Get the list of the resource adapter names
try {
String rs = (String) ctx.lookup(RESOURCE_LIST);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "resource list= " + rs);
}
if (rs != null) {
StringTokenizer st = new StringTokenizer(rs, ",");
String resFilename = null;
while (st.hasMoreTokens()) {
resFilename = normalizePath(st.nextToken().trim());
resourceNames.add(resFilename);
}
}
} catch (NamingException e) {
logger.log(BasicLevel.ERROR, "Cannot lookup the configuration context at Resource service starting");
}
// Get a reference to the Transaction service
try {
ServiceManager sm = ServiceManager.getInstance();
ts = (TransactionService) sm.getTransactionService();
tm = ts.getTransactionManager();
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "Cannot get the Transaction service: " + e);
throw new ServiceException("Cannot get the Transaction service: ", e);
}
// Get the JMX Server via JMX Service
try {
mbeanServer =
((JmxService) ServiceManager.getInstance().getJmxService()).getJmxServer();
} catch (Exception e) {
// the JMX service may not be started
mbeanServer = null;
}
// Init the XML parsing mode to no validation
String parsingMode = "false";
try {
parsingMode = (String) ctx.lookup(PARSINGWITHVALIDATION);
} catch (NamingException e) {
// No problem if there is no value for 'parsingwithvalidation' (false by default)
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "No parsingwithvalidation value specified in context");
}
}
if ("false".equalsIgnoreCase(parsingMode)) {
RarManagerWrapper.setParsingWithValidation(false);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "XML parsing without validation");
}
} else {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "XML parsing with validation");
}
}
// Get the WorkManager defined in the EJB Service, if it exists
EJBService ejbService = null;
try {
ejbService = (EJBService) ServiceManager.getInstance().getEjbService();
workMgr = ejbService.getWorkManager();
} catch (Exception e) {
// the EJB service may not be started
workMgr = null;
}
// Get the parameters for the WorkManager
int execTime = 0;
try {
String etime = (String) ctx.lookup(EXECTIMEOUT);
execTime = (new Integer(etime)).intValue();
} catch (NamingException e) {
// No problem if there is no value --> default value
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "No exectimeout value specified in context, usually for client container");
}
}
// Thread wait timeout
int threadWaitTimeout = DEF_WRK_THREADWAITTIMEOUT;
try {
String tTimeout = (String) ctx.lookup(THREADWAITTIMEOUT);
threadWaitTimeout = (new Integer(tTimeout)).intValue();
if (threadWaitTimeout <= 0) {
threadWaitTimeout = DEF_WRK_THREADWAITTIMEOUT;
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Resetting thread wait timeout to " + DEF_WRK_THREADWAITTIMEOUT);
}
}
} catch (Exception e) {
// default value will be used.
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "No workthread wait timeout value specified in context");
}
}
// MIN thread pool size
int minWorkThreads = DEF_WRK_THREADS;
try {
String wThreads = (String) ctx.lookup(MINWORKTHREADS);
minWorkThreads = (new Integer(wThreads)).intValue();
if (minWorkThreads <= 0) {
minWorkThreads = DEF_WRK_THREADS;
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Resetting min threads to " + DEF_WRK_THREADS);
}
}
} catch (Exception e) {
// default value will be used.
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "No min workthreads value specified in context");
}
}
// MAX thread pool size
int maxWorkThreads = DEF_MAX_WRK_THREADS;
try {
String wThreads = (String) ctx.lookup(MAXWORKTHREADS);
maxWorkThreads = (new Integer(wThreads)).intValue();
} catch (Exception e) {
// default value will be used.
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "No max workthreads value specified in context");
}
}
// Create WorkManager if we cannot use the one defined in ejb
if (maxWorkThreads > 0 || workMgr == null) {
logger.log(BasicLevel.DEBUG, "Create a WorkManager for Resources");
if (maxWorkThreads <= 0) {
maxWorkThreads = DEF_MAX_WRK_THREADS;
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Resetting max threads to " + DEF_WRK_THREADS);
}
}
workMgr = new JWorkManager(minWorkThreads, maxWorkThreads, tm, threadWaitTimeout);
}
// Create BootstrapContext
XATerminator xat = null;
try {
xat = ts.getCurrent().getXATerminator();
} catch (Exception ex) {
logger.log(BasicLevel.ERROR, "Unable to get an XATerminator from the TransactionService");
throw new ServiceException("Unable to get an XATerminator from the TransactionService", ex);
}
bootCtx = new ResourceBootstrapContext(workMgr, xat);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "ResourceService initialized");
}
}
/**
* Start the Resource service.
* @throws ServiceException if the startup failed.
*/
public void doStart() throws ServiceException {
// creates each resource
String rarFileName = null;
CompNamingContext ctx = null;
for (int i = 0; i < resourceNames.size(); i++) {
rarFileName = (String) resourceNames.elementAt(i);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "rarFileName=" + rarFileName);
}
try {
ctx = new CompNamingContext(rarFileName);
ctx.rebind("rarFileName", rarFileName);
ctx.rebind("isInEar", new Boolean(false));
ctx.rebind("classloader", appsClassLoader);
createResourceAdapter(ctx);
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "JOnAS: Cannot create resource: " + rarFileName + " exception: " + e);
e.printStackTrace();
}
}
// process any delayed rars
if (!delayedRAs.isEmpty()) {
try {
processingDelayed = true;
Object [] rList = null;
rList = delayedRAs.toArray();
for (int i = 0; i < rList.length; i++) {
try {
createResourceAdapter((CompNamingContext) rList[i]);
} catch (Exception e) {
e.printStackTrace();
String rFile = (String) ((CompNamingContext) rList[i]).lookup("rarFileName");
logger.log(BasicLevel.ERROR, "JOnAS: Cannot create resource: " + rFile + " exception: " + e);
logger.log(BasicLevel.ERROR, "Please verify that the rarlink is correct/deployed");
}
}
} catch (Exception e) {
e.printStackTrace();
logger.log(BasicLevel.ERROR, "ResourceService: Error with delayed RAR file deployment\n" + e);
throw new ServiceException("ResourceService: Error with delayed RAR file deployment", e);
}
}
// Create and register the Resource Service MBean
if (mbeanServer != null) {
try {
mbeanServer.registerMBean(this, JonasObjectName.resourceService());
} catch (InstanceAlreadyExistsException iae) {
logger.log(BasicLevel.ERROR, "Cannot start the Resource Service Already Exists:\n" + iae);
throw new ServiceException("Cannot start the Resource Service Already Exists", iae);
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "ResourceService: Cannot start the Resource service:\n" + e);
throw new ServiceException("ResourceService: Cannot start the Resource service", e);
}
// Create and register the archive configuration MBeans
try {
ManagedBean oManaged = JonasMBeanTools.getRegistry().findManagedBean("ArchiveConfigMBean");
ModelMBean oMBean = oManaged.createMBean(new ArchiveConfigMBean());
mbeanServer.registerMBean(oMBean, JonasObjectName.ArchiveConfig());
oManaged = JonasMBeanTools.getRegistry().findManagedBean("RarConfigMBean");
oMBean = oManaged.createMBean(new RarConfigMBean());
mbeanServer.registerMBean(oMBean, JonasObjectName.RarConfig());
} catch (Exception e) {
logger.log(BasicLevel.WARN, "Could not register Archive Configuration MBean");
e.printStackTrace();
}
}
}
/**
* Stop the Resource service.
* @throws ServiceException if the stop failed.
*/
public void doStop() throws ServiceException {
ServiceException se = null;
synchronized (Rar.fileName2RA) {
Enumeration keys = Rar.fileName2RA.elements();
while (keys.hasMoreElements()) {
Rar ra = (Rar) keys.nextElement();
try {
ra.unRegister();
Rar.fileName2RA.remove(ra);
} catch (Exception ex) {
logger.log(BasicLevel.ERROR, "ResourceService: Received the following:" + ex);
ex.printStackTrace();
if (se == null) {
se = new ServiceException(ex.getMessage());
}
}
}
}
// unregister resource MBeans
if (mbeanServer != null) {
try {
// unregister Archive Config MBeans
mbeanServer.unregisterMBean(JonasObjectName.ArchiveConfig());
mbeanServer.unregisterMBean(JonasObjectName.RarConfig());
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "ResourceService: Cannot stop the Archive Config MBean:\n" + e);
}
try {
// unregister resource Service MBean
mbeanServer.unregisterMBean(JonasObjectName.resourceService());
} catch (MBeanRegistrationException mr) {
logger.log(BasicLevel.ERROR, "Cannot cleanly stop the ResourceService: "
+ mr.getMessage());
} catch (InstanceNotFoundException infe) {
logger.log(BasicLevel.ERROR, "Cannot cleanly stop the ResourceService: "
+ infe.getMessage());
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "ResourceService: Cannot stop the Resource service:\n" + e);
throw new ServiceException("ResourceService: Cannot stop the Resource service", e);
}
}
if (se != null) {
throw se;
}
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "ResourceService stopped");
}
}
// IMPLEMENTATION OF 'ResourceService' INTERFACE //
/**
* Create a new resource adapter. This Resource Adapter is configured via
* xml files in the rar file
* @param ctx Context to use for deploying an RAR
* @return Sting resource objectName
* @throws Exception error encountered
*/
public String createResourceAdapter(Context ctx) throws Exception {
// Parameters :
// rarFileName, isInEar, classloader and possible AltDD and earUrl
String rarFileName;
try {
rarFileName = (String) ctx.lookup("rarFileName");
ctx.rebind("deployed", new Boolean(false));
} catch (Exception ex) {
String err = "Error while getting parameter from context param.";
logger.log(BasicLevel.ERROR, err + ex.getMessage());
throw new ResourceServiceException(err, ex);
}
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, rarFileName);
}
if (!rarFileName.endsWith(".rar")) {
rarFileName += ".rar";
ctx.rebind("rarFileName", rarFileName);
}
// Determine if the RAR file exists
File f = new File(rarFileName);
if (!f.exists()) {
boolean found = false;
String resFileName = null;
// In case of the name is a rar file name, check also in
// the JONAS_BASE/rars directory
resFileName = RARSDIR + File.separator + rarFileName;
f = new File(resFileName);
found = f.exists();
if (found) {
rarFileName = resFileName;
ctx.rebind("rarFileName", rarFileName);
} else {
logger.log(BasicLevel.ERROR, "createResourceAdapter: " + resFileName + " not found");
Exception e = new NamingException(resFileName + " not found");
throw e;
}
}
URL rarUrl = f.toURL();
Rar rar = new Rar(ctx, getDomainName(), getJonasServerName(), workMgr, bootCtx);
try {
Context ctxRar = rar.processRar();
} catch (Exception ex) {
// Exception error in processing unregister
String err = "Error processing Rar: " + ex.getMessage();
try {
rar.unRegister();
} catch (Exception exc) {
err = err + " Unregister also failed with " + exc.getMessage();
}
if (ex.getMessage().indexOf("no jonas-ra.xml") > 0) {
throw new ResourceServiceException("", ex);
}
logger.log(BasicLevel.ERROR, err);
throw new ResourceServiceException(err, ex);
}
boolean isDeployed = false;
try {
isDeployed = ((Boolean) ctx.lookup("deployed")).booleanValue();
} catch (Exception ex) {
String err = "Error while getting parameter(isDeployed) from context param.";
logger.log(BasicLevel.ERROR, err + ex.getMessage());
throw new ResourceServiceException(err, ex);
}
if (!isDeployed) {
// If isDeployed in not set, then an rar-link was specified that is not deployed and if
// we are already processing the delayed rar files, then throw an exception otherwise
// update the delayedRAs vector and process it again later.
if (processingDelayed) {
logger.log(BasicLevel.ERROR, "ResourceService.createRA: Resource (" + rarFileName + ") contains an invalid rarlink.");
throw new ResourceServiceException("resource input file incorrect: invalid rarlink");
}
delayedRAs.add(ctx);
return null;
}
Vector jNames = rar.getJndinames();
if (jNames != null) {
for (int i = 0; i < jNames.size(); i++) {
Rar.jndiName2RA.put(jNames.get(i), rar);
}
}
// Processed and deployed rar, so add it to our lists
Rar.fileName2RA.put(rarUrl.getPath(), rar);
String onRar = null;
try {
onRar = (String) ctx.lookup("onRar");
} catch (Exception ex) {
String err = "Error while getting parameter(onRar) from context param.";
logger.log(BasicLevel.ERROR, err + ex.getMessage());
throw new ResourceServiceException(err, ex);
}
return onRar.toString();
}
/**
* Deploy the given rars of an ear file with the specified parent
* classloader (ear classloader). (This method is only used for
* for ear applications).
* @param ctx the context containing the configuration
* to deploy the rars.<BR>
* This context contains the following parameters :<BR>
* - urls the list of the urls of the rars to deploy.<BR>
* - earRootURL the URL of the ear application file.<BR>
* - earClassLoader the ear classLoader of the j2ee app.<BR>
* - altDDs the optional URI of deployment descriptor.<BR>
* @throws ResourceServiceException if an error occurs during
* the deployment.
*/
public void deployRars(Context ctx) throws ResourceServiceException {
// Gets the parameters from the context :
// - urls the list of the urls of the rars to deploy.
// - earRootURL the URL of the ear application file.
// - earClassLoader the ear classLoader of the j2ee app.
// - altDDs the optional URI of deployment descriptor.
URL[] urls = null;
URL earUrl = null;
ClassLoader earClassLoader = null;
URL[] altDDs = null;
try {
urls = (URL[]) ctx.lookup("urls");
earUrl = (URL) ctx.lookup("earUrl");
earClassLoader = (ClassLoader) ctx.lookup("earClassLoader");
altDDs = (URL[]) ctx.lookup("altDDs");
} catch (NamingException e) {
String err = "Error while getting parameter from context param ";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new ResourceServiceException(err, e);
}
delayedRAs.clear(); // reset the delayed RAs
// Deploy all the rars of the ear application.
for (int i = 0; i < urls.length; i++) {
// Get the name of a rar to deploy.
String fileName = urls[i].getFile();
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Deploy rar '" + 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 CompNamingContext(fileName);
contctx.rebind("rarFileName", fileName);
contctx.rebind("isInEar", new Boolean(true));
contctx.rebind("earUrl", earUrl);
if (altDDs[i] != null) {
contctx.rebind("altDD", altDDs[i]);
}
contctx.rebind("classloader", earClassLoader);
createResourceAdapter(contctx);
} catch (Exception e) {
// A rar is corrupted so undeploy all the deployed rar
// of the ear application.
logger.log(BasicLevel.ERROR, "Error when deploying '" + fileName + "'");
logger.log(BasicLevel.ERROR, e.getMessage());
logger.log(BasicLevel.ERROR, "Undeploy rar of the ear application");
for (int j = 0; j < i; j++) {
String rarFileName = urls[j].getFile();
try {
// Try to undeploy a rar of the ear application.
CompNamingContext compctx = new CompNamingContext(rarFileName);
compctx.rebind("rarFileName", rarFileName);
compctx.rebind("isInEar", new Boolean(true));
contctx.rebind("earUrl", earUrl);
unRegisterRar(compctx);
} catch (Exception ex) {
// Cannot undeploy a rar of the ear application
// So there is an error message.
logger.log(BasicLevel.ERROR, "Error when undeploying '" + rarFileName + "'");
logger.log(BasicLevel.ERROR, ex.getMessage());
logger.log(BasicLevel.ERROR, "Cannot undeploy rar of the ear application");
}
}
throw new ResourceServiceException("Error during the deployment", e);
}
}
// process any delayed rars
if (!delayedRAs.isEmpty()) {
try {
processingDelayed = true;
Object [] rList = null;
rList = delayedRAs.toArray();
for (int i = 0; i < rList.length; i++) {
try {
createResourceAdapter((CompNamingContext) rList[i]);
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "JOnAS: Cannot create resource: " + (String) rList[i] + " exception: " + e);
logger.log(BasicLevel.ERROR, "Please verify that the rarlink is correct");
e.printStackTrace();
}
}
} catch (Exception e) {
logger.log(BasicLevel.ERROR, "ResourceService: Error with delayed RAR file deployment\n" + e);
throw new ServiceException("ResourceService: Error with delayed RAR file deployment", e);
}
}
}
/**
* Undeploy the given rars of an ear file. (This method is only
* used for the ear applications).
* @param urls the list of the urls of the rars to undeploy.
* @param earUrl the URL of the associated EAR file
*/
public void unDeployRars(URL[] urls, URL earUrl) {
for (int i = 0; i < urls.length; i++) {
String fileName = urls[i].getFile();
if (Rar.fileName2RA.containsKey(fileName)) {
try {
// Try to undeploy a rar of the ear application.
CompNamingContext compctx = new CompNamingContext(fileName);
compctx.rebind("rarFileName", fileName);
compctx.rebind("isInEar", new Boolean(true));
compctx.rebind("earUrl", earUrl);
unRegisterRar(compctx);
} catch (Exception ex) {
logger.log(BasicLevel.ERROR, "Cannot undeploy resource: " + fileName + " " + ex);
}
} else {
logger.log(BasicLevel.ERROR, "Cannot remove the non-existant rar '" + fileName + "'");
}
}
}
/**
* Unregister the resource adapter.
* @param ctx Context to use for unregistering an RAR
* @throws Exception error encountered
*/
public void unRegisterRar(Context ctx) throws Exception {
String rarFileName;
try {
rarFileName = (String) ctx.lookup("rarFileName");
} catch (NamingException e) {
String err = "Error while getting parameter from context param.";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new ResourceServiceException(err, e);
} catch (Exception ex) {
String err = "Error while getting parameter from context param.";
logger.log(BasicLevel.ERROR, err + ex.getMessage());
throw new ResourceServiceException(err, ex);
}
if (manageLogger.isLoggable(BasicLevel.DEBUG)) {
manageLogger.log(BasicLevel.DEBUG, "TEST Unregister MBeans for RAR in file: " + rarFileName);
}
String rarPath = (new File(rarFileName)).toURL().getPath();
Rar rar = (Rar) Rar.fileName2RA.get(rarPath);
Vector jNames = rar.getJndinames();
rar.unRegister();
// Remove rars from hashtables
for (int i = 0; i < jNames.size(); i++) {
Rar.jndiName2RA.remove(jNames.get(i));
}
Rar.fileName2RA.remove(rarPath);
resourceNames.remove(normalizePath(rarFileName));
logger.log(BasicLevel.INFO,
"ResourceService: unRegisterRar: " + rarFileName);
}
/**
* Return the JDBC ResourceAdapter MBean ObjectNames deployed in the current server.
* The JDBC ResourceAdapters have a 'properties' attribue containing the following properties
* set (not null and not empty): 'dsClass', 'URL'.
* @return The found MBean ObjectNames or null if no JDBC ResourceAdapter MBean registered for
* the current server in the current domain.
* @throws Exception The ResourceAdapter MBeans checking failed.
*/
public ObjectName[] getJDBCResourceAdapaters() throws Exception {
ObjectName[] result = null;
ArrayList al = null;
ObjectName raOns = J2eeObjectName.getResourceAdapters(getDomainName(), getJonasServerName());
Set ons = mbeanServer.queryNames(raOns, null);
if (ons.isEmpty()) {
return null;
}
// Got ResourceAdapters for this server
al = new ArrayList();
Iterator it = ons.iterator();
for (; it.hasNext();) {
ObjectName aRaOn = (ObjectName) it.next();
Properties props = (Properties) mbeanServer.getAttribute(aRaOn, "properties");
String dsClassValue = props.getProperty("dsClass");
String urlValue = props.getProperty("URL");
if (dsClassValue != null
&& dsClassValue.length() != 0
&& urlValue != null
&& urlValue.length() != 0) {
// Thsis is a well configured JDBC ResourceAdapter
al.add(aRaOn);
}
}
int nbJDBCResourceAdapaters = al.size();
if (nbJDBCResourceAdapaters == 0) {
return null;
} else {
result = new ObjectName[nbJDBCResourceAdapaters];
for (int i = 0; i < nbJDBCResourceAdapaters; i++) {
result[i] = (ObjectName) al.get(i);
}
}
return result;
}
/**
* Return the JDBC ResourceAdapter MBean OBJECT_NAME deployed in the current server
* haveing the 'jndiName' attribue value equal to the given jndiName
* @param jndiName A DataSource jndi name we are looking for.
* @return The found MBean OBJECT_NAME or null if none of the JDBC ResourceAdapter MBean
* have the given jndi name.
* @throws Exception The ResourceAdapter MBeans checking failed.
*/
public String getJDBCResourceAdapater(String jndiName) throws Exception {
String result = null;
ObjectName[] raOns = getJDBCResourceAdapaters();
ObjectName raOn = null;
String raJndiName = null;
if (raOns != null) {
for (int i = 0; i < raOns.length; i++) {
raOn = raOns[i];
raJndiName = (String) mbeanServer.getAttribute(raOn, "jndiName");
if (jndiName.equals(raJndiName)) {
// found the JDBC RA MBean having the givent jndi name
return raOn.toString();
}
}
}
return result;
}
//--------------------------------------------------------------
// MBean Methods
//--------------------------------------------------------------
/**
* @return Integer Total Number of Resources available in JOnAS
*/
public Integer getCurrentNumberOfResource() {
return getCurrentNumberOfRars();
}
/**
* @return Integer Total Number of Rars available in JOnAS
*/
public Integer getCurrentNumberOfRars() {
return new Integer(Rar.fileName2RA.size());
}
/**
* @return the list of RAR files deployed
*/
public List getDeployedRars() {
ArrayList al = new ArrayList();
String rarFileName = null;
Enumeration keys = Rar.fileName2RA.keys();
while (keys.hasMoreElements()) {
rarFileName = keys.nextElement().toString();
try {
al.add((new File(rarFileName)).toURL().getPath());
} catch (Exception e) {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Unable to add rarfile " + rarFileName + " to arraylist");
}
}
}
return al;
}
/**
* Return the list of installed RAR containers.
* The RAR files or the directories with expanded RAR container are searched
* in JONAS_BASE/rars and all rar directories 'autoload'.
* @return The list of RAR files or the directories with expanded RAR container found
* @throws Exception if the list can't be retrieved
*/
public List getInstalledRars() throws Exception {
// get JAR files found in JONAS_BASE/rars
ArrayList al = JModule.getInstalledContainersInDir(RARSDIR, JModule.RAR_EXTENSION
, JModule.RAR_CHILD_DIR, JModule.RAR_CONFIRM_FILE);
// get RAR files found in all autoload directories
for (int i = 0; i < autoNames.size(); i++) {
al.addAll(JModule.getInstalledContainersInDir(autoNames.get(i).toString(),
JModule.RAR_EXTENSION, JModule.RAR_CHILD_DIR, JModule.RAR_CONFIRM_FILE));
}
return al;
}
/**
* This method is added temporarily. It will disapear when Rars will have their associated MBeans
* (when Rars will become manageable)
* @return the names of the rars currently deployed in the JOnAS server
*/
public Set getRarNames() {
HashSet names = new HashSet();
String rarFileName = null;
for (int i = 0; i < resourceNames.size(); i++) {
rarFileName = (String) resourceNames.elementAt(i);
names.add(rarFileName);
}
return names;
}
/**
* Deploy an RAR by delegating the operation to the createResourceAdapter method.
* This is used for JMX management.
* @param fileName the fileName of the rar which must be be deployed.
* @return The ObjectName of the MBean associated to the deployed J2EE Application
* @throws RemoteException if rmi call failed.
* @throws ResourceServiceException if the deployment of the RAR failed.
*/
public String deployRarMBean(String fileName) throws RemoteException, ResourceServiceException {
Context ctx = null;
String onRar = null;
try {
ctx = new CompNamingContext(fileName);
ctx.rebind("rarFileName", fileName);
ctx.rebind("isInEar", new Boolean(false));
ctx.rebind("classloader", appsClassLoader);
onRar = createResourceAdapter(ctx);
} catch (Exception e) {
String err = "Error when deploying the rar file: " + fileName;
logger.log(BasicLevel.ERROR, err + e.getMessage());
e.printStackTrace();
throw new ResourceServiceException(err, e);
}
return onRar;
}
/**
* Deploy the resource adapter
* @param fileName the name of the rar file.
* @throws Exception if unable to deploy the rar
* @return String ObjectName of the deployed rar
*/
public String deployRar(String fileName) throws Exception {
return deployRarMBean(fileName);
}
/**
* Test if the specified filename is already deployed or not.
* @param fileName the name of the rar file.
* @return true if the rar is deployed, else false.
*/
public Boolean isRarDeployed(String fileName) {
return new Boolean(isRarLoaded(fileName));
}
/**
* Test if the specified unpack name is already deployed or not. This
* method is defined in the ResourceService interface.
* @param unpackName the name of the rar file.
* @return true if the rar is deployed, else false.
*/
public boolean isRarDeployedByUnpackName(String unpackName) {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "entering for unpackName= " + unpackName);
}
/* // for each rar loaded
Enumeration lc = ears.elements();
while (lc.hasMoreElements()) {
Ear ear = (Ear) lc.nextElement();
// get unpack name of the ear
String deployedUnpackName = new File(ear.getUnpackName()).getName() ;
logger.log(BasicLevel.DEBUG, "deployedUnpackName=" + deployedUnpackName);
if (deployedUnpackName.equals(unpackName)) {
return true;
}
// else, go to the next loop
}
// not found
*/
return false;
}
/**
* Undeploy an RAR by delegating the operation to the unRegisterRar() method.
* This is used for JMX management.
* @param fileName the fileName of the rar which must be be undeployed.
* @throws RemoteException if rmi call failed.
* @throws ResourceServiceException if the undeployment of the RAR failed.
*/
public void unDeployRarMBean(String fileName) throws RemoteException, ResourceServiceException {
/* We have only the name of the file, not its associated path, so we look in
the current directory and in the rar applications directory
*/
boolean found = true;
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Trying to undeploy: " + fileName
+ " with the following deployed:" + Rar.fileName2RA);
}
try {
// Determine if the RAR is in list
File f = new File(fileName);
if (!Rar.fileName2RA.containsKey(f.toURL().getPath())) {
found = false;
// Check also in the JONAS_BASE/rars directory
String resFileName = RARSDIR + File.separator + fileName;
f = new File(resFileName);
if (Rar.fileName2RA.containsKey(f.toURL().getPath())) {
fileName = resFileName;
found = true;
}
}
if (!found) {
String err = "Cannot undeploy the rar '" + fileName + "', it is not deployed.";
logger.log(BasicLevel.ERROR, err);
throw new ResourceServiceException(err);
}
} catch (Exception ex) {
String err = "Error trying to undeployRarMBean " + fileName;
logger.log(BasicLevel.ERROR, err + ex.getMessage());
throw new ResourceServiceException(err, ex);
}
//We've got the file, now we bind the params
CompNamingContext compctx = null;
try {
compctx = new CompNamingContext(fileName);
compctx.rebind("rarFileName", fileName);
compctx.rebind("isInEar", new Boolean(false));
//Call the function
unRegisterRar(compctx);
} catch (NamingException e) {
String err = "Error when binding parameters";
logger.log(BasicLevel.ERROR, err + e.getMessage());
throw new ResourceServiceException(err, e);
} catch (Exception ex) {
String err = "Error when unRegistering rar " + fileName;
logger.log(BasicLevel.ERROR, err + ex.getMessage());
ex.printStackTrace();
throw new ResourceServiceException(err, ex);
}
}
/**
* Undeploy the resource adapter
* @param fileName the name of the rar file.
* @throws Exception if not able to undeploy the rar
*/
public void unDeployRar(String fileName) throws Exception {
unDeployRarMBean(fileName);
}
/**
* Test if the specified filename is already deployed or not
* @param fileName the name of the rar file.
* @return true if the rar is deployed, else false.
*/
public boolean isRarLoaded(String fileName) {
String updateName = null;
boolean isLoaded = false;
try {
if (Rar.fileName2RA.containsKey(fileName)) {
isLoaded = true;
}
// If not found check the exact filename
if (!isLoaded) {
// construct name for rars in JONAS_BASE/rars directory
updateName = RARSDIR + File.separator + fileName;
//Check if the rar is already deployed or not
if (Rar.fileName2RA.containsKey(updateName)) {
isLoaded = true;
}
}
} catch (Exception e) {
String err = "Cannot determine if the rar is deployed or not";
logger.log(BasicLevel.ERROR, err);
return false;
}
return isLoaded;
}
/**
* Return the list of installed RAR container ready to deploy.
*
* @return The list of deployable RAR container
* @throws Exception if error retrieving the list
*/
public List getDeployableRars() throws Exception {
List al = getInstalledRars();
al.removeAll(getDeployedRars());
return al;
}
/**
* Return the list of "autoload" directories for RAR containers.
* @return The list of all "autoload" directories
*/
public List getAutoloadDirectories() {
ArrayList al = new ArrayList();
for (int i = 0; i < autoNames.size(); i++) {
try {
al.add((new File(autoNames.get(i).toString())).toURL().getPath());
} catch (Exception e) {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG, "Can't get autoload directories : " + e.getMessage());
}
}
}
return al;
}
/**
* Return the Rars directory.
* @return The Rars directory
*/
public String getRarsDirectory() {
String sRet = null;
try {
sRet = (new File(RARSDIR)).toURL().getPath();
} catch (Exception e) {
throw new RuntimeException("Cannot get the RARS directory", e);
}
return sRet;
}
//--------------------------------------------------------------
// Private Methods
//--------------------------------------------------------------
/**
* Add recursively the rars of the specified directory.
* If the dir has a relative path, this path is relative from where
* the Application Server is launched. If the dir is not found it will
* be searched in $JONAS_BASE/rars/ directory.
* @param dirPath the path to the directory containing the rars to
* load.
*/
private void addRars(String dirPath) {
boolean found = false;
// Look the directory relative to the $JONAS_BASE/rars directory
File dir = new File(RARSDIR + File.separator + dirPath);
found = dir.isDirectory();
if (found) {
autoNames.add(dir);
addRarsFrom(dir);
} else {
String err = "Warning: Cannot load dir: '" + dirPath + "' ";
err += "is not a directory or directory doesn't exist";
logger.log(BasicLevel.WARN, err);
}
}
/**
* Add the rars of the specified directory.
* @param dir the directory from which the rars are loaded.
* @throws ResourceServiceException if the argument is not a directory
*/
private void addRarsFrom(File dir) throws ResourceServiceException {
try {
if (dir.isDirectory()) {
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
if (files[i].getPath().toLowerCase().endsWith(".rar")) {
resourceNames.add(files[i].getCanonicalPath());
}
} else {
autoNames.add(files[i]);
addRarsFrom(files[i]);
}
}
} else {
String err = "Cannot load dir: '" + dir.getPath();
err += "' is not a directory";
logger.log(BasicLevel.ERROR, err);
throw new ResourceServiceException(err);
}
} catch (IOException e) {
String err = "Invalid file name '" + dir.getPath();
logger.log(BasicLevel.ERROR, err);
throw new ResourceServiceException(err, e);
}
}
/**
* Normalize the path for the platform
* @param path the path to normalize
* @return String normalized path
*/
private String normalizePath(String path) {
String ret = null;
if (File.separatorChar == '/') {
ret = path.replace('\\', File.separatorChar);
} else {
ret = path.replace('/', File.separatorChar);
}
return ret;
}
}
|