/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/**
* PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
*
* Copyright 2001-2002 by iPlanet/Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*/
package com.sun.enterprise.admin.event;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sun.enterprise.admin.common.constant.AdminConstants;
import com.sun.enterprise.admin.server.core.channel.AdminChannel;
import com.sun.enterprise.admin.server.core.channel.RMIClient;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.ConfigAdd;
import com.sun.enterprise.config.ConfigBean;
import com.sun.enterprise.config.ConfigChange;
import com.sun.enterprise.config.ConfigDelete;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.ConfigSet;
import com.sun.enterprise.config.ConfigUpdate;
import com.sun.enterprise.config.impl.ConfigUpdateImpl;
import com.sun.enterprise.config.serverbeans.ServerTags;
import com.sun.enterprise.config.serverbeans.ServerXPathHelper;
//i18n import
import com.sun.enterprise.util.i18n.StringManager;
/**
* AdminEventCache is used to cache events during "Apply". It also is the
* single point where ConfigChange objects are associated to the events. This
* class has evolved from being a cache that tracked events between "Apply"
* boundaries to its current form, so a lot of methods have been deprecated.
* <p>
* User interface allows several changes to configuration to be sent to the
* instance by one operation -- Apply. The cache is used to store events
* generated by processing configuration changes obtained from
* ConfigContext. The apply operation then sends all events one after
* another to the administered instance.
* </p>
* <p>
* A typical sequence of calls will be -- where <code>name</code> is a <code>
* String</code> representing name of the server instance and <code>context
* </code> is an instance of type <code>com.sun.enterprise.config.ConfigContext
* </code> applicable to the server instance.
* </p>
* <pre>
AdminEventCache eventCache = AdminEventCache.getInstance(name);
ArrayList changeList = context.getConfigChangeList();
context.resetConfigChangeList();
eventCache.processConfigChangeList(changeList);
ArrayList eventList = eventCache.getAndResetCachedEvents();
Iterator iter = eventList.iterator();
while (iter.hasNext()) {
AdminEvent event = (AdminEvent)iter.next();
AdminEventResult result = AdminEventMulticaster.multicastEvent(event);
if (result.getResultCode() != AdminEventResult.SUCCESS) {
// Handle error
}
}
* </pre>
* <p>
* The method <code>processConfigChangeList</code> now handles all events,
* including those related to deployment of applications and modules.
* If Deployment action is accompanied with a implicit apply then it should
* be handled by the method <code>populateConfigChange</code>.
*</p>
*/
public class AdminEventCache {
/**
* A reference to logger object
*/
static Logger logger = Logger.getLogger(AdminConstants.kLoggerName);
/**
* A map of instance and its cache
*/
private static final transient HashMap instanceCacheMap = new HashMap();
/**
* Name of the server instance. The event cache is for this instance.
*/
private String instanceName;
/**
* Event cache. The cache is used to keep events during "Apply" processing
*/
private ArrayList cache;
/**
* Is restart needed.
*/
private boolean restartNeeded = false;
/**
* Timestamp restart is needed since.
*/
private long tsRestartNeededSince;
/**
* Admin config context. This is used to resolve application and resource
* references. The references do not contain types and a search through
* the config context is needed to determine the type.
*/
private ConfigContext adminConfigContext;
/**
* Create an instance of AdminEventCache. Every event cache is for a
* specific instance.
* @param instanceName name of the instance
*/
AdminEventCache(String instanceName) {
this.instanceName = instanceName;
cache = new ArrayList();
RMIClient channel = AdminChannel.getRMIClient(instanceName);
if (channel.isRestartNeeded()) {
setRestartNeededTrue(false);
}
}
/**
* Get event cache for specified instance.
* @param instanceName name of the instance
* @return event cache for the specified instance
*/
public synchronized static AdminEventCache getInstance(
String instanceName) {
AdminEventCache aec =
(AdminEventCache)instanceCacheMap.get(instanceName);
if (aec == null) {
aec = new AdminEventCache(instanceName);
instanceCacheMap.put(instanceName, aec);
}
return aec;
}
/**
* Set admin config context.
*/
public void setAdminConfigContext(ConfigContext ctx) {
adminConfigContext = ctx;
}
/**
* Get list of cached events. This method returns the list object
* being used inside this class, therefore, all changes to the list
* should be carefully considered.
* @return list of cached events.
*/
ArrayList getCachedEvents() {
return cache;
}
/**
* Get list of cached events and re-initialize the cache. This method
* should be called only after a call to processConfigChangeList(),
* @return list of cached events
*/
public synchronized ArrayList getAndResetCachedEvents() {
ArrayList saved = cache;
cache = new ArrayList();
return saved;
}
/**
* Add an event to the cache.
* @param event Event to be added to cache
* @deprecated with no substitution
*/
public void addEvent(AdminEvent event) {
cache.add(event);
}
/**
* Add specified list of events to the cache.
* @param eventList list of events to add to the cache
* @deprecated with no substitution
*/
public void addEvents(ArrayList eventList) {
cache.addAll(eventList);
}
/**
* Remove specified event from the cache.
* @param event the event to remove from cache
* @deprecated with no substitution
*/
public void removeEvent(AdminEvent event) {
cache.remove(event);
}
/**
* Process config change list and update cache with appropriate events.
* At the end of this method the cache will have zero or more events.
* It will contain an instance of ConfigChangeEvent if the specified
* parameter otherConfFilesChanges is true or if specified changeList is
* not null and the change does not fit in any of following events --
* MonitoringEvent with actionCode START_MONITOR or STOP_MONITOR or
* ResourceDeployEvent. If the cache already contains an instance
* ResourceDeployEvent for a given resource, then this method will not
* add any new instance of ResourceDeployEvent for that resource.
* @param changeList list of server.xml config changes
* @param initOrObFilesChanged whether conf files init.conf or obj.conf
* were changed
* @param mimeFileChanged whether mime type file(s) were changed
*/
public synchronized void processConfigChangeList(ArrayList changeList,
boolean initOrObjFilesChanged, boolean mimeFileChanged) {
ConfigChangeEvent dfltEvent = null;
boolean dfltEventCached = false;
Iterator iter = cache.iterator();
while (iter.hasNext()) {
Object obj = iter.next();
if (obj instanceof ConfigChangeEvent) {
dfltEvent = (ConfigChangeEvent)obj;
dfltEventCached = true;
break;
}
}
if (initOrObjFilesChanged || mimeFileChanged) {
if (dfltEvent == null) {
dfltEvent = new ConfigChangeEvent(instanceName, null);
}
dfltEvent.setWebCoreReconfigNeeded(true);
}
if (initOrObjFilesChanged) {
if (dfltEvent == null) {
dfltEvent = new ConfigChangeEvent(instanceName, null);
}
dfltEvent.setInitOrObjConfChanged(true);
}
if (changeList != null && !changeList.isEmpty()) {
iter = changeList.iterator();
while (iter.hasNext()) {
ConfigChange change = (ConfigChange)iter.next();
if (change != null) {
doChangeBucketing(change, dfltEvent, changeList);
}
}
}
if (( dfltEvent != null) && (!dfltEventCached) ){
cache.add(dfltEvent);
}
purgeNopEvents();
}
/**
* Process the specifid change and generate appropriate events.
* @param change the config change
* @param dflt the default config change event
* @param changeList all changes being processed. This is needed to
* handle references because if a resource has been deleted its
* type can only be found from the change list.
*/
private void doChangeBucketing(ConfigChange change,
ConfigChangeEvent dflt, ArrayList changeList) {
logger.log(Level.FINE, PROCESS_CHANGE, change);
if (change == null || change.getXPath() == null) {
logger.log(Level.FINE, CHANGE_NULL, change);
return;
}
boolean processed = false;
//processed = processLogLevelChangeEvent(change);
// if (!processed) {
// processed = processMonitoringLevelChangeEvent(change);
// }
// if (!processed) {
// processed = processResourceChangeEvent(change);
// }
// if (!processed) {
// processed = processResourceReference(change, changeList);
// }
/*
if (!processed) {
processed = processOtherDeployEvent(change);
}
if (!processed) {
processed = processApplicationReference(change, changeList);
}
*/
if (( dflt != null) && (!processed)) {
dflt.addConfigChange(change);
if (!dflt.isWebCoreReconfigNeeded()) {
setWebCoreReconfig(change, dflt);
}
}
}
/**
* Process changes to module log levels. One event is generated for every
* module whose log level is changed. The method returns true if change is
* for module log levels (excluding properties).
* @param change the change to be processed
* @return true if the change is for module log levels, false otherwise.
*/
private boolean processLogLevelChangeEvent(ConfigChange change) {
return processLevelChangeEvent(change,
new LogLevelChangeProcessor(this));
}
/**
* Process changes to module monitoring levels. One event is generated
* for every module whose monitoring level is changed. The method returns
* true if change is for module monitoring levels (excluding properties).
* @param change the change to be processed
* @return true if the change is for module monitoring levels, false
* otherwise.
*/
private boolean processMonitoringLevelChangeEvent(ConfigChange change) {
return processLevelChangeEvent(change,
new MonitoringLevelChangeProcessor(this));
}
/**
* Process changes to module level.
* @param change the change to be processed
* @param processor the handler for the change
* @return true if the change is applicable and events are generated,
* false otherwise.
*/
private boolean processLevelChangeEvent(ConfigChange change,
LevelChangeProcessor processor) {
// Only updates for level change can be handled dynamically, all
// other changes will require restart.
ConfigUpdate update = convertToConfigUpdate(change);
if (update == null) {
return false;
}
String xpath = cleanXPath(update.getXPath());
if (!processor.isRelevant(xpath)) {
return false;
}
Set attrs = update.getAttributeSet();
if (attrs == null) {
logger.log(Level.FINEST, "admin.event.null_updated_attrs",
update.getXPath());
return false;
}
Iterator iter = attrs.iterator();
while (iter.hasNext()) {
String compName = (String)iter.next();
String oldValue = update.getOldValue(compName);
String newValue = update.getNewValue(compName);
AdminEvent event = processor.createEvent(compName, oldValue,
newValue);
cache.add(event);
ConfigUpdate upd = new ConfigUpdateImpl(xpath, compName, oldValue,
newValue);
event.addConfigChange(upd);
}
return true;
}
/**
* Process the change and generate ResourceDeployEvent. If the change is
* to a xpath that represents a resource, then a resource deploy event for
* the resource represented by the xpath is added to cache, provided the
* cache does not already contain a resource deploy event for the same
* resource. If the attribute enabled is changed then the actionCode for
* the event is ENABLE or DISABLE, otherwise it is REDEPLOY. The change is
* considered fully processed if the xpath is for a resource.
* @return true if the change is fully processed, false otherwise.
*/
private boolean processResourceChangeEvent(ConfigChange change) {
String xpath = cleanXPath(change.getXPath());
boolean processed = false;
if (isResourceXPath(xpath)) {
String actionCode = null;
if (change instanceof ConfigUpdate) {
ConfigUpdate update = (ConfigUpdate)change;
String enableStr = update.getNewValue(ServerTags.ENABLED);
if (enableStr != null) {
if (getServerXmlBooleanValue(enableStr)) {
actionCode = ResourceDeployEvent.ENABLE;
} else {
actionCode = ResourceDeployEvent.DISABLE;
}
} else {
actionCode = ResourceDeployEvent.REDEPLOY;
}
} else if (change instanceof ConfigAdd) {
// In case of security-map, addition should fire
// redeploy event as it is part of connector-connection-pool
// resource.
boolean isMap = xpath.indexOf(ServerTags.SECURITY_MAP) != -1;
if (isPropertyXPath(xpath) || isMap) {
actionCode = ResourceDeployEvent.REDEPLOY;
} else {
actionCode = ResourceDeployEvent.DEPLOY;
}
} else if (change instanceof ConfigDelete) {
// In case of security-map, delete should fire redeploy event
// as it is part of connector-connection-pool resource.
boolean isMap = xpath.indexOf(ServerTags.SECURITY_MAP) != -1;
if (isPropertyXPath(xpath) || isMap) {
actionCode = ResourceDeployEvent.REDEPLOY;
} else {
actionCode = ResourceDeployEvent.UNDEPLOY;
}
} else if (change instanceof ConfigSet) {
// As of now set is used for existing properties in resources.
// Existing properties imply that resource exists.
actionCode = ResourceDeployEvent.REDEPLOY;
} else {
// Unknown ConfigChange cannot be handled
String msg = localStrings.getString( "admin.event.unknown_configchange_for_resources");
throw new IllegalStateException( msg );
}
String resType = getResourceType(xpath);
String resName = getResourceName(xpath);
ResourceDeployEvent resEvent =
findResourceDeployEvent(resType, resName);
if (resEvent == null) {
resEvent = new ResourceDeployEvent(instanceName, resName,
resType, actionCode);
cache.add(resEvent);
} else {
if (isActionValidForCache(actionCode)) {
resEvent.setNewAction(actionCode);
} else {
// As resEvent was not null, this is not the first change
// being processed for this xpath. Enable and Disable are
// not valid actions for second change of a resource xpath
}
}
resEvent.addConfigChange(change);
processed = true;
}
return processed;
}
/**
* Is this a resource XPATH. The method returns true if the XPATH is for
* a resource.
* @param xpath the xpath
* @return true if the xpath is for a resource, false otherwise.
*/
private boolean isResourceXPath(String xpath) {
String xpathLcase = xpath.toLowerCase();
if (xpathLcase.startsWith(RES_PFX)) {
return true;
}
return false;
}
/**
* Is specified xpath for property.
* @param xpath the xpath to be checked
* @returns true if the xpath is for a property, false otherwise
*/
private boolean isPropertyXPath(String xpath) {
return AdminEventCache.matchRegex(PROPERTY_REGEX, xpath);
}
/**
* Is specified xpath for module log levels.
* @param xpath the xpath to be checked
* @returns true if the xpath is for module log levels, false otherwise
*/
private boolean isLogLevelXPath(String xpath) {
return (LOG_LEVEL_XPATH.equalsIgnoreCase(xpath));
}
/**
* Is specified xpath for module monitoring levels.
* @param xpath the xpath to be checked
* @returns true if the xpath is for module monitoring levels, false
* otherwise
*/
private boolean isMonitoringLevelXPath(String xpath) {
return (MONITORING_LEVEL_XPATH.equalsIgnoreCase(xpath));
}
/**
* Is specified xpath for application reference
* @param xpath the xpath to be checked
* @returns true if the xpath is for application reference, false
* otherwise
*/
private boolean isAppRefXPath(String xpath) {
if (xpath == null) {
return false;
}
String serverXPath = ServerXPathHelper.getServerIdXpath(instanceName);
String appRefXPath = serverXPath + ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.APPLICATION_REF;
return xpath.startsWith(appRefXPath);
}
/**
* Is specified xpath for application reference
* @param xpath the xpath to be checked
* @returns true if the xpath is for resource reference, false
* otherwise
*/
private boolean isResRefXPath(String xpath) {
if (xpath == null) {
return false;
}
String serverXPath = ServerXPathHelper.getServerIdXpath(instanceName);
String resRefXPath = serverXPath + ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.RESOURCE_REF;
return xpath.startsWith(resRefXPath);
}
/**
* Get app ref xpath for specified app and server.
* @param instance name of the server
* @param appName name of the application
* @return xpath corresponding to the application ref
*/
private static String getAppRefXPath(String instance, String appName) {
return ServerXPathHelper.getServerIdXpath(instance)
+ ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.APPLICATION_REF + "[@"
+ ServerTags.REF + "='" + appName + "']";
}
/**
* Get resource type from the xpath.
* @param xpath the xpath for a resource
* @return the type of the resource, appropriate for use in
* constructor of ResourceDeployEvent.
*/
private String getResourceType(String xpath) {
String resType = "unknown";
String xpathLcase = xpath.toLowerCase();
if (xpathLcase.startsWith(ServerXPathHelper.XPATH_CUSTOM_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_CUSTOM;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_JNDI_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_EXTERNAL_JNDI;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_JDBC_CONNECTION_POOL)) {
resType = ResourceDeployEvent.RES_TYPE_JCP;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_JDBC_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_JDBC;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_MAIL_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_MAIL;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_PM_FACTORY_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_PMF;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_ADMIN_OBJECT_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_AOR;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_CONNECTOR_CONNECTION_POOL)) {
resType = ResourceDeployEvent.RES_TYPE_CCP;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_CONNECTOR_RESOURCE)) {
resType = ResourceDeployEvent.RES_TYPE_CR;
} else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_RESOURCE_ADAPTER_CONFIG)) {
resType = ResourceDeployEvent.RES_TYPE_RAC;
}
return resType;
}
/**
* Get name of the resource from a resource xpath.
* @param xpath the xpath for a resource
* @return the name of the resource
*/
private String getResourceName(String xpath) {
return getXPathToken(xpath, 1);
}
/**
* Extract token separated by single-quote character (') after
* discarding specified number of tokens. For example,
* <pre>
xpath numToDiscard Returns
/a/b/c[@name='myName'] 1 myName
/a/b/c[@name='myName']/d[@id='myId'] 3 myId
* </pre>
* Note that the value contains single-quote character, the xpath will
* be formed with ' and the caller has to convert to appropriate
* character.
* @param xpath the xpath from where token needs to be extracted
* @param numToDiscard number of tokens to discard
* @throws IllegalArgumentException if the xpath does not contain enough
* tokens.
* @return the token after discarding numToDiscard tokens from xpath
*/
private String getXPathToken(String xpath, int numToDiscard) {
StringTokenizer tok = new StringTokenizer(xpath, "'");
if (tok.countTokens() <= numToDiscard) {
Object[] params = new Object[] {xpath,
new Integer(numToDiscard + 1),
new Integer(tok.countTokens())};
logger.log(Level.FINE, INVALID_XPATH_TOKENIZATION, params);
String msg = localStrings.getString(
"admin.event.invalid_xpath_tokenization", params );
throw new IllegalArgumentException(msg);
}
for (int i = numToDiscard; i > 0; i--) {
String discard = tok.nextToken();
}
return tok.nextToken();
}
/**
* Process the change and generate ApplicationDeployEvent or
* ModuleDeployEvent. If the change is to a xpath that represents an
* application or module, then an application or module deploy event for
* the resource represented by the xpath is added to cache, provided the
* cache does not already contain a application or module deploy event for
* the same resource. If the attribute enabled is changed then the
* actionCode for the event is ENABLE or DISABLE, otherwise it is REDEPLOY.
* The change is considered fully processed if the xpath is for an
* application or a module.
* @return true if the change is fully processed, false otherwise.
*/
private boolean processOtherDeployEvent(ConfigChange change) {
String xpath = cleanXPath(change.getXPath());
String xpathLcase = xpath.toLowerCase();
boolean processed = false;
String componentType = null;
String moduleType = null;
if (xpathLcase.startsWith(APP_PFX)) {
componentType = BaseDeployEvent.APPLICATION;
} else if (xpathLcase.startsWith(EJB_PFX)) {
componentType = BaseDeployEvent.MODULE;
moduleType = ModuleDeployEvent.TYPE_EJBMODULE;
} else if (xpathLcase.startsWith(WEB_PFX)) {
componentType = BaseDeployEvent.MODULE;
moduleType = ModuleDeployEvent.TYPE_WEBMODULE;
} else if (xpathLcase.startsWith(RAR_PFX)) {
componentType = BaseDeployEvent.MODULE;
moduleType = ModuleDeployEvent.TYPE_CONNECTOR;
} else if (xpathLcase.startsWith(ACC_PFX)) {
componentType = BaseDeployEvent.MODULE;
moduleType = ModuleDeployEvent.TYPE_APPCLIENT;
} else {
return false;
}
String componentName = getResourceName(xpath);
BaseDeployEvent theEvent = null;
if (BaseDeployEvent.APPLICATION.equals(componentType)) {
theEvent = findApplicationDeployEvent(componentName);
} else {
theEvent = findModuleDeployEvent(moduleType, componentName);
}
if (theEvent == null) {
String actionCode = null;
if (change instanceof ConfigUpdate) {
/* krav
ConfigUpdate update = (ConfigUpdate)change;
String enableStr = update.getNewValue(ServerTags.ENABLED);
if (enableStr != null) {
if (getServerXmlBooleanValue(enableStr)) {
actionCode = BaseDeployEvent.ENABLE;
} else {
actionCode = BaseDeployEvent.DISABLE;
}
} else {
actionCode = BaseDeployEvent.REDEPLOY;
}
*/
} else if (change instanceof ConfigAdd) {
actionCode = BaseDeployEvent.DEPLOY;
} else if (change instanceof ConfigDelete) {
actionCode = BaseDeployEvent.UNDEPLOY;
} else {
String msg = localStrings.getString( "admin.event.handle_add_delete_set_configchange" );
throw new IllegalStateException( msg );
}
if (actionCode != null) {
if (BaseDeployEvent.APPLICATION.equals(componentType)) {
theEvent = new ApplicationDeployEvent(instanceName,
componentName, actionCode);
} else {
theEvent = new ModuleDeployEvent(instanceName, componentName,
moduleType, actionCode);
}
cache.add(theEvent);
processed = true;
}
} else { // (theEvent != null)
// Event is not null. Any update will not affect it. If the change
// is not update (add, delete or set) -- assume that it already
// affected the state of event when the change was made
processed = true;
}
theEvent.addConfigChange(change);
return processed;
}
/**
* Process the change and create/update appropriate resource events, if the
* change represents a resource reference.
* @param change the change to be processed
* @param changeList all the changes being processed in the current batch
* @return true if the change is for a resource reference and was added
* to an existing or a new event.
*/
private boolean processResourceReference(ConfigChange change,
ArrayList changeList) {
return processReference(change, changeList, new ResRefProcessor(this));
}
/**
* Process the change and create/update appropriate application or module
* events, if the change represents a application reference.
* @param change the change to be processed
* @param changeList all the changes being processed in the current batch
* @return true if the change is for a application reference and was added
* to an existing or a new event.
*/
private boolean processApplicationReference(ConfigChange change,
ArrayList changeList) {
return processReference(change, changeList, new AppRefProcessor(this));
}
/**
* Process reference and create/update appropriate event in the cache.
* @param change the change to be processed
* @param changeList all changes being processed along with this change.
* The change list is needed to determine type of the config object
* that the ref is referring to, in cases when the actual config
* object has been deleted and is no longer present in config context.
* @param processor the processor for the reference. It is the abstraction
* that hides differences between application refs and resource refs.
* @return true if the change can be handled by specified processor and
* is handled successfully, false otherwise.
*/
private boolean processReference(ConfigChange change, ArrayList changeList,
RefProcessor processor) {
String xpath = cleanXPath(change.getXPath());
if (!processor.isRelevant(xpath)) {
return false;
}
String refName = processor.getRefName(xpath);
processor.initRefTypeXPathMap(refName);
String refType = processor.getRefType(refName, changeList);
if (refType == null) {
// The ref is not interesting, for example, lifecycle module ref
return false;
}
return processor.process(refName, refType, change);
}
/**
* Set web core reconfig status in specified event if the change warrants
* that. Any config change to http-service or web container element require
* a web core reconfig.
* @param change the config change object
* @param dflt the default config change event
*/
private void setWebCoreReconfig(ConfigChange change,
ConfigChangeEvent dflt) {
String xpath = cleanXPath(change.getXPath());
if (isWebCoreXPath(xpath)) {
dflt.setWebCoreReconfigNeeded(true);
}
return;
}
/**
* Is specified XPath handled only by web core. All elements under
* http-service and web-container are handled exclusively by web core.
* @param xpath the xpath to process
* @return true if the xpath is handled only by web core, false otherwise.
*/
private boolean isWebCoreXPath(String xpath) {
boolean webCoreXPath = false;
if (xpath == null) {
return webCoreXPath;
} else {
xpath = xpath.toLowerCase();
}
if (xpath.startsWith(HTTP_SERVICE) || xpath.startsWith(WEB_CONTAINER)) {
webCoreXPath = true;
}
return webCoreXPath;
}
/**
* Get a boolean value corresponding to the string value in xml.
* @param xmlValue the xml string representing a boolean
* @return true if the string is "true", "yes", "on" or "1"
*/
public static boolean getServerXmlBooleanValue(String xmlValue) {
boolean retval = false;
if (xmlValue == null) {
return retval;
}
if (xmlValue.equalsIgnoreCase("true")
|| xmlValue.equalsIgnoreCase("yes")
|| xmlValue.equalsIgnoreCase("on")
|| xmlValue.equalsIgnoreCase("1")) {
retval = true;
}
return retval;
}
/**
* Convert to config update, if possible. If specified change is not
* an instanceof ConfigUpdate, the method returns null
*/
private ConfigUpdate convertToConfigUpdate(ConfigChange change) {
ConfigUpdate update = null;
if (change instanceof ConfigUpdate) {
update = (ConfigUpdate)change;
}
return update;
}
/**
* Cache a resource change. This method inspects the cache and either
* updates the existing event or creates a new resource event.
* @param resourceType Type of the resource
* @param resourceName Name of the resource
* @param actionCode Action code, one of BaseDeployEvent.DEPLOY,
* BaseDeployEvent.REDEPLOY or BaseDeployEvent.UNDEPLOY
* @deprecated with no substitution.
*/
public void cacheResourceChange(String resourceType, String resourceName,
String actionCode) {
// Valid values for actionCode are DEPLOY, UNDEPLOY and REDEPLOY and
// not ENABLE and DISABLE which can come only from analyzing config
// changes.
if (!isActionValidForCache(actionCode)) {
String msg = localStrings.getString( "admin.event.invalid_action", actionCode );
throw new IllegalArgumentException( msg );
}
ResourceDeployEvent resEvent = findResourceDeployEvent(resourceType,
resourceName);
if (resEvent == null) {
resEvent = new ResourceDeployEvent(instanceName, resourceName,
resourceType, actionCode);
cache.add(resEvent);
} else {
resEvent.setNewAction(actionCode);
}
}
/**
* Check whether specified deploy action can be cached. Only deploy actions
* - DEPLOY, UNDEPLOY and REDEPLOY can be cached. The other deploy actions
* ENABLE, DISABLE are derived from the cache of changes.
* @param deployAction the deployment action
* @return true if deploy action is valid, false otherwise
*/
private boolean isActionValidForCache(String deployAction) {
boolean valid = false;
if (deployAction != null) {
if (deployAction.equals(BaseDeployEvent.DEPLOY)
|| deployAction.equals(BaseDeployEvent.UNDEPLOY)
|| deployAction.equals(BaseDeployEvent.REDEPLOY)) {
valid = true;
}
}
return valid;
}
/**
* Populate config changes in the specified event. This method looks for
* changes matching the event in the specified config context and if there
* are any the changes are moved from config context to the event. This
* method can only handle ApplicationDeployEvent and ModuleDeployEvent.
* @param ctx The config context where the cache of changes is examined for
* match
* @param event The event for which matching changes should be looked up
* @throws UnsupportedOperationException if the event is not Application or
* Module deploy event.
*/
public static void populateConfigChange(ConfigContext ctx, AdminEvent event) {
if (event instanceof ApplicationDeployEvent) {
populateApplicationConfigChange(ctx, (ApplicationDeployEvent)event);
} else if (event instanceof ModuleDeployEvent) {
populateModuleConfigChange(ctx, (ModuleDeployEvent)event);
} else {
String msg = localStrings.getString( "admin.event.unsupported_populateconfigchange", event.getClass().getName() );
throw new UnsupportedOperationException( msg );
}
}
/**
* Populate config changes from specified config context into the specified
* application deployment event.
* @param ctx the config context
* @param event the application deployment event
*/
private static void populateApplicationConfigChange(ConfigContext ctx,
ApplicationDeployEvent event) {
String xpath = ServerXPathHelper.getAppIdXpathExpression(
event.getApplicationName());
xpath = cleanXPath(xpath);
event.addConfigChange(extractConfigChanges(ctx, xpath));
// Now look for any changes to application ref
String refXPath = getAppRefXPath(event.getInstanceName(),
event.getApplicationName());
event.addConfigChange(extractConfigChanges(ctx, refXPath));
}
/**
* Populate config changes from specified config context into the specified
* module deployment event.
* @param ctx the config context
* @param event the module deployment event
* @throws IllegalArgumentException if module type as specified in the
* event is not one of EJB, WEB, CONNECTOR or APPCLIENT
*/
private static void populateModuleConfigChange(ConfigContext ctx,
ModuleDeployEvent event) {
String moduleType = event.getModuleType();
String moduleName = event.getModuleName();
String xpath = null;
if (event.TYPE_WEBMODULE.equals(moduleType)) {
xpath = ServerXPathHelper.getWebModuleIdXpathExpression(moduleName);
} else if (event.TYPE_EJBMODULE.equals(moduleType)) {
xpath = ServerXPathHelper.getEjbModuleIdXpathExpression(moduleName);
} else if (event.TYPE_CONNECTOR.equals(moduleType)) {
xpath = ServerXPathHelper.getConnectorModuleIdXpathExpression(
moduleName);
} else if (event.TYPE_APPCLIENT.equals(moduleType)) {
xpath = ServerXPathHelper.getAppClientModuleIdXpathExpression(
moduleName);
} else {
String msg = localStrings.getString( "admin.event.invalid_module_type" , moduleType );
throw new IllegalArgumentException( msg );
}
xpath = cleanXPath(xpath);
event.addConfigChange(extractConfigChanges(ctx, xpath));
// Now look for any changes to application ref
String refXPath = getAppRefXPath(event.getInstanceName(), moduleName);
event.addConfigChange(extractConfigChanges(ctx, refXPath));
}
/**
* Extract config changes matching specified xpath from config context.
* @param configContext the context from where changes are extracted
* @param xpath the xpath for which all changes should be extracted
* @throws IllegalArgumentException if specified config context is null
* @throws IllegalStateException if list of changes maintained by config
* context is null.
*/
private static ArrayList extractConfigChanges(ConfigContext configContext,
String xpath) {
if (configContext == null) {
String msg = localStrings.getString( "admin.event.null_config_context" );
throw new IllegalArgumentException( msg );
}
ArrayList myChanges = new ArrayList();
ArrayList allChanges = configContext.getConfigChangeList();
if (allChanges == null) {
String msg = localStrings.getString( "admin.event.null_config_changes_in_configcontext" );
throw new IllegalStateException( msg );
}
logger.log(Level.FINE, EXTRACT_CHANGE, xpath);
Iterator iter = allChanges.iterator();
while (iter.hasNext()) {
ConfigChange change = (ConfigChange)iter.next();
logger.log(Level.FINE, PROCESS_CHANGE, change);
String changeXPath = null;
if (change != null) {
changeXPath = cleanXPath(change.getXPath());
logger.log(Level.FINEST, CONFIG_CHANGE_XPATH, changeXPath);
}
if (change == null || changeXPath == null) {
logger.log(Level.FINE, CHANGE_NULL, change);
continue;
}
if (changeXPath.equals(xpath)) {
//System.out.println("Xpath matches, adding change to the list");
myChanges.add(change);
} else {
//System.out.println("No match, ignoring");
}
}
iter = myChanges.iterator();
while (iter.hasNext()) {
configContext.removeConfigChange((ConfigChange)iter.next());
}
return myChanges;
}
/**
* Clean XPath. This method converts all xpaths to lower case and replaces
* two or more consecutive forward slash ('/') character by a single
* forward slash.
* @return modified XPath
*/
private static String cleanXPath(String xpath) {
if (xpath == null) {
return xpath;
}
return xpath.replaceAll("/{2,}", "/");
}
/**
* Match a string against a regular expression.
* @param regex the regular expression to match
* @param str the string to match
* @returns true if the regular expression matches string
*/
private static boolean matchRegex(String regex, String str) {
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher.matches();
}
/**
* Find matching resource deploy event in the cache. This method iterates
* through all cached events and tries to find a ResourceDeployEvent for
* specified resource type and name. The method returns null if it doesn't
* find a match.
* @param resType type of the resource
* @param resName name of the resource
* @throws IllegalArgumentException if resource type or name is null
* @return matching ResourceDeployEvent if found, null otherwise.
*/
private ResourceDeployEvent findResourceDeployEvent(String resType,
String resName) {
if (resType == null || resName == null) {
String msg = localStrings.getString( "admin.event.null_resource_type_or_name", resType, resName );
throw new IllegalArgumentException( msg );
}
ResourceDeployEvent resEvent = null;
Iterator iter = cache.iterator();
while (iter.hasNext()) {
AdminEvent event = (AdminEvent)iter.next();
if (event instanceof ResourceDeployEvent) {
resEvent = (ResourceDeployEvent)event;
if (resType.equals(resEvent.getResourceType())
&& resName.equals(resEvent.getResourceName())) {
break;
} else {
resEvent = null;
}
}
}
return resEvent;
}
/**
* Find matching application deploy event in the cache. This method iterates
* through all cached events and tries to find an ApplicationDeployEvent for
* specified name. The method returns null if it doesn't find a match.
* @param appName name of the application
* @throws IllegalArgumentException if specified application name is null
* @return matching ApplicationDeployEvent if found, null otherwise.
*/
private ApplicationDeployEvent findApplicationDeployEvent(String appName) {
if (appName == null) {
String msg = localStrings.getString( "admin.event.null_application_name" );
throw new IllegalArgumentException( msg );
}
ApplicationDeployEvent appEvent = null;
Iterator iter = cache.iterator();
while (iter.hasNext()) {
AdminEvent event = (AdminEvent)iter.next();
if (event instanceof ApplicationDeployEvent) {
appEvent = (ApplicationDeployEvent)event;
if (appName.equals(appEvent.getApplicationName())) {
break;
} else {
appEvent = null;
}
}
}
return appEvent;
}
/**
* Find matching module deploy event in the cache. This method iterates
* through all cached events and tries to find a ModuleDeployEvent for
* specified module type and name. The method returns null if it doesn't
* find a match.
* @param modType type of the module
* @param modName name of the module
* @throws IllegalArgumentException if module type or name is null
* @return matching ModuleDeployEvent if found, null otherwise.
*/
private ModuleDeployEvent findModuleDeployEvent(String modType,
String modName) {
if (modType == null || modName == null) {
String msg = localStrings.getString( "admin.event.null_module_type_or_name", modType, modName );
throw new IllegalArgumentException( msg );
}
ModuleDeployEvent modEvent = null;
Iterator iter = cache.iterator();
while (iter.hasNext()) {
AdminEvent event = (AdminEvent)iter.next();
if (event instanceof ModuleDeployEvent) {
modEvent = (ModuleDeployEvent)event;
if (modEvent.getModuleType().equals(modType)
&& modEvent.getModuleName().equals(modName)) {
break;
} else {
modEvent = null;
}
}
}
return modEvent;
}
/**
* Purge events that are NO-OP.
*/
private void purgeNopEvents() {
Iterator iter = cache.iterator();
while (iter.hasNext()) {
AdminEvent event = (AdminEvent)iter.next();
if (event.isNoOp()) {
logger.log(Level.FINE, PURGE_NOOP, event);
iter.remove();
}
}
}
/**
* Set whether the instance requires restart. Cache is invalid if instance
* requires restart.
*/
public void setRestartNeeded(boolean flag) {
if (flag) {
if (!restartNeeded) {
setRestartNeededTrue(true);
}
} else {
restartNeeded = false;
}
}
/**
* Set restart needed to true. This method also records the timestamp
* when restart needed was set to true. If parameter notifyInstance is
* true the instance is notified that it requires a restart.
* @param notifyInstance if true the instance is notified of the restart
* required status.
*/
private void setRestartNeededTrue(boolean notifyInstance) {
restartNeeded = true;
tsRestartNeededSince = System.currentTimeMillis();
if (notifyInstance) {
RMIClient channel = AdminChannel.getRMIClient(instanceName);
channel.setRestartNeeded(true);
}
}
/**
* Is restart of instance required.
*/
public boolean isInstanceRestartNeeded() {
if (restartNeeded) {
RMIClient channel = AdminChannel.getRMIClient(instanceName);
boolean alreadyRestarted =
channel.hasRestartedSince(tsRestartNeededSince);
if (alreadyRestarted) {
restartNeeded = false;
}
}
return restartNeeded;
}
private final static String RES_PFX = ServerXPathHelper.XPATH_RESOURCES;
private final static String APP_PFX = ServerXPathHelper.XPATH_J2EE_APPLICATION;
private final static String WEB_PFX = ServerXPathHelper.XPATH_WEB_MODULE;
private final static String EJB_PFX = ServerXPathHelper.XPATH_EJB_MODULE;
private final static String RAR_PFX = ServerXPathHelper.XPATH_CONNECTOR_MODULE;
private final static String ACC_PFX = ServerXPathHelper.XPATH_APPCLIENT_MODULE;
private final static String HTTP_SERVICE = ServerXPathHelper.XPATH_HTTP_SERVICE;
private final static String WEB_CONTAINER = ServerXPathHelper.XPATH_WEB_CONTAINER;
private final static String PROPERTY_REGEX = ServerXPathHelper.XPATH_DOMAIN
+ ServerXPathHelper.XPATH_SEPARATOR + "{1,}" + ".*"
+ ServerXPathHelper.XPATH_SEPARATOR + "{1,}"
+ ServerTags.ELEMENT_PROPERTY + ".*";
private final static String LOG_LEVEL_XPATH =
ServerXPathHelper.XPATH_CONFIG + ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.LOG_SERVICE + ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.MODULE_LOG_LEVELS;
private final static String MONITORING_LEVEL_XPATH =
ServerXPathHelper.XPATH_CONFIG + ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.MONITORING_SERVICE + ServerXPathHelper.XPATH_SEPARATOR
+ ServerTags.MODULE_MONITORING_LEVELS;
private final static String PROCESS_CHANGE = "event.process_change";
private final static String CHANGE_NULL = "event.change_null";
private final static String EXTRACT_CHANGE = "event.extract_change";
private final static String CONFIG_CHANGE_XPATH = "event.config_change_xpath";
private final static String PURGE_NOOP = "event.purge_noop";
private final static String NULL_UPDATED_ATTRS = "event.null_updated_attrs";
private final static String INVALID_XPATH_TOKENIZATION =
"event.invalid_xpath_tokenization";
// i18n StringManager
private static StringManager localStrings =
StringManager.getManager( AdminEventCache.class );
/**
* An abstraction to allow processing of all level changes in same method.
* The processing to generate events for log level changes and monitoring
* level changes are very similar. This class abstracts out the differences
* such that the code to generate event can be implemented in a single
* method.
*/
abstract class LevelChangeProcessor {
AdminEventCache eventCache;
LevelChangeProcessor(AdminEventCache cache) {
eventCache = cache;
}
abstract boolean isRelevant(String xpath);
abstract AdminEvent createEvent(String componentName, String oldValue,
String newValue);
}
/**
* Processor for changes to log level.
*/
class LogLevelChangeProcessor extends LevelChangeProcessor {
LogLevelChangeProcessor(AdminEventCache cache) {
super(cache);
}
boolean isRelevant(String xpath) {
return eventCache.isLogLevelXPath(xpath);
}
AdminEvent createEvent(String componentName, String oldValue,
String newValue) {
LogLevelChangeEvent event = new LogLevelChangeEvent(
eventCache.instanceName);
event.setModuleName(componentName);
event.setOldLogLevel(oldValue);
event.setNewLogLevel(newValue);
return event;
}
}
/**
* Processor for changes to monitoring level.
*/
class MonitoringLevelChangeProcessor extends LevelChangeProcessor {
MonitoringLevelChangeProcessor(AdminEventCache cache) {
super(cache);
}
boolean isRelevant(String xpath) {
return eventCache.isMonitoringLevelXPath(xpath);
}
AdminEvent createEvent(String componentName, String oldValue,
String newValue) {
MonitoringLevelChangeEvent event = new MonitoringLevelChangeEvent(
eventCache.instanceName);
event.setComponentName(componentName);
event.setOldMonitoringLevel(oldValue);
event.setNewMonitoringLevel(newValue);
return event;
}
}
/**
* RefProcessor is an abstraction for references. The configuration
* element server contains references to applications and resources.
* There is a lot of commonality between the events generated for
* changes to all references. This class tries to abstract the common
* behavior out.
*/
abstract class RefProcessor {
AdminEventCache adminEventCache;
Map refTypeXPathMap = new HashMap();
boolean resEnabled;
RefProcessor(AdminEventCache cache) {
adminEventCache = cache;
}
/**
* Is the xpath relevant. Used to determine whether to continue
* processing the config change.
*/
abstract boolean isRelevant(String xpath);
/**
* Process the config change and generate events for specified ref
* name and ref type.
* @param refName name of the reference. The reference name is unique
* for any given type. For example, no two resource refs can share
* the same name.
* @param refType type of the reference. This represents the type
* used in events. For example, ResourceDeployEvent.RES_TYPE_JCP or
* ApplicationDeployEvent.APPLICATION or
* ModuleDeployEvent.TYPE_WEBMODULE
* @param change the change object for the reference
* @return true if the change was added to an existing or new event,
* false otherwise.
*/
abstract boolean process(String refName, String refType,
ConfigChange change);
/**
* Get name of reference from xpath.
*/
String getRefName(String xpath) {
return adminEventCache.getXPathToken(xpath, 3);
}
/**
* Get type of reference for specified refName.
*/
String getRefType(String refName, ArrayList allChanges) {
// Look for object in config first. It may not exist in config
// if it has been deleted
String refType = getRefTypeFromConfig(refName);
if (refType == null) {
// If not found, then look in the config changes
refType = getRefTypeFromChanges(refName, allChanges);
}
return refType;
}
/**
* Get type of reference from config.
*/
String getRefTypeFromConfig(String refName) {
ConfigContext ctx = adminEventCache.adminConfigContext;
if (ctx == null) {
return null;
}
String refType = null;
Iterator iter = refTypeXPathMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
String xpath = (String)entry.getValue();
ConfigBean bean = null;
try {
bean = ctx.exactLookup(xpath);
} catch (ConfigException ce) {
// Ignore config exception, as it is not relevant for the
// purpose of finding the ref type.
}
if (bean != null) {
refType = (String)entry.getKey();
resEnabled = getEnabledState(bean);
break;
}
}
return refType;
}
/**
* Get ref type from config changes. This will be used only if the
* object no longer exists in config context (can happen if it has
* been deleted).
*/
String getRefTypeFromChanges(String refName, ArrayList allChanges) {
if (allChanges == null) {
return null;
}
String refType = null;
Iterator iter = allChanges.iterator();
while (iter.hasNext()) {
ConfigChange change = (ConfigChange)iter.next();
String xpath = adminEventCache.cleanXPath(change.getXPath());
Iterator iter2 = refTypeXPathMap.entrySet().iterator();
while (iter2.hasNext()) {
Map.Entry entry = (Map.Entry)iter2.next();
String xpath2 = (String)entry.getValue();
if (xpath != null && xpath.equals(xpath2)) {
refType = (String)entry.getKey();
if (change instanceof ConfigAdd) {
ConfigBean b = ((ConfigAdd)change).getConfigBean();
resEnabled = getEnabledState(b);
} else {
// The change must be delete (otherwise we would
// have found the refType from config context
resEnabled = false;
}
break;
}
}
if (refType != null) {
break;
}
}
return refType;
}
/**
* Get enabled state for the specified config bean. If the bean does
* not have an enabled attribute, the method returns true (objects
* without an enabled attribute are enabled)
*/
boolean getEnabledState(ConfigBean bean) {
String enabledStr = null;
try {
enabledStr = bean.getAttributeValue(ServerTags.ENABLED);
} catch (IllegalArgumentException iae) {
// Some resources do not have enabled attribute.
enabledStr = "true";
}
return adminEventCache.getServerXmlBooleanValue(enabledStr);
}
/**
* Get action code from the change. The method determines the action
* code for the event using the change object type (for the ref) and
* enabled state of corresponding config object.
*/
String getActionCode(ConfigChange change) {
String actionCode = null;
if (change instanceof ConfigUpdate) {
ConfigUpdate update = (ConfigUpdate)change;
String enableStr = update.getNewValue(ServerTags.ENABLED);
if (enableStr != null) {
boolean enabled =
adminEventCache.getServerXmlBooleanValue(
enableStr);
if (enabled && resEnabled) {
actionCode = BaseDeployEvent.ENABLE;
} else if (enabled && !resEnabled) {
actionCode = BaseDeployEvent.REDEPLOY;
} else {
actionCode = BaseDeployEvent.DISABLE;
}
} else {
actionCode = BaseDeployEvent.REDEPLOY;
}
} else if (change instanceof ConfigAdd) {
actionCode = BaseDeployEvent.DEPLOY;
} else if (change instanceof ConfigDelete) {
actionCode = BaseDeployEvent.UNDEPLOY;
} else if (change instanceof ConfigSet) {
// Typically set is used for existing entries
actionCode = BaseDeployEvent.REDEPLOY;
} else {
// Unknown ConfigChange cannot be handled
String msg = localStrings.getString(
"admin.event.unknown_configchange_for_resources");
throw new IllegalStateException( msg );
}
return actionCode;
}
/**
* Initialize the map of ref types and config object xpath. This map
* is used to determine the type of ref.
*/
abstract void initRefTypeXPathMap(String refName);
}
/**
* Processor for application references.
*/
class AppRefProcessor extends RefProcessor {
AppRefProcessor(AdminEventCache cache) {
super(cache);
}
boolean isRelevant(String xpath) {
return adminEventCache.isAppRefXPath(xpath);
}
/**
* Create or update the event for application ref.
*/
boolean process(String refName, String refType, ConfigChange change) {
String compType = null;
String modType = null;
if (BaseDeployEvent.APPLICATION.equals(refType)) {
compType = BaseDeployEvent.APPLICATION;
} else if ((ModuleDeployEvent.TYPE_WEBMODULE.equals(refType))
|| (ModuleDeployEvent.TYPE_EJBMODULE.equals(refType))
|| (ModuleDeployEvent.TYPE_CONNECTOR.equals(refType))
|| (ModuleDeployEvent.TYPE_APPCLIENT.equals(refType))) {
compType = BaseDeployEvent.MODULE;
modType = refType;
} else {
// Unhandled ref type
return false;
}
AdminEvent theEvent = null;
if (BaseDeployEvent.APPLICATION.equals(compType)) {
theEvent = adminEventCache.findApplicationDeployEvent(refName);
} else {
theEvent = adminEventCache.findModuleDeployEvent(
modType, refName);
}
if (theEvent == null) {
String actionCode = getActionCode(change);
// enable - disable functionality is moved to
// ElementChange event factory
if(BaseDeployEvent.ENABLE.equals(actionCode) ||
BaseDeployEvent.DISABLE.equals(actionCode) ||
BaseDeployEvent.REDEPLOY.equals(actionCode))
return false;
if (BaseDeployEvent.APPLICATION.equals(compType)) {
theEvent = new ApplicationDeployEvent(
adminEventCache.instanceName, refName,
actionCode);
} else {
theEvent = new ModuleDeployEvent(
adminEventCache.instanceName, refName,
modType, actionCode);
}
cache.add(theEvent);
}
theEvent.addConfigChange(change);
return true;
}
/**
* Initialize map for application ref types. Dynamic reconfig of
* lifecycle modules is not supported and hence the map only includes
* entries for J2EE application, EJB Module, Web Module, Connector
* module and appclient module.
*/
void initRefTypeXPathMap(String refName) {
refTypeXPathMap.put(
BaseDeployEvent.APPLICATION,
ServerXPathHelper.getAppIdXpathExpression(refName));
refTypeXPathMap.put(
ModuleDeployEvent.TYPE_WEBMODULE,
ServerXPathHelper.getWebModuleIdXpathExpression(refName));
refTypeXPathMap.put(
ModuleDeployEvent.TYPE_EJBMODULE,
ServerXPathHelper.getEjbModuleIdXpathExpression(refName));
refTypeXPathMap.put(
ModuleDeployEvent.TYPE_CONNECTOR,
ServerXPathHelper.getConnectorModuleIdXpathExpression(
refName));
refTypeXPathMap.put(
ModuleDeployEvent.TYPE_APPCLIENT,
ServerXPathHelper.getAppClientModuleIdXpathExpression(
refName));
}
}
/**
* Processor for resource references.
*/
class ResRefProcessor extends RefProcessor {
ResRefProcessor(AdminEventCache cache) {
super(cache);
}
boolean isRelevant(String xpath) {
return adminEventCache.isResRefXPath(xpath);
}
/**
* Create or update the event for resource ref.
*/
boolean process(String refName, String refType, ConfigChange change) {
ResourceDeployEvent event =
findResourceDeployEvent(refType, refName);
if (event == null) {
String actionCode = getActionCode(change);
event = new ResourceDeployEvent(adminEventCache.instanceName,
refName, refType, actionCode);
cache.add(event);
}
event.addConfigChange(change);
return true;
}
/**
* Initialize map for resource types.
*/
void initRefTypeXPathMap(String refName) {
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_CUSTOM,
ServerXPathHelper.getCustomResourceIdXpath(refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_EXTERNAL_JNDI,
ServerXPathHelper.getJNDIResourceIdXpath(refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_JCP,
ServerXPathHelper.getJDBCConnectionPoolIdXpath(refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_JDBC,
ServerXPathHelper.getJDBCResourceIdXpath(refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_MAIL,
ServerXPathHelper.getMailResourceIdXpath(refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_PMF,
ServerXPathHelper.getPMFactoryResourceIdXpath(refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_AOR,
ServerXPathHelper.getAbsoluteIdXpathExpression(
ServerXPathHelper.XPATH_ADMIN_OBJECT_RESOURCE,
ServerTags.JNDI_NAME, refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_CCP,
ServerXPathHelper.getAbsoluteIdXpathExpression(
ServerXPathHelper.XPATH_CONNECTOR_CONNECTION_POOL,
ServerTags.NAME, refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_CR,
ServerXPathHelper.getAbsoluteIdXpathExpression(
ServerXPathHelper.XPATH_CONNECTOR_RESOURCE,
ServerTags.JNDI_NAME, refName));
refTypeXPathMap.put(
ResourceDeployEvent.RES_TYPE_RAC,
ServerXPathHelper.getAbsoluteIdXpathExpression(
ServerXPathHelper.XPATH_RESOURCE_ADAPTER_CONFIG,
ServerTags.NAME, refName));
}
}
}
|