KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > admin > event > AdminEventCache


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /**
25  * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
26  *
27  * Copyright 2001-2002 by iPlanet/Sun Microsystems, Inc.,
28  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
29  * All rights reserved.
30  */

31 package com.sun.enterprise.admin.event;
32
33 import java.util.ArrayList JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.Map JavaDoc;
37 import java.util.Set JavaDoc;
38 import java.util.StringTokenizer JavaDoc;
39 import java.util.logging.Level JavaDoc;
40 import java.util.logging.Logger JavaDoc;
41 import java.util.regex.Matcher JavaDoc;
42 import java.util.regex.Pattern JavaDoc;
43
44 import com.sun.enterprise.admin.common.constant.AdminConstants;
45 import com.sun.enterprise.admin.server.core.channel.AdminChannel;
46 import com.sun.enterprise.admin.server.core.channel.RMIClient;
47 import com.sun.enterprise.config.ConfigContext;
48 import com.sun.enterprise.config.ConfigAdd;
49 import com.sun.enterprise.config.ConfigBean;
50 import com.sun.enterprise.config.ConfigChange;
51 import com.sun.enterprise.config.ConfigDelete;
52 import com.sun.enterprise.config.ConfigException;
53 import com.sun.enterprise.config.ConfigSet;
54 import com.sun.enterprise.config.ConfigUpdate;
55 import com.sun.enterprise.config.impl.ConfigUpdateImpl;
56 import com.sun.enterprise.config.serverbeans.ServerTags;
57 import com.sun.enterprise.config.serverbeans.ServerXPathHelper;
58
59 //i18n import
60
import com.sun.enterprise.util.i18n.StringManager;
61
62 /**
63  * AdminEventCache is used to cache events during "Apply". It also is the
64  * single point where ConfigChange objects are associated to the events. This
65  * class has evolved from being a cache that tracked events between "Apply"
66  * boundaries to its current form, so a lot of methods have been deprecated.
67  * <p>
68  * User interface allows several changes to configuration to be sent to the
69  * instance by one operation -- Apply. The cache is used to store events
70  * generated by processing configuration changes obtained from
71  * ConfigContext. The apply operation then sends all events one after
72  * another to the administered instance.
73  * </p>
74  * <p>
75  * A typical sequence of calls will be -- where <code>name</code> is a <code>
76  * String</code> representing name of the server instance and <code>context
77  * </code> is an instance of type <code>com.sun.enterprise.config.ConfigContext
78  * </code> applicable to the server instance.
79  * </p>
80  * <pre>
81     AdminEventCache eventCache = AdminEventCache.getInstance(name);
82     ArrayList changeList = context.getConfigChangeList();
83     context.resetConfigChangeList();
84     eventCache.processConfigChangeList(changeList);
85     ArrayList eventList = eventCache.getAndResetCachedEvents();
86     Iterator iter = eventList.iterator();
87     while (iter.hasNext()) {
88         AdminEvent event = (AdminEvent)iter.next();
89         AdminEventResult result = AdminEventMulticaster.multicastEvent(event);
90         if (result.getResultCode() != AdminEventResult.SUCCESS) {
91             // Handle error
92         }
93     }
94  * </pre>
95  * <p>
96  * The method <code>processConfigChangeList</code> now handles all events,
97  * including those related to deployment of applications and modules.
98  * If Deployment action is accompanied with a implicit apply then it should
99  * be handled by the method <code>populateConfigChange</code>.
100  *</p>
101  */

