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.lib.web.service;
028:
029: import java.net.URLEncoder;
030: import java.util.ArrayList;
031: import java.util.List;
032:
033: import javax.servlet.Servlet;
034: import javax.servlet.ServletConfig;
035:
036: import org.cougaar.core.component.Component;
037: import org.cougaar.core.component.NullService;
038: import org.cougaar.core.component.Service;
039: import org.cougaar.core.component.ServiceBroker;
040: import org.cougaar.core.component.ServiceProvider;
041: import org.cougaar.core.mts.MessageAddress;
042: import org.cougaar.core.service.AgentIdentificationService;
043: import org.cougaar.core.service.ServletService;
044: import org.cougaar.lib.web.arch.ServletRegistry;
045: import org.cougaar.lib.web.arch.leaf.LeafServlet;
046: import org.cougaar.lib.web.arch.leaf.LeafServletRegistry;
047: import org.cougaar.lib.web.arch.leaf.LeafToRootRedirectServlet;
048: import org.cougaar.util.GenericStateModelAdapter;
049:
050: /**
051: * This component advertises the agent-internal {@link ServletService}, based
052: * upon the node-level {@link RootServletService}.
053: * <p>
054: * This component also blocks the RootServletService, since agent components
055: * should use the ServletService.
056: */
057: public class LeafServletServiceComponent extends
058: GenericStateModelAdapter implements Component {
059: private ServiceBroker sb;
060:
061: private String encName;
062: private RootServletService rootServletService;
063: private LeafServletServiceProviderImpl leafSP;
064: private RootBlockerSP rootBlockerSP;
065:
066: public void setServiceBroker(ServiceBroker sb) {
067: this .sb = sb;
068: }
069:
070: public void setParameter(Object o) {
071: // ignore old-style passing of the "encName"
072: }
073:
074: public void load() {
075: super .load();
076:
077: // get our agent's name
078: AgentIdentificationService ais = (AgentIdentificationService) sb
079: .getService(this , AgentIdentificationService.class,
080: null);
081: if (ais == null) {
082: throw new RuntimeException(
083: "Unable to obtain the agent identification service");
084: }
085: MessageAddress addr = ais.getMessageAddress();
086: sb.releaseService(this , AgentIdentificationService.class, ais);
087:
088: // encode the agent name for HTTP safety.
089: //
090: // This is done to protect raw-names such as "x y",
091: // which would produce invalid "../$x y/.." URLs.
092: try {
093: String rawName = addr.getAddress();
094: this .encName = URLEncoder.encode(rawName, "UTF-8");
095: } catch (Exception e) {
096: throw new RuntimeException("Invalid name \"" + addr + "\"",
097: e);
098: }
099:
100: // get the (root) servlet service
101: if (rootServletService == null) {
102: rootServletService = (RootServletService) sb.getService(
103: this , RootServletService.class, null);
104: if (rootServletService == null) {
105: throw new RuntimeException(
106: "Leaf servlet-service unable to obtain RootServletService");
107: }
108: }
109:
110: // create and advertise our service
111: if (leafSP == null) {
112: this .leafSP = new LeafServletServiceProviderImpl();
113: leafSP.start();
114: sb.addService(ServletService.class, leafSP);
115: }
116:
117: // block the RootServletService
118: if (rootBlockerSP == null) {
119: rootBlockerSP = new RootBlockerSP();
120: sb.addService(RootServletService.class, rootBlockerSP);
121: }
122: }
123:
124: public void suspend() {
125: super .suspend();
126: if (leafSP != null) {
127: leafSP.stop();
128: }
129: }
130:
131: public void resume() {
132: if (leafSP != null) {
133: leafSP.start();
134: }
135: super .resume();
136: }
137:
138: public void unload() {
139: // unblock the RootServletService
140: if (rootBlockerSP != null) {
141: sb.revokeService(RootServletService.class, rootBlockerSP);
142: rootBlockerSP = null;
143: }
144:
145: // revoke our service
146: if (leafSP != null) {
147: leafSP.stop();
148: sb.revokeService(ServletService.class, leafSP);
149: leafSP = null;
150: }
151:
152: // release the root servlet service
153: if (rootServletService != null) {
154: sb.releaseService(this , RootServletService.class,
155: rootServletService);
156: rootServletService = null;
157: }
158:
159: super .unload();
160: }
161:
162: //
163: // private utility methods and classes:
164: //
165:
166: /**
167: * Service provider for our <code>ServletService</code>.
168: */
169: private class LeafServletServiceProviderImpl implements
170: ServiceProvider {
171:
172: private final ServletRegistry leafReg;
173: private final LeafServlet leafServlet;
174: private boolean isRegistered;
175:
176: public LeafServletServiceProviderImpl() {
177: // create a servlet and registry
178: this .leafReg = new LeafServletRegistry();
179: Servlet unknownPathServlet = new UnknownLeafPathServlet(
180: encName);
181: this .leafServlet = new LeafServlet(leafReg,
182: unknownPathServlet);
183:
184: // get our own service
185: ServletService ss = new LeafServletServiceImpl();
186:
187: // add our own "/list" Servlet to display the
188: // contents of the leafReg
189: try {
190: Servlet listServlet = new ListRegistryServlet(leafReg,
191: encName);
192: ss.register("/list", listServlet);
193: } catch (Exception e) {
194: // shouldn't happen
195: throw new RuntimeException(
196: "Unable to register \"/list\" servlet", e);
197: }
198:
199: // redirect "/agents" back to the root
200: try {
201: Servlet agentsServlet = new LeafToRootRedirectServlet();
202: ss.register("/agents", agentsServlet);
203: } catch (Exception e) {
204: // shouldn't happen
205: throw new RuntimeException(
206: "Unable to register \"/agents\" servlet", e);
207: }
208:
209: // wait until "start()" to register
210: }
211:
212: public void start() {
213: if (!(isRegistered)) {
214: try {
215: // register encoded name
216: rootServletService.register(encName, leafServlet);
217: } catch (Exception e) {
218: throw new RuntimeException("Unable to register \""
219: + encName + "\" for Servlet service", e);
220: }
221: isRegistered = true;
222: }
223: }
224:
225: public void stop() {
226: if (isRegistered) {
227: try {
228: // unregister encoded name
229: rootServletService.unregister(encName);
230:
231: // FIXME wait until all child servlets have halted
232: } finally {
233: isRegistered = false;
234: }
235: }
236: }
237:
238: public Object getService(ServiceBroker sb, Object requestor,
239: Class serviceClass) {
240: // create a new service instance
241: if (serviceClass == ServletService.class) {
242: return new LeafServletServiceImpl();
243: } else {
244: throw new IllegalArgumentException(
245: "ServletService does not provide a service for: "
246: + serviceClass);
247: }
248: }
249:
250: public void releaseService(ServiceBroker sb, Object requestor,
251: Class serviceClass, Object service) {
252: // unregister all servlets of this service instance
253: if (!(service instanceof LeafServletServiceImpl)) {
254: throw new IllegalArgumentException(
255: "ServletService unable to release service: "
256: + ((service != null) ? service
257: .getClass().toString() : "null"));
258: }
259: LeafServletServiceImpl lssi = (LeafServletServiceImpl) service;
260: lssi.unregisterAll();
261: }
262:
263: //
264: // private utility methods and classes:
265: //
266:
267: /**
268: * Leaf's ServletService implementation.
269: */
270: private class LeafServletServiceImpl implements ServletService {
271:
272: // List of paths registered by this requestor; typically a
273: // tiny list.
274: //
275: // All the methods of this impl are synchronized on this
276: // list. Partially this is for List safety, but also
277: // it makes sense that one shouldn't be able to
278: // simultaneously register and unregister a Servlet...
279: private final List l = new ArrayList(3);
280:
281: private String trimPath(String path) {
282: String p = path.trim();
283: if (p.length() <= 1) {
284: throw new IllegalArgumentException(
285: "Must specify a non-empty path, not \""
286: + path + "\"");
287: }
288: if (p.charAt(0) != '/') {
289: throw new IllegalArgumentException("Path \"" + path
290: + "\" must start with \"/\"");
291: }
292: return p;
293: }
294:
295: public void register(String path, Servlet servlet)
296: throws Exception {
297: String p = trimPath(path);
298: synchronized (l) {
299: leafReg.register(p, servlet);
300: l.add(p);
301: }
302: }
303:
304: public void unregister(String path) {
305: String p = trimPath(path);
306: synchronized (l) {
307: leafReg.unregister(p);
308: l.remove(p);
309: }
310: }
311:
312: public void unregisterAll() {
313: // unregister all servlets
314: synchronized (l) {
315: for (int n = l.size() - 1; n >= 0; n--) {
316: String p = (String) l.get(n);
317: leafReg.unregister(p);
318: }
319: l.clear();
320: }
321: }
322:
323: public int getHttpPort() {
324: return rootServletService.getHttpPort();
325: }
326:
327: public int getHttpsPort() {
328: return rootServletService.getHttpsPort();
329: }
330: }
331: }
332:
333: private static final class RootBlockerSP implements ServiceProvider {
334: private final Service NULL = new NullService() {
335: };
336:
337: public Object getService(ServiceBroker sb, Object requestor,
338: Class serviceClass) {
339: if (RootServletService.class.isAssignableFrom(serviceClass)) {
340: return NULL; // service blocker!
341: } else {
342: return null;
343: }
344: }
345:
346: public void releaseService(ServiceBroker sb, Object requestor,
347: Class serviceClass, Object service) {
348: }
349: }
350: }
|