001: /* Copyright 2001 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.io.BufferedReader;
009: import java.io.IOException;
010: import java.io.InputStream;
011: import java.io.InputStreamReader;
012: import java.io.OutputStreamWriter;
013: import java.io.UnsupportedEncodingException;
014: import java.net.URL;
015: import java.util.StringTokenizer;
016: import java.util.Vector;
017:
018: import javax.servlet.http.HttpServletRequest;
019:
020: import org.jasig.portal.properties.PropertiesManager;
021: import org.jasig.portal.serialize.BaseMarkupSerializer;
022: import org.jasig.portal.serialize.CachingHTMLSerializer;
023: import org.jasig.portal.serialize.CachingXHTMLSerializer;
024: import org.jasig.portal.serialize.OutputFormat;
025: import org.jasig.portal.serialize.XMLSerializer;
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028:
029: /**
030: * A tool for managing various media properties.
031: * Given a request object, MediaManager determines
032: * a client browser type (media). MediaManager also
033: * provides information on the mime type that generated
034: * response should carry.
035: * @author Peter Kharchenko
036: * @version $Revision: 36781 $
037: */
038: public class MediaManager {
039:
040: private static final Log log = LogFactory
041: .getLog(MediaManager.class);
042:
043: protected OrderedProps mediaProps = null;
044: protected OrderedProps mimeProps = null;
045: protected OrderedProps serializerProps = null;
046: private static boolean outputIndenting = PropertiesManager
047: .getPropertyAsBoolean(
048: "org.jasig.portal.MediaManager.output_indenting",
049: false);
050: /**
051: * In uPortal 2.5.x, this property defaulted to true. As of uPortal 2.6.0,
052: * it defaults to false.
053: */
054: private boolean omitDoctype = PropertiesManager
055: .getPropertyAsBoolean(
056: "org.jasig.portal.MediaManager.omit_doctype", false);
057:
058: private static final String mediaPropsUrl = MediaManager.class
059: .getResource("/properties/media.properties").toString();
060: private static final String mimePropsUrl = MediaManager.class
061: .getResource("/properties/mime.properties").toString();
062: private static final String serializerPropsUrl = MediaManager.class
063: .getResource("/properties/serializer.properties")
064: .toString();
065:
066: private static final MediaManager MEDIAMANAGER = new MediaManager(
067: mediaPropsUrl, mimePropsUrl, serializerPropsUrl);
068: private static final MediaManager MEDIAMANAGER_OMIT_DOCTYPE = new MediaManager(
069: mediaPropsUrl, mimePropsUrl, serializerPropsUrl, true);
070: private static final MediaManager MEDIAMANAGER_INCLUDE_DOCTYPE = new MediaManager(
071: mediaPropsUrl, mimePropsUrl, serializerPropsUrl, false);
072:
073: /**
074: * A user agent string to use when the user-agent header value itself is null.
075: *
076: */
077: public static final String NULL_USER_AGENT = "null";
078: public static final String UNKNOWN = "unknown";
079:
080: //doctype fields
081: public static String HTMLPublicId = PropertiesManager.getProperty(
082: "org.jasig.portal.MediaManager.HTMLPublicId",
083: "-//W3C//DTD HTML 4.01 Transitional//EN");
084: public static String HTMLSystemId = PropertiesManager.getProperty(
085: "org.jasig.portal.MediaManager.HTMLSystemId",
086: "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd");
087: public static String XHTMLPublicId = PropertiesManager.getProperty(
088: "org.jasig.portal.MediaManager.XHTMLPublicId",
089: "-//W3C//DTD XHTML 1.0 Transitional//EN");
090: public static String XHTMLSystemId = PropertiesManager.getProperty(
091: "org.jasig.portal.MediaManager.XHTMLSystemId",
092: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
093: public static String WMLPublicId = PropertiesManager.getProperty(
094: "org.jasig.portal.MediaManager.WMLPublicId",
095: "-//WAPFORUM//DTD WML 1.1//EN");
096: public static String WMLSystemId = PropertiesManager.getProperty(
097: "org.jasig.portal.MediaManager.WMLSystemId",
098: "http://www.wapforum.org/DTD/wml_1.1.xml");
099:
100: /**
101: * Constructs a MediaManager
102: */
103: private MediaManager() {
104: }
105:
106: /**
107: * 7/25/05 - UP-1181 - change MediaManager into a singleton
108: *
109: * Returns the default MediaManager singleton
110: */
111: public static MediaManager getMediaManager() {
112: return (MEDIAMANAGER);
113: }
114:
115: public static MediaManager getMediaManager(boolean omitDocType) {
116: if (omitDocType) {
117: return MEDIAMANAGER_OMIT_DOCTYPE;
118: } else {
119: return MEDIAMANAGER_INCLUDE_DOCTYPE;
120: }
121: }
122:
123: /**
124: * Constructor that initializes all of the property tables.
125: * This is equivalent to running a base constructor and
126: * setMediaProps(), setMimeProps() and setSerializerProps() afterwards.
127: *
128: * @param mediaPropsFile location of the media properties file
129: * @param mimePropsFile location of the mime properties file
130: * @param serializerPropsFile location of the serializer properties file
131: */
132: private MediaManager(String mediaPropsFile, String mimePropsFile,
133: String serializerPropsFile) {
134: setMediaProps(mediaPropsFile);
135: setMimeProps(mimePropsFile);
136: setSerializerProps(serializerPropsFile);
137: }
138:
139: /**
140: * Constructor that overrides the omitDocType setting.
141: *
142: * @param mediaPropsFile location of the media properties file
143: * @param mimePropsFile location of the mime properties file
144: * @param serializerPropsFile location of the serializer properties file
145: */
146: private MediaManager(String mediaPropsFile, String mimePropsFile,
147: String serializerPropsFile, boolean omitDocType) {
148: this (mediaPropsFile, mimePropsFile, serializerPropsFile);
149: this .omitDoctype = omitDocType;
150: }
151:
152: /**
153: * Initializes media properties table.
154: * @param uri location of the media properties file, complete with the filename
155: */
156: public void setMediaProps(String uri) {
157: URL url = null;
158: try {
159: if (uri == null)
160: url = this .getClass().getResource(
161: "/properties/media.properties");
162: else
163: url = new URL(uri);
164: if (url != null) {
165: InputStream in = url.openStream();
166: try {
167: mediaProps = new OrderedProps(in);
168: } finally {
169: in.close();
170: }
171: }
172: } catch (IOException ioe) {
173: log
174: .error("MediaManager::setMediaProps : Exception occurred while loading media properties file: "
175: + uri + ". " + ioe);
176: }
177: }
178:
179: /**
180: * Initializes mime properties table.
181: * @param uri location of the mime properties file, complete with the filename
182: */
183: public void setMimeProps(String uri) {
184: URL url = null;
185: try {
186: if (uri == null)
187: url = this .getClass().getResource(
188: "/properties/mime.properties");
189: else
190: url = new URL(uri);
191: if (url != null) {
192: InputStream in = url.openStream();
193: try {
194: mimeProps = new OrderedProps(in);
195: } finally {
196: in.close();
197: }
198: }
199: } catch (IOException ioe) {
200: log
201: .error("MediaManager::setMimeProps : Exception occurred while loading mime properties file: "
202: + uri + ". " + ioe);
203: }
204: }
205:
206: /**
207: * Initializes serializer properties table.
208: * @param uri location of the serializer properties file, complete with the filename
209: */
210: public void setSerializerProps(String uri) {
211: URL url = null;
212: try {
213: if (uri == null)
214: url = this .getClass().getResource(
215: "/properties/serializer.properties");
216: else
217: url = new URL(uri);
218: if (url != null) {
219: InputStream in = url.openStream();
220: try {
221: serializerProps = new OrderedProps(in);
222: } finally {
223: in.close();
224: }
225: }
226: } catch (IOException ioe) {
227: log
228: .error("MediaManager::setSerializerProps : Exception occurred while loading serializer properties file: "
229: + uri + ". " + ioe);
230: }
231: }
232:
233: /**
234: * Determines a media name from the request object.
235: * @param req the request object
236: * @return media name
237: */
238: public String getMedia(HttpServletRequest req) {
239: if (mediaProps == null) {
240: this .setMediaProps((String) null);
241: }
242: if (mediaProps != null) {
243: String ua = req.getHeader("User-Agent");
244: if (ua == null || ua.equals("")) {
245: ua = NULL_USER_AGENT;
246: }
247: return mediaProps.getValue(ua);
248: }
249: return (String) null;
250: }
251:
252: /**
253: * Determines a media name from the browser info object.
254: * @param bi the browser info
255: * @return media name
256: */
257: public String getMedia(BrowserInfo bi) {
258: if (mediaProps == null) {
259: this .setMediaProps((String) null);
260: }
261: if (mediaProps != null) {
262: return mediaProps.getValue(bi.getUserAgent());
263: }
264: return (String) null;
265: }
266:
267: /**
268: * Return a default media type.
269: * The default media type is the first
270: * media listed in the media.properties file
271: * @return default media name
272: */
273: public String getDefaultMedia() {
274: if (mediaProps == null) {
275: this .setMediaProps((String) null);
276: }
277: if (mediaProps != null) {
278: return mediaProps.getDefaultValue();
279: }
280: return (String) null;
281: }
282:
283: /**
284: * Determines a mime name from the request object.
285: * @param req the request object
286: * @return mime type string
287: */
288: public String getReturnMimeType(HttpServletRequest req) {
289: String mimeType = this .getReturnMimeType(this .getMedia(req));
290: if (UNKNOWN.equals(mimeType)) {
291: String accepts = req.getHeader("accept");
292: if (accepts != null && accepts.indexOf("text/html") != -1) {
293: mimeType = "text/html";
294: }
295: }
296: return mimeType;
297: }
298:
299: /**
300: * Determines a mime name from a media type name.
301: * @param mediaType the media type name
302: * @return mime type string
303: */
304: public String getReturnMimeType(String mediaType) {
305: if (mimeProps == null) {
306: this .setMimeProps((String) null);
307: }
308: if (mimeProps != null) {
309: return mimeProps.getValue(mediaType);
310: } else {
311: return null;
312: }
313: }
314:
315: /**
316: * Determines and configures a serialzier that is proper
317: * for the specified media type.
318: * "serializer.properties" file contains mapping of media
319: * names to serializer names.
320: * Prior to using a serializer returned by this function,
321: * make sure to set it up by calling asContentHandler(),
322: * asDocumentHandler() or asDOMSerializer().
323: *
324: * @param mediaType media name
325: * @param out output writer
326: * @return the serializer
327: */
328: public BaseMarkupSerializer getSerializer(String mediaType,
329: java.io.Writer out) {
330: // I don't like this function, here's why :
331: // 1. I would like to make it read all preferences
332: // from some kind of a .properties file, just like
333: // mime and media functions do. The problem with doing
334: // it so is that the often serializer needs additional
335: // parameters passed to it during the initialization time.
336: // For example, OutputFormat object constructor parameters
337: // are very important for WML, and there's no way to store
338: // such information in a simple properties file.
339: // So the end result is that in order to support another
340: // mark up language, one would need to edit this function
341: // and recompile the code.
342: //
343: // 2. It shouldn't be the "mediaType" passed as parameter, but
344: // the mime type. Unfortunately, there are differences in the
345: // markup rules inside a particular mime type.
346: // (i.e. netscape vs. AvantGo)
347: //
348: // please imporve on this if you can.
349: String serializerName = null;
350: if (serializerProps == null) {
351: this .setSerializerProps((String) null);
352: }
353: if (serializerProps != null) {
354: serializerName = serializerProps.getValue(mediaType);
355: }
356: if (serializerName != null) {
357: return getSerializerByName(serializerName, out);
358: } else {
359: log
360: .error("MediaManager::getSerializer() : Unable to initialize serializerProperties. Returning a null serializer object");
361: return null;
362: }
363: }
364:
365: /**
366: * Gets a serializer by name which writes to the provided OutputStream
367: * @param serializerName
368: * @param out
369: * @return the serializer
370: */
371: public BaseMarkupSerializer getSerializerByName(
372: String serializerName, java.io.OutputStream out)
373: throws UnsupportedEncodingException {
374: return getSerializerByName(serializerName,
375: new OutputStreamWriter(out, "UTF-8"));
376: }
377:
378: /**
379: * Gets a serializer by name which writes to the provided Writer
380: * @param serializerName
381: * @param out
382: * @return the serializer
383: */
384: public BaseMarkupSerializer getSerializerByName(
385: String serializerName, java.io.Writer out) {
386: if (serializerName != null && serializerName.equals("WML")) {
387: OutputFormat frmt = new OutputFormat("wml", "UTF-8", true);
388: frmt.setDoctype(WMLPublicId, WMLSystemId);
389: return new XMLSerializer(out, frmt);
390: } /* else if (serializerName != null && serializerName.equals("PalmHTML")) {
391: OutputFormat frmt = new OutputFormat("HTML", "UTF-8", true);
392: return new PalmHTMLSerializer(out, frmt);
393: } */else if (serializerName != null
394: && serializerName.equals("XML")) {
395: OutputFormat frmt = new OutputFormat("XML", "UTF-8", true);
396: return new XMLSerializer(out, frmt);
397: } else if (serializerName != null
398: && serializerName.equals("XHTML")) {
399: OutputFormat frmt = new OutputFormat("XHTML", "UTF-8", true);
400: frmt.setPreserveSpace(true);
401: frmt.setIndenting(outputIndenting);
402: frmt.setDoctype(XHTMLPublicId, XHTMLSystemId);
403: frmt.setOmitDocumentType(omitDoctype);
404: return new CachingXHTMLSerializer(out, frmt);
405: } else {
406: // default case is HTML, such as that for netscape and explorer
407: OutputFormat frmt = new OutputFormat("HTML", "UTF-8", true);
408: frmt.setPreserveSpace(true);
409: frmt.setIndenting(outputIndenting);
410: frmt.setDoctype(HTMLPublicId, HTMLSystemId);
411: frmt.setOmitDocumentType(omitDoctype);
412: return new CachingHTMLSerializer(out, frmt);
413: }
414: }
415:
416: /**
417: * Another version of getSerializer() with OutputStream as one of the parameters.
418: * @param mediaType media type string
419: * @param out output stream
420: * @return the markup serializer
421: */
422: public BaseMarkupSerializer getSerializer(String mediaType,
423: java.io.OutputStream out)
424: throws UnsupportedEncodingException {
425: return getSerializer(mediaType, new OutputStreamWriter(out,
426: "UTF-8"));
427: }
428:
429: /**
430: * Automatically determines the media type from the request object,
431: * @param req the request object
432: * @param out the output writer object
433: * @return the markup serializer
434: */
435: public BaseMarkupSerializer getSerializer(HttpServletRequest req,
436: java.io.Writer out) {
437: if (mediaProps == null) {
438: this .setMediaProps((String) null);
439: }
440: if (mediaProps != null) {
441: String ua = req.getHeader("User-Agent");
442: if (ua == null || ua.equals("")) {
443: ua = NULL_USER_AGENT;
444: }
445: return getSerializer(mediaProps.getValue(ua), out);
446: } else {
447: log
448: .error("MediaManager::getSerializer() : Unable to initialize mediaProperties. Returning a null serializer object");
449: return null;
450: }
451: }
452:
453: /**
454: * Automatically determines the media type from the request object,
455: * @param req the request object
456: * @param out the output stream object
457: * @return the markup serializer
458: */
459: public BaseMarkupSerializer getSerializer(HttpServletRequest req,
460: java.io.OutputStream out)
461: throws UnsupportedEncodingException {
462: return getSerializer(req, new OutputStreamWriter(out, "UTF-8"));
463: }
464:
465: /**
466: * COPIED FROM XALAN SOURCE
467: * Stores the keys and values from a file (similar to a properties file) and
468: * can return the first value which has a key contained in its string.
469: * File can have comment lines starting with '#" and for each line the entries are
470: * separated by tabs and '=' char.
471: */
472: class OrderedProps {
473: /**
474: * Stores the Key and Values as an array of Strings
475: */
476: private Vector attVec = new Vector(15);
477:
478: /**
479: * Constructor.
480: * @param inputStream Stream containing the properties file.
481: * @exception IOException Thrown if unable to read from stream
482: */
483: OrderedProps(InputStream inputStream) throws IOException {
484: BufferedReader input = new BufferedReader(
485: new InputStreamReader(inputStream, "UTF-8"));
486: String currentLine, Key = null;
487: StringTokenizer currentTokens;
488: while ((currentLine = input.readLine()) != null) {
489: currentTokens = new StringTokenizer(currentLine,
490: "=\t\r\n");
491: if (currentTokens.hasMoreTokens()) {
492: Key = currentTokens.nextToken().trim();
493: }
494: if ((Key != null) && !Key.startsWith("#")
495: && currentTokens.hasMoreTokens()) {
496: String temp[] = new String[2];
497: temp[0] = Key;
498: temp[1] = currentTokens.nextToken().trim();
499: attVec.addElement(temp);
500: }
501: }
502: input.close();
503: }
504:
505: /**
506: * Iterates through the Key list and returns the first value for whose
507: * key the given string contains. Returns "unknown" if no key is contained
508: * in the string.
509: * @param s String being searched for a key.
510: * @return Value for key found in string, otherwise "unknown"
511: */
512: String getValue(String s) {
513: int i, j = attVec.size();
514: for (i = 0; i < j; i++) {
515: String temp[] = (String[]) attVec.elementAt(i);
516: if (s.indexOf(temp[0]) > -1) {
517: return temp[1];
518: }
519: }
520: return UNKNOWN;
521: }
522:
523: String getDefaultValue() {
524: return ((String[]) attVec.elementAt(0))[1];
525: }
526: }
527: }
|