102 public class AdminEventCache {
103
104     /**
105      * A reference to logger object
106      */

107     static Logger JavaDoc logger = Logger.getLogger(AdminConstants.kLoggerName);
108
109     /**
110      * A map of instance and its cache
111      */

112     private static final transient HashMap JavaDoc instanceCacheMap = new HashMap JavaDoc();
113
114     /**
115      * Name of the server instance. The event cache is for this instance.
116      */

117     private String JavaDoc instanceName;
118
119     /**
120      * Event cache. The cache is used to keep events during "Apply" processing
121      */

122     private ArrayList JavaDoc cache;
123
124     /**
125      * Is restart needed.
126      */

127     private boolean restartNeeded = false;
128
129     /**
130      * Timestamp restart is needed since.
131      */

132     private long tsRestartNeededSince;
133
134     /**
135      * Admin config context. This is used to resolve application and resource
136      * references. The references do not contain types and a search through
137      * the config context is needed to determine the type.
138      */

139     private ConfigContext adminConfigContext;
140
141     /**
142      * Create an instance of AdminEventCache. Every event cache is for a
143      * specific instance.
144      * @param instanceName name of the instance
145      */

146     AdminEventCache(String JavaDoc instanceName) {
147         this.instanceName = instanceName;
148         cache = new ArrayList JavaDoc();
149         RMIClient channel = AdminChannel.getRMIClient(instanceName);
150         if (channel.isRestartNeeded()) {
151             setRestartNeededTrue(false);
152         }
153     }
154
155     /**
156      * Get event cache for specified instance.
157      * @param instanceName name of the instance
158      * @return event cache for the specified instance
159      */

160     public synchronized static AdminEventCache getInstance(
161             String JavaDoc instanceName) {
162         AdminEventCache aec =
163                 (AdminEventCache)instanceCacheMap.get(instanceName);
164         if (aec == null) {
165             aec = new AdminEventCache(instanceName);
166             instanceCacheMap.put(instanceName, aec);
167         }
168         return aec;
169     }
170
171     /**
172      * Set admin config context.
173      */

174     public void setAdminConfigContext(ConfigContext ctx) {
175         adminConfigContext = ctx;
176     }
177
178     /**
179      * Get list of cached events. This method returns the list object
180      * being used inside this class, therefore, all changes to the list
181      * should be carefully considered.
182      * @return list of cached events.
183      */

184     ArrayList JavaDoc getCachedEvents() {
185         return cache;
186     }
187
188     /**
189      * Get list of cached events and re-initialize the cache. This method
190      * should be called only after a call to processConfigChangeList(),
191      * @return list of cached events
192      */

193     public synchronized ArrayList JavaDoc getAndResetCachedEvents() {
194         ArrayList JavaDoc saved = cache;
195         cache = new ArrayList JavaDoc();
196         return saved;
197     }
198
199     /**
200      * Add an event to the cache.
201      * @param event Event to be added to cache
202      * @deprecated with no substitution
203      */

204     public void addEvent(AdminEvent event) {
205         cache.add(event);
206     }
207
208     /**
209      * Add specified list of events to the cache.
210      * @param eventList list of events to add to the cache
211      * @deprecated with no substitution
212      */

213     public void addEvents(ArrayList JavaDoc eventList) {
214         cache.addAll(eventList);
215     }
216
217     /**
218      * Remove specified event from the cache.
219      * @param event the event to remove from cache
220      * @deprecated with no substitution
221      */

222     public void removeEvent(AdminEvent event) {
223         cache.remove(event);
224     }
225
226     /**
227      * Process config change list and update cache with appropriate events.
228      * At the end of this method the cache will have zero or more events.
229      * It will contain an instance of ConfigChangeEvent if the specified
230      * parameter otherConfFilesChanges is true or if specified changeList is
231      * not null and the change does not fit in any of following events --
232      * MonitoringEvent with actionCode START_MONITOR or STOP_MONITOR or
233      * ResourceDeployEvent. If the cache already contains an instance
234      * ResourceDeployEvent for a given resource, then this method will not
235      * add any new instance of ResourceDeployEvent for that resource.
236      * @param changeList list of server.xml config changes
237      * @param initOrObFilesChanged whether conf files init.conf or obj.conf
238      * were changed
239      * @param mimeFileChanged whether mime type file(s) were changed
240      */

241     public synchronized void processConfigChangeList(ArrayList JavaDoc changeList,
242             boolean initOrObjFilesChanged, boolean mimeFileChanged) {
243         ConfigChangeEvent dfltEvent = null;
244         boolean dfltEventCached = false;
245         Iterator JavaDoc iter = cache.iterator();
246         while (iter.hasNext()) {
247             Object JavaDoc obj = iter.next();
248             if (obj instanceof ConfigChangeEvent) {
249                 dfltEvent = (ConfigChangeEvent)obj;
250                 dfltEventCached = true;
251                 break;
252             }
253         }
254         if (initOrObjFilesChanged || mimeFileChanged) {
255             if (dfltEvent == null) {
256                 dfltEvent = new ConfigChangeEvent(instanceName, null);
257             }
258             dfltEvent.setWebCoreReconfigNeeded(true);
259         }
260         if (initOrObjFilesChanged) {
261             if (dfltEvent == null) {
262                 dfltEvent = new ConfigChangeEvent(instanceName, null);
263             }
264             dfltEvent.setInitOrObjConfChanged(true);
265         }
266         if (changeList != null && !changeList.isEmpty()) {
267             iter = changeList.iterator();
268             while (iter.hasNext()) {
269                 ConfigChange change = (ConfigChange)iter.next();
270                 if (change != null) {
271                     doChangeBucketing(change, dfltEvent, changeList);
272                 }
273             }
274         }
275         if (( dfltEvent != null) && (!dfltEventCached) ){
276             cache.add(dfltEvent);
277         }
278         purgeNopEvents();
279     }
280
281     /**
282      * Process the specifid change and generate appropriate events.
283      * @param change the config change
284      * @param dflt the default config change event
285      * @param changeList all changes being processed. This is needed to
286      * handle references because if a resource has been deleted its
287      * type can only be found from the change list.
288      */

289     private void doChangeBucketing(ConfigChange change,
290             ConfigChangeEvent dflt, ArrayList JavaDoc changeList) {
291         logger.log(Level.FINE, PROCESS_CHANGE, change);
292         if (change == null || change.getXPath() == null) {
293             logger.log(Level.FINE, CHANGE_NULL, change);
294             return;
295         }
296         boolean processed = false;
297         //processed = processLogLevelChangeEvent(change);
298
// if (!processed) {
299
// processed = processMonitoringLevelChangeEvent(change);
300
// }
301
// if (!processed) {
302
// processed = processResourceChangeEvent(change);
303
// }
304
// if (!processed) {
305
// processed = processResourceReference(change, changeList);
306
// }
307
/*
308         if (!processed) {
309             processed = processOtherDeployEvent(change);
310         }
311         if (!processed) {
312             processed = processApplicationReference(change, changeList);
313         }
314 */

315         if (( dflt != null) && (!processed)) {
316             dflt.addConfigChange(change);
317             if (!dflt.isWebCoreReconfigNeeded()) {
318                 setWebCoreReconfig(change, dflt);
319             }
320         }
321     }
322
323     /**
324      * Process changes to module log levels. One event is generated for every
325      * module whose log level is changed. The method returns true if change is
326      * for module log levels (excluding properties).
327      * @param change the change to be processed
328      * @return true if the change is for module log levels, false otherwise.
329      */

330     private boolean processLogLevelChangeEvent(ConfigChange change) {
331         return processLevelChangeEvent(change,
332                 new LogLevelChangeProcessor(this));
333     }
334
335     /**
336      * Process changes to module monitoring levels. One event is generated
337      * for every module whose monitoring level is changed. The method returns
338      * true if change is for module monitoring levels (excluding properties).
339      * @param change the change to be processed
340      * @return true if the change is for module monitoring levels, false
341      * otherwise.
342      */

343     private boolean processMonitoringLevelChangeEvent(ConfigChange change) {
344         return processLevelChangeEvent(change,
345                 new MonitoringLevelChangeProcessor(this));
346     }
347
348     /**
349      * Process changes to module level.
350      * @param change the change to be processed
351      * @param processor the handler for the change
352      * @return true if the change is applicable and events are generated,
353      * false otherwise.
354      */

355     private boolean processLevelChangeEvent(ConfigChange change,
356             LevelChangeProcessor processor) {
357         // Only updates for level change can be handled dynamically, all
358
// other changes will require restart.
359
ConfigUpdate update = convertToConfigUpdate(change);
360         if (update == null) {
361             return false;
362         }
363         String JavaDoc xpath = cleanXPath(update.getXPath());
364         if (!processor.isRelevant(xpath)) {
365             return false;
366         }
367         Set JavaDoc attrs = update.getAttributeSet();
368         if (attrs == null) {
369             logger.log(Level.FINEST, "admin.event.null_updated_attrs",
370                     update.getXPath());
371             return false;
372         }
373         Iterator JavaDoc iter = attrs.iterator();
374         while (iter.hasNext()) {
375             String JavaDoc compName = (String JavaDoc)iter.next();
376             String JavaDoc oldValue = update.getOldValue(compName);
377             String JavaDoc newValue = update.getNewValue(compName);
378             AdminEvent event = processor.createEvent(compName, oldValue,
379                     newValue);
380             cache.add(event);
381             ConfigUpdate upd = new ConfigUpdateImpl(xpath, compName, oldValue,
382                     newValue);
383             event.addConfigChange(upd);
384         }
385         return true;
386     }
387
388     /**
389      * Process the change and generate ResourceDeployEvent. If the change is
390      * to a xpath that represents a resource, then a resource deploy event for
391      * the resource represented by the xpath is added to cache, provided the
392      * cache does not already contain a resource deploy event for the same
393      * resource. If the attribute enabled is changed then the actionCode for
394      * the event is ENABLE or DISABLE, otherwise it is REDEPLOY. The change is
395      * considered fully processed if the xpath is for a resource.
396      * @return true if the change is fully processed, false otherwise.
397      */

398     private boolean processResourceChangeEvent(ConfigChange change) {
399         String JavaDoc xpath = cleanXPath(change.getXPath());
400         boolean processed = false;
401         if (isResourceXPath(xpath)) {
402             String JavaDoc actionCode = null;
403             if (change instanceof ConfigUpdate) {
404                 ConfigUpdate update = (ConfigUpdate)change;
405                 String JavaDoc enableStr = update.getNewValue(ServerTags.ENABLED);
406                 if (enableStr != null) {
407                     if (getServerXmlBooleanValue(enableStr)) {
408                         actionCode = ResourceDeployEvent.ENABLE;
409                     } else {
410                         actionCode = ResourceDeployEvent.DISABLE;
411                     }
412                 } else {
413                     actionCode = ResourceDeployEvent.REDEPLOY;
414                 }
415             } else if (change instanceof ConfigAdd) {
416                 // In case of security-map, addition should fire
417
// redeploy event as it is part of connector-connection-pool
418
// resource.
419
boolean isMap = xpath.indexOf(ServerTags.SECURITY_MAP) != -1;
420                 if (isPropertyXPath(xpath) || isMap) {
421                     actionCode = ResourceDeployEvent.REDEPLOY;
422                 } else {
423                     actionCode = ResourceDeployEvent.DEPLOY;
424                 }
425             } else if (change instanceof ConfigDelete) {
426                 // In case of security-map, delete should fire redeploy event
427
// as it is part of connector-connection-pool resource.
428
boolean isMap = xpath.indexOf(ServerTags.SECURITY_MAP) != -1;
429                 if (isPropertyXPath(xpath) || isMap) {
430                     actionCode = ResourceDeployEvent.REDEPLOY;
431                 } else {
432                      actionCode = ResourceDeployEvent.UNDEPLOY;
433                 }
434             } else if (change instanceof ConfigSet) {
435                 // As of now set is used for existing properties in resources.
436
// Existing properties imply that resource exists.
437
actionCode = ResourceDeployEvent.REDEPLOY;
438             } else {
439                 // Unknown ConfigChange cannot be handled
440
String JavaDoc msg = localStrings.getString( "admin.event.unknown_configchange_for_resources");
441                 throw new IllegalStateException JavaDoc( msg );
442             }
443             String JavaDoc resType = getResourceType(xpath);
444             String JavaDoc resName = getResourceName(xpath);
445             ResourceDeployEvent resEvent =
446                     findResourceDeployEvent(resType, resName);
447             if (resEvent == null) {
448                 resEvent = new ResourceDeployEvent(instanceName, resName,
449                         resType, actionCode);
450                 cache.add(resEvent);
451             } else {
452                 if (isActionValidForCache(actionCode)) {
453                     resEvent.setNewAction(actionCode);
454                 } else {
455                     // As resEvent was not null, this is not the first change
456
// being processed for this xpath. Enable and Disable are
457
// not valid actions for second change of a resource xpath
458
}
459             }
460             resEvent.addConfigChange(change);
461             processed = true;
462         }
463         return processed;
464     }
465
466     /**
467      * Is this a resource XPATH. The method returns true if the XPATH is for
468      * a resource.
469      * @param xpath the xpath
470      * @return true if the xpath is for a resource, false otherwise.
471      */

472     private boolean isResourceXPath(String JavaDoc xpath) {
473         String JavaDoc xpathLcase = xpath.toLowerCase();
474         if (xpathLcase.startsWith(RES_PFX)) {
475             return true;
476         }
477         return false;
478     }
479
480     /**
481      * Is specified xpath for property.
482      * @param xpath the xpath to be checked
483      * @returns true if the xpath is for a property, false otherwise
484      */

485     private boolean isPropertyXPath(String JavaDoc xpath) {
486         return AdminEventCache.matchRegex(PROPERTY_REGEX, xpath);
487     }
488
489     /**
490      * Is specified xpath for module log levels.
491      * @param xpath the xpath to be checked
492      * @returns true if the xpath is for module log levels, false otherwise
493      */

494     private boolean isLogLevelXPath(String JavaDoc xpath) {
495         return (LOG_LEVEL_XPATH.equalsIgnoreCase(xpath));
496     }
497
498     /**
499      * Is specified xpath for module monitoring levels.
500      * @param xpath the xpath to be checked
501      * @returns true if the xpath is for module monitoring levels, false
502      * otherwise
503      */

504     private boolean isMonitoringLevelXPath(String JavaDoc xpath) {
505         return (MONITORING_LEVEL_XPATH.equalsIgnoreCase(xpath));
506     }
507
508     /**
509      * Is specified xpath for application reference
510      * @param xpath the xpath to be checked
511      * @returns true if the xpath is for application reference, false
512      * otherwise
513      */

514     private boolean isAppRefXPath(String JavaDoc xpath) {
515         if (xpath == null) {
516             return false;
517         }
518         String JavaDoc serverXPath = ServerXPathHelper.getServerIdXpath(instanceName);
519         String JavaDoc appRefXPath = serverXPath + ServerXPathHelper.XPATH_SEPARATOR
520                 + ServerTags.APPLICATION_REF;
521         return xpath.startsWith(appRefXPath);
522     }
523
524     /**
525      * Is specified xpath for application reference
526      * @param xpath the xpath to be checked
527      * @returns true if the xpath is for resource reference, false
528      * otherwise
529      */

530     private boolean isResRefXPath(String JavaDoc xpath) {
531         if (xpath == null) {
532             return false;
533         }
534         String JavaDoc serverXPath = ServerXPathHelper.getServerIdXpath(instanceName);
535         String JavaDoc resRefXPath = serverXPath + ServerXPathHelper.XPATH_SEPARATOR
536                 + ServerTags.RESOURCE_REF;
537         return xpath.startsWith(resRefXPath);
538     }
539
540     /**
541      * Get app ref xpath for specified app and server.
542      * @param instance name of the server
543      * @param appName name of the application
544      * @return xpath corresponding to the application ref
545      */

546     private static String JavaDoc getAppRefXPath(String JavaDoc instance, String JavaDoc appName) {
547         return ServerXPathHelper.getServerIdXpath(instance)
548                 + ServerXPathHelper.XPATH_SEPARATOR
549                 + ServerTags.APPLICATION_REF + "[@"
550                 + ServerTags.REF + "='" + appName + "']";
551     }
552
553     /**
554      * Get resource type from the xpath.
555      * @param xpath the xpath for a resource
556      * @return the type of the resource, appropriate for use in
557      * constructor of ResourceDeployEvent.
558      */

559     private String JavaDoc getResourceType(String JavaDoc xpath) {
560         String JavaDoc resType = "unknown";
561         String JavaDoc xpathLcase = xpath.toLowerCase();
562         if (xpathLcase.startsWith(ServerXPathHelper.XPATH_CUSTOM_RESOURCE)) {
563             resType = ResourceDeployEvent.RES_TYPE_CUSTOM;
564         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_JNDI_RESOURCE)) {
565             resType = ResourceDeployEvent.RES_TYPE_EXTERNAL_JNDI;
566         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_JDBC_CONNECTION_POOL)) {
567             resType = ResourceDeployEvent.RES_TYPE_JCP;
568         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_JDBC_RESOURCE)) {
569             resType = ResourceDeployEvent.RES_TYPE_JDBC;
570         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_MAIL_RESOURCE)) {
571             resType = ResourceDeployEvent.RES_TYPE_MAIL;
572         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_PM_FACTORY_RESOURCE)) {
573             resType = ResourceDeployEvent.RES_TYPE_PMF;
574         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_ADMIN_OBJECT_RESOURCE)) {
575             resType = ResourceDeployEvent.RES_TYPE_AOR;
576         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_CONNECTOR_CONNECTION_POOL)) {
577             resType = ResourceDeployEvent.RES_TYPE_CCP;
578         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_CONNECTOR_RESOURCE)) {
579             resType = ResourceDeployEvent.RES_TYPE_CR;
580         } else if (xpathLcase.startsWith(ServerXPathHelper.XPATH_RESOURCE_ADAPTER_CONFIG)) {
581              resType = ResourceDeployEvent.RES_TYPE_RAC;
582         }
583
584         return resType;
585     }
586
587     /**
588      * Get name of the resource from a resource xpath.
589      * @param xpath the xpath for a resource
590      * @return the name of the resource
591      */

