1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.jetspeed.portal.portlets.viewprocessor;
17
18
19 import java.io.Reader;
20 import java.io.StringReader;
21 import java.util.Enumeration;
22 import java.util.Hashtable;
23 import java.util.Iterator;
24 import java.io.IOException;
25
26
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29
30
31 import org.apache.jetspeed.cache.disk.JetspeedDiskCache;
32 import org.apache.jetspeed.capability.CapabilityMap;
33 import org.apache.jetspeed.capability.CapabilityMapFactory;
34 import org.apache.jetspeed.portal.Portlet;
35 import org.apache.jetspeed.portal.PortletException;
36 import org.apache.jetspeed.portal.portlets.GenericMVCContext;
37 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
38 import org.apache.jetspeed.services.logging.JetspeedLogger;
39 import org.apache.jetspeed.services.rundata.JetspeedRunData;
40 import org.apache.jetspeed.util.JetspeedClearElement;
41 import org.apache.jetspeed.util.MimeType;
42 import org.apache.jetspeed.util.SimpleTransform;
43 import org.apache.jetspeed.xml.JetspeedXMLEntityResolver;
44
45
46 import org.apache.ecs.ConcreteElement;
47
48
49 import org.apache.turbine.util.RunData;
50
51
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Node;
54 import org.w3c.dom.NodeList;
55 import org.xml.sax.InputSource;
56 import org.xml.sax.SAXException;
57
58 /***
59 * Simple ViewProcessor which does a basic XSLT transform with the stylesheet parameter
60 * and the given URL.
61 *
62 * @author tkuebler@cisco.com
63 * @version $Id: $
64 * @since 1.4b4
65 */
66
67 public class XSLViewProcessor implements ViewProcessor
68 {
69
70 /***
71 * Static initialization of the logger for this class
72 */
73 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(XSLViewProcessor.class.getName());
74
75 private static final String XMLDECL = "<?xml version=";
76 public static final String ERROR_NOT_VALID = "This does not appear to be an XML document";
77 public static final String INVALID_TYPE = "Unable to display for this browser";
78 protected Document document = null;
79 protected Hashtable stylesheets = null;
80 private Hashtable params = null;
81
82 /***
83 * This method loads the init parameters and
84 * parse the document tied to this portlet
85 *
86 * @param portlet
87 * @exception PortletException
88 */
89 public void init(Portlet portlet)
90 throws PortletException
91 {
92
93 DocumentBuilder parser = null;
94 String url = null;
95
96
97 stylesheets = new Hashtable();
98 params = new Hashtable();
99
100 Iterator i = portlet.getPortletConfig().getInitParameterNames();
101
102 while (i.hasNext())
103 {
104
105 String name = (String) i.next();
106 String base = MimeType.HTML.toString();
107
108 if (name.startsWith("stylesheet"))
109 {
110
111 int idx = -1;
112
113 if ((idx = name.indexOf(".")) > -1)
114 {
115 base = name.substring(idx + 1, name.length());
116 }
117
118 stylesheets.put(base, portlet.getPortletConfig().getInitParameter(name));
119 }
120 else
121 {
122 params.put(name.toLowerCase(), portlet.getPortletConfig().getInitParameter(name));
123 }
124 }
125
126
127 try
128 {
129
130 final DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
131
132
133 docfactory.setValidating(false);
134 parser = docfactory.newDocumentBuilder();
135 parser.setEntityResolver(new JetspeedXMLEntityResolver());
136 url = portlet.getPortletConfig().getURL();
137
138 String content = JetspeedDiskCache.getInstance().getEntry(url).getData();
139 CapabilityMap xmap = CapabilityMapFactory.getCapabilityMap(CapabilityMapFactory.AGENT_XML);
140
141
142 InputSource isrc = new InputSource(this.cleanse(content));
143 isrc.setSystemId(url);
144 isrc.setEncoding("UTF-8");
145 this.document = parser.parse(isrc);
146 }
147 catch (Throwable t)
148 {
149
150 String message = "XSLViewProcessor: Couldn't parse out XML document -> " + url;
151 logger.error(message, t);
152 throw new PortletException(t.getMessage());
153 }
154
155 }
156
157 /***
158 * This methods outputs the content of the portlet for a given
159 * request.
160 *
161 * @param context
162 * @return the content to be displayed to the user-agent
163 */
164 public Object processView(GenericMVCContext context)
165 {
166
167 try
168 {
169 init((Portlet) context.get("portlet"));
170 }
171 catch (PortletException pe)
172 {
173 logger.error("XSLViewProcessor - error: " + pe.getMessage(), pe);
174 }
175
176 RunData data = (RunData) context.get("data");
177 CapabilityMap map = ((JetspeedRunData) data).getCapability();
178 String type = map.getPreferredType().toString();
179 ConcreteElement content = new JetspeedClearElement(INVALID_TYPE);
180 String stylesheet = (String) stylesheets.get(type);
181
182 if (stylesheet != null)
183 {
184
185 try
186 {
187 content = new JetspeedClearElement(SimpleTransform.transform(this.document, stylesheet, this.params));
188
189
190 }
191 catch (SAXException e)
192 {
193 logger.error("SAXException", e);
194 content = new JetspeedClearElement(e.getMessage());
195 }
196 }
197 else
198 {
199 content = new JetspeedClearElement("stylesheet not defined");
200 }
201
202 return content;
203 }
204
205 /***
206 * This portlet supports has many types as those
207 * it has stylesheets defined for in its parameters
208 *
209 * @param mimeType the MIME type queried
210 * @return true if the portlet knows how to display
211 * content for mimeType
212 * @see Portlet#supportsType
213 */
214 public boolean supportsType(MimeType mimeType)
215 {
216
217 Enumeration en = stylesheets.keys();
218
219 while (en.hasMoreElements())
220 {
221
222 String type = (String) en.nextElement();
223
224 if (type.equals(mimeType.toString()))
225 {
226
227 return true;
228 }
229 }
230
231 return false;
232 }
233
234 /***
235 * Utility method for traversing the document parsed
236 * DOM tree and retrieving a Node by tagname
237 *
238 * @param start the parent node for the search
239 * @param name the tag name to be searched for
240 * @return the first child node of start whose tagname
241 * is name
242 */
243 protected Node getNode(Node start, String name)
244 {
245
246 NodeList list = start.getChildNodes();
247
248 for (int i = 0; i < list.getLength(); ++i)
249 {
250
251 Node node = list.item(i);
252
253 if (node.getNodeName().equals(name))
254 {
255
256 return node;
257 }
258 }
259
260 return null;
261 }
262
263 /***
264 * Given a URL to some content, clean the content to Xerces can handle it
265 * better. Right now this involves:
266 * <ul>
267 * <li>
268 * If the document doesn't begin with "<?xml version=" truncate the
269 * content until this is the first line
270 * </li>
271 *
272 * </ul>
273 *
274 * @param content
275 * @return
276 * @exception IOException
277 */
278 protected Reader cleanse(String content)
279 throws IOException
280 {
281
282 String filtered = null;
283 int start = content.indexOf(XMLDECL);
284
285 if (start <= 0)
286 {
287 filtered = content;
288 }
289 else
290 {
291 filtered = content.substring(start, content.length());
292 }
293
294 return new StringReader(filtered);
295 }
296 }