001: /* Copyright 2003 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.layout.dlm.channels.guide;
007:
008: import java.io.File;
009: import java.util.HashMap;
010: import java.util.Map;
011:
012: import javax.xml.parsers.DocumentBuilder;
013: import javax.xml.parsers.DocumentBuilderFactory;
014:
015: import org.jasig.portal.ChannelCacheKey;
016: import org.jasig.portal.ChannelRuntimeData;
017: import org.jasig.portal.ICacheable;
018: import org.jasig.portal.PortalEvent;
019: import org.jasig.portal.PortalException;
020: import org.jasig.portal.ResourceMissingException;
021: import org.jasig.portal.channels.CAbstractXslt;
022: import org.jasig.portal.utils.DTDResolver;
023: import org.jasig.portal.utils.ResourceLoader;
024: import org.w3c.dom.Document;
025:
026: /**
027: * A simple channel for introducing the capabilities of DLM in the portal. This
028: * channel gets its content from a file, "dlmIntro.html", included with the
029: * channel's source.
030: *
031: * @author mboyd@sungardsct.com
032: */
033: public class DlmIntroChannel extends CAbstractXslt implements
034: ICacheable {
035: private Map cacheKeys = new HashMap();
036: private String mediaBase = null;
037: private static final String CONTENT_FILE = "dlmIntro.xml";
038: private static final String STYLESHEET_FILE = "dlmIntro.xsl";
039: private String currentSection = "1";
040:
041: /**
042: * Create a globally shared cache key for a section with the validity
043: * object being a string of the long value representing the last time
044: * that the content file was updated.
045: *
046: * @return
047: */
048: private ChannelCacheKey initKey(String id) {
049: ChannelCacheKey key = new ChannelCacheKey();
050: key.setKeyScope(ChannelCacheKey.INSTANCE_KEY_SCOPE);
051: key.setKey(this .getClass().getName() + ":" + id);
052:
053: try {
054: File contentFile = ResourceLoader.getResourceAsFile(this
055: .getClass(), CONTENT_FILE);
056: long contentModified = contentFile.lastModified();
057: File stylesheetFile = ResourceLoader.getResourceAsFile(this
058: .getClass(), STYLESHEET_FILE);
059: long stylesheetModified = stylesheetFile.lastModified();
060: if (contentModified > stylesheetModified)
061: key.setKeyValidity("" + contentModified);
062: else
063: key.setKeyValidity("" + stylesheetModified);
064: } catch (ResourceMissingException e) {
065: // if we can't tell when the file was modified then it will
066: // force rendering everytime. This should never happen but
067: // handles that scenario if it does occur.
068: key.setKeyValidity("1");
069: }
070: return key;
071: }
072:
073: /**
074: * Return our cache key which is a system cache key so all users share
075: * the same output and it never changes meaning that it never regenerates.
076: *
077: * @see org.jasig.portal.ICacheable#generateKey()
078: */
079: public ChannelCacheKey generateKey() {
080: ChannelCacheKey key = (ChannelCacheKey) this .cacheKeys
081: .get(currentSection);
082: if (key == null) // haven't asked for this section yet
083: key = initKey(currentSection);
084:
085: return key;
086: }
087:
088: public boolean isCacheValid(Object validity) {
089: try {
090: long lastRefreshed = Long.parseLong((String) validity);
091: File contentFile = ResourceLoader.getResourceAsFile(this
092: .getClass(), CONTENT_FILE);
093: File stylesheetFile = ResourceLoader.getResourceAsFile(this
094: .getClass(), STYLESHEET_FILE);
095: long contentModified = contentFile.lastModified();
096: // TODO remove stylesheet checking after development done since
097: // it gets cached and regular users can't purge the cache.
098: long stylesheetModified = stylesheetFile.lastModified();
099:
100: if (contentModified > lastRefreshed
101: || stylesheetModified > lastRefreshed)
102: return false;
103: return true;
104: } catch (ResourceMissingException e) {
105: // exception can't be thrown from here so toss this to force it to
106: // look again for the file in renderCharacters and toss the
107: // exception there where it will be seen in the portal.
108: return false;
109: }
110: }
111:
112: /**
113: * Sets up the base media URL if not done already and determines which
114: * section is desired by the user if any.
115: */
116: @Override
117: protected void runtimeDataSet() throws PortalException {
118: ChannelRuntimeData crd = getRuntimeData();
119: // get an appropriate media path for this channel's images
120: if (mediaBase == null) {
121: mediaBase = crd.getBaseMediaURL(this );
122: String cls = getClass().getName();
123: String pkg = cls.substring(0, cls.lastIndexOf('.'));
124: mediaBase = mediaBase + pkg.replace('.', '/') + '/';
125: }
126: String section = crd.getParameter("section");
127:
128: if (section == null || section.equals(""))
129: currentSection = "1";
130: else
131: currentSection = section;
132: }
133:
134: public void receiveEvent(PortalEvent ev) {
135: // do nothing on events
136: }
137:
138: @Override
139: protected Map getStylesheetParams() throws Exception {
140: // TODO Auto-generated method stub
141:
142: Map<String, String> paramMap = new HashMap<String, String>();
143: paramMap.put("baseActionUrl", this .getRuntimeData()
144: .getBaseActionURL(true));
145: paramMap.put("baseMediaUrl", mediaBase);
146: paramMap.put("selectedSection", currentSection);
147: return paramMap;
148: }
149:
150: @Override
151: protected Document getXml() throws Exception {
152:
153: File contents = ResourceLoader.getResourceAsFile(this
154: .getClass(), CONTENT_FILE);
155:
156: DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
157: .newInstance();
158: docBuilderFactory.setNamespaceAware(true);
159: DocumentBuilder docBuilder = docBuilderFactory
160: .newDocumentBuilder();
161: DTDResolver dtdResolver = new DTDResolver();
162: docBuilder.setEntityResolver(dtdResolver);
163: Document dom = docBuilder.parse(contents);
164: return dom;
165: }
166:
167: @Override
168: protected String getXsltUri() throws Exception {
169: return STYLESHEET_FILE;
170: }
171: }
|