592     private String JavaDoc getResourceName(String JavaDoc xpath) {
593         return getXPathToken(xpath, 1);
594     }
595
596     /**
597      * Extract token separated by single-quote character (&#39;) after
598      * discarding specified number of tokens. For example,
599      * <pre>
600        xpath numToDiscard Returns
601        /a/b/c[@name='myName'] 1 myName
602        /a/b/c[@name='myName']/d[@id='myId'] 3 myId
603      * </pre>
604      * Note that the value contains single-quote character, the xpath will
605      * be formed with &amp;#39; and the caller has to convert to appropriate
606      * character.
607      * @param xpath the xpath from where token needs to be extracted
608      * @param numToDiscard number of tokens to discard
609      * @throws IllegalArgumentException if the xpath does not contain enough
610      * tokens.
611      * @return the token after discarding numToDiscard tokens from xpath
612      */

613     private String JavaDoc getXPathToken(String JavaDoc xpath, int numToDiscard) {
614         StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(xpath, "'");
615         if (tok.countTokens() <= numToDiscard) {
616             Object JavaDoc[] params = new Object JavaDoc[] {xpath,
617                     new Integer JavaDoc(numToDiscard + 1),
618                     new Integer JavaDoc(tok.countTokens())};
619             logger.log(Level.FINE, INVALID_XPATH_TOKENIZATION, params);
620             String JavaDoc msg = localStrings.getString(
621                     "admin.event.invalid_xpath_tokenization", params );
622             throw new IllegalArgumentException JavaDoc(msg);
623         }
624         for (int i = numToDiscard; i > 0; i--) {
625             String JavaDoc discard = tok.nextToken();
626         }
627         return tok.nextToken();
628     }
629
630     /**
631      * Process the change and generate ApplicationDeployEvent or
632      * ModuleDeployEvent. If the change is to a xpath that represents an
633      * application or module, then an application or module deploy event for
634      * the resource represented by the xpath is added to cache, provided the
635      * cache does not already contain a application or module deploy event for
636      * the same resource. If the attribute enabled is changed then the
637      * actionCode for the event is ENABLE or DISABLE, otherwise it is REDEPLOY.
638      * The change is considered fully processed if the xpath is for an
639      * application or a module.
640      * @return true if the change is fully processed, false otherwise.
641      */

