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.util;
028:
029: import org.cougaar.tools.csmart.ui.viewer.CSMART;
030: import org.cougaar.util.log.Logger;
031:
032: import java.io.BufferedReader;
033: import java.io.IOException;
034: import java.io.InputStream;
035: import java.io.InputStreamReader;
036: import java.io.ObjectInputStream;
037: import java.io.ObjectOutputStream;
038: import java.io.OutputStream;
039: import java.io.UnsupportedEncodingException;
040: import java.net.HttpURLConnection;
041: import java.net.SocketException;
042: import java.net.URL;
043: import java.net.URLConnection;
044: import java.net.URLEncoder;
045: import java.util.ArrayList;
046: import java.util.Collection;
047: import java.util.List;
048: import java.util.Vector;
049:
050: /**
051: * Utilities for contacting servlets in societies.
052: */
053: public class ClientServletUtil {
054: // names of servlets used by CSMART
055: public static final String COMMUNITY_SERVLET = "CSMART_CommunityProviderServlet";
056: public static final String AGENT_INFO_SERVLET = "CSMART_AgentInfoServlet";
057: public static final String AGENT_PROVIDER_SERVLET = "agents?scope=all&format=text";
058: public static final String PLAN_SERVLET = "CSMART_PlanServlet";
059: public static final String SEARCH_SERVLET = "CSMART_SearchServlet";
060: public static final String METRICS_SERVLET = "CSMART_MetricsServlet";
061: private static final String HTTP_PROTOCOL = "http";
062: private static final String HTTPS_PROTOCOL = "https";
063:
064: /**
065: * Get data which is a list of text strings from the specified url.
066: * @param string a URL string
067: * @return Vector list of strings returned
068: */
069:
070: // public static Vector getDataFromURL(String URLString) throws Exception {
071: // URL url = new URL(URLString);
072: // URLConnection connection = url.openConnection();
073: // connection.setDoInput(true);
074: // connection.setDoOutput(true);
075: // InputStream is = connection.getInputStream();
076: // BufferedReader r =
077: // new BufferedReader(new InputStreamReader(is));
078: // Vector data = new Vector();
079: // String s = r.readLine();
080: // while (s != null) {
081: // data.add(s);
082: // s = r.readLine();
083: // }
084: // return data;
085: // }
086: /**
087: * Contact the agent provider servlet at the specified URL,
088: * which returns the URLs of all the agents in the society.
089: * This may return null or a vector with zero elements;
090: * in these cases, appropriate error messages are displayed for the user.
091: * @param URLString the URL of the agent to contact
092: * @return vector of String; URLs of agents in society
093: */
094: public static Vector getAgentURLs(String URLString)
095: throws Exception {
096: String urlSpec = URLString + "/"
097: + ClientServletUtil.AGENT_PROVIDER_SERVLET;
098: URL url = new URL(urlSpec);
099:
100: // FIXME!! This must do the HTTPS version as necessary, possibly getting user
101: // credentials
102: URLConnection connection = url.openConnection();
103: connection.setDoInput(true);
104: connection.setDoOutput(true);
105: InputStream is = connection.getInputStream();
106: BufferedReader r = new BufferedReader(new InputStreamReader(is));
107: Vector urls = new Vector();
108: String s = r.readLine();
109: while (s != null) {
110: if (s.indexOf('.') == 0) {
111: // This is an agent name that starts with a '.' -- no good!
112: // IE, the .comm entry in the WP
113: System.err.println("Skipping agent named " + s);
114: } else
115: urls.add(URLString + "/$" + s + "/");
116: s = r.readLine();
117: }
118: return urls;
119: }
120:
121: /**
122: * Get a collection from specified agents and servlet.
123: * The servlet must be one that returns a Collection.
124: * to determine what objects to include in the collection.
125: * Returns null if the agent or servlet cannot be contacted.
126: * @param agentURLs the agents to contact; vector of String
127: * @param servletId the servlet to contact
128: * @param limit the limit for the number of objects to return, or -1 if
129: * there is no limit -- the servlet must
130: accept a limit=N argument
131: * @return results from servlets
132: */
133: public static ServletResult getCollectionFromAgents(
134: Vector agentURLs, String servletId,
135: ArrayList parameterNames, ArrayList parameterValues,
136: int limit) {
137: if (agentURLs == null || agentURLs.size() == 0)
138: return null;
139:
140: boolean hasLimit = (limit >= 0);
141: // limit that is decremented for each call
142: int remainingLimit = (hasLimit ? limit : -1);
143: int nAgentURLs = agentURLs.size();
144:
145: ServletResult result = new ServletResult();
146:
147: for (int i = 0; i < nAgentURLs; i++) {
148: String url = (String) agentURLs.elementAt(i);
149: ServletResponse response = getCollectionFromAgent(url,
150: servletId, parameterNames, parameterValues, null,
151: remainingLimit);
152: result.addServletResponse(response);
153: // check limit, and set flag in result if its exceeded
154: if (hasLimit) {
155: remainingLimit = remainingLimit
156: - response.getCollection().size();
157: if (remainingLimit < 0) {
158: result.setLimitExceeded(true);
159: break;
160: }
161: }
162: }
163: return result;
164: }
165:
166: /**
167: * Get a collection from a single agent and servlet.
168: * Same as getCollectionFromAgents for a single agent.
169: * @param agentURL the agent to contact
170: * @param servletId the servlet to contact
171: * @param data data to be sent to the servlet if non-null
172: * @param limit max. number of objects to return, or -1 if no limit
173: * @return the collection from the servlet or null
174: */
175: public static ServletResponse getCollectionFromAgent(
176: String agentURL, String servletId,
177: ArrayList parameterNames, ArrayList parameterValues,
178: List data, int limit) {
179: Logger log = CSMART.createLogger("org.cougaar.tools.csmart.ui");
180: URLSpec.setBase(agentURL + servletId);
181: if (parameterNames != null)
182: URLSpec.addArgs(parameterNames, parameterValues);
183: if (limit >= 0)
184: URLSpec.addArg("limit", limit);
185: String urlSpec = URLSpec.getResult();
186: String errorMessage = null;
187: Collection results = null;
188:
189: // FIXME! This must do the https thing as necessary, possibly getting user credentials!
190: HttpURLConnection connection = null;
191: try {
192: URL url = new URL(urlSpec);
193: connection = (HttpURLConnection) url.openConnection();
194:
195: // force URL connection to use the PUT method for data
196: if (data != null) {
197: connection.setRequestMethod("PUT");
198: }
199:
200: connection.setDoInput(true);
201: connection.setDoOutput(true);
202:
203: try {
204: connection.connect();
205: } catch (IOException ioe) {
206: if (log.isErrorEnabled()) {
207: log.error("Got IOE talking to " + urlSpec, ioe);
208: }
209: return new ServletResponse(urlSpec, null,
210: "Error contacting servlet.");
211: }
212:
213: // If we have any data to send to the client, do it now.
214: if (data != null) {
215: OutputStream os = connection.getOutputStream();
216: ObjectOutputStream oos = new ObjectOutputStream(os);
217: oos.writeObject(data);
218: oos.close();
219: }
220:
221: // get the response from the client
222: try {
223: int resp = ((HttpURLConnection) connection)
224: .getResponseCode();
225: if (resp != HttpURLConnection.HTTP_OK) {
226: String cougaarError = ((HttpURLConnection) connection)
227: .getHeaderField("Cougaar-error");
228: if (cougaarError == null)
229: errorMessage = "Error "
230: + resp
231: + ": "
232: + ((HttpURLConnection) connection)
233: .getResponseMessage() + ").";
234: else if (cougaarError.equals("agent"))
235: errorMessage = "No such agent.";
236: else if (cougaarError.equals("path"))
237: errorMessage = "No such servlet.";
238: else
239: errorMessage = "Unknown error (" + cougaarError
240: + ").";
241: if (log.isWarnEnabled()) {
242: log.warn("Got "
243: + resp
244: + " - "
245: + ((HttpURLConnection) connection)
246: .getResponseMessage()
247: + " - trying to reach: " + urlSpec);
248: }
249: return new ServletResponse(urlSpec, null,
250: errorMessage);
251: } else {
252: if (log.isInfoEnabled()) {
253: log.info("Got OK connection: " + resp
254: + " talking to " + urlSpec);
255: }
256: }
257: } catch (SocketException e) {
258: if (log.isErrorEnabled()) {
259: log.error("Exception contacting: " + urlSpec
260: + ". Got SocketException ", e);
261: }
262: return new ServletResponse(urlSpec, null,
263: "Error getting servlet response.");
264: }
265:
266: InputStream is = connection.getInputStream();
267: if (is != null) {
268: ObjectInputStream p = new ObjectInputStream(is);
269: results = (Collection) p.readObject();
270: is.close();
271: } else {
272: if (log.isInfoEnabled()) {
273: log.info("Got null input stream talking to "
274: + urlSpec);
275: }
276: return new ServletResponse(urlSpec, null,
277: "Error reading servlet response.");
278: }
279: } catch (Exception e) {
280: if (log.isErrorEnabled())
281: log.error("Exception contacting: " + urlSpec, e);
282: } finally {
283: // close the connection
284: connection.disconnect();
285: }
286: return new ServletResponse(urlSpec, results, errorMessage);
287: }
288:
289: // This is used in CSMARTUL:304,542 and ThreadUtils:317
290: /**
291: * Return a URL string of the form:
292: * http://host:port/
293: * @param host the host in the URL
294: * @param port the port in the URL
295: * @return the URL string
296: */
297: public static String makeURL(String host, int port) {
298: return HTTP_PROTOCOL + "://" + host + ":"
299: + String.valueOf(port);
300: }
301:
302: /**
303: * Make a URL that uses HTTPS
304: **/
305: public static String makeSecureURL(String host, int port) {
306: return HTTPS_PROTOCOL + "://" + host + ":"
307: + String.valueOf(port);
308: }
309:
310: /**
311: * This class handles building a URL.
312: * The first parameter is preceeded by a question mark
313: * and all other parameters are preceeded by an ampersand.
314: */
315:
316: static class URLSpec {
317: static StringBuffer buf;
318: static char parameterPrefix;
319:
320: public static void setBase(String base) {
321: buf = new StringBuffer(100);
322: buf.append(base);
323: if (base.indexOf('?') == -1)
324: parameterPrefix = '?';
325: else
326: parameterPrefix = '&';
327: }
328:
329: public static void addArgs(ArrayList names, ArrayList values) {
330: for (int i = 0; i < names.size(); i++)
331: URLSpec.addArg((String) names.get(i), values.get(i));
332: }
333:
334: public static void addArg(String argName, Object argValue) {
335: Logger log = CSMART
336: .createLogger("org.cougaar.tools.csmart.ui");
337: buf.append(parameterPrefix);
338: buf.append(argName);
339: buf.append('=');
340: try {
341: buf.append(URLEncoder.encode(argValue.toString(),
342: "UTF-8"));
343: } catch (UnsupportedEncodingException e) {
344: if (log.isErrorEnabled())
345: log.error("Exception Encoding ", e);
346: }
347:
348: parameterPrefix = '&';
349: }
350:
351: public static void addArg(String argName, int argValue) {
352: URLSpec.addArg(argName, String.valueOf(argValue));
353: }
354:
355: public static String getResult() {
356: return buf.toString();
357: }
358: }
359:
360: }
|