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: package org.cougaar.lib.web.arch.root;
027:
028: import java.io.IOException;
029: import java.util.List;
030: import javax.servlet.Servlet;
031: import javax.servlet.ServletConfig;
032: import javax.servlet.ServletException;
033: import javax.servlet.ServletRequest;
034: import javax.servlet.ServletResponse;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.http.HttpServletResponse;
037:
038: import org.cougaar.lib.web.arch.ServletRegistry;
039: import org.cougaar.lib.web.arch.util.PathParser;
040: import org.cougaar.lib.web.arch.util.PrefixMatch;
041:
042: /**
043: * This <code>Servlet</code> handles all incoming requests,
044: * typically by delegating "/$name" requests to the local {@link
045: * org.cougaar.lib.web.arch.leaf.LeafServlet}s or by redirecting
046: * the client if the named agent is remote.
047: * <p>
048: * The following rules are used to handle requests:
049: * <ol>
050: * <li>If the request path is "/" then the
051: * <code>welcomeServlet</code> is used to print a friendly
052: * welcome page.</li>
053: * <li>If the path is "/agent" then the <code>agentsServlet</code>
054: * is used.</li>
055: * <li>If the name lacks a "/$" prefix, or is "/$/", or is "/$~/",
056: * then the request is handled as if the prefix is
057: * "/$<i>rootName</i>", and the following rules are invoked.
058: * </li>
059: * <li>If the "/$name[/.*]" name is locally registered then the
060: * request is delegated to the registered LeafServlet. The
061: * LeafServlet in turn invokes the registered path within that
062: * name, or complains if the path does not exist. This is the
063: * most common case.</li>
064: * <li>If the "/$name[/.*]" name is not locally registered then the
065: * <code>Redirector</code> is used to redirect the client
066: * to the appropriate remote host, based on a nameserver
067: * lookup.</li>
068: * <li>If the prefix is "/$~name[/.*]" and the name is locally
069: * registered then the request is passed to the
070: * "/$<i>rootName</i>" -- the "~" is interpreted as
071: * "the home of <i>name</i>".</li>
072: * <li>If the prefix is "/$~name[/.*]" and the name is not locally
073: * registered then the <code>Redirector</code> is used as
074: * noted above.<li>
075: * </ol>
076: */
077: public class RootServlet implements Servlet {
078:
079: /** Global (name, Servlet) registry. */
080: private final ServletRegistry servletReg;
081:
082: /** Name for "/$~" requests. */
083: private final String rootName;
084:
085: /** Servlet to handle "/" requests. */
086: private final Servlet welcomeServlet;
087:
088: /** Servlet to handle "/agents" requests. */
089: private final Servlet agentsServlet;
090:
091: /** Handler for all non-local "/$name[/.*]" requests. */
092: private final Redirector redirector;
093:
094: public RootServlet(ServletRegistry servletReg, String rootName,
095: Servlet welcomeServlet, Servlet agentsServlet,
096: Redirector redirector) {
097: this .servletReg = servletReg;
098: this .rootName = rootName;
099: this .welcomeServlet = welcomeServlet;
100: this .agentsServlet = agentsServlet;
101: this .redirector = redirector;
102:
103: // null-check
104: String s = (servletReg == null ? "servletReg"
105: : rootName == null ? "rootName"
106: : welcomeServlet == null ? "welcomeServlet"
107: : redirector == null ? "redirector"
108: : null);
109: if (s != null) {
110: throw new IllegalArgumentException("null " + s);
111: }
112:
113: // initialize the servlets
114:
115: try {
116: welcomeServlet.init(getServletConfig());
117: } catch (ServletException se) {
118: throw new RuntimeException(
119: "Unable to initialize the no-name-servlet: "
120: + se.getMessage());
121: }
122: }
123:
124: public void service(ServletRequest sreq, ServletResponse sres)
125: throws ServletException, IOException {
126:
127: // cast
128: HttpServletRequest req = (HttpServletRequest) sreq;
129: HttpServletResponse res = (HttpServletResponse) sres;
130:
131: // trim off basePath, e.g. "/foo/$bar" -> "/$bar"
132: String path = req.getRequestURI();
133: int pathLength = (path == null ? 0 : path.length());
134: String contextPath = req.getContextPath();
135: int contextLength = (contextPath == null ? 0 : contextPath
136: .length());
137: if (contextLength > 0 && contextLength <= pathLength) {
138: path = path.substring(contextLength);
139: }
140:
141: // look for "/"
142: if (pathLength <= 1) {
143: welcomeServlet.service(sreq, sres);
144: return;
145: }
146:
147: // parse path
148: PathParser pathInfo = new PathParser(path);
149: String name = pathInfo.getName();
150: boolean is_node_of = pathInfo.isNodeOf();
151: List options = pathInfo.getOptions();
152: String subpath = pathInfo.getSubpath();
153:
154: if (name == null || name.length() == 0) {
155: name = rootName;
156: }
157:
158: // look for "[/$*]/agents[/*]" where the agent is local
159: //
160: // this is awkward but currently required, since only the root-level
161: // servlet has access to the globReg. Ideally this servlet would run
162: // in the lower-level node's LeafServlet, but that level doesn't have
163: // access to our globReg.
164: //
165: // we also want to catch any local agents, to avoid an unnecessary
166: // redirect. E.g. if "x" is local and the request is "/$x/agents" then
167: // we want to handle that here instead of making "/$x/" redirect the
168: // client to "/$rootName/agents".
169: if (subpath != null && subpath.startsWith("/agents")
170: && (subpath.length() == 7 || subpath.charAt(7) == '/')) {
171: boolean is_local = (servletReg.get(name) != null);
172: if (is_local) {
173: agentsServlet.service(sreq, sres);
174: return;
175: }
176: }
177:
178: // check for "is_node_of" flag and local agent
179: if (is_node_of) {
180: boolean is_local = (servletReg.get(name) != null);
181: if (is_local) {
182: // act as if the request is for "/$rootName"
183: name = rootName;
184: }
185: }
186:
187: // lookup possibly local agent
188: Servlet localServlet;
189: Object o = servletReg.get(name);
190: if (o == null) {
191: localServlet = null;
192: } else if (o instanceof Servlet) {
193: localServlet = (Servlet) o;
194: } else {
195: // unexpected!
196: localServlet = (Servlet) ((PrefixMatch) o).getValue();
197: }
198: if (localServlet != null) {
199: localServlet.service(sreq, sres);
200: return;
201: }
202:
203: // redirect to remote agent
204: redirector.redirect(name, options, req, res);
205: }
206:
207: public void init(ServletConfig config) throws ServletException {
208: servletReg.init(config);
209: }
210:
211: public ServletConfig getServletConfig() {
212: return servletReg.getServletConfig();
213: }
214:
215: public String getServletInfo() {
216: return "root-servlet";
217: }
218:
219: public void destroy() {
220: // ignore -- we're using the dummy config...
221: }
222: }
|