642     private boolean processOtherDeployEvent(ConfigChange change) {
643         String JavaDoc xpath = cleanXPath(change.getXPath());
644         String JavaDoc xpathLcase = xpath.toLowerCase();
645         boolean processed = false;
646         String JavaDoc componentType = null;
647         String JavaDoc moduleType = null;
648         if (xpathLcase.startsWith(APP_PFX)) {
649             componentType = BaseDeployEvent.APPLICATION;
650         } else if (xpathLcase.startsWith(EJB_PFX)) {
651             componentType = BaseDeployEvent.MODULE;
652             moduleType = ModuleDeployEvent.TYPE_EJBMODULE;
653         } else if (xpathLcase.startsWith(WEB_PFX)) {
654             componentType = BaseDeployEvent.MODULE;
655             moduleType = ModuleDeployEvent.TYPE_WEBMODULE;
656         } else if (xpathLcase.startsWith(RAR_PFX)) {
657             componentType = BaseDeployEvent.MODULE;
658             moduleType = ModuleDeployEvent.TYPE_CONNECTOR;
659         } else if (xpathLcase.startsWith(ACC_PFX)) {
660             componentType = BaseDeployEvent.MODULE;
661             moduleType = ModuleDeployEvent.TYPE_APPCLIENT;
662         } else {
663             return false;
664         }
665         String JavaDoc componentName = getResourceName(xpath);
666         BaseDeployEvent theEvent = null;
667         if (BaseDeployEvent.APPLICATION.equals(componentType)) {
668             theEvent = findApplicationDeployEvent(componentName);
669         } else {
670             theEvent = findModuleDeployEvent(moduleType, componentName);
671         }
672         if (theEvent == null) {
673             String JavaDoc actionCode = null;
674             if (change instanceof ConfigUpdate) {
675 /* krav
676                 ConfigUpdate update = (ConfigUpdate)change;
677                 String enableStr = update.getNewValue(ServerTags.ENABLED);
678                 if (enableStr != null) {
679                     if (getServerXmlBooleanValue(enableStr)) {
680                         actionCode = BaseDeployEvent.ENABLE;
681                     } else {
682                         actionCode = BaseDeployEvent.DISABLE;
683                     }
684                 } else {
685                     actionCode = BaseDeployEvent.REDEPLOY;
686                 }
687  */

688              } else if (change instanceof ConfigAdd) {
689                 actionCode = BaseDeployEvent.DEPLOY;
690              } else if (change instanceof ConfigDelete) {
691                 actionCode = BaseDeployEvent.UNDEPLOY;
692              } else {
693         String JavaDoc msg = localStrings.getString( "admin.event.handle_add_delete_set_configchange" );
694                 throw new IllegalStateException JavaDoc( msg );
695              }
696              if (actionCode != null) {
697                 if (BaseDeployEvent.APPLICATION.equals(componentType)) {
698                     theEvent = new ApplicationDeployEvent(instanceName,
699                     componentName, actionCode);
700                 } else {
701                     theEvent = new ModuleDeployEvent(instanceName, componentName,
702                     moduleType, actionCode);
703                 }
704                 cache.add(theEvent);
705                 processed = true;
706             }
707         } else { // (theEvent != null)
708
// Event is not null. Any update will not affect it. If the change
709
// is not update (add, delete or set) -- assume that it already
710
// affected the state of event when the change was made
711
processed = true;
712         }
713         theEvent.addConfigChange(change);
714         return processed;
715     }
716
717     /**
718      * Process the change and create/update appropriate resource events, if the
719      * change represents a resource reference.
720      * @param change the change to be processed
721      * @param changeList all the changes being processed in the current batch
722      * @return true if the change is for a resource reference and was added
723      * to an existing or a new event.
724      */

725     private boolean processResourceReference(ConfigChange change,
726             ArrayList JavaDoc changeList) {
727         return processReference(change, changeList, new ResRefProcessor(this));
728     }
729
730     /**
731      * Process the change and create/update appropriate application or module
732      * events, if the change represents a application reference.
733      * @param change the change to be processed
734      * @param changeList all the changes being processed in the current batch
735      * @return true if the change is for a application reference and was added
736      * to an existing or a new event.
737      */

738     private boolean processApplicationReference(ConfigChange change,
739             ArrayList JavaDoc changeList) {
740         return processReference(change, changeList, new AppRefProcessor(this));
741     }
742
743     /**
744      * Process reference and create/update appropriate event in the cache.
745      * @param change the change to be processed
746      * @param changeList all changes being processed along with this change.
747      * The change list is needed to determine type of the config object
748      * that the ref is referring to, in cases when the actual config
749      * object has been deleted and is no longer present in config context.
750      * @param processor the processor for the reference. It is the abstraction
751      * that hides differences between application refs and resource refs.
752      * @return true if the change can be handled by specified processor and
753      * is handled successfully, false otherwise.
754      */

755     private boolean processReference(ConfigChange change, ArrayList JavaDoc changeList,
756             RefProcessor processor) {
757         String JavaDoc xpath = cleanXPath(change.getXPath());
758         if (!processor.isRelevant(xpath)) {
759             return false;
760         }
761         String JavaDoc refName = processor.getRefName(xpath);
762         processor.initRefTypeXPathMap(refName);
763         String JavaDoc refType = processor.getRefType(refName, changeList);
764         if (refType == null) {
765             // The ref is not interesting, for example, lifecycle module ref
766
return false;
767         }
768         return processor.process(refName, refType, change);
769     }
770
771     /**
772      * Set web core reconfig status in specified event if the change warrants
773      * that. Any config change to http-service or web container element require
774      * a web core reconfig.
775      * @param change the config change object
776      * @param dflt the default config change event
777      */

778     private void setWebCoreReconfig(ConfigChange change,
779             ConfigChangeEvent dflt) {
780         String JavaDoc xpath = cleanXPath(change.getXPath());
781         if (isWebCoreXPath(xpath)) {
782             dflt.setWebCoreReconfigNeeded(true);
783         }
784         return;
785     }
786
787     /**
788      * Is specified XPath handled only by web core. All elements under
789      * http-service and web-container are handled exclusively by web core.
790      * @param xpath the xpath to process
791      * @return true if the xpath is handled only by web core, false otherwise.
792      */

793     private boolean isWebCoreXPath(String JavaDoc xpath) {
794         boolean webCoreXPath = false;
795         if (xpath == null) {
796             return webCoreXPath;
797         } else {
798             xpath = xpath.toLowerCase();
799         }
800         if (xpath.startsWith(HTTP_SERVICE) || xpath.startsWith(WEB_CONTAINER)) {
801             webCoreXPath = true;
802         }
803         return webCoreXPath;
804     }
805
806     /**
807      * Get a boolean value corresponding to the string value in xml.
808      * @param xmlValue the xml string representing a boolean
809      * @return true if the string is "true", "yes", "on" or "1"
810      */

811     public static boolean getServerXmlBooleanValue(String JavaDoc xmlValue) {
812         boolean retval = false;
813         if (xmlValue == null) {
814             return retval;
815         }
816         if (xmlValue.equalsIgnoreCase("true")
817                 || xmlValue.equalsIgnoreCase("yes")
818                 || xmlValue.equalsIgnoreCase("on")
819                 || xmlValue.equalsIgnoreCase("1")) {
820             retval = true;
821         }
822         return retval;
823     }
824
825     /**
826      * Convert to config update, if possible. If specified change is not
827      * an instanceof ConfigUpdate, the method returns null
828      */

829     private ConfigUpdate convertToConfigUpdate(ConfigChange change) {
830         ConfigUpdate update = null;
831         if (change instanceof ConfigUpdate) {
832             update = (ConfigUpdate)change;
833         }
834         return update;
835     }
836
837     /**
838      * Cache a resource change. This method inspects the cache and either
839      * updates the existing event or creates a new resource event.
840      * @param resourceType Type of the resource
841      * @param resourceName Name of the resource
842      * @param actionCode Action code, one of BaseDeployEvent.DEPLOY,
843      * BaseDeployEvent.REDEPLOY or BaseDeployEvent.UNDEPLOY
844      * @deprecated with no substitution.
845      */

846     public void cacheResourceChange(String JavaDoc resourceType, String JavaDoc resourceName,
847             String JavaDoc actionCode) {
848         // Valid values for actionCode are DEPLOY, UNDEPLOY and REDEPLOY and
849
// not ENABLE and DISABLE which can come only from analyzing config
850
// changes.
851
if (!isActionValidForCache(actionCode)) {
852             String JavaDoc msg = localStrings.getString( "admin.event.invalid_action", actionCode );
853             throw new IllegalArgumentException JavaDoc( msg );
854         }
855         ResourceDeployEvent resEvent = findResourceDeployEvent(resourceType,
856                 resourceName);
857         if (resEvent == null) {
858             resEvent = new ResourceDeployEvent(instanceName, resourceName,
859                     resourceType, actionCode);
860             cache.add(resEvent);
861         } else {
862             resEvent.setNewAction(actionCode);
863         }
864     }
865
866     /**
867      * Check whether specified deploy action can be cached. Only deploy actions
868      * - DEPLOY, UNDEPLOY and REDEPLOY can be cached. The other deploy actions
869      * ENABLE, DISABLE are derived from the cache of changes.
870      * @param deployAction the deployment action
871      * @return true if deploy action is valid, false otherwise
872      */

