001: /*
002: * <copyright>
003: *
004: * Copyright 2000-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.lib.web.redirect;
028:
029: import java.io.IOException;
030: import java.util.ArrayList;
031: import java.util.Collections;
032: import java.util.List;
033: import java.util.Map;
034: import javax.servlet.ServletException;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.http.HttpServletResponse;
037:
038: import org.cougaar.bootstrap.SystemProperties;
039: import org.cougaar.core.component.Component;
040: import org.cougaar.core.component.ServiceBroker;
041: import org.cougaar.core.component.ServiceProvider;
042: import org.cougaar.core.service.LoggingService;
043: import org.cougaar.util.Arguments;
044: import org.cougaar.util.CSVUtility;
045: import org.cougaar.util.GenericStateModelAdapter;
046:
047: /**
048: * This component advertises the {@link ServletRedirectRegistryService}.
049: * <p>
050: * The servlet request URL can optionally specify redirector filters,
051: * e.g.:<br>
052: * http://localhost:8800/$(http_redirect,foo)MyAgent/bar<br>
053: * where the options are:<br>
054: * [http_redirect, foo]<br>
055: * In this example, these explicit redirectors will be attempted in that
056: * specified order. If no redirectors are specified then the "default_order"
057: * list defined in this class will be used, which defaults to null. If the
058: * list is null then all loaded redirectors will be attempted in the order in
059: * which they were loaded.
060: *
061: * @property org.cougaar.lib.web.redirect.default_order=null
062: * Default servlet redirector attempt order, defaults to null.
063: */
064: public class ServletRedirectorRegistry extends GenericStateModelAdapter
065: implements Component {
066:
067: private ServiceBroker sb;
068:
069: protected LoggingService log;
070:
071: private Arguments args = Arguments.EMPTY_INSTANCE;
072: private List default_order = null;
073:
074: private ServiceProvider srs_sp;
075: private ServiceProvider srrs_sp;
076:
077: private final Object lock = new Object();
078: private List redirectors = Collections.EMPTY_LIST;
079:
080: public void setServiceBroker(ServiceBroker sb) {
081: this .sb = sb;
082: }
083:
084: public void setParameter(Object o) {
085: args = new Arguments(o);
086: }
087:
088: public void load() {
089: super .load();
090:
091: // parse parameters
092: String prefix = "org.cougaar.lib.web.redirect.";
093: String s_order = args.getString("default_order",
094: SystemProperties.getProperty(prefix + "default_order"));
095: if (s_order != null && !"null".equals(s_order)) {
096: List l = CSVUtility.parseToList(s_order);
097: default_order = Collections.unmodifiableList(l);
098: }
099:
100: // get services
101: log = (LoggingService) sb.getService(this ,
102: LoggingService.class, null);
103:
104: // advertise registry
105: final ServletRedirectorRegistry thiz = this ;
106: final ServletRedirectorRegistryService srrs = new ServletRedirectorRegistryService() {
107: public void add(ServletRedirector redirector) {
108: thiz.add(redirector);
109: }
110:
111: public void remove(ServletRedirector redirector) {
112: thiz.remove(redirector);
113: }
114: };
115: final Class srrs_cl = ServletRedirectorRegistryService.class;
116: srrs_sp = new ServiceProvider() {
117: public Object getService(ServiceBroker sb, Object req,
118: Class scl) {
119: return (srrs_cl.isAssignableFrom(scl) ? srrs : null);
120: }
121:
122: public void releaseService(ServiceBroker sb, Object req,
123: Class scl, Object svc) {
124: }
125: };
126: sb.addService(srrs_cl, srrs_sp);
127:
128: // advertise redirector
129: final ServletRedirectorService srs = new ServletRedirectorService() {
130: public int redirect(String encName, List options,
131: NamingSupport namingSupport,
132: HttpServletRequest req, HttpServletResponse res)
133: throws ServletException, IOException {
134: return thiz.redirect(encName, options, namingSupport,
135: req, res);
136: }
137: };
138: final Class srs_cl = ServletRedirectorService.class;
139: srs_sp = new ServiceProvider() {
140: public Object getService(ServiceBroker sb, Object req,
141: Class scl) {
142: return (srs_cl.isAssignableFrom(scl) ? srs : null);
143: }
144:
145: public void releaseService(ServiceBroker sb, Object req,
146: Class scl, Object svc) {
147: }
148: };
149: sb.addService(srs_cl, srs_sp);
150: }
151:
152: public void unload() {
153: // revoke redirector
154: if (srs_sp != null) {
155: Class srs_cl = ServletRedirectorService.class;
156: sb.revokeService(srs_cl, srs_sp);
157: srs_sp = null;
158: }
159:
160: // revoke registry
161: if (srrs_sp != null) {
162: Class srrs_cl = ServletRedirectorRegistryService.class;
163: sb.revokeService(srrs_cl, srrs_sp);
164: srrs_sp = null;
165: }
166:
167: // release services
168: if (log != null) {
169: sb.releaseService(this , LoggingService.class, log);
170: log = null;
171: }
172:
173: super .unload();
174: }
175:
176: // copy-on-write
177: private void add(ServletRedirector redirector) {
178: synchronized (lock) {
179: if (redirectors.contains(redirector)) {
180: return;
181: }
182: List l = new ArrayList(redirectors);
183: l.add(redirector);
184: redirectors = Collections.unmodifiableList(l);
185: }
186: }
187:
188: private void remove(ServletRedirector redirector) {
189: synchronized (lock) {
190: if (!redirectors.contains(redirector)) {
191: return;
192: }
193: List l = new ArrayList(redirectors);
194: l.remove(redirector);
195: redirectors = Collections.unmodifiableList(l);
196: }
197: }
198:
199: private List getRedirectors() {
200: synchronized (lock) {
201: return redirectors;
202: }
203: }
204:
205: private int redirect(String encName, List orig_options,
206: NamingSupport namingSupport, HttpServletRequest req,
207: HttpServletResponse res) throws ServletException,
208: IOException {
209:
210: List options = (orig_options == null ? default_order
211: : orig_options);
212:
213: int ret = ServletRedirector.NOT_SUPPORTED;
214: if (options != null && options.isEmpty()) {
215: // do nothing
216: return ret;
217: }
218: List l = getRedirectors();
219:
220: if (options == null) {
221: // if no options are specified then we run all loaded redirectors in the
222: // order in which they were added.
223: if (log.isDebugEnabled()) {
224: log.debug("attempt all redirectors in load order");
225: }
226: return attempt(encName, namingSupport, req, res, l, null,
227: ret);
228: }
229:
230: // call our redirectors in the specified options order
231: if (log.isDebugEnabled()) {
232: log.debug("attempt options: " + options);
233: }
234: for (int i = 0, n = options.size(); i < n; i++) {
235: List single_opt = Collections.singletonList(options.get(i));
236: ret = attempt(encName, namingSupport, req, res, l,
237: single_opt, ret);
238: if (ret == ServletRedirector.REDIRECTED) {
239: break;
240: }
241: }
242: if (log.isDebugEnabled()) {
243: log.debug(" returning " + ret);
244: }
245: return ret;
246: }
247:
248: private int attempt(String encName, NamingSupport namingSupport,
249: HttpServletRequest req, HttpServletResponse res, List l,
250: List opts, int prior_ret) throws ServletException,
251: IOException {
252: int ret = prior_ret;
253: for (int i = 0, n = l.size(); i < n; i++) {
254: ServletRedirector ri = (ServletRedirector) l.get(i);
255: int status = ri.redirect(encName, opts, namingSupport, req,
256: res);
257:
258: if (log.isDebugEnabled()) {
259: log.debug(" redir(" + opts + ") == " + status
260: + " from " + ri);
261: }
262:
263: // update our return value
264: //
265: // we keep a "ret" value that is updated in order of:
266: // NOT_SUPPORTED
267: // NO_NAMING_ENTRIES
268: // DETECTED_LOOP or OTHER_ERROR
269: // REDIRECTED
270: // This ensures that we return the most significant result, not just the
271: // last one we tried.
272: switch (status) {
273: case ServletRedirector.REDIRECTED:
274: // success, we're done
275: return ServletRedirector.REDIRECTED;
276: case ServletRedirector.NOT_SUPPORTED:
277: // leave ret as-is
278: break;
279: case ServletRedirector.NO_NAMING_ENTRIES:
280: // don't change ret if it's a LOOP or ERROR
281: if (ret == ServletRedirector.NOT_SUPPORTED) {
282: ret = ServletRedirector.NO_NAMING_ENTRIES;
283: }
284: break;
285: case ServletRedirector.DETECTED_LOOP:
286: // save
287: ret = ServletRedirector.DETECTED_LOOP;
288: break;
289: default:
290: // save
291: ret = ServletRedirector.OTHER_ERROR;
292: }
293: }
294: return ret;
295: }
296: }
|