001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2007 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.agent;
028:
029: import java.util.ArrayList;
030: import java.util.List;
031: import org.cougaar.core.component.Component;
032: import org.cougaar.core.component.ComponentDescription;
033: import org.cougaar.core.component.ComponentDescriptions;
034: import org.cougaar.core.component.ServiceBroker;
035: import org.cougaar.core.component.ServiceProvider;
036: import org.cougaar.core.component.StateTuple;
037: import org.cougaar.core.persist.PersistenceClient;
038: import org.cougaar.core.persist.PersistenceIdentity;
039: import org.cougaar.core.persist.PersistenceService;
040: import org.cougaar.core.persist.RehydrationData;
041: import org.cougaar.core.service.LoggingService;
042: import org.cougaar.util.GenericStateModel; // inlined
043: import org.cougaar.util.GenericStateModelAdapter;
044:
045: /**
046: * This component registers with persistence as the component
047: * model tracker and finds the agent's component descriptions
048: * in the rehydrated persistence snapshot.
049: *
050: * @see FindComponentsLoadService
051: */
052: public final class FindComponentsEarly extends GenericStateModelAdapter
053: implements Component {
054:
055: private ServiceBroker sb;
056:
057: private LoggingService log;
058:
059: private MySP fclsp;
060:
061: private PersistenceService ps;
062: private PersistenceClient pc;
063:
064: private boolean foundDescs;
065: private List initialDescs;
066:
067: public void setServiceBroker(ServiceBroker sb) {
068: this .sb = sb;
069: }
070:
071: public void load() {
072: super .load();
073:
074: log = (LoggingService) sb.getService(this ,
075: LoggingService.class, null);
076:
077: register_persistence();
078:
079: // rehydrate from mobile state (if available)
080: load_early();
081:
082: fclsp = new MySP();
083: sb.addService(FindComponentsLoadService.class, fclsp);
084:
085: // called later via FindComponentsLoadService:
086: //load_late();
087: }
088:
089: public void start() {
090: super .start();
091:
092: initialDescs = null;
093:
094: // once loaded we revoke our service
095: if (fclsp != null) {
096: sb.revokeService(FindComponentsLoadService.class, fclsp);
097: fclsp = null;
098: }
099: }
100:
101: public void unload() {
102: super .unload();
103:
104: unregister_persistence();
105: }
106:
107: private void load_early() {
108: if (log.isDebugEnabled()) {
109: log
110: .debug("Attempting early rehydrate, in case mobile persistence"
111: + " data exists");
112: }
113:
114: List l = null;
115:
116: // get list from persisted state
117: Object o = rehydrate();
118: if (o instanceof List) {
119: l = (List) o;
120: }
121: o = null;
122:
123: if (l != null) {
124: foundDescs = true;
125: if (log.isInfoEnabled()) {
126: log.info("Restoring mobile components descriptions");
127: }
128: overrideComponentList(l);
129: return;
130: }
131:
132: if (log.isInfoEnabled()) {
133: log
134: .info("No persistence data found, loading component descriptions"
135: + " from the initializer service");
136: }
137: }
138:
139: private void load_late() {
140: // See comment in load_early() above.
141: if (foundDescs) {
142: if (log.isDebugEnabled()) {
143: log
144: .debug("Already rehydrated component descriptions from"
145: + " mobile state");
146: }
147: return;
148: }
149: foundDescs = true;
150:
151: // We "load_late" to allow other components to load before
152: // the second rehydration attempt, such as necessary security
153: // components required to decrypt the snapshot.
154: if (log.isDebugEnabled()) {
155: log.debug("Attempting second rehydrate");
156: }
157:
158: List l = null;
159:
160: // try to rehydrate a second time!
161: Object o = rehydrate();
162: if (o instanceof List) {
163: l = (List) o;
164: }
165: o = null;
166:
167: if (l == null) {
168: if (log.isInfoEnabled()) {
169: log.info("No components found in snapshot, keeping our"
170: + " initial config");
171: }
172: return;
173: }
174:
175: // rehydrating late, so we've already added our
176: // "FindComponentsLate" component, which we must now
177: // trim out of the list
178: List l2 = trimListUntilAfter(l, FindComponentsLate.class
179: .getName());
180:
181: if (log.isInfoEnabled()) {
182: log.info("Restoring components descriptions");
183: }
184:
185: overrideComponentList(l2);
186: }
187:
188: private Object captureState() {
189: if (log.isInfoEnabled()) {
190: log.info("Capturing component descriptions");
191: }
192: return getComponentList();
193: }
194:
195: private void register_persistence() {
196: // get persistence
197: pc = new PersistenceClient() {
198: public PersistenceIdentity getPersistenceIdentity() {
199: String id = getClass().getName();
200: return new PersistenceIdentity(id);
201: }
202:
203: public List getPersistenceData() {
204: Object o = captureState();
205: // must return mutable list!
206: List l = new ArrayList(1);
207: l.add(o);
208: return l;
209: }
210: };
211: ps = (PersistenceService) sb.getService(pc,
212: PersistenceService.class, null);
213: }
214:
215: private void unregister_persistence() {
216: if (ps != null) {
217: sb.releaseService(pc, PersistenceService.class, ps);
218: ps = null;
219: pc = null;
220: }
221: }
222:
223: private Object rehydrate() {
224: RehydrationData rd = ps.getRehydrationData();
225: if (rd == null) {
226: if (log.isInfoEnabled()) {
227: log.info("No rehydration data found");
228: }
229: return null;
230: }
231:
232: List l = rd.getObjects();
233: rd = null;
234: int lsize = (l == null ? 0 : l.size());
235: if (lsize < 1) {
236: if (log.isInfoEnabled()) {
237: log.info("Invalid rehydration list? " + l);
238: }
239: return null;
240: }
241: Object o = l.get(0);
242: if (o == null) {
243: if (log.isInfoEnabled()) {
244: log.info("Null rehydration state?");
245: }
246: return null;
247: }
248:
249: if (log.isInfoEnabled()) {
250: log.info("Found rehydrated state");
251: if (log.isDetailEnabled()) {
252: log.detail("state is " + o);
253: }
254: }
255:
256: return o;
257: }
258:
259: private void overrideComponentList(List l) {
260: if (log.isDebugEnabled()) {
261: log.debug("overrideComponentList(" + l + ")");
262: }
263:
264: // save for state capture while loading
265: initialDescs = l;
266:
267: AgentBootstrapService abs = (AgentBootstrapService) sb
268: .getService(this , AgentBootstrapService.class, null);
269: if (abs == null) {
270: throw new RuntimeException(
271: "Unable to obtain AgentBootstrapService"
272: + ", can not override component list");
273: }
274: abs.overrideComponentList(l);
275: sb.releaseService(this , AgentBootstrapService.class, abs);
276: abs = null;
277: }
278:
279: private List getComponentList() {
280: if (initialDescs != null) {
281: // actively loading, use override list
282: if (log.isInfoEnabled()) {
283: log
284: .info("Asked to \"getComponentList\" while loading,"
285: + " which would find a partially loaded model,"
286: + " so instead return our initial component list["
287: + initialDescs.size() + "]");
288: if (log.isDebugEnabled()) {
289: log.debug("initialDescs[" + initialDescs.size()
290: + "]=" + initialDescs);
291: }
292: }
293: return initialDescs;
294: }
295:
296: if (getModelState() == GenericStateModel.LOADED
297: && log.isErrorEnabled()) {
298: // this shouldn't happen, since during load we always
299: // save our override list
300: log
301: .error("Attempting to capture model state while loading,"
302: + " initialDescs is null,"
303: + " this may find a partial configuration!");
304: }
305:
306: // get descriptions
307: AgentComponentModelService acms = (AgentComponentModelService) sb
308: .getService(this , AgentComponentModelService.class,
309: null);
310: if (acms == null) {
311: throw new RuntimeException(
312: "Unable to obtain AgentComponentModelService"
313: + ", can not override component list");
314: }
315: ComponentDescriptions descs = acms.getComponentDescriptions();
316: sb.releaseService(this , AgentComponentModelService.class, acms);
317: acms = null;
318:
319: if (log.isDebugEnabled()) {
320: log.debug("ComponentModel found: " + descs);
321: }
322:
323: // convert to list
324: List l = flattenComponents(descs);
325:
326: if (log.isDebugEnabled()) {
327: log.debug("Flattened to list: " + l);
328: }
329:
330: // trim to exclude our component and components loaded before us
331: //
332: // Note that this is the correct list for mobility, but if
333: // we're capturing the list for persistence we should further
334: // trim the list until "FindComponentsLate". For now we'll
335: // do this when we "load_late()" rehydrate.
336: List l2 = trimListUntilAfter(l, FindComponentsEarly.class
337: .getName());
338:
339: if (log.isDebugEnabled()) {
340: log.debug("Trimmed list to: " + l2);
341: }
342:
343: return l2;
344: }
345:
346: private List trimListUntilAfter(List l, String classname) {
347: // find the index of the classname
348: int i = 0;
349: int n = l.size();
350: while (true) {
351: if (i >= n) {
352: // not found?
353: if (log.isDetailEnabled()) {
354: log.detail("classname " + classname
355: + " not found in " + l);
356: }
357: return l;
358: }
359: Object o = l.get(i++);
360: ComponentDescription cd = ((o instanceof StateTuple) ? (((StateTuple) o)
361: .getComponentDescription())
362: : ((ComponentDescription) o));
363: if (classname.equals(cd.getClassname())) {
364: if (log.isDetailEnabled()) {
365: log.detail("found classname " + classname + " as "
366: + cd + " at index " + (i - 1) + " of " + n
367: + " in list " + l);
368: }
369: break;
370: }
371: }
372: // trim list to remainder
373: //
374: // can't l.subList, since it's not serializable!
375: // just loop instead...
376: List ret = new ArrayList(n - (i + 1));
377: for (int j = i; j < n; j++) {
378: ret.add(l.get(j));
379: }
380: if (log.isDetailEnabled()) {
381: log.detail("trimmed list[" + i + ".." + n + "] to " + ret);
382: }
383: return ret;
384: }
385:
386: private static List flattenComponents(ComponentDescriptions descs) {
387: List l = new ArrayList();
388: l.addAll(findComponents(descs,
389: ComponentDescription.PRIORITY_HIGH));
390: l.addAll(findComponents(descs,
391: ComponentDescription.PRIORITY_INTERNAL));
392: l.addAll(findComponents(descs,
393: ComponentDescription.PRIORITY_BINDER));
394: l.addAll(findComponents(descs,
395: ComponentDescription.PRIORITY_COMPONENT));
396: l.addAll(findComponents(descs,
397: ComponentDescription.PRIORITY_LOW));
398: return l;
399: }
400:
401: private static List findComponents(ComponentDescriptions descs,
402: int priority) {
403: return findComponents(descs, "Node.AgentManager.Agent.",
404: priority);
405: }
406:
407: private static List findComponents(ComponentDescriptions descs,
408: String containmentPoint, int priority) {
409: List ret = new ArrayList();
410: if (descs == null)
411: return ret;
412: List pcd = descs.selectComponentDescriptions(priority);
413: if (pcd == null)
414: return ret;
415: for (Object o : pcd) {
416: ComponentDescription cd = ((o instanceof StateTuple) ? (((StateTuple) o)
417: .getComponentDescription())
418: : ((ComponentDescription) o));
419: String ip = cd.getInsertionPoint();
420: if (ip.startsWith(containmentPoint)
421: && ip.indexOf(".", containmentPoint.length() + 1) < 0) {
422: ret.add(o);
423: }
424: }
425: return ret;
426: }
427:
428: private final class MySP implements ServiceProvider {
429: private final FindComponentsLoadService fcls;
430:
431: public MySP() {
432: fcls = new FindComponentsLoadService() {
433: public void rehydrate() {
434: load_late();
435: }
436: };
437: }
438:
439: public Object getService(ServiceBroker sb, Object requestor,
440: Class serviceClass) {
441: if (FindComponentsLoadService.class
442: .isAssignableFrom(serviceClass)) {
443: return fcls;
444: } else {
445: return null;
446: }
447: }
448:
449: public void releaseService(ServiceBroker sb, Object requestor,
450: Class serviceClass, Object service) {
451: }
452: }
453: }
|