873     private boolean isActionValidForCache(String JavaDoc deployAction) {
874         boolean valid = false;
875         if (deployAction != null) {
876             if (deployAction.equals(BaseDeployEvent.DEPLOY)
877                     || deployAction.equals(BaseDeployEvent.UNDEPLOY)
878                     || deployAction.equals(BaseDeployEvent.REDEPLOY)) {
879                 valid = true;
880             }
881         }
882         return valid;
883     }
884
885     /**
886      * Populate config changes in the specified event. This method looks for
887      * changes matching the event in the specified config context and if there
888      * are any the changes are moved from config context to the event. This
889      * method can only handle ApplicationDeployEvent and ModuleDeployEvent.
890      * @param ctx The config context where the cache of changes is examined for
891      * match
892      * @param event The event for which matching changes should be looked up
893      * @throws UnsupportedOperationException if the event is not Application or
894      * Module deploy event.
895      */

896     public static void populateConfigChange(ConfigContext ctx, AdminEvent event) {
897         if (event instanceof ApplicationDeployEvent) {
898             populateApplicationConfigChange(ctx, (ApplicationDeployEvent)event);
899         } else if (event instanceof ModuleDeployEvent) {
900             populateModuleConfigChange(ctx, (ModuleDeployEvent)event);
901         } else {
902             String JavaDoc msg = localStrings.getString( "admin.event.unsupported_populateconfigchange", event.getClass().getName() );
903             throw new UnsupportedOperationException JavaDoc( msg );
904         }
905     }
906
907     /**
908      * Populate config changes from specified config context into the specified
909      * application deployment event.
910      * @param ctx the config context
911      * @param event the application deployment event
912      */

913     private static void populateApplicationConfigChange(ConfigContext ctx,
914             ApplicationDeployEvent event) {
915         String JavaDoc xpath = ServerXPathHelper.getAppIdXpathExpression(
916                 event.getApplicationName());
917         xpath = cleanXPath(xpath);
918         event.addConfigChange(extractConfigChanges(ctx, xpath));
919         // Now look for any changes to application ref
920
String JavaDoc refXPath = getAppRefXPath(event.getInstanceName(),
921                 event.getApplicationName());
922         event.addConfigChange(extractConfigChanges(ctx, refXPath));
923     }
924
925     /**
926      * Populate config changes from specified config context into the specified
927      * module deployment event.
928      * @param ctx the config context
929      * @param event the module deployment event
930      * @throws IllegalArgumentException if module type as specified in the
931      * event is not one of EJB, WEB, CONNECTOR or APPCLIENT
932      */

933     private static void populateModuleConfigChange(ConfigContext ctx,
934             ModuleDeployEvent event) {
935         String JavaDoc moduleType = event.getModuleType();
936         String JavaDoc moduleName = event.getModuleName();
937         String JavaDoc xpath = null;
938         if (event.TYPE_WEBMODULE.equals(moduleType)) {
939             xpath = ServerXPathHelper.getWebModuleIdXpathExpression(moduleName);
940         } else if (event.TYPE_EJBMODULE.equals(moduleType)) {
941             xpath = ServerXPathHelper.getEjbModuleIdXpathExpression(moduleName);
942         } else if (event.TYPE_CONNECTOR.equals(moduleType)) {
943             xpath = ServerXPathHelper.getConnectorModuleIdXpathExpression(
944                     moduleName);
945         } else if (event.TYPE_APPCLIENT.equals(moduleType)) {
946             xpath = ServerXPathHelper.getAppClientModuleIdXpathExpression(
947                     moduleName);
948         } else {
949             String JavaDoc msg = localStrings.getString( "admin.event.invalid_module_type" , moduleType );
950             throw new IllegalArgumentException JavaDoc( msg );
951         }
952         xpath = cleanXPath(xpath);
953         event.addConfigChange(extractConfigChanges(ctx, xpath));
954         // Now look for any changes to application ref
955
String JavaDoc refXPath = getAppRefXPath(event.getInstanceName(), moduleName);
956         event.addConfigChange(extractConfigChanges(ctx, refXPath));
957     }
958
959     /**
960      * Extract config changes matching specified xpath from config context.
961      * @param configContext the context from where changes are extracted
962      * @param xpath the xpath for which all changes should be extracted
963      * @throws IllegalArgumentException if specified config context is null
964      * @throws IllegalStateException if list of changes maintained by config
965      * context is null.
966      */

967     private static ArrayList JavaDoc extractConfigChanges(ConfigContext configContext,
968             String JavaDoc xpath) {
969         if (configContext == null) {
970             String JavaDoc msg = localStrings.getString( "admin.event.null_config_context" );
971             throw new IllegalArgumentException JavaDoc( msg );
972         }
973         ArrayList JavaDoc myChanges = new ArrayList JavaDoc();
974         ArrayList JavaDoc allChanges = configContext.getConfigChangeList();
975         if (allChanges == null) {
976             String JavaDoc msg = localStrings.getString( "admin.event.null_config_changes_in_configcontext" );
977             throw new IllegalStateException JavaDoc( msg );
978         }
979         logger.log(Level.FINE, EXTRACT_CHANGE, xpath);
980         Iterator JavaDoc iter = allChanges.iterator();
981         while (iter.hasNext()) {
982             ConfigChange change = (ConfigChange)iter.next();
983             logger.log(Level.FINE, PROCESS_CHANGE, change);
984             String JavaDoc changeXPath = null;
985             if (change != null) {
986                 changeXPath = cleanXPath(change.getXPath());
987                 logger.log(Level.FINEST, CONFIG_CHANGE_XPATH, changeXPath);
988             }
989             if (change == null || changeXPath == null) {
990                 logger.log(Level.FINE, CHANGE_NULL, change);
991                 continue;
992             }
993             if (changeXPath.equals(xpath)) {
994         //System.out.println("Xpath matches, adding change to the list");
995
myChanges.add(change);
996             } else {
997         //System.out.println("No match, ignoring");
998
}
999         }
1000        iter = myChanges.iterator();
1001        while (iter.hasNext()) {
1002            configContext.removeConfigChange((ConfigChange)iter.next());
1003        }
1004        return myChanges;
1005    }
1006
1007    /**
1008     * Clean XPath. This method converts all xpaths to lower case and replaces
1009     * two or more consecutive forward slash ('/') character by a single
1010     * forward slash.
1011     * @return modified XPath
1012     */

1013    private static String JavaDoc cleanXPath(String JavaDoc xpath) {
1014        if (xpath == null) {
1015            return xpath;
1016        }
1017        return xpath.replaceAll("/{2,}", "/");
1018    }
1019
1020    /**
1021     * Match a string against a regular expression.
1022     * @param regex the regular expression to match
1023     * @param str the string to match
1024     * @returns true if the regular expression matches string
1025     */

1026    private static boolean matchRegex(String JavaDoc regex, String JavaDoc str) {
1027        Pattern JavaDoc pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
1028        Matcher JavaDoc matcher = pattern.matcher(str);
1029        return matcher.matches();
1030    }
1031
1032    /**
1033     * Find matching resource deploy event in the cache. This method iterates
1034     * through all cached events and tries to find a ResourceDeployEvent for
1035     * specified resource type and name. The method returns null if it doesn't
1036     * find a match.
1037     * @param resType type of the resource
1038     * @param resName name of the resource
1039     * @throws IllegalArgumentException if resource type or name is null
1040     * @return matching ResourceDeployEvent if found, null otherwise.
1041     */

1042    private ResourceDeployEvent findResourceDeployEvent(String JavaDoc resType,
1043            String JavaDoc resName) {
1044        if (resType == null || resName == null) {
1045            String JavaDoc msg = localStrings.getString( "admin.event.null_resource_type_or_name", resType, resName );
1046            throw new IllegalArgumentException JavaDoc( msg );
1047        }
1048        ResourceDeployEvent resEvent = null;
1049        Iterator JavaDoc iter = cache.iterator();
1050        while (iter.hasNext()) {
1051            AdminEvent event = (AdminEvent)iter.next();
1052            if (event instanceof ResourceDeployEvent) {
1053                resEvent = (ResourceDeployEvent)event;
1054                if (resType.equals(resEvent.getResourceType())
1055                        && resName.equals(resEvent.getResourceName())) {
1056                    break;
1057                } else {
1058                    resEvent = null;
1059                }
1060            }
1061        }
1062        return resEvent;
1063    }
1064
1065    /**
1066     * Find matching application deploy event in the cache. This method iterates
1067     * through all cached events and tries to find an ApplicationDeployEvent for
1068     * specified name. The method returns null if it doesn't find a match.
1069     * @param appName name of the application
1070     * @throws IllegalArgumentException if specified application name is null
1071     * @return matching ApplicationDeployEvent if found, null otherwise.
1072     */

