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.tools.csmart.ui.servlet;
028:
029: import org.cougaar.core.servlet.SimpleServletSupport;
030: import org.cougaar.core.util.UID;
031: import org.cougaar.planning.ldm.asset.Asset;
032: import org.cougaar.planning.ldm.asset.CommunityPG;
033: import org.cougaar.planning.ldm.asset.LocationSchedulePG;
034: import org.cougaar.planning.ldm.plan.*;
035: import org.cougaar.tools.csmart.ui.monitor.PropertyNames;
036: import org.cougaar.util.PropertyTree;
037: import org.cougaar.util.UnaryPredicate;
038:
039: import javax.servlet.ServletException;
040: import javax.servlet.ServletOutputStream;
041: import javax.servlet.http.HttpServlet;
042: import javax.servlet.http.HttpServletRequest;
043: import javax.servlet.http.HttpServletResponse;
044: import java.io.IOException;
045: import java.io.ObjectOutputStream;
046: import java.util.ArrayList;
047: import java.util.Collection;
048: import java.util.Enumeration;
049: import java.util.Iterator;
050: import java.util.Vector;
051:
052: /**
053: * This Servlet gathers information about agents and their relationships.
054: * The information is encoded in name/value pairs stored in <code>PropertyTree</code>
055: * objects which are serialized to the client. <br>
056: *
057: * <p>
058: * Can be loaded manually by including this line in an agent's .ini configuration file: <pre/>
059: * plugin = org.cougaar.core.servlet.SimpleServletComponent(org.cougaar.tools.csmart.ui.servlet.AgentInfoServlet,
060: * /CSMART_AgentInfoServlet) </pre>
061: *
062: * <p>
063: * Is loaded from a URL on a CSMART machine, on agent 'Agent': <br>
064: * http://localhost:port/$Agent/CSMART_AgentInfoServlet
065: */
066: public class AgentInfoServlet extends HttpServlet {
067: /** Role for Self **/
068: public static final Role SELF_ROLE = Role.getRole("Self");
069:
070: private SimpleServletSupport support;
071:
072: /**
073: * @param support <code>SimpleServletSupport</code> object
074: */
075: public void setSimpleServletSupport(SimpleServletSupport support) {
076: this .support = support;
077: if (!("/CSMART_AgentInfoServlet".equals(support.getPath()))) {
078: support.getLog().error(
079: "Incorrect servlet path: " + support.getPath());
080: }
081: }
082:
083: /**
084: * Processes an HTTP get command.
085: *
086: *
087: * @param request Request Object
088: * @param response Response Object
089: * @exception IOException if an error occurs
090: * @exception ServletException if an error occurs
091: */
092: public void doGet(HttpServletRequest request,
093: HttpServletResponse response) throws IOException,
094: ServletException {
095: // create a new "AgentInfo" context per request
096: AgentInfo ai = new AgentInfo(support);
097: ai.execute(request, response);
098: }
099:
100: /**
101: * Processes an HTTP put command.
102: *
103: * @param request Request Object
104: * @param response Response Object
105: * @exception IOException if an error occurs
106: * @exception ServletException if an error occurs
107: */
108: public void doPut(HttpServletRequest request,
109: HttpServletResponse response) throws IOException,
110: ServletException {
111: // create a new "AgentInfo" context per request
112: AgentInfo ai = new AgentInfo(support);
113: ai.execute(request, response);
114: }
115:
116: /**
117: * This inner class does all the work.
118: * <p>
119: * A new class is created per request, to keep all the
120: * instance fields separate. If there was only one
121: * instance then multiple simultaneous requests would
122: * corrupt the instance fields (e.g. the "out" stream).
123: * <p>
124: * This acts as a <b>context</b> per request.
125: */
126: private static class AgentInfo {
127:
128: /*
129: * parameters from the URL:
130: */
131: ServletOutputStream out;
132:
133: /* since "AgentInfo" is a static inner class, here
134: * we hold onto the support API.
135: *
136: * this makes it clear that AgentInfo only uses
137: * the "support" from the outer class.
138: */
139: private SimpleServletSupport support;
140:
141: public AgentInfo(SimpleServletSupport support) {
142: this .support = support;
143: }
144:
145: /**
146: * This is the main Servlet method called by the infrastructure in response
147: * to receiving a request from a client.
148: * Get information about this agent and its relationships
149: * and return these to the client in a serialized PropertyTree.
150: */
151: public void execute(HttpServletRequest request,
152: HttpServletResponse response) throws IOException,
153: ServletException {
154:
155: //this.out = response.getOutputStream();
156:
157: // There is no mode, as it only returns the list of agent
158: // names, so do nothing but set up for parameter parsing.
159:
160: if (request.getQueryString() == null) {
161: response.setStatus(HttpServletResponse.SC_OK);
162: }
163:
164: // check for illegal arguments
165: if (request.getQueryString() != null) {
166: response.sendError(HttpServletResponse.SC_BAD_REQUEST,
167: "<html><body><br><font size=4>"
168: + "<font size = 5><B>"
169: + request.getQueryString()
170: + "</B></font>"
171: + " Is Not A Legal Parameter List<br>"
172: + "This servlet expects no parameters"
173: + "</font></body></html>");
174: }
175:
176: this .out = response.getOutputStream();
177: try {
178: Vector collection = getSelfInformation();
179: if (collection != null) {
180: ObjectOutputStream p = new ObjectOutputStream(out);
181: p.writeObject(collection);
182: }
183: } catch (Exception e) {
184: System.out
185: .println("CSMART_AgentInfoServlet Exception: "
186: + e);
187: e.printStackTrace();
188: }
189: }
190:
191: /**
192: * Get information about this agent by getting assets that:
193: * are instances of HasRelationships and
194: * have a community property group and
195: * have a cluster property group
196: * and isLocal
197: */
198: private static UnaryPredicate getSelfPred() {
199: return new UnaryPredicate() {
200: public boolean execute(Object o) {
201: if (o instanceof Asset) {
202: Asset asset = (Asset) o;
203: if ((asset instanceof HasRelationships)
204: && ((HasRelationships) asset).isLocal()
205: && (asset.hasClusterPG()))
206: return true;
207: }
208: return false;
209: }
210: };
211: }
212:
213: /**
214: * Get information about this agent including community name,
215: * roles and relationships.
216: * Returns a vector which contains a single PropertyTree which contains the
217: * properties for this agent.
218: */
219: private Vector getSelfInformation() {
220: Collection container = support
221: .queryBlackboard(getSelfPred());
222: Iterator iter = container.iterator();
223: Vector results = new Vector(1);
224: int n = 0; // unique index for relationships
225: while (iter.hasNext()) {
226: Asset asset = (Asset) iter.next();
227: PropertyTree properties = new PropertyTree();
228: // treat this like an organization at the client end
229: properties.put(PropertyNames.OBJECT_TYPE,
230: PropertyNames.ORGANIZATION_OBJECT);
231: properties.put(PropertyNames.UID_ATTR,
232: getUIDAsString(asset.getUID()));
233: String assetKeyName = asset.getKey().toString();
234: if (assetKeyName == null)
235: return results;
236: properties.put(PropertyNames.ORGANIZATION_KEY_NAME,
237: TranslateUtils.trimAngles(assetKeyName));
238: properties.put(PropertyNames.ORGANIZATION_NAME, asset
239: .getItemIdentificationPG().getNomenclature());
240: RelationshipSchedule schedule = ((HasRelationships) asset)
241: .getRelationshipSchedule();
242: Iterator schedIter = new ArrayList(schedule).iterator();
243: PropertyTree uniqueRelationships = new PropertyTree();
244: while (schedIter.hasNext()) {
245: Relationship relationship = (Relationship) schedIter
246: .next();
247: // skip relationships with self
248: if ((relationship.getRoleA().equals(SELF_ROLE))
249: || (relationship.getRoleB()
250: .equals(SELF_ROLE)))
251: continue;
252: Object otherObject = schedule
253: .getOther(relationship);
254: // skip relationships with non-assets; does this occur???
255: if (!(otherObject instanceof Asset))
256: continue;
257: // get the name of the organization this one is related to;
258: // on the client side, this is compared to organization name
259: // so use the same getter
260: String relatedTo = ((Asset) otherObject).getKey()
261: .toString();
262: if (relatedTo == null)
263: continue;
264: // filter duplicates
265: relatedTo = TranslateUtils.trimAngles(relatedTo);
266: String rel = schedule.getOtherRole(relationship)
267: .getName();
268: String entry = (String) uniqueRelationships.get(rel
269: + relatedTo);
270: if (entry != null && entry.equals(relatedTo))
271: continue;
272: uniqueRelationships.put(rel + relatedTo, relatedTo);
273: // property is related_to_n_name
274: properties.put(
275: PropertyNames.ORGANIZATION_RELATED_TO + "_"
276: + n++ + "_" + rel, relatedTo);
277: }
278: // add location schedule
279: LocationSchedulePG locSchedPG;
280: Schedule locSched;
281: if (((locSchedPG = asset.getLocationSchedulePG()) != null)
282: && ((locSched = locSchedPG.getSchedule()) != null)
283: && (!(locSched.isEmpty()))) {
284: Enumeration locSchedEn = locSched
285: .getAllScheduleElements();
286: boolean includeStartEndTime = false;
287: int locNumber = 0;
288: while (locSchedEn.hasMoreElements()) {
289: Object oi = locSchedEn.nextElement();
290: if (!(oi instanceof LocationScheduleElement)) {
291: continue;
292: }
293: LocationScheduleElement lse = (LocationScheduleElement) oi;
294: Location loc = lse.getLocation();
295: if (!(loc instanceof LatLonPoint)) {
296: continue;
297: }
298: LatLonPoint lseLoc = (LatLonPoint) loc;
299: if ((lseLoc.getLatitude() == null)
300: || (lseLoc.getLongitude() == null)) {
301: continue;
302: }
303: properties
304: .put(
305: PropertyNames.ORGANIZATION_LOCATION_ELEMENT_START_TIME
306: + "_" + locNumber,
307: new Long(lse.getStartTime()));
308: properties
309: .put(
310: PropertyNames.ORGANIZATION_LOCATION_ELEMENT_END_TIME
311: + "_" + locNumber,
312: new Long(lse.getEndTime()));
313: properties
314: .put(
315: PropertyNames.ORGANIZATION_LOCATION_ELEMENT_LATITUDE
316: + "_" + locNumber,
317: new Double(lseLoc.getLatitude()
318: .getDegrees()));
319: properties
320: .put(
321: PropertyNames.ORGANIZATION_LOCATION_ELEMENT_LONGITUDE
322: + "_" + locNumber,
323: new Double(lseLoc
324: .getLongitude()
325: .getDegrees()));
326: properties
327: .put(
328: PropertyNames.ORGANIZATION_LOCATION_ELEMENT_VERBOSE
329: + "_" + locNumber,
330: lseLoc.toString());
331: includeStartEndTime = true;
332: locNumber++;
333: }
334: if (includeStartEndTime) {
335: properties
336: .put(
337: PropertyNames.ORGANIZATION_LOCATION_START_TIME,
338: new Long(locSched
339: .getStartTime()));
340: properties
341: .put(
342: PropertyNames.ORGANIZATION_LOCATION_END_TIME,
343: new Long(locSched.getEndTime()));
344: includeStartEndTime = false;
345: }
346: }
347: results.add(properties);
348: }
349: return results;
350: }
351:
352: private String getUIDAsString(UID uid) {
353: if (uid == null)
354: return "null";
355: return uid.getOwner() + "/" + uid.getId();
356: }
357: }
358: }
|