1/*2 * Copyright 2000-2004 The Apache Software Foundation.3 * 4 * Licensed under the Apache License, Version 2.0 (the "License");5 * you may not use this file except in compliance with the License.6 * You may obtain a copy of the License at7 * 8 * http://www.apache.org/licenses/LICENSE-2.09 * 10 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15 */1617packageorg.apache.jetspeed.portal.portlets;
1819//standard java stuff20import java.io.IOException;
21import java.io.Reader;
22import java.io.StringReader;
23import java.util.Enumeration;
24import java.util.Hashtable;
25import java.util.Iterator;
2627//Element Construction Set28import org.apache.jetspeed.util.JetspeedClearElement;
29import org.apache.ecs.ConcreteElement;
3031//standard Jetspeed stuff32import org.apache.jetspeed.util.MimeType;
33import org.apache.jetspeed.util.SimpleTransform;
34import org.apache.jetspeed.cache.disk.JetspeedDiskCache;
35import org.apache.jetspeed.portal.PortletException;
36import org.apache.jetspeed.xml.JetspeedXMLEntityResolver;
37import org.apache.jetspeed.capability.CapabilityMap;
38import org.apache.jetspeed.capability.CapabilityMapFactory;
39import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
40import org.apache.jetspeed.services.logging.JetspeedLogger;
41import org.apache.jetspeed.services.rundata.JetspeedRunData;
4243//turbine44import org.apache.turbine.util.RunData;
4546//JAXP support47import javax.xml.parsers.DocumentBuilder;
48import javax.xml.parsers.DocumentBuilderFactory;
4950//XML stuff51import org.w3c.dom.Document;
52import org.w3c.dom.Node;
53import org.w3c.dom.NodeList;
54import org.xml.sax.InputSource;
55import org.xml.sax.SAXException;
5657/***58<p>Portlet which renders RDF Site Summary.</p>59<p>This portlet uses XML stylesheet for transforming the RSS60content into display markup depending on the MimeType requested61by the user-agent</p>62<p>It accepts the following parameters :63<dl>64<dt>itemDisplayed</dt>65<dd>The number of items from the RSS file to display on screen. Default 15 for HTML, 5 for WML</dd>66<dt>showDescription</dt>67<dd>Should the portlet show the item descriptions. Must be true or false. Default: true for HTML, false for WML</dd>68<dt>showTitle</dt>69<dd>Should the portlet show the channel description. Must be true or false. Default: true for HTML, false for WML</dd>70<dt>stylesheet[.<mime>]</dt>71<dd>The stylesheet URL. If a mime-type is specified, the stylesheet72is only used for this mime-type</dd>73</dl>74@author <A HREF="mailto:raphael@apache.org">Raphaël Luta</A>75@version $Id: NewRSSPortlet.java,v 1.22 2004/02/23 04:03:34 jford Exp $76*/77publicclassNewRSSPortletextendsFileWatchPortlet78 {
7980/***81 * Static initialization of the logger for this class82 */83privatestaticfinalJetspeedLogger logger = JetspeedLogFactoryService.getLogger(NewRSSPortlet.class.getName());
8485publicfinalstatic String ERROR_NOT_VALID = "This does not appear to be an RSS document";
86publicfinalstatic String INVALID_TYPE = "Unable to display for this browser";
8788private Document document = null;
89private Hashtable stylesheets = null;
90private Hashtable params = null;
9192/***93 This method loads the init parameters and94 parse the document tied to this portlet95 */96publicvoid init( ) throws PortletException {
9798// first make sure we propagate init99super.init();
100101 DocumentBuilder parser = null;
102 String url = null;
103104// load stylesheets available105 stylesheets = new Hashtable();
106 params = new Hashtable();
107 Iterator i = this.getPortletConfig().getInitParameterNames();
108while (i.hasNext()) {
109 String name = (String)i.next();
110 String base = MimeType.HTML.toString();
111112if (name.startsWith("stylesheet")) {
113int idx=-1;
114if ((idx=name.indexOf("."))>-1) {
115 base= name.substring(idx+1,name.length());
116 }
117 stylesheets.put(base, getPortletConfig().getInitParameter(name));
118 } else {
119 params.put(name.toLowerCase(), getPortletConfig().getInitParameter(name));
120 }
121 }
122123// read content, clean it, parse it and cache the DOM124try125 {
126final DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
127//Have it non-validating128 docfactory.setValidating(false);
129 parser= docfactory.newDocumentBuilder();
130 parser.setEntityResolver(newJetspeedXMLEntityResolver() );
131132 url = getPortletConfig().getURL();
133 String content = JetspeedDiskCache.getInstance().getEntry( url ).getData();
134CapabilityMap xmap =
135 CapabilityMapFactory.getCapabilityMap(CapabilityMapFactory.AGENT_XML);
136 setContent( new JetspeedClearElement(content), xmap );
137 InputSource isrc = new InputSource( this.cleanse( content ) );
138 isrc.setSystemId( url );
139 isrc.setEncoding("UTF-8");
140this.document = parser.parse( isrc );
141this.setMetainfo(document);
142143 } catch ( Throwable t )
144 {
145146 String message = "RSSPortlet: Couldn't parse out XML document -> " +
147 url;
148149 logger.error( message, t );
150thrownewPortletException( t.getMessage() );
151 }
152153154 }
155156/***157 * Parse out title and description158 * 159 * @param document160 */161privatevoid setMetainfo(Document document) throws PortletException
162 {
163//Determine title and description for this portlet164 String title = null;
165 String description = null;
166167//now find the channel node.168 Node channel = null;
169170 NodeList list = document.getElementsByTagName( "channel" );
171172if ( list.getLength() != 1 ) {
173thrownewPortletException( ERROR_NOT_VALID );
174 }
175176 channel = list.item( 0 );
177178 Node tn = getNode( channel, "title" );
179180if ( tn == null ) {
181thrownewPortletException( ERROR_NOT_VALID );
182 }
183else184 {
185 Node fc = tn.getFirstChild();
186if (fc != null)
187 {
188 title = fc.getNodeValue();
189 }
190 }
191192 Node dn = getNode( channel, "description" );
193194if ( dn != null )
195 {
196 Node fc = dn.getFirstChild();
197if (fc != null)
198 {
199 description = fc.getNodeValue();
200 }
201 }
202203this.setTitle( title );
204this.setDescription( description );
205 }
206207/***208 This methods outputs the content of the portlet for a given209 request.210211 @param data the RunData object for the request212 @return the content to be displayed to the user-agent213 */214public ConcreteElement getContent( RunData data )
215 {
216if (org.apache.jetspeed.util.PortletSessionState.getPortletConfigChanged(this, data))
217 {
218try219 {
220 init();
221 }
222catch (PortletException pe)
223 {
224 logger.error("Exception", pe);
225 }
226 }
227CapabilityMap map = ((JetspeedRunData)data).getCapability();
228 String type = map.getPreferredType().toString();
229 ConcreteElement content = newJetspeedClearElement(INVALID_TYPE);
230 String stylesheet = (String)stylesheets.get(type);
231232if (stylesheet != null) {
233 content = getContent( data, map );
234if ( content == null ) {
235try {
236 content = newJetspeedClearElement(
237 SimpleTransform.transform( this.document,
238 stylesheet,
239this.params ) );
240 setContent( content, map );
241 } catch ( SAXException e ) {
242 logger.error("Exception", e);
243 content = newJetspeedClearElement(e.getMessage());
244 }
245 }
246 }
247else248 {
249if (map.getPreferredType().equals(MimeType.XML))
250 {
251return getContent( data, map );
252 }
253 }
254255return content;
256 }
257258/***259 This portlet supports has many types as those260 it has stylesheets defined for in its parameters261262 @see Portlet#supportsType263 @param mimeType the MIME type queried264 @return true if the portlet knows how to display265 content for mimeType266 */267publicboolean supportsType( MimeType mimeType ) {
268269 Enumeration en = stylesheets.keys();
270while(en.hasMoreElements()) {
271 String type = (String)en.nextElement();
272if (type.equals(mimeType.toString())) returntrue;
273 }
274275return false;
276 }
277278/***279 Utility method for traversing the document parsed280 DOM tree and retrieving a Node by tagname281282 @param start the parent node for the search283 @param name the tag name to be searched for284 @return the first child node of start whose tagname285 is name286 */287privatefinal Node getNode( Node start, String name ) {
288289 NodeList list = start.getChildNodes();
290291for ( int i = 0; i < list.getLength(); ++i ) {
292293 Node node = list.item( i );
294295if ( node.getNodeName().equals( name ) ) {
296return node;
297 }
298 }
299returnnull;
300 }
301302/***303 Given a URL to some content, clean the content to Xerces can handle it304 better. Right now this involves:305 <ul>306 <li>307 If the document doesn't begin with "<?xml version=" truncate the308 content until this is the first line309 </li>310311 </ul>312313 */314private Reader cleanse( String content ) throws IOException {
315316 String filtered = null;
317318//specify the XML declaration to search for... this is just a subset319//of the content but it will always exist.320 String XMLDECL = "<?xml version=";
321322int start = content.indexOf( XMLDECL );
323324if ( start <= 0 ) {
325 filtered = content;
326 } else {
327 filtered = content.substring( start, content.length() );
328 }
329330returnnew StringReader( filtered );
331 }
332333 }
334