1073    private ApplicationDeployEvent findApplicationDeployEvent(String JavaDoc appName) {
1074        if (appName == null) {
1075            String JavaDoc msg = localStrings.getString( "admin.event.null_application_name" );
1076            throw new IllegalArgumentException JavaDoc( msg );
1077        }
1078        ApplicationDeployEvent appEvent = null;
1079        Iterator JavaDoc iter = cache.iterator();
1080        while (iter.hasNext()) {
1081            AdminEvent event = (AdminEvent)iter.next();
1082            if (event instanceof ApplicationDeployEvent) {
1083                appEvent = (ApplicationDeployEvent)event;
1084                if (appName.equals(appEvent.getApplicationName())) {
1085                    break;
1086                } else {
1087                    appEvent = null;
1088                }
1089            }
1090        }
1091        return appEvent;
1092    }
1093
1094    /**
1095     * Find matching module deploy event in the cache. This method iterates
1096     * through all cached events and tries to find a ModuleDeployEvent for
1097     * specified module type and name. The method returns null if it doesn't
1098     * find a match.
1099     * @param modType type of the module
1100     * @param modName name of the module
1101     * @throws IllegalArgumentException if module type or name is null
1102     * @return matching ModuleDeployEvent if found, null otherwise.
1103     */

1104    private ModuleDeployEvent findModuleDeployEvent(String JavaDoc modType,
1105            String JavaDoc modName) {
1106        if (modType == null || modName == null) {
1107            String JavaDoc msg = localStrings.getString( "admin.event.null_module_type_or_name", modType, modName );
1108            throw new IllegalArgumentException JavaDoc( msg );
1109        }
1110        ModuleDeployEvent modEvent = null;
1111        Iterator JavaDoc iter = cache.iterator();
1112        while (iter.hasNext()) {
1113            AdminEvent event = (AdminEvent)iter.next();
1114            if (event instanceof ModuleDeployEvent) {
1115                modEvent = (ModuleDeployEvent)event;
1116                if (modEvent.getModuleType().equals(modType)
1117                        && modEvent.getModuleName().equals(modName)) {
1118                    break;
1119                } else {
1120                    modEvent = null;
1121                }
1122            }
1123        }
1124        return modEvent;
1125    }
1126
1127    /**
1128     * Purge events that are NO-OP.
1129     */

1130    private void purgeNopEvents() {
1131        Iterator JavaDoc iter = cache.iterator();
1132        while (iter.hasNext()) {
1133            AdminEvent event = (AdminEvent)iter.next();
1134            if (event.isNoOp()) {
1135                logger.log(Level.FINE, PURGE_NOOP, event);
1136                iter.remove();
1137            }
1138        }
1139    }
1140
1141    /**
1142     * Set whether the instance requires restart. Cache is invalid if instance
1143     * requires restart.
1144     */

1145    public void setRestartNeeded(boolean flag) {
1146        if (flag) {
1147            if (!restartNeeded) {
1148                setRestartNeededTrue(true);
1149            }
1150        } else {
1151            restartNeeded = false;
1152        }
1153    }
1154
1155    /**
1156     * Set restart needed to true. This method also records the timestamp
1157     * when restart needed was set to true. If parameter notifyInstance is
1158     * true the instance is notified that it requires a restart.
1159     * @param notifyInstance if true the instance is notified of the restart
1160     * required status.
1161     */

1162    private void setRestartNeededTrue(boolean notifyInstance) {
1163        restartNeeded = true;
1164        tsRestartNeededSince = System.currentTimeMillis();
1165        if (notifyInstance) {
1166            RMIClient channel = AdminChannel.getRMIClient(instanceName);
1167            channel.setRestartNeeded(true);
1168        }
1169    }
1170
1171    /**
1172     * Is restart of instance required.
1173     */

1174    public boolean isInstanceRestartNeeded() {
1175        if (restartNeeded) {
1176            RMIClient channel = AdminChannel.getRMIClient(instanceName);
1177            boolean alreadyRestarted =
1178                    channel.hasRestartedSince(tsRestartNeededSince);
1179            if (alreadyRestarted) {
1180                restartNeeded = false;
1181            }
1182        }
1183        return restartNeeded;
1184    }
1185
1186    private final static String JavaDoc RES_PFX = ServerXPathHelper.XPATH_RESOURCES;
1187    private final static String JavaDoc APP_PFX = ServerXPathHelper.XPATH_J2EE_APPLICATION;
1188    private final static String JavaDoc WEB_PFX = ServerXPathHelper.XPATH_WEB_MODULE;
1189    private final static String JavaDoc EJB_PFX = ServerXPathHelper.XPATH_EJB_MODULE;
1190    private final static String JavaDoc RAR_PFX = ServerXPathHelper.XPATH_CONNECTOR_MODULE;
1191    private final static String JavaDoc ACC_PFX = ServerXPathHelper.XPATH_APPCLIENT_MODULE;
1192
1193    private final static String JavaDoc HTTP_SERVICE = ServerXPathHelper.XPATH_HTTP_SERVICE;
1194    private final static String JavaDoc WEB_CONTAINER = ServerXPathHelper.XPATH_WEB_CONTAINER;
1195
1196    private final static String JavaDoc PROPERTY_REGEX = ServerXPathHelper.XPATH_DOMAIN
1197            + ServerXPathHelper.XPATH_SEPARATOR + "{1,}" + ".*"
1198            + ServerXPathHelper.XPATH_SEPARATOR + "{1,}"
1199            + ServerTags.ELEMENT_PROPERTY + ".*";
1200
1201    private final static String JavaDoc LOG_LEVEL_XPATH =
1202            ServerXPathHelper.XPATH_CONFIG + ServerXPathHelper.XPATH_SEPARATOR
1203            + ServerTags.LOG_SERVICE + ServerXPathHelper.XPATH_SEPARATOR
1204            + ServerTags.MODULE_LOG_LEVELS;
1205
1206    private final static String JavaDoc MONITORING_LEVEL_XPATH =
1207            ServerXPathHelper.XPATH_CONFIG + ServerXPathHelper.XPATH_SEPARATOR
1208            + ServerTags.MONITORING_SERVICE + ServerXPathHelper.XPATH_SEPARATOR
1209            + ServerTags.MODULE_MONITORING_LEVELS;
1210
1211    private final static String JavaDoc PROCESS_CHANGE = "event.process_change";
1212    private final static String JavaDoc CHANGE_NULL = "event.change_null";
1213    private final static String JavaDoc EXTRACT_CHANGE = "event.extract_change";
1214    private final static String JavaDoc CONFIG_CHANGE_XPATH = "event.config_change_xpath";
1215    private final static String JavaDoc PURGE_NOOP = "event.purge_noop";
1216    private final static String JavaDoc NULL_UPDATED_ATTRS = "event.null_updated_attrs";
1217    private final static String JavaDoc INVALID_XPATH_TOKENIZATION =
1218            "event.invalid_xpath_tokenization";
1219
1220    // i18n StringManager
1221
private static StringManager localStrings =
1222        StringManager.getManager( AdminEventCache.class );
1223
1224    /**
1225     * An abstraction to allow processing of all level changes in same method.
1226     * The processing to generate events for log level changes and monitoring
1227     * level changes are very similar. This class abstracts out the differences
1228     * such that the code to generate event can be implemented in a single
1229     * method.
1230     */

1231    abstract class LevelChangeProcessor {
1232        AdminEventCache eventCache;
1233
1234        LevelChangeProcessor(AdminEventCache cache) {
1235            eventCache = cache;
1236        }
1237
1238        abstract boolean isRelevant(String JavaDoc xpath);
1239
1240        abstract AdminEvent createEvent(String JavaDoc componentName, String JavaDoc oldValue,
1241                String JavaDoc newValue);
1242    }
1243
1244    /**
1245     * Processor for changes to log level.
1246     */

