001: /* Copyright 2002 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.util.Enumeration;
009: import java.util.Hashtable;
010: import java.util.Locale;
011: import java.util.Map;
012:
013: import org.jasig.portal.car.CarResources;
014: import org.apache.commons.logging.Log;
015: import org.apache.commons.logging.LogFactory;
016:
017: import com.oreilly.servlet.multipart.Part;
018:
019: /**
020: * A set of runtime data accessible by a channel.
021: *
022: * @author <a href="mailto:pkharchenko@unicon.net">Peter Kharchenko</a>
023: * @version $Revision: 42267 $
024: */
025: public class ChannelRuntimeData extends Hashtable<String, Object>
026: implements Cloneable {
027:
028: private static final Log log = LogFactory
029: .getLog(ChannelRuntimeData.class);
030:
031: private BrowserInfo binfo = null;
032: private Locale[] locales = null;
033: private UPFileSpec channelUPFile;
034: private String baseActionURL = null;
035: private String httpRequestMethod = null;
036: private String remoteAddress = null;
037: private String keywords = null;
038: private boolean renderingAsRoot = false;
039: private boolean targeted = false;
040: private static final String TRADITIONAL_MEDIA_BASE = "media/";
041: public static final String CAR_BASE = "/CAR_BASE";
042: public static final String WEB_APP_BASE = null;
043:
044: /**
045: * Default empty constructor
046: */
047: public ChannelRuntimeData() {
048: super ();
049: channelUPFile = new UPFileSpec();
050: }
051:
052: /**
053: * Create a new instance of ourself
054: * Used by the CError channel
055: * @return crd the cloned ChannelRuntimeData object
056: */
057: public Object clone() {
058: ChannelRuntimeData crd = (ChannelRuntimeData) super .clone();
059: crd.binfo = binfo;
060: crd.locales = locales;
061: crd.channelUPFile = channelUPFile;
062: crd.baseActionURL = baseActionURL;
063: crd.httpRequestMethod = httpRequestMethod;
064: crd.keywords = keywords;
065: crd.renderingAsRoot = renderingAsRoot;
066: crd.targeted = targeted;
067: crd.putAll(this );
068: return crd;
069: }
070:
071: /**
072: * Set a UPFileSpec which will be used to produce
073: * baseActionURL and workerActionURL.
074: * @param upfs the UPFileSpec
075: */
076: public void setUPFile(UPFileSpec upfs) {
077: channelUPFile = upfs;
078: }
079:
080: /**
081: * Get the UPFileSpec
082: * @return channelUPFile the UPFileSpec
083: */
084: public UPFileSpec getUPFile() {
085: return this .channelUPFile;
086: }
087:
088: /**
089: * Set the HTTP Request method.
090: *
091: * @param method a <code>String</code> value
092: */
093: public void setHttpRequestMethod(String method) {
094: this .httpRequestMethod = method;
095: }
096:
097: /**
098: * Get HTTP request method (i.e. GET, POST)
099: *
100: * @return a <code>String</code> value
101: */
102: public String getHttpRequestMethod() {
103: return this .httpRequestMethod;
104: }
105:
106: /**
107: * Sets the base action URL. This was added back in for the benefit
108: * of web services. Not sure if it is going to stay this way.
109: * @param baseActionURL the base action URL
110: */
111: public void setBaseActionURL(String baseActionURL) {
112: this .baseActionURL = baseActionURL;
113: }
114:
115: /**
116: * Sets whether or not the channel is rendering as the root of the layout.
117: * @param rar <code>true</code> if channel is rendering as the root, otherwise <code>false</code>
118: */
119: public void setRenderingAsRoot(boolean rar) {
120: renderingAsRoot = rar;
121: }
122:
123: /**
124: * Sets whether or not the channel is currently targeted. A channel is targeted
125: * if an incoming request specifies the channel's subscribe ID as the targeted node ID.
126: * @param targeted <code>true</code> if channel is targeted, otherwise <code>false</code>
127: */
128: public void setTargeted(boolean targeted) {
129: this .targeted = targeted;
130: }
131:
132: /**
133: * Setter method for browser info object.
134: *
135: * @param bi a browser info associated with the current request
136: */
137: public void setBrowserInfo(BrowserInfo bi) {
138: this .binfo = bi;
139: }
140:
141: /**
142: * Provides information about a user-agent associated with the current request/response.
143: *
144: * @return a <code>BrowserInfo</code> object ecapsulating various user-agent information.
145: */
146: public BrowserInfo getBrowserInfo() {
147: return binfo;
148: }
149:
150: /**
151: * Setter method for array of locales. A channel should
152: * make an effort to render itself according to the
153: * order of the locales in this array.
154: * @param locales an ordered list of locales
155: */
156: public void setLocales(Locale[] locales) {
157: this .locales = locales;
158: }
159:
160: /**
161: * Accessor method for ordered set of locales.
162: * @return locales an ordered list of locales
163: */
164: public Locale[] getLocales() {
165: return locales;
166: }
167:
168: /**
169: * A convenience method for setting a whole set of parameters at once.
170: * The values in the Map must be object arrays. If (name, value[]) is in
171: * the Map, then a future call to getParameter(name) will return value[0].
172: * @param params a <code>Map</code> of parameter names to parameter value arrays.
173: */
174: public void setParameters(Map<String, Object> params) {
175: this .putAll(params); // copy a Map
176: }
177:
178: /**
179: * A convenience method for setting a whole set of parameters at once.
180: * The Map should contain name-value pairs. The name should be a String
181: * and the value should be either a String or a Part.
182: * If (name, value) is in the Map then a future call to getParameter(name)
183: * will return value.
184: * @param params a <code>Map</code> of parameter names to parameter value arrays.
185: */
186: public void setParametersSingleValued(Map<String, Object> params) {
187: if (params != null) {
188: java.util.Iterator iter = params.keySet().iterator();
189: while (iter.hasNext()) {
190: String key = (String) iter.next();
191: Object value = params.get(key);
192: if (value instanceof String)
193: setParameter(key, (String) value);
194: else if (value instanceof Part)
195: setParameter(key, (Part) value);
196: }
197: }
198: }
199:
200: /**
201: * Sets multi-valued parameter.
202: *
203: * @param pName parameter name
204: * @param values an array of parameter values
205: * @return an array of parameter values
206: */
207: public String[] setParameterValues(String pName, String[] values) {
208: return (String[]) super .put(pName, values);
209: }
210:
211: /**
212: * Establish a parameter name-value pair.
213: *
214: * @param pName parameter name
215: * @param value parameter value
216: */
217: public void setParameter(String pName, String value) {
218: String[] valueArray = new String[1];
219: valueArray[0] = value;
220: super .put(pName, valueArray);
221: }
222:
223: public com.oreilly.servlet.multipart.Part[] setParameterValues(
224: String pName, com.oreilly.servlet.multipart.Part[] values) {
225: return (com.oreilly.servlet.multipart.Part[]) super .put(pName,
226: values);
227: }
228:
229: public synchronized void setParameter(String key, Part value) {
230: Part[] valueArray = new Part[1];
231: valueArray[0] = value;
232: super .put(key, valueArray);
233: }
234:
235: /**
236: * Returns a baseActionURL - parameters of a request coming in on the baseActionURL
237: * will be placed into the ChannelRuntimeData object for channel's use.
238: *
239: * @return a value of URL to which parameter sequences should be appended.
240: */
241: public String getBaseActionURL() {
242: return this .getBaseActionURL(false);
243: }
244:
245: /**
246: * Returns a baseActionURL - parameters of a request coming in on the baseActionURL
247: * will be placed into the ChannelRuntimeData object for channel's use.
248: *
249: * @param idempotent a <code>boolean</code> value specifying if a given URL should be idepotent.
250: * @return a value of URL to which parameter sequences should be appended.
251: */
252: public String getBaseActionURL(boolean idempotent) {
253: // If the base action URL was explicitly set, use it
254: // peterk: we should probably introduce idepotent version of this one as well, at some point
255: if (baseActionURL != null) {
256: return baseActionURL;
257: }
258:
259: String url = null;
260: try {
261: if (idempotent) {
262: UPFileSpec upfs = new UPFileSpec(channelUPFile);
263: upfs.setTagId(PortalSessionManager.IDEMPOTENT_URL_TAG);
264: url = upfs.getUPFile();
265: } else {
266: url = channelUPFile.getUPFile();
267: }
268: } catch (Exception e) {
269: log
270: .error("ChannelRuntimeData::getBaseActionURL() : unable to construct a base action URL!");
271: }
272: return url;
273: }
274:
275: /**
276: * Returns an idempotent URL that includes a single query parameter that
277: * targets a channel for focus mode by functional name. Additional
278: * query parameters appended will be passed to the focused channel via
279: * the channel's ChannelRuntimeData object.
280: *
281: * @return a value of URL including a single query parameter.
282: * @since 2.5.1
283: */
284: public String getFnameActionURL(String fname) {
285: String url = null;
286: try {
287: UPFileSpec upfs = new UPFileSpec(channelUPFile);
288: upfs.setTagId(PortalSessionManager.IDEMPOTENT_URL_TAG);
289: url = upfs.getUPFile();
290: url = url + "?" + Constants.FNAME_PARAM + "=" + fname;
291: } catch (Exception e) {
292: log.error("Unable to construct a fname action URL!", e);
293: }
294: return url;
295: }
296:
297: /**
298: * Returns the URL to invoke one of the workers specified in PortalSessionManager.
299: * Typically the channel that is invoked with the worker will have to implement an
300: * interface specific for that worker.
301: * @param worker - Worker string must be a UPFileSpec.xxx value.
302: * @return URL to invoke the worker.
303: */
304: public String getBaseWorkerURL(String worker) {
305: // todo: propagate the exception
306: String url = null;
307: try {
308: url = getBaseWorkerURL(worker, false);
309: } catch (Exception e) {
310: log
311: .error("ChannelRuntimeData::getBaseWorkerURL() : unable to construct a worker action URL for a worker \""
312: + worker + "\".");
313: }
314: return url;
315: }
316:
317: /**
318: Returns a media base appropriate for web-visible resources used by and
319: deployed with the passed in object. If the class of the passed in
320: object was loaded from a CAR then a URL appropriate for accessing
321: images in CARs is returned. Otherwise, a URL to the base media
322: in the web application's document root is returned.
323: */
324: public String getBaseMediaURL(Object aChannelObject)
325: throws PortalException {
326: return getBaseMediaURL(aChannelObject.getClass());
327: }
328:
329: /**
330: Returns a media base appropriate for web-visible resources used by and
331: deployed with the passed in class. If the class of the passed in
332: object was loaded from a CAR then a URL appropriate for accessing
333: images in CARs is returned. Otherwise, a URL to the base media
334: in the web application's document root is returned.
335: */
336: public String getBaseMediaURL(Class aChannelClass)
337: throws PortalException {
338:
339: String mediaBase = null;
340:
341: if (aChannelClass == null) {
342: mediaBase = TRADITIONAL_MEDIA_BASE;
343: } else if (aChannelClass == CarResources.class) {
344: mediaBase = createBaseCarMediaURL();
345: } else if (aChannelClass.getClassLoader() == CarResources
346: .getInstance().getClassLoader()) {
347: mediaBase = createBaseCarMediaURL();
348: } else {
349: mediaBase = TRADITIONAL_MEDIA_BASE;
350: }
351:
352: if (log.isTraceEnabled()) {
353: log.trace("Returning media base [" + mediaBase
354: + "] for class [" + aChannelClass + "]");
355: }
356:
357: return mediaBase;
358: }
359:
360: /**
361: Returns a media base appropriate for the resource path passed in. The
362: resource path is the path to the resource within its channel archive.
363: (See org.jasig.portal.car.CarResources class for more information.)
364: If the passed in resourcePath matches that of a resource loaded from
365: CARs then this method returns a URL appropriate to obtain CAR
366: deployed, web-visible resources. Otherwise it returns a URL to the
367: traditional media path under the uPortal web application's document
368: root.
369: */
370: public String getBaseMediaURL(String resourcePath)
371: throws PortalException {
372: if (resourcePath == null || resourcePath.equals(WEB_APP_BASE))
373: return TRADITIONAL_MEDIA_BASE;
374: if (resourcePath.equals(CAR_BASE))
375: return createBaseCarMediaURL();
376: if (CarResources.getInstance().containsResource(resourcePath))
377: return createBaseCarMediaURL();
378: return TRADITIONAL_MEDIA_BASE;
379: }
380:
381: /**
382: * Creates the CAR media base URL.
383: */
384: private String createBaseCarMediaURL() throws PortalException {
385: String url = getBaseWorkerURL(CarResources.CAR_WORKER_ID, true);
386: return url.concat("?" + CarResources.CAR_RESOURCE_PARM + "=");
387: }
388:
389: /**
390: * Returns the URL to invoke one of the workers specified in PortalSessionManager.
391: * Typically the channel that is invoked with the worker will have to implement an
392: * interface specific for that worker.
393: * @param worker - Worker string must be a UPFileSpec.xxx value.
394: * @param idempotent a <code>boolean</code> value sepcifying if a URL should be idempotent
395: * @return URL to invoke the worker.
396: * @exception PortalException if an error occurs
397: */
398: public String getBaseWorkerURL(String worker, boolean idempotent)
399: throws PortalException {
400: String url = null;
401: UPFileSpec upfs = new UPFileSpec(channelUPFile);
402: upfs.setMethod(UPFileSpec.WORKER_METHOD);
403: upfs.setMethodNodeId(worker);
404: if (idempotent) {
405: upfs.setTagId(PortalSessionManager.IDEMPOTENT_URL_TAG);
406: }
407:
408: url = upfs.getUPFile();
409:
410: return url;
411: }
412:
413: /**
414: * Tells whether or not the channel is rendering as the root of the layout.
415: * @return <code>true</code> if channel is rendering as the root, otherwise <code>false</code>
416: */
417: public boolean isRenderingAsRoot() {
418: return renderingAsRoot;
419: }
420:
421: /**
422: * Tells whether or not the channel is currently targeted. A channel is targeted
423: * if an incoming request specifies the channel's subscribe ID as the targeted node ID.
424: * @return <code>true</code> if channel is targeted, otherwise <code>false</code>
425: */
426: public boolean isTargeted() {
427: return targeted;
428: }
429:
430: /**
431: * Get a parameter value. If the parameter has multiple values, only the first value is returned.
432: *
433: * @param pName parameter name
434: * @return parameter value
435: */
436: public String getParameter(String pName) {
437: String[] value_array = this .getParameterValues(pName);
438: if ((value_array != null) && (value_array.length > 0))
439: return value_array[0];
440: else
441: return null;
442: }
443:
444: /**
445: * Obtain an <code>Object</code> parameter value. If the parameter has multiple values, only the first value is returned.
446: *
447: * @param pName parameter name
448: * @return parameter value
449: */
450: public Object getObjectParameter(String pName) {
451: Object[] value_array = this .getObjectParameterValues(pName);
452: if ((value_array != null) && (value_array.length > 0)) {
453: return value_array[0];
454: } else {
455: return null;
456: }
457: }
458:
459: /**
460: * Obtain all values for a given parameter.
461: *
462: * @param pName parameter name
463: * @return an array of parameter string values
464: */
465: public String[] getParameterValues(String pName) {
466: Object[] pars = (Object[]) super .get(pName);
467: if (pars instanceof String[]) {
468: return (String[]) pars;
469: } else {
470: return null;
471: }
472: }
473:
474: /**
475: * Obtain all values for a given parameter as <code>Object</code>s.
476: *
477: * @param pName parameter name
478: * @return a vector of parameter <code>Object[]</code> values
479: */
480: public Object[] getObjectParameterValues(String pName) {
481: return (Object[]) super .get(pName);
482: }
483:
484: /**
485: * Get an enumeration of parameter names.
486: *
487: * @return an <code>Enumeration</code> of parameter names.
488: */
489: public Enumeration getParameterNames() {
490: return (Enumeration) super .keys();
491: }
492:
493: /**
494: * Get the parameters as a Map
495: * @return a Map of parameter name-value pairs
496: */
497: public Map<String, Object> getParameters() {
498: Map<String, Object> params = new java.util.HashMap(this .size());
499: Enumeration e = this .getParameterNames();
500: while (e.hasMoreElements()) {
501: String name = (String) e.nextElement();
502: String value = this .getParameter(name);
503: params.put(name, value);
504: }
505: return params;
506: }
507:
508: /**
509: * Sets the keywords
510: * @param keywords a String of keywords
511: */
512: public void setKeywords(String keywords) {
513: this .keywords = keywords;
514: }
515:
516: /**
517: * Returns the keywords
518: * @return a String of keywords, null if there were none
519: */
520: public String getKeywords() {
521: return keywords;
522: }
523:
524: /**
525: * @return the remote address
526: */
527: public String getRemoteAddress() {
528: return remoteAddress;
529: }
530:
531: /**
532: * @param string
533: */
534: public void setRemoteAddress(String string) {
535: remoteAddress = string;
536: }
537:
538: public String toString() {
539: StringBuffer sb = new StringBuffer();
540: sb.append("ChannelRuntimeData: map=[").append(super .toString())
541: .append("]");
542: sb.append(" browserInfo = [").append(this .binfo).append("] ");
543: sb.append(" locales = [").append(this .locales).append("] ");
544: sb.append(" channelUPFile = [").append(this .channelUPFile)
545: .append("] ");
546: sb.append(" baseActionURL = [").append(this .baseActionURL)
547: .append("] ");
548: sb.append(" httpRequestMethod = [").append(
549: this .httpRequestMethod).append("] ");
550: sb.append(" remoteAddress = [").append(this .remoteAddress)
551: .append("] ");
552: sb.append(" keywords = [").append(this .keywords).append("] ");
553: sb.append(" renderingAsRoot = [").append(this .renderingAsRoot)
554: .append("] ");
555: sb.append(" targeted = [").append(this .targeted).append("]");
556:
557: return sb.toString();
558: }
559:
560: }
|