001: /*
002: * <copyright>
003: *
004: * Copyright 2000-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.servlet;
028:
029: import java.lang.reflect.Method;
030: import java.util.List;
031:
032: import javax.servlet.Servlet;
033:
034: import org.cougaar.core.component.BindingUtility;
035: import org.cougaar.core.component.Component;
036: import org.cougaar.core.mts.MessageAddress;
037: import org.cougaar.core.service.AgentIdentificationService;
038: import org.cougaar.core.service.BlackboardQueryService;
039: import org.cougaar.core.service.LoggingService;
040: import org.cougaar.util.GenericStateModel;
041:
042: /**
043: * Component that loads a <code>Servlet</code> and provides
044: * the <code>SimpleServletSupport</code>.
045: * <p>
046: * Usage in an ".ini" file is:<pre>
047: * ...
048: * plugin = <this-class>(<servlet-class>, <path>)
049: * ...</pre><br>
050: * where<pre>
051: * <this-class>
052: * is "org.cougaar.core.servlet.SimpleServletComponent"
053: * <servlet-class>
054: * is the class name of a Servlet.
055: * The servlet must have a zero-argument constructor.
056: * If the Servlet has a
057: * public void setSimpleServletSupport(SimpleServletSupport support)
058: * method then a SimpleServletSupport is passed, which provides
059: * <i>limited</i> access to Cougaar internals.
060: * <path>
061: * is the path for the Servlet, such as "/test".
062: * </pre><br>
063: * <p>
064: *
065: * Most of this code is "reflection-glue" to:<ul>
066: * <li>capture the (classname, path) parameters</li>
067: * <li>construct the class instance</li>
068: * <li>examine the class's method(s)</li>
069: * <li>setup and create a <code>SimpleServletSupportImpl</code>
070: * instance</li>
071: * </ul>
072: * Most subclass developers have the classname and path hard-coded,
073: * so they should consider not extending SimpleServletComponent and
074: * instead use <code>BaseServletComponent</code>. The additional
075: * benefit is that subclasses of BaseServletComponent have full
076: * access to the ServiceBroker.
077: *
078: * @see SimpleServletSupport
079: */
080: public class SimpleServletComponent extends BaseServletComponent {
081:
082: /**
083: * Servlet classname from "setParameter(..)".
084: */
085: protected String classname;
086:
087: /**
088: * Servlet path from "setParameter(..)".
089: */
090: protected String path;
091:
092: /**
093: * Agent identifier for the Agent that loaded this Component.
094: */
095: protected MessageAddress agentId;
096:
097: // servlet that we'll load
098: protected Servlet servlet;
099:
100: // backwards compatibility!
101: protected Component comp;
102:
103: //
104: // Services for our SimpleServletSupport use
105: //
106: protected BlackboardQueryService blackboardQuery;
107: protected LoggingService log;
108:
109: public final void setAgentIdentificationService(
110: AgentIdentificationService ais) {
111: if ((ais != null)) {
112: this .agentId = ais.getMessageAddress();
113: }
114: }
115:
116: /**
117: * Save our Servlet's configurable path, for example
118: * "/test".
119: * <p>
120: * This is only set during initialization and is constant
121: * for the lifetime of the Servlet.
122: */
123: public void setParameter(Object o) {
124: // expecting a List of [String, String]
125: if (!(o instanceof List)) {
126: throw new IllegalArgumentException(
127: "Expecting a List parameter, not : "
128: + ((o != null) ? o.getClass().getName()
129: : "null"));
130: }
131: List l = (List) o;
132: if (l.size() < 2) {
133: throw new IllegalArgumentException(
134: "Expecting a List with at least two elements,"
135: + " \"classname\" and \"path\", not "
136: + l.size());
137: }
138: Object o1 = l.get(0);
139: Object o2 = l.get(1);
140: if ((!(o1 instanceof String)) || (!(o2 instanceof String))) {
141: throw new IllegalArgumentException(
142: "Expecting two Strings, not (" + o1 + ", " + o2
143: + ")");
144: }
145:
146: // save the servlet classname and path
147: this .classname = (String) o1;
148: this .path = (String) o2;
149: }
150:
151: protected String getPath() {
152: return path;
153: }
154:
155: protected Servlet createServlet() {
156: // load the servlet class
157: Class cl;
158: try {
159: cl = Class.forName(classname);
160: } catch (Exception e) {
161: throw new RuntimeException("Unable to load Servlet class: "
162: + classname);
163: }
164: if (Servlet.class.isAssignableFrom(cl)) {
165: // good
166: } else if (Component.class.isAssignableFrom(cl)) {
167: // deprecated!
168: } else {
169: throw new IllegalArgumentException("Class \"" + classname
170: + "\" does not implement \""
171: + Servlet.class.getName() + "\"");
172: }
173:
174: // create a zero-arg instance
175: Object inst;
176: try {
177: inst = cl.newInstance();
178: } catch (Exception e) {
179: // throw the general "no-constructor" exception
180: throw new RuntimeException(
181: "Unable to create Servlet instance: ", e);
182: }
183:
184: if (inst instanceof Component) {
185: this .comp = (Component) inst;
186: try {
187: Method m = cl.getMethod("setParameter",
188: new Class[] { Object.class });
189: m.invoke(comp, new Object[] { path });
190: } catch (NoSuchMethodException nsme) {
191: // ignore, support a couple broken clients
192: // (cant log cause log service comes later)
193: } catch (Exception e) {
194: throw new RuntimeException("Unable to setParameter("
195: + path + ")", e);
196: }
197: BindingUtility.activate(inst, bindingSite, serviceBroker);
198: return null;
199: }
200:
201: this .servlet = (Servlet) inst;
202:
203: // check for the support requirement
204: Method supportMethod;
205: try {
206: supportMethod = cl.getMethod("setSimpleServletSupport",
207: new Class[] { SimpleServletSupport.class });
208: } catch (NoSuchMethodException e) {
209: // simple non-cougaar-aware servlet
210: return servlet;
211: }
212:
213: // create the support
214: SimpleServletSupport support;
215: try {
216: support = createSimpleServletSupport(servlet);
217: } catch (Exception e) {
218: throw new RuntimeException(
219: "Unable to create Servlet support", e);
220: }
221:
222: // set the support
223: try {
224: supportMethod.invoke(servlet, new Object[] { support });
225: } catch (Exception e) {
226: throw new RuntimeException("Unable to set Servlet support",
227: e);
228: }
229:
230: return servlet;
231: }
232:
233: /**
234: * Obtain services for the servlet, using the servlet as
235: * the requestor.
236: */
237: protected SimpleServletSupport createSimpleServletSupport(
238: Servlet servlet) {
239: // the agentId is known from "setAgentIdentificationService(..)"
240:
241: // get the blackboard query service
242: blackboardQuery = (BlackboardQueryService) serviceBroker
243: .getService(servlet, BlackboardQueryService.class, null);
244: if (blackboardQuery == null) {
245: throw new RuntimeException(
246: "Unable to obtain blackboard query service");
247: }
248:
249: // get the logging service (for "getLogger")
250: log = (LoggingService) serviceBroker.getService(servlet,
251: LoggingService.class, null);
252: if (log == null) {
253: // continue loading -- let the "support" use a null-logger.
254: }
255:
256: // create a new "SimpleServletSupport" instance
257: return new SimpleServletSupportImpl(path, agentId,
258: blackboardQuery, log);
259: }
260:
261: public void unload() {
262: // release all services
263: super .unload();
264:
265: if (servlet != null) {
266: if (log != null) {
267: serviceBroker.releaseService(servlet,
268: LoggingService.class, log);
269: log = null;
270: }
271: if (blackboardQuery != null) {
272: serviceBroker.releaseService(servlet,
273: BlackboardQueryService.class, blackboardQuery);
274: blackboardQuery = null;
275: }
276: servlet = null;
277: }
278: if (comp != null) {
279: switch (comp.getModelState()) {
280: case GenericStateModel.ACTIVE:
281: comp.suspend();
282: // fall-through
283: case GenericStateModel.IDLE:
284: comp.stop();
285: // fall-through
286: case GenericStateModel.LOADED:
287: comp.unload();
288: // fall-through
289: case GenericStateModel.UNLOADED:
290: // unloaded
291: break;
292: default:
293: // never?
294: }
295: comp = null;
296: }
297: }
298:
299: public String toString() {
300: return classname + "(" + path + ")";
301: }
302: }
|