1247    class LogLevelChangeProcessor extends LevelChangeProcessor {
1248        LogLevelChangeProcessor(AdminEventCache cache) {
1249            super(cache);
1250        }
1251
1252        boolean isRelevant(String JavaDoc xpath) {
1253            return eventCache.isLogLevelXPath(xpath);
1254        }
1255
1256        AdminEvent createEvent(String JavaDoc componentName, String JavaDoc oldValue,
1257                String JavaDoc newValue) {
1258            LogLevelChangeEvent event = new LogLevelChangeEvent(
1259                   eventCache.instanceName);
1260            event.setModuleName(componentName);
1261            event.setOldLogLevel(oldValue);
1262            event.setNewLogLevel(newValue);
1263            return event;
1264        }
1265    }
1266
1267    /**
1268     * Processor for changes to monitoring level.
1269     */

1270    class MonitoringLevelChangeProcessor extends LevelChangeProcessor {
1271        MonitoringLevelChangeProcessor(AdminEventCache cache) {
1272            super(cache);
1273        }
1274
1275        boolean isRelevant(String JavaDoc xpath) {
1276            return eventCache.isMonitoringLevelXPath(xpath);
1277        }
1278
1279        AdminEvent createEvent(String JavaDoc componentName, String JavaDoc oldValue,
1280                String JavaDoc newValue) {
1281            MonitoringLevelChangeEvent event = new MonitoringLevelChangeEvent(
1282                   eventCache.instanceName);
1283            event.setComponentName(componentName);
1284            event.setOldMonitoringLevel(oldValue);
1285            event.setNewMonitoringLevel(newValue);
1286            return event;
1287        }
1288    }
1289
1290    /**
1291     * RefProcessor is an abstraction for references. The configuration
1292     * element server contains references to applications and resources.
1293     * There is a lot of commonality between the events generated for
1294     * changes to all references. This class tries to abstract the common
1295     * behavior out.
1296     */

1297    abstract class RefProcessor {
1298        AdminEventCache adminEventCache;
1299        Map JavaDoc refTypeXPathMap = new HashMap JavaDoc();
1300        boolean resEnabled;
1301
1302        RefProcessor(AdminEventCache cache) {
1303            adminEventCache = cache;
1304        }
1305
1306        /**
1307         * Is the xpath relevant. Used to determine whether to continue
1308         * processing the config change.
1309         */

1310        abstract boolean isRelevant(String JavaDoc xpath);
1311
1312        /**
1313         * Process the config change and generate events for specified ref
1314         * name and ref type.
1315         * @param refName name of the reference. The reference name is unique
1316         * for any given type. For example, no two resource refs can share
1317         * the same name.
1318         * @param refType type of the reference. This represents the type
1319         * used in events. For example, ResourceDeployEvent.RES_TYPE_JCP or
1320         * ApplicationDeployEvent.APPLICATION or
1321         * ModuleDeployEvent.TYPE_WEBMODULE
1322         * @param change the change object for the reference
1323         * @return true if the change was added to an existing or new event,
1324         * false otherwise.
1325         */

1326        abstract boolean process(String JavaDoc refName, String JavaDoc refType,
1327                ConfigChange change);
1328
1329        /**
1330         * Get name of reference from xpath.
1331         */

1332        String JavaDoc getRefName(String JavaDoc xpath) {
1333            return adminEventCache.getXPathToken(xpath, 3);
1334        }
1335
1336        /**
1337         * Get type of reference for specified refName.
1338         */

1339        String JavaDoc getRefType(String JavaDoc refName, ArrayList JavaDoc allChanges) {
1340            // Look for object in config first. It may not exist in config
1341
// if it has been deleted
1342
String JavaDoc refType = getRefTypeFromConfig(refName);
1343            if (refType == null) {
1344                // If not found, then look in the config changes
1345
refType = getRefTypeFromChanges(refName, allChanges);
1346            }
1347            return refType;
1348        }
1349
1350        /**
1351         * Get type of reference from config.
1352         */

1353        String JavaDoc getRefTypeFromConfig(String JavaDoc refName) {
1354            ConfigContext ctx = adminEventCache.adminConfigContext;
1355            if (ctx == null) {
1356                return null;
1357            }
1358            String JavaDoc refType = null;
1359            Iterator JavaDoc iter = refTypeXPathMap.entrySet().iterator();
1360            while (iter.hasNext()) {
1361                Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
1362                String JavaDoc xpath = (String JavaDoc)entry.getValue();
1363                ConfigBean bean = null;
1364                try {
1365                    bean = ctx.exactLookup(xpath);
1366                } catch (ConfigException ce) {
1367                    // Ignore config exception, as it is not relevant for the
1368
// purpose of finding the ref type.
1369
}
1370                if (bean != null) {
1371                    refType = (String JavaDoc)entry.getKey();
1372                    resEnabled = getEnabledState(bean);
1373                    break;
1374                }
1375            }
1376            return refType;
1377        }
1378
1379        /**
1380         * Get ref type from config changes. This will be used only if the
1381         * object no longer exists in config context (can happen if it has
1382         * been deleted).
1383         */

1384        String JavaDoc getRefTypeFromChanges(String JavaDoc refName, ArrayList JavaDoc allChanges) {
1385            if (allChanges == null) {
1386                return null;
1387            }
1388            String JavaDoc refType = null;
1389            Iterator JavaDoc iter = allChanges.iterator();
1390            while (iter.hasNext()) {
1391                ConfigChange change = (ConfigChange)iter.next();
1392                String JavaDoc xpath = adminEventCache.cleanXPath(change.getXPath());
1393                Iterator JavaDoc iter2 = refTypeXPathMap.entrySet().iterator();
1394                while (iter2.hasNext()) {
1395                    Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter2.next();
1396                    String JavaDoc xpath2 = (String JavaDoc)entry.getValue();
1397                    if (xpath != null && xpath.equals(xpath2)) {
1398                        refType = (String JavaDoc)entry.getKey();
1399                        if (change instanceof ConfigAdd) {
1400                            ConfigBean b = ((ConfigAdd)change).getConfigBean();
1401                            resEnabled = getEnabledState(b);
1402                        } else {
1403                            // The change must be delete (otherwise we would
1404
// have found the refType from config context
1405
resEnabled = false;
1406                        }
1407                        break;
1408                    }
1409                }
1410                if (refType != null) {
1411                    break;
1412                }
1413            }
1414            return refType;
1415        }
1416
1417        /**
1418         * Get enabled state for the specified config bean. If the bean does
1419         * not have an enabled attribute, the method returns true (objects
1420         * without an enabled attribute are enabled)
1421         */

1422        boolean getEnabledState(ConfigBean bean) {
1423            String JavaDoc enabledStr = null;
1424            try {
1425                enabledStr = bean.getAttributeValue(ServerTags.ENABLED);
1426            } catch (IllegalArgumentException JavaDoc iae) {
1427                // Some resources do not have enabled attribute.
1428
enabledStr = "true";
1429            }
1430            return adminEventCache.getServerXmlBooleanValue(enabledStr);
1431        }
1432
1433        /**
1434         * Get action code from the change. The method determines the action
1435         * code for the event using the change object type (for the ref) and
1436         * enabled state of corresponding config object.
1437         */

1438        String JavaDoc getActionCode(ConfigChange change) {
1439            String JavaDoc actionCode = null;
1440            if (change instanceof ConfigUpdate) {
1441                ConfigUpdate update = (ConfigUpdate)change;
1442                String JavaDoc enableStr = update.getNewValue(ServerTags.ENABLED);
1443                if (enableStr != null) {
1444                    boolean enabled =
1445                            adminEventCache.getServerXmlBooleanValue(
1446                                enableStr);
1447                    if (enabled && resEnabled) {
1448                        actionCode = BaseDeployEvent.ENABLE;
1449                    } else if (enabled && !resEnabled) {
1450                        actionCode = BaseDeployEvent.REDEPLOY;
1451                    } else {
1452                        actionCode = BaseDeployEvent.DISABLE;
1453                    }
1454                } else {
1455                    actionCode = BaseDeployEvent.REDEPLOY;
1456                }
1457            } else if (change instanceof ConfigAdd) {
1458                actionCode = BaseDeployEvent.DEPLOY;
1459            } else if (change instanceof ConfigDelete) {
1460                actionCode = BaseDeployEvent.UNDEPLOY;
1461            } else if (change instanceof ConfigSet) {
1462                // Typically set is used for existing entries
1463
actionCode = BaseDeployEvent.REDEPLOY;
1464            } else {
1465                // Unknown ConfigChange cannot be handled
1466
String JavaDoc msg = localStrings.getString(
1467                        "admin.event.unknown_configchange_for_resources");
1468                throw new IllegalStateException JavaDoc( msg );
1469            }
1470            return actionCode;
1471        }
1472
1473        /**
1474         * Initialize the map of ref types and config object xpath. This map
1475         * is used to determine the type of ref.
1476         */

1477        abstract void initRefTypeXPathMap(String JavaDoc refName);
1478
1479    }
1480
1481    /**
1482     * Processor for application references.
1483     */

