001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 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.ServiceBroker;
033: import org.cougaar.core.component.ServiceRevokedListener;
034: import org.cougaar.core.mts.MessageAddress;
035: import org.cougaar.core.persist.PersistenceClient;
036: import org.cougaar.core.persist.PersistenceIdentity;
037: import org.cougaar.core.persist.PersistenceService;
038: import org.cougaar.core.persist.RehydrationData;
039: import org.cougaar.core.service.AgentIdentificationService;
040: import org.cougaar.core.service.LoggingService;
041: import org.cougaar.core.service.identity.AgentIdentityClient;
042: import org.cougaar.core.service.identity.AgentIdentityService;
043: import org.cougaar.core.service.identity.CrlReason;
044: import org.cougaar.core.service.identity.TransferableIdentity;
045: import org.cougaar.util.GenericStateModelAdapter;
046:
047: /**
048: * This component acquires the agent's security identity from the
049: * optional {@link AgentIdentityService} and transfers the identity
050: * when the agent moves.
051: *
052: * @see AgentIdentityService
053: */
054: public final class AcquireIdentity extends GenericStateModelAdapter
055: implements Component {
056:
057: private ServiceBroker sb;
058:
059: // identity either from prior location or moving away
060: private TransferableIdentity mobileIdentity;
061:
062: private AgentIdentityClient agentIdentityClient;
063:
064: private LoggingService log;
065:
066: private PersistenceService ps;
067: private PersistenceClient pc;
068:
069: private AgentIdentityService agentIdentityService;
070:
071: private MobilityNotificationClient mnc;
072: private MobilityNotificationService mns;
073:
074: private MessageAddress moveTargetNode;
075:
076: private MessageAddress localAgent;
077:
078: public void setServiceBroker(ServiceBroker sb) {
079: this .sb = sb;
080: }
081:
082: public void load() {
083: super .load();
084:
085: log = (LoggingService) sb.getService(this ,
086: LoggingService.class, null);
087:
088: localAgent = find_local_agent();
089:
090: register_persistence();
091:
092: // get mobile state
093: Object o = rehydrate();
094: if (o instanceof TransferableIdentity) {
095: // fill in prior (mobile) identity
096: mobileIdentity = (TransferableIdentity) o;
097: }
098: o = null;
099:
100: // take and clear the saved identity
101: TransferableIdentity tmp = mobileIdentity;
102: mobileIdentity = null;
103: if (tmp == NULL_MOBILE_IDENTITY) {
104: tmp = null;
105: }
106: if (log.isInfoEnabled()) {
107: log.info("Acquiring "
108: + ((tmp == null) ? ("new identity")
109: : ("transfered identity: " + tmp)));
110: }
111:
112: agentIdentityClient = new AgentIdentityClient() {
113: public void identityRevoked(CrlReason reason) {
114: log.warn("Identity has been revoked: " + reason);
115: // ignore for now, re-acquire or die TBA
116: }
117:
118: public String getName() {
119: return localAgent.getAddress();
120: }
121: };
122: agentIdentityService = (AgentIdentityService) sb.getService(
123: agentIdentityClient, AgentIdentityService.class, null);
124: if (agentIdentityService == null) {
125: if (log.isInfoEnabled()) {
126: log.info("Agent identity service not found");
127: }
128: return;
129: }
130:
131: try {
132: agentIdentityService.acquire(tmp);
133: } catch (Exception e) {
134: throw new RuntimeException(
135: ("Unable to acquire agent identity for agent "
136: + localAgent + ((tmp == null) ? ("")
137: : (" from transfered identity: " + tmp))),
138: e);
139: }
140:
141: // mobility watcher
142: mnc = new MobilityNotificationClient() {
143: public void movingTo(MessageAddress destinationNode) {
144: moveTargetNode = destinationNode;
145: }
146: };
147: mns = (MobilityNotificationService) sb.getService(mnc,
148: MobilityNotificationService.class, null);
149: if (mns == null && log.isInfoEnabled()) {
150: log.info("Unable to obtain MobilityNotificationService"
151: + ", mobility is disabled");
152: }
153: }
154:
155: public void suspend() {
156: super .suspend();
157:
158: if (moveTargetNode == null) {
159: // non-moving suspend?
160: if (log.isInfoEnabled()) {
161: log.info("Releasing identity");
162: }
163: if (agentIdentityService != null) {
164: agentIdentityService.release();
165: }
166: } else {
167: // moving, delay identity transfer until persist
168: if (log.isInfoEnabled()) {
169: log.info("Postponing identity transfer to node "
170: + moveTargetNode);
171: }
172: }
173: }
174:
175: public void resume() {
176: super .resume();
177:
178: // re-establish our identity
179: if (moveTargetNode == null) {
180: // resume after non-move suspend
181: if (log.isInfoEnabled()) {
182: log.info("Acquiring agent identify from scratch");
183: }
184: if (agentIdentityService != null) {
185: try {
186: agentIdentityService.acquire(null);
187: } catch (Exception e) {
188: throw new RuntimeException(
189: "Unable to resume agent " + localAgent
190: + " after non-move suspend", e);
191: }
192: }
193: } else {
194: // failed move, restart
195: MessageAddress mtn = moveTargetNode;
196: moveTargetNode = null;
197: if (mobileIdentity == null) {
198: // never transfered identity (state capture failed?)
199: if (log.isInfoEnabled()) {
200: log.info("Identity was never transfered to " + mtn);
201: }
202: } else {
203: // take and clear the saved identity
204: TransferableIdentity tmp = mobileIdentity;
205: mobileIdentity = null;
206: if (tmp == NULL_MOBILE_IDENTITY) {
207: tmp = null;
208: }
209: if (log.isInfoEnabled()) {
210: log.info("Acquiring agent identify from"
211: + " failed move to " + mtn
212: + " and transfer-identity " + tmp);
213: }
214: if (agentIdentityService != null) {
215: try {
216: agentIdentityService.acquire(tmp);
217: } catch (Exception e) {
218: throw new RuntimeException(
219: "Unable to restart agent " + localAgent
220: + " after failed move to "
221: + mtn
222: + " and transfer-identity "
223: + tmp, e);
224: }
225: }
226: }
227: }
228: }
229:
230: public void unload() {
231: super .unload();
232:
233: if (mns != null) {
234: sb.releaseService(mnc, MobilityNotificationService.class,
235: mns);
236: mns = null;
237: }
238:
239: if (agentIdentityService != null) {
240: sb.releaseService(agentIdentityClient,
241: AgentIdentityService.class, agentIdentityService);
242: agentIdentityService = null;
243: }
244:
245: unregister_persistence();
246: }
247:
248: private MessageAddress find_local_agent() {
249: AgentIdentificationService ais = (AgentIdentificationService) sb
250: .getService(this , AgentIdentificationService.class,
251: null);
252: if (ais == null) {
253: return null;
254: }
255: MessageAddress ret = ais.getMessageAddress();
256: sb.releaseService(this , AgentIdentificationService.class, ais);
257: return ret;
258: }
259:
260: private Object captureState() {
261: if (getModelState() == ACTIVE) {
262: if (log.isDebugEnabled()) {
263: log.debug("Ignoring identity persist while active");
264: }
265: return null;
266: }
267:
268: return mobileIdentity;
269: }
270:
271: private void register_persistence() {
272: // get persistence
273: pc = new PersistenceClient() {
274: public PersistenceIdentity getPersistenceIdentity() {
275: String id = getClass().getName();
276: return new PersistenceIdentity(id);
277: }
278:
279: public List getPersistenceData() {
280: Object o = captureState();
281: // must return mutable list!
282: List l = new ArrayList(1);
283: l.add(o);
284: return l;
285: }
286: };
287: ps = (PersistenceService) sb.getService(pc,
288: PersistenceService.class, null);
289: }
290:
291: private void unregister_persistence() {
292: if (ps != null) {
293: sb.releaseService(pc, PersistenceService.class, ps);
294: ps = null;
295: pc = null;
296: }
297: }
298:
299: private Object rehydrate() {
300: RehydrationData rd = ps.getRehydrationData();
301: if (rd == null) {
302: if (log.isInfoEnabled()) {
303: log.info("No rehydration data found");
304: }
305: return null;
306: }
307:
308: List l = rd.getObjects();
309: rd = null;
310: int lsize = (l == null ? 0 : l.size());
311: if (lsize < 1) {
312: if (log.isInfoEnabled()) {
313: log.info("Invalid rehydration list? " + l);
314: }
315: return null;
316: }
317: Object o = l.get(0);
318: if (o == null) {
319: if (log.isInfoEnabled()) {
320: log.info("Null rehydration state?");
321: }
322: return null;
323: }
324:
325: if (log.isInfoEnabled()) {
326: log.info("Found rehydrated state");
327: if (log.isDetailEnabled()) {
328: log.detail("state is " + o);
329: }
330: }
331:
332: return o;
333: }
334:
335: private static final TransferableIdentity NULL_MOBILE_IDENTITY = new TransferableIdentity() {
336: private Object readResolve() {
337: return NULL_MOBILE_IDENTITY;
338: }
339: };
340: }
|