001: /*
002: * <copyright>
003: *
004: * Copyright 2002-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.yp;
028:
029: import org.cougaar.core.persist.Persistable;
030: import org.cougaar.core.thread.SchedulableStatus;
031: import org.cougaar.util.log.Logger;
032: import org.cougaar.util.log.Logging;
033: import org.uddi4j.UDDIException;
034: import org.w3c.dom.Element;
035:
036: final class YPFutureImpl implements YPFuture, Persistable {
037: private static final Logger logger = Logging
038: .getLogger(YPProxy.class); // reuse proxy's logger
039:
040: private Object initialContext;
041: private Element element;
042: private boolean queryP;
043: private boolean ready = false;
044: private Object result = null;
045: private Callback callback = null;
046: private Object finalContext = null;
047: private Class resultClass;
048: private boolean isSubmitted = false;
049: private boolean blackboardp = false;
050: private int searchMode;
051:
052: YPFutureImpl(Object context, Element e, boolean qp,
053: Class resultClass, int searchMode) {
054: this .initialContext = context;
055: this .element = e;
056: this .queryP = qp;
057: this .resultClass = resultClass;
058: this .searchMode = searchMode;
059: }
060:
061: public Element getElement() {
062: return element;
063: }
064:
065: public boolean isInquiry() {
066: return queryP;
067: }
068:
069: public Object getInitialContext() {
070: return initialContext;
071: }
072:
073: public int getSearchMode() {
074: return searchMode;
075: }
076:
077: public synchronized boolean isReady() {
078: return ready;
079: }
080:
081: public Object get() throws UDDIException {
082: return get(0L);
083: }
084:
085: public synchronized Object get(final long msecs)
086: throws UDDIException {
087: if (!ready) {
088: SchedulableStatus.withWait("YP Lookup", new Runnable() {
089: public void run() {
090: try {
091: (YPFutureImpl.this ).wait(msecs); // don't wait on the runnable!
092: } catch (InterruptedException ie) {
093: logger
094: .warn(
095: "Saw InterruptedException while waiting for YPReponse",
096: ie);
097: }
098: }
099: });
100: }
101: if (ready) {
102: if (result instanceof Throwable) {
103: if (result instanceof RuntimeException) {
104: // Leave original exception so that clients can catch explicitly.
105: throw (RuntimeException) result;
106: } else {
107: throw new RuntimeException("YPFuture exception",
108: (Throwable) result);
109: }
110: } else {
111: return convert(result); // convert to UDDI response object
112: }
113: } else {
114: return null;
115: }
116: }
117:
118: private static class ResponseCallbackAdapter implements Callback {
119: private final ResponseCallback rc;
120:
121: ResponseCallbackAdapter(ResponseCallback c) {
122: this .rc = c;
123: }
124:
125: public final void ready(YPFuture response) {
126: try {
127: Object r = response.get();
128: try {
129: if (logger.isDebugEnabled()) {
130: logger
131: .debug("ResponseCallbackAdapter.read() calling "
132: + rc);
133: }
134: rc.invoke(r);
135: } catch (RuntimeException ix) {
136: logger
137: .error(
138: "Invocation of YPFuture ResponseCallback resulted in Exception",
139: ix);
140: }
141: } catch (Exception e) {
142: rc.handle(e);
143: }
144: }
145: }
146:
147: public synchronized void setCallback(YPComplete notifier) {
148: Callback c;
149: if (notifier instanceof ResponseCallback) {
150: c = new ResponseCallbackAdapter((ResponseCallback) notifier);
151: } else if (notifier instanceof Callback) {
152: c = (Callback) notifier;
153: } else {
154: throw new IllegalArgumentException(
155: "Only Callback and ResponseCallback instances are allowed");
156: }
157:
158: if (callback != null)
159: throw new IllegalArgumentException("Already had a callback");
160: callback = c;
161: if (ready) {
162: callback.ready(this );
163: }
164: }
165:
166: public Object getFinalContext() {
167: return finalContext;
168: }
169:
170: // package-private setters
171: void set(Object value) {
172: synchronized (this ) {
173: if (ready)
174: throw new RuntimeException("Cannot reset a YPFuture");
175: result = value;
176: ready = true;
177: this .notifyAll();
178: }
179:
180: if (callback != null) {
181: callback.ready(this );
182: }
183: }
184:
185: void setException(Throwable t) {
186: set(t);
187: }
188:
189: void setFinalContext(Object fc) {
190: if (logger.isDebugEnabled()) {
191: logger.debug("setFinalContext(): fc " + fc + " callback "
192: + callback);
193: }
194: finalContext = fc;
195: }
196:
197: synchronized void submitted() {
198: if (isSubmitted) {
199: throw new IllegalArgumentException(
200: "YPFuture was previously submitted");
201: }
202: isSubmitted = true;
203: }
204:
205: synchronized void setIsFromBlackboard(boolean v) {
206: blackboardp = v;
207: }
208:
209: synchronized boolean isFromBlackboard() {
210: return blackboardp;
211: }
212:
213: private static final Class[] cargs = new Class[] { Element.class };
214:
215: /** Convert from an XML Element to a UDDI response object **/
216: private Object convert(Object el) throws UDDIException {
217: if (el == null) {
218: return null;
219: } else {
220: if (el instanceof Element) {
221: Element ell = (Element) el;
222: if (logger.isDebugEnabled()) {
223: logger.debug("convert: " + ell);
224: }
225: if (UDDIException.isValidElement(ell)) {
226: if (logger.isDebugEnabled()) {
227: RuntimeException re = new RuntimeException();
228: logger.debug("Throwing UDDI exception " + ell,
229: re);
230: }
231: throw new UDDIException(ell, true);
232: }
233: }
234:
235: if (resultClass == null) { // no class conversion
236: return el;
237: } else { // otherwise, construct from the element
238: try {
239: java.lang.reflect.Constructor c = resultClass
240: .getConstructor(cargs);
241: return c.newInstance(new Object[] { el });
242: } catch (Exception e) {
243: throw new RuntimeException(
244: "Could not convert response Element to "
245: + resultClass, e);
246: }
247: }
248: }
249: }
250:
251: // implement Persistable
252: public boolean isPersistable() {
253: return false;
254: }
255: }
|