1484    class AppRefProcessor extends RefProcessor {
1485        AppRefProcessor(AdminEventCache cache) {
1486            super(cache);
1487        }
1488
1489        boolean isRelevant(String JavaDoc xpath) {
1490            return adminEventCache.isAppRefXPath(xpath);
1491        }
1492
1493        /**
1494         * Create or update the event for application ref.
1495         */

1496        boolean process(String JavaDoc refName, String JavaDoc refType, ConfigChange change) {
1497            String JavaDoc compType = null;
1498            String JavaDoc modType = null;
1499            if (BaseDeployEvent.APPLICATION.equals(refType)) {
1500                compType = BaseDeployEvent.APPLICATION;
1501            } else if ((ModuleDeployEvent.TYPE_WEBMODULE.equals(refType))
1502                    || (ModuleDeployEvent.TYPE_EJBMODULE.equals(refType))
1503                    || (ModuleDeployEvent.TYPE_CONNECTOR.equals(refType))
1504                    || (ModuleDeployEvent.TYPE_APPCLIENT.equals(refType))) {
1505                compType = BaseDeployEvent.MODULE;
1506                modType = refType;
1507            } else {
1508                // Unhandled ref type
1509
return false;
1510            }
1511            AdminEvent theEvent = null;
1512            if (BaseDeployEvent.APPLICATION.equals(compType)) {
1513                theEvent = adminEventCache.findApplicationDeployEvent(refName);
1514            } else {
1515                theEvent = adminEventCache.findModuleDeployEvent(
1516                        modType, refName);
1517            }
1518            if (theEvent == null) {
1519                String JavaDoc actionCode = getActionCode(change);
1520                // enable - disable functionality is moved to
1521
// ElementChange event factory
1522
if(BaseDeployEvent.ENABLE.equals(actionCode) ||
1523                   BaseDeployEvent.DISABLE.equals(actionCode) ||
1524                   BaseDeployEvent.REDEPLOY.equals(actionCode))
1525                    return false;
1526                if (BaseDeployEvent.APPLICATION.equals(compType)) {
1527                    theEvent = new ApplicationDeployEvent(
1528                            adminEventCache.instanceName, refName,
1529                            actionCode);
1530                } else {
1531                    theEvent = new ModuleDeployEvent(
1532                            adminEventCache.instanceName, refName,
1533                            modType, actionCode);
1534                }
1535                cache.add(theEvent);
1536            }
1537            theEvent.addConfigChange(change);
1538            return true;
1539        }
1540
1541        /**
1542         * Initialize map for application ref types. Dynamic reconfig of
1543         * lifecycle modules is not supported and hence the map only includes
1544         * entries for J2EE application, EJB Module, Web Module, Connector
1545         * module and appclient module.
1546         */

1547        void initRefTypeXPathMap(String JavaDoc refName) {
1548            refTypeXPathMap.put(
1549                    BaseDeployEvent.APPLICATION,
1550                    ServerXPathHelper.getAppIdXpathExpression(refName));
1551            refTypeXPathMap.put(
1552                    ModuleDeployEvent.TYPE_WEBMODULE,
1553                    ServerXPathHelper.getWebModuleIdXpathExpression(refName));
1554            refTypeXPathMap.put(
1555                    ModuleDeployEvent.TYPE_EJBMODULE,
1556                    ServerXPathHelper.getEjbModuleIdXpathExpression(refName));
1557            refTypeXPathMap.put(
1558                    ModuleDeployEvent.TYPE_CONNECTOR,
1559                    ServerXPathHelper.getConnectorModuleIdXpathExpression(
1560                            refName));
1561            refTypeXPathMap.put(
1562                    ModuleDeployEvent.TYPE_APPCLIENT,
1563                    ServerXPathHelper.getAppClientModuleIdXpathExpression(
1564                            refName));
1565        }
1566    }
1567
1568    /**
1569     * Processor for resource references.
1570     */

1571    class ResRefProcessor extends RefProcessor {
1572        ResRefProcessor(AdminEventCache cache) {
1573            super(cache);
1574        }
1575
1576        boolean isRelevant(String JavaDoc xpath) {
1577            return adminEventCache.isResRefXPath(xpath);
1578        }
1579
1580        /**
1581         * Create or update the event for resource ref.
1582         */

1583        boolean process(String JavaDoc refName, String JavaDoc refType, ConfigChange change) {
1584            ResourceDeployEvent event =
1585                    findResourceDeployEvent(refType, refName);
1586            if (event == null) {
1587                String JavaDoc actionCode = getActionCode(change);
1588                event = new ResourceDeployEvent(adminEventCache.instanceName,
1589                        refName, refType, actionCode);
1590                cache.add(event);
1591            }
1592            event.addConfigChange(change);
1593            return true;
1594        }
1595
1596        /**
1597         * Initialize map for resource types.
1598         */

1599        void initRefTypeXPathMap(String JavaDoc refName) {
1600            refTypeXPathMap.put(
1601                    ResourceDeployEvent.RES_TYPE_CUSTOM,
1602                    ServerXPathHelper.getCustomResourceIdXpath(refName));
1603            refTypeXPathMap.put(
1604                    ResourceDeployEvent.RES_TYPE_EXTERNAL_JNDI,
1605                    ServerXPathHelper.getJNDIResourceIdXpath(refName));
1606            refTypeXPathMap.put(
1607                    ResourceDeployEvent.RES_TYPE_JCP,
1608                    ServerXPathHelper.getJDBCConnectionPoolIdXpath(refName));
1609            refTypeXPathMap.put(
1610                    ResourceDeployEvent.RES_TYPE_JDBC,
1611                    ServerXPathHelper.getJDBCResourceIdXpath(refName));
1612            refTypeXPathMap.put(
1613                    ResourceDeployEvent.RES_TYPE_MAIL,
1614                    ServerXPathHelper.getMailResourceIdXpath(refName));
1615            refTypeXPathMap.put(
1616                    ResourceDeployEvent.RES_TYPE_PMF,
1617                    ServerXPathHelper.getPMFactoryResourceIdXpath(refName));
1618            refTypeXPathMap.put(
1619                    ResourceDeployEvent.RES_TYPE_AOR,
1620                    ServerXPathHelper.getAbsoluteIdXpathExpression(
1621                        ServerXPathHelper.XPATH_ADMIN_OBJECT_RESOURCE,
1622                        ServerTags.JNDI_NAME, refName));
1623            refTypeXPathMap.put(
1624                    ResourceDeployEvent.RES_TYPE_CCP,
1625                    ServerXPathHelper.getAbsoluteIdXpathExpression(
1626                        ServerXPathHelper.XPATH_CONNECTOR_CONNECTION_POOL,
1627                        ServerTags.NAME, refName));
1628            refTypeXPathMap.put(
1629                    ResourceDeployEvent.RES_TYPE_CR,
1630                    ServerXPathHelper.getAbsoluteIdXpathExpression(
1631                        ServerXPathHelper.XPATH_CONNECTOR_RESOURCE,
1632                        ServerTags.JNDI_NAME, refName));
1633            refTypeXPathMap.put(
1634                    ResourceDeployEvent.RES_TYPE_RAC,
1635                    ServerXPathHelper.getAbsoluteIdXpathExpression(
1636                        ServerXPathHelper.XPATH_RESOURCE_ADAPTER_CONFIG,
1637                        ServerTags.NAME, refName));
1638        }
1639    }
1640}
1641
Popular Tags