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.tools.csmart.ui.servlet;
028:
029: import org.cougaar.core.servlet.ServletUtil;
030: import org.cougaar.core.servlet.SimpleServletSupport;
031: import org.cougaar.core.util.UID;
032: import org.cougaar.planning.ldm.asset.Asset;
033: import org.cougaar.planning.ldm.plan.Expansion;
034: import org.cougaar.planning.ldm.plan.HasRelationships;
035: import org.cougaar.planning.ldm.plan.PlanElement;
036: import org.cougaar.planning.ldm.plan.Task;
037: import org.cougaar.planning.ldm.plan.Workflow;
038: import org.cougaar.tools.csmart.ui.monitor.PropertyNames;
039: import org.cougaar.util.UnaryPredicate;
040: import org.cougaar.util.log.Logger;
041:
042: import javax.servlet.ServletException;
043: import javax.servlet.ServletInputStream;
044: import javax.servlet.ServletOutputStream;
045: import javax.servlet.http.HttpServlet;
046: import javax.servlet.http.HttpServletRequest;
047: import javax.servlet.http.HttpServletResponse;
048: import java.io.IOException;
049: import java.io.ObjectOutputStream;
050: import java.util.ArrayList;
051: import java.util.Collection;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.StringTokenizer;
055:
056: /**
057: * <p>
058: * This Servlet traverses Tasks and related objects (plan elements, assets,
059: * workflows) and returns information on them.
060: * The information is encoded in name/value pairs stored in PropertyTree. <br>
061: *
062: * <p>
063: * Can be loaded manually by including this line in an agent's .ini configuration file: <pre/>
064: * plugin = org.cougaar.core.servlet.SimpleServletComponent(org.cougaar.tools.csmart.ui.servlet.PlanServlet,
065: * /CSMART_PlanServlet)
066: * </pre>
067: *
068: * <p>
069: * Is loaded from a URL on a CSMART machine, on agent 'Agent':
070: * http://localhost:port/$Agent/CSMART_PlanServlet objects which are serialized to the client.
071: */
072: public class PlanServlet extends HttpServlet {
073: /*
074: * Cougaar hook
075: */
076: private SimpleServletSupport support;
077:
078: public void setSimpleServletSupport(SimpleServletSupport support) {
079: this .support = support;
080: if (!("/CSMART_PlanServlet".equals(support.getPath()))) {
081: support.getLog().error(
082: "Incorrect servlet path: " + support.getPath());
083: }
084: }
085:
086: public void doGet(HttpServletRequest request,
087: HttpServletResponse response) throws IOException,
088: ServletException {
089: // create a new "PlanProvider" context per request
090: PlanProvider pi = new PlanProvider(support);
091: pi.execute(request, response);
092: }
093:
094: public void doPut(HttpServletRequest request,
095: HttpServletResponse response) throws IOException,
096: ServletException {
097:
098: // create a new "PlanProvider" context per request
099: PlanProvider pi = new PlanProvider(support);
100: pi.execute(request, response);
101: }
102:
103: /**
104: * Captures the URL parameters.
105: *
106: * If input from the client contains the name/value pair:
107: * planObjectsToIgnore?value
108: * then extract the value, which is a comma separated list
109: * of types of objects to ignore (defined in PropertyNames).
110: * Use these object types, to set appropriate flags used
111: * in the getter methods.
112: *
113: * If the URL includes "?limit=NUMBER", then a limit is set
114: * for the number of objects to return. If the limit is
115: * negative then no limit is set, which is the default. If
116: * the limit is exceeded then (limit+1) objects are returned.
117: * For example, if "?limit=50" and there are 100 matching
118: * objects, then 51 PropertyTrees are returned.
119: */
120: private static class PlanProvider implements
121: ServletUtil.ParamVisitor {
122:
123: /* flags set by the client to control what objects are returned */
124: boolean ignorePlanElements = false;
125: boolean ignoreWorkflows = false;
126: boolean ignoreAssets = false;
127:
128: /* stream variables */
129: ServletInputStream in;
130: ServletOutputStream out;
131:
132: /* limit on number of PropertyTrees to return; see javadocs above */
133: int limit = Integer.MAX_VALUE;
134:
135: /* since "PlanProvider" is a static inner class, here
136: * we hold onto the support API.
137: *
138: * this makes it clear that PlanProvider only uses
139: * the "support" from the outer class.
140: */
141: SimpleServletSupport support;
142: private Logger log;
143:
144: public PlanProvider(SimpleServletSupport support) {
145: this .support = support;
146: this .log = support.getLog();
147: }
148:
149: /**
150: * Our predicate for finding Blackboard objects.
151: */
152: private static UnaryPredicate getPred() {
153: return new UnaryPredicate() {
154: public boolean execute(Object o) {
155: return (o instanceof Task
156: || o instanceof PlanElement || o instanceof Asset);
157: }
158: };
159: }
160:
161: /**
162: * This is the main Servlet method called by the infrastructure in response
163: * to receiving a request from a client.
164: * Get all the plan objects, ignoring those the client specifies,
165: * and return their properties to the client in a serialized PropertyTree.
166: */
167: public void execute(HttpServletRequest request,
168: HttpServletResponse response) throws IOException {
169: this .out = response.getOutputStream();
170:
171: try {
172: ServletUtil.parseParams(this , request);
173:
174: List ret = getObjects();
175: if (ret != null) {
176: ObjectOutputStream p = new ObjectOutputStream(out);
177: p.writeObject(ret);
178:
179: if (log.isDebugEnabled()) {
180: log.debug("Sent Objects");
181: }
182: }
183: } catch (Exception e) {
184: if (log.isErrorEnabled()) {
185: log.error("PlanServlet Exception: ", e);
186: }
187: }
188: }
189:
190: /**
191: * Returns a vector of PropertyTree for either a Task and
192: * all its related objects (planelements, workflows, assets)
193: * @return List
194: */
195: private List getObjects() {
196:
197: // create predicate
198: UnaryPredicate pred = getPred();
199:
200: // query
201: Collection col = support.queryBlackboard(pred);
202:
203: int colSize = col.size();
204:
205: // check limit
206: int maxRetSize;
207: if (limit < colSize) {
208: maxRetSize = limit + 1;
209: } else {
210: maxRetSize = colSize;
211: }
212:
213: // build result list
214: //
215: // assume maximum List size, since most objects are kept
216: List ret = new ArrayList(maxRetSize);
217: int retSize = 0;
218:
219: // keep agent name for later use
220: String agent = support.getAgentIdentifier().getAddress();
221:
222: // scan query results
223: Iterator iter = col.iterator();
224: for (int i = 0; i < colSize; i++) {
225: Object planObject = iter.next();
226:
227: // scan object
228: if (planObject instanceof Asset) {
229: if (ignoreAssets)
230: continue;
231: Asset asset = (Asset) planObject;
232: if ((asset.hasClusterPG())
233: && (asset instanceof HasRelationships)
234: && (!((HasRelationships) asset).isLocal())) {
235: // ignore non-local agent assets
236: //
237: // add below back in once Communities are added?
238: // (asset.hasCommunityPG())
239: continue;
240: }
241: } else if ((ignorePlanElements)
242: && (planObject instanceof PlanElement)) {
243: continue; // optionally ignore plan elements
244: } else if ((!(ignoreWorkflows))
245: && (planObject instanceof Expansion)) {
246: // optionally include workflows
247: Workflow workflow = ((Expansion) planObject)
248: .getWorkflow();
249: Object wObj = TranslateUtils.toPropertyTree(
250: workflow, agent);
251: // TranslateUtils will return null for some objects
252: if (wObj != null) {
253: ret.add(wObj);
254:
255: if (++retSize >= maxRetSize) {
256: // reached our limit
257: break;
258: }
259: }
260: }
261:
262: // translate to a property-tree
263: Object tmp = TranslateUtils.toPropertyTree(planObject,
264: agent);
265: if (tmp != null) {
266: ret.add(tmp);
267:
268: if (++retSize >= maxRetSize) {
269: // reached our limit
270: break;
271: }
272: }
273: }
274:
275: return ret;
276: }
277:
278: /**
279: * Sets "objects to ignore" variables from
280: * string in URL predicated with ?ignorePlanObjects
281: * @param name name of parameter
282: * @param value value of parameter
283: */
284: public void setParam(String name, String value) {
285: if (name.equals(PropertyNames.PLAN_OBJECTS_TO_IGNORE)) {
286: try {
287: StringTokenizer st = new StringTokenizer(value, ",");
288: while (st.hasMoreTokens()) {
289: String s = st.nextToken();
290: if (s.equals(PropertyNames.PLAN_ELEMENT_OBJECT)) {
291: ignorePlanElements = true;
292: } else if (s
293: .equals(PropertyNames.WORKFLOW_OBJECT)) {
294: ignoreWorkflows = true;
295: } else if (s.equals(PropertyNames.ASSET_OBJECT)) {
296: ignoreAssets = true;
297: }
298: }
299: } catch (Exception e) {
300: if (log.isErrorEnabled()) {
301: log.error("Illegal parameter: " + name + "="
302: + value, e);
303: }
304: }
305: } else if (name.equals("limit")) {
306: try {
307: limit = Integer.parseInt(value);
308: if (limit < 0) {
309: limit = Integer.MAX_VALUE;
310: }
311: } catch (Exception e) {
312: if (log.isErrorEnabled()) {
313: log.error("Illegal parameter: " + name + "="
314: + value, e);
315: }
316: }
317: }
318: }
319: }
320: }
|