001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2007 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.wp.bootstrap.http;
028:
029: import java.io.IOException;
030: import java.io.PrintWriter;
031: import java.net.URI;
032: import java.util.Collection;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Map;
036: import javax.servlet.Servlet;
037: import javax.servlet.http.HttpServlet;
038: import javax.servlet.http.HttpServletRequest;
039: import javax.servlet.http.HttpServletResponse;
040: import org.cougaar.core.component.ServiceBroker;
041: import org.cougaar.core.component.ServiceRevokedListener;
042: import org.cougaar.core.mts.MessageAddress;
043: import org.cougaar.core.service.LoggingService;
044: import org.cougaar.core.service.ServletService;
045: import org.cougaar.core.service.wp.AddressEntry;
046: import org.cougaar.core.wp.bootstrap.AdvertiseBase;
047: import org.cougaar.core.wp.bootstrap.Bundle;
048: import org.cougaar.core.wp.bootstrap.ConfigService;
049: import org.cougaar.core.wp.bootstrap.Util;
050:
051: /**
052: * This component advertises bundles through HTTP by using the
053: * {@link ServletService}.
054: * <p>
055: * It looks in the {@link ConfigService} for config entries of type
056: * "-HTTP_REG" and scheme "http", or "-HTTPS_REG" and "https",
057: * e.g.<pre>
058: * X={-HTTP_REG=http://test.com:8800}
059: * </pre>
060: * and if the localhost is "test.com" and the local {@link
061: * ServletService} port is "8800" then this component registers in
062: * the {@link ServletService} as "/wp_bootstrap". The bound
063: * {@link Servlet} responds to "doGet" request with text-encoded
064: * bundles tracked by the {@link
065: * org.cougaar.core.wp.bootstrap.AdvertiseService} (i.e. locally bound
066: * leases).
067: * <p>
068: * Another possibility is to push bundles to a remote server, using
069: * a {@link java.net.URLConnection}.
070: */
071: public class HttpAdvertise extends AdvertiseBase {
072:
073: private static final String DEFAULT_PATH = "/wp_bootstrap";
074:
075: private String defaultPath = DEFAULT_PATH;
076: private ConfigService configService;
077: private ServletService servletService;
078:
079: private final ConfigService.Client configClient = new ConfigService.Client() {
080: public void add(Bundle b) {
081: addAdvertiser(getBootEntry(b));
082: }
083:
084: public void change(Bundle b) {
085: add(b);
086: }
087:
088: public void remove(Bundle b) {
089: removeAdvertiser(getBootEntry(b));
090: }
091: };
092:
093: public void setParameter(Object o) {
094: List l;
095: Object p;
096: if ((o instanceof List) && (!(l = (List) o).isEmpty())
097: && ((p = l.get(0)) instanceof String)) {
098: defaultPath = (String) p;
099: }
100: }
101:
102: public void load() {
103: super .load();
104:
105: servletService = (ServletService) sb.getService(this ,
106: ServletService.class, null);
107: if (servletService == null && log.isWarnEnabled()) {
108: log.warn("Unable to obtain ServletService");
109: }
110: configService = (ConfigService) sb.getService(configClient,
111: ConfigService.class, null);
112: if (configService == null) {
113: throw new RuntimeException("Unable to obtain ConfigService");
114: }
115: }
116:
117: public void unload() {
118: if (configService != null) {
119: sb.releaseService(configClient, ConfigService.class,
120: configService);
121: configService = null;
122: }
123: if (servletService != null) {
124: sb.releaseService(this , ServletService.class,
125: servletService);
126: servletService = null;
127: }
128:
129: super .unload();
130: }
131:
132: protected AddressEntry getBootEntry(Bundle b) {
133: AddressEntry entry = HttpUtil.getBootEntry(b);
134: if (entry == null) {
135: return null;
136: }
137: URI uri = entry.getURI();
138: String host = (uri == null ? null : uri.getHost());
139: if (!Util.isLocalHost(host)) {
140: return null;
141: }
142: int port = uri.getPort();
143: String scheme = uri.getScheme();
144: boolean isHttp = "http".equals(scheme);
145: if (servletService == null) {
146: return null;
147: }
148: int localport = (isHttp ? servletService.getHttpPort()
149: : servletService.getHttpsPort());
150: if (port != localport) {
151: return null;
152: }
153: return entry;
154: }
155:
156: protected Advertiser createAdvertiser(Object bootObj) {
157: return new HttpAdvertiser(bootObj);
158: }
159:
160: private class HttpAdvertiser extends Advertiser {
161:
162: private final AddressEntry bootEntry;
163:
164: private final String filter;
165: private final String path;
166: private Servlet servlet;
167:
168: public HttpAdvertiser(Object bootObj) {
169: super (bootObj);
170:
171: bootEntry = (AddressEntry) bootObj;
172:
173: filter = HttpUtil.getFilter(bootEntry, agentId, log);
174:
175: URI uri = bootEntry.getURI();
176: String s = uri.getPath();
177: if (s != null && s.startsWith("/$")) {
178: // remove "/$name" prefix
179: if (s.startsWith("/$" + agentName + "/")) {
180: s = s.substring(2 + agentName.length());
181: } else if (s.startsWith("/$~/")) {
182: s = s.substring(3);
183: }
184: if (s.equals("/")) {
185: s = null;
186: }
187: }
188: if (s == null || s.length() == 0) {
189: s = defaultPath;
190: }
191: path = s;
192: }
193:
194: public void start() {
195: // register servlet
196: servlet = new MyServlet();
197: try {
198: servletService.register(path, servlet);
199: } catch (Exception e) {
200: throw new RuntimeException(
201: "Unable to register servlet", e);
202: }
203:
204: // okay, listening for calls to "getBundles()"
205: }
206:
207: private Map getBundles() {
208: // serve remote caller
209: Map ret = HttpAdvertise.this .getBundles();
210: // filter for specific agent
211: ret = HttpUtil.filterBundles(ret, filter, log);
212: if (log.isDebugEnabled()) {
213: log.debug("Serving bundles: " + ret);
214: }
215: return ret;
216: }
217:
218: public void update(String name, Bundle bundle) {
219: // do nothing, since we server bundles (as opposed to posting
220: // them at external server)
221: }
222:
223: public void stop() {
224: servletService.unregister(path);
225: }
226:
227: public String toString() {
228: return "(http_advertise " + super .toString() + ")";
229: }
230:
231: private class MyServlet extends HttpServlet {
232: public void doGet(HttpServletRequest sreq,
233: HttpServletResponse sres) throws IOException {
234: Map m = getBundles();
235: sres.setContentType("text/plain");
236: PrintWriter pr = sres.getWriter();
237: pr.println("# white pages bootstrap data");
238: for (Iterator iter = m.values().iterator(); iter
239: .hasNext();) {
240: Bundle b = (Bundle) iter.next();
241: String s = b.encode();
242: if (s == null) {
243: continue;
244: }
245: pr.println(s);
246: }
247: pr.close();
248: }
249: }
250: }
251: }
|