source: greenstone3/trunk/src/java/org/greenstone/gsdl3/core/Skin.java@ 16374

Last change on this file since 16374 was 16374, checked in by davidb, 16 years ago

Change to Skin code (returning Node note Element) so XSLT encodes its DocType -- important information for IE to render resultant HTML correctly. This also required Skin.java to be changed from using DomResult to StreamResult. The former is known to have a problem with loosing its DocType info, and as it's then read-only, has no elegant way to put back this info.

File size: 14.0 KB
Line 
1package org.greenstone.gsdl3.core;
2
3import java.io.*;
4
5import org.apache.xerces.parsers.DOMParser;
6import org.greenstone.gsdl3.util.*;
7import org.w3c.dom.*;
8import org.xml.sax.InputSource;
9
10import java.util.*;
11import javax.xml.transform.*;
12import javax.xml.transform.dom.*;
13import javax.xml.transform.dom.DOMSource;
14import javax.xml.transform.stream.*;
15
16
17
18
19public class Skin {
20
21 public File rootDirectory ;
22 public Document config ;
23 private Receptionist receptionist ;
24
25 protected DOMParser parser = null;
26 TransformerFactory transformerFactory=null;
27
28 // delete this later??
29 //protected XMLConverter converter = null;
30
31 private HashMap<String, String> xsltPagesByAction ;
32
33 public Skin(Page page, Receptionist receptionist) throws Exception{
34
35 this.receptionist = receptionist ;
36 this.transformerFactory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
37 //this.converter = new XMLConverter();
38 transformerFactory.setURIResolver(new MyUriResolver()) ;
39
40 this.parser = new DOMParser();
41 this.parser.setFeature("http://xml.org/sax/features/validation", true);
42 // don't try and load external DTD - no need if we are not validating, and may cause connection errors if a proxy is not set up.
43 this.parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
44 // a performance test showed that having this on lead to increased
45 // memory use for small-medium docs, and not much gain for large
46 // docs.
47 // http://www.sosnoski.com/opensrc/xmlbench/conclusions.html
48 this.parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
49
50
51
52 String siteHome = GSFile.siteHome(GlobalProperties.getGSDL3Home(), page.getSite()) ;
53 Document collectUi = page.getCollectUi() ;
54
55 if (collectUi != null) {
56 //System.out.println("looking for skin defined at collect level") ;
57
58 String collectHome = GSFile.collectionBaseDir(siteHome, page.getCollection()) ;
59 Element xmlSkin = (Element) GSXML.getChildByTagName(collectUi.getFirstChild(), "skin") ;
60 if (xmlSkin != null) {
61 //System.out.println("skin defined at collect level") ;
62
63 boolean inherit = Boolean.parseBoolean(xmlSkin.getAttribute("inherit")) ;
64
65 if (inherit != true) {
66 boolean local = Boolean.parseBoolean(xmlSkin.getAttribute("local")) ;
67 if (local == true) {
68 rootDirectory = new File(collectHome + File.separatorChar + "ui") ;
69 } else {
70 String name = xmlSkin.getAttribute("name") ;
71 rootDirectory = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "skins" + File.separatorChar + File.separatorChar + name) ;
72 }
73 }
74 }
75 }
76
77 Document siteUi = page.getSiteUi() ;
78
79 if (rootDirectory == null && siteUi != null) {
80 //System.out.println("lookding for skin defined at site level") ;
81
82 Element xmlSkin = (Element) GSXML.getChildByTagName(siteUi.getFirstChild(), "skin") ;
83 if (xmlSkin != null) {
84 //System.out.println("skin defined at site level") ;
85 boolean local = Boolean.parseBoolean(xmlSkin.getAttribute("local")) ;
86 if (local == true) {
87 rootDirectory = new File(siteHome + File.separatorChar + "ui") ;
88 } else {
89 String name = xmlSkin.getAttribute("name") ;
90 rootDirectory = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "skins" + File.separatorChar + name) ;
91 }
92 }
93 }
94
95 if(rootDirectory == null) {
96 rootDirectory = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "skins" + File.separatorChar + "default") ;
97 }
98
99
100 File configFile = new File(rootDirectory.getAbsolutePath() + File.separatorChar + "skin.xml") ;
101 config = receptionist.converter.getDOM(configFile, "utf-8");
102
103
104 // store which xslt pages are responsible for which actions
105
106 xsltPagesByAction = new HashMap() ;
107
108 NodeList actions = config.getElementsByTagName("action") ;
109
110 for (int ai=0 , an=actions.getLength() ; ai<an ; ai++){
111 Element action = (Element) actions.item(ai) ;
112 String a = action.getAttribute("name") ;
113
114 String xsl = action.getAttribute("xslt") ;
115 if (!xsl.equals(""))
116 xsltPagesByAction.put(a, xsl) ;
117
118 NodeList subactions = action.getElementsByTagName("subaction") ;
119
120 for (int si=0 , sn=subactions.getLength() ; si<sn ; si++){
121 Element subaction = (Element) subactions.item(si) ;
122
123 String sa = subaction.getAttribute("name") ;
124 xsl = subaction.getAttribute("xslt") ;
125 xsltPagesByAction.put(a + "_" + sa, xsl) ;
126 }
127 }
128 }
129
130 private Document getXSLTDoc(String action, String subaction) throws Exception {
131 //System.out.println("getting xslt for " + action + ", " + subaction) ;
132
133 String name = xsltPagesByAction.get(action + "_" + subaction) ;
134
135 if (name == null)
136 name = xsltPagesByAction.get(action) ;
137
138 File xslt_file = new File(rootDirectory.getAbsolutePath() + File.separatorChar + "xsl" + File.separatorChar + name) ;
139 //System.out.println("Skinning page using: " + xslt_file) ;
140
141 //if (!xslt_file.canRead())
142 // xslt_file = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "xslt" + File.separatorChar + "error.xsl") ;
143
144 FileReader reader = new FileReader(xslt_file);
145 InputSource xml_source = new InputSource(reader);
146 this.parser.parse(xml_source);
147 Document doc = this.parser.getDocument();
148
149 return doc ;
150 }
151
152 private Document getPreprocessDoc() throws Exception {
153
154 File xslt_file = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "xslt" + File.separatorChar + "preProcess.xsl") ;
155
156 FileReader reader = new FileReader(xslt_file);
157 InputSource xml_source = new InputSource(reader);
158 this.parser.parse(xml_source);
159 Document doc = this.parser.getDocument();
160
161 return doc ;
162 }
163
164 private Document getLibraryDoc() throws Exception {
165
166 File xslt_file = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "xslt" + File.separatorChar + "library.xsl") ;
167
168 FileReader reader = new FileReader(xslt_file);
169 InputSource xml_source = new InputSource(reader);
170 this.parser.parse(xml_source);
171 Document doc = this.parser.getDocument();
172
173 return doc ;
174 }
175
176
177 public Node transformPage(Page page) throws Exception{
178
179 Element p = page.getPage() ;
180 Element pr = page.getPageResponse() ;
181 Element transformedPage = null ;
182
183 Element blah = receptionist.doc.createElement("Skin") ;
184 blah.setAttribute("skinLocation", rootDirectory.getAbsolutePath()) ;
185 pr.appendChild(blah) ;
186
187 Document sourceXml ;
188 try {
189 sourceXml = receptionist.converter.newDOM();
190 sourceXml.appendChild(sourceXml.importNode(p, true));
191 } catch (Exception e) {
192 System.out.println("error loading source data") ;
193 e.printStackTrace() ;
194 return constructErrorPage(e) ;
195 }
196
197 Document skinXsl ;
198 try {
199 skinXsl = getXSLTDoc(page.getAction(), page.getSubaction()) ;
200 } catch (Exception e) {
201 System.out.println("error loading skin xslt") ;
202 e.printStackTrace() ;
203 return constructErrorPage(e) ;
204 }
205
206 Document preprocessingXsl ;
207 try {
208 preprocessingXsl = getPreprocessDoc() ;
209 } catch (Exception e) {
210 System.out.println("error loading preprocessing xslt") ;
211 e.printStackTrace() ;
212 return constructErrorPage(e) ;
213 }
214
215 Document libraryXsl ;
216 try {
217 libraryXsl = getLibraryDoc() ;
218 } catch (Exception e) {
219 System.out.println("error loading preprocessing xslt") ;
220 e.printStackTrace() ;
221 return constructErrorPage(e) ;
222 }
223
224 // combine skin file and library variables/templates into one document.
225 // we dont just use xsl:import because the preprocessing stage needs
226 // to know what's available in the library.
227
228 Document skinAndLibraryXsl ;
229 Document processedXsl = receptionist.converter.newDOM();
230 try {
231
232 skinAndLibraryXsl = receptionist.converter.newDOM();
233 Element root = skinAndLibraryXsl.createElement("skinAndLibraryXsl") ;
234 skinAndLibraryXsl.appendChild(root) ;
235
236 Element s = skinAndLibraryXsl.createElement("skinXsl") ;
237 s.appendChild(skinAndLibraryXsl.importNode(skinXsl.getDocumentElement(), true)) ;
238 root.appendChild(s) ;
239
240 Element l = skinAndLibraryXsl.createElement("libraryXsl") ;
241 l.appendChild(skinAndLibraryXsl.importNode(libraryXsl.getDocumentElement(), true)) ;
242 root.appendChild(l) ;
243
244
245 System.out.println("Pre - processing") ;
246 //pre-process the skin style sheet
247 Transformer preProcessor = transformerFactory.newTransformer(new DOMSource(preprocessingXsl));
248 DOMResult result = new DOMResult();
249 result.setNode(processedXsl) ;
250 preProcessor.transform(new DOMSource(skinAndLibraryXsl), result);
251 } catch (TransformerException e) {
252 return constructErrorPage(e) ;
253 } catch (Exception e) {
254 System.out.println("error preprocessing the skin xslt") ;
255 e.printStackTrace() ;
256 return constructErrorPage(e) ;
257 }
258
259 //return sourceXml.getDocumentElement() ;
260
261 // Document finalPage = receptionist.converter.newDOM(); // ****
262 Document finalPageParsed = null;
263
264 //transform source doc
265 try {
266
267 /*
268 //Tranform XSL DOM to String
269 TransformerFactory tf = TransformerFactory.newInstance();
270 Transformer trans = tf.newTransformer();
271 StringWriter sw = new StringWriter();
272 trans.transform(new DOMSource(processedXsl), new StreamResult(sw));
273 // String theXSLAnswer = sw.toString(); // ****
274
275
276 //Tranform XML DOM to String
277 TransformerFactory tf2 = TransformerFactory.newInstance();
278 Transformer trans2 = tf2.newTransformer();
279 StringWriter sw2 = new StringWriter();
280 trans2.transform(new DOMSource(sourceXml), new StreamResult(sw2));
281 //String theXMLAnswer = sw2.toString();
282 */
283
284 Transformer transformer = transformerFactory.newTransformer(new DOMSource(processedXsl));
285 // transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
286 //DOMResult result = new DOMResult();
287 //result.setNode(finalPage);
288
289 //transformer.transform(new DOMSource(sourceXml), result2);
290 StringWriter result2 = new StringWriter();
291 transformer.transform(new DOMSource(sourceXml), new StreamResult(result2));
292
293 XMLConverter converter = new XMLConverter();
294 finalPageParsed = converter.getDOM(result2.toString());
295
296 } catch (TransformerException e) {
297 return constructErrorPage(e) ;
298 } catch (Exception e) {
299
300 System.out.println("error transforming page") ;
301 e.printStackTrace() ;
302
303 //return processedXsl.getDocumentElement() ;
304 return constructErrorPage(e) ;
305 }
306
307 return finalPageParsed;
308 }
309
310 private Element constructErrorPage(TransformerException exception) {
311 Element page = receptionist.doc.createElement("page") ;
312
313 Element header = receptionist.doc.createElement("h1") ;
314 header.setTextContent("Error") ;
315 page.appendChild(header) ;
316
317 Element prompt = receptionist.doc.createElement("p") ;
318 prompt.setTextContent("The following exception occured: ") ;
319 page.appendChild((prompt)) ;
320
321 Element errorXml = receptionist.doc.createElement("code") ;
322 errorXml.setTextContent(exception.getMessageAndLocation()) ;
323 page.appendChild(errorXml) ;
324
325 return page ;
326
327 }
328
329 private Element constructErrorPage(Exception exception) {
330 Element page = receptionist.doc.createElement("page") ;
331
332 Element header = receptionist.doc.createElement("h1") ;
333 header.setTextContent("Error") ;
334 page.appendChild(header) ;
335
336 Element prompt = receptionist.doc.createElement("p") ;
337 prompt.setTextContent("The following exception occured: ") ;
338 page.appendChild((prompt)) ;
339
340 Element errorXml = receptionist.doc.createElement("code") ;
341 errorXml.setTextContent(exception.toString()) ;
342 page.appendChild(errorXml) ;
343
344
345 return page ;
346 }
347
348
349 private Element constructErrorPage(Element source, Document style, Exception exception) {
350 Element page = receptionist.doc.createElement("page") ;
351
352 Element header = receptionist.doc.createElement("h1") ;
353 header.setTextContent("Error") ;
354 page.appendChild(header) ;
355
356 Element prompt = receptionist.doc.createElement("p") ;
357 prompt.setTextContent("The following exception occured: ") ;
358 page.appendChild((prompt)) ;
359
360 Element errorXml = receptionist.doc.createElement("code") ;
361 errorXml.setTextContent(exception.getMessage()) ;
362 page.appendChild(errorXml) ;
363
364 /*
365 Element stackTrace = receptionist.doc.createElement("ul") ;
366
367 StackTraceElement[] st = exception.getStackTrace() ;
368 for (int i=0 ; i< st.length ; i++) {
369 Element ste = receptionist.doc.createElement("li") ;
370 ste.setTextContent(st[i].toString()) ;
371 stackTrace.appendChild(ste) ;
372 }
373 errorMessage.appendChild(stackTrace) ;
374 */
375
376 Element sourceHeader = receptionist.doc.createElement("h2") ;
377 sourceHeader.setTextContent("Source page:") ;
378 page.appendChild(sourceHeader) ;
379
380 Element sourceXml = receptionist.doc.createElement("pre") ;
381 sourceXml.setTextContent(receptionist.converter.getPrettyString(source)) ;
382 page.appendChild(sourceXml) ;
383
384 Element styleHeader = receptionist.doc.createElement("h2") ;
385 styleHeader.setTextContent("Style page:") ;
386 page.appendChild(styleHeader) ;
387
388 Element styleXml = receptionist.doc.createElement("pre") ;
389 styleXml.setTextContent(receptionist.converter.getPrettyString(style)) ;
390 page.appendChild(styleXml) ;
391
392
393 return (Element)page ;
394 }
395
396 private class MyUriResolver implements URIResolver {
397
398 public Source resolve(String href, String base) {
399
400 System.out.println("resolving href='" + href + "', base='" + base + "'") ;
401
402 // check in the skin directory first
403
404 File file = new File(rootDirectory.getAbsolutePath() + File.separatorChar + "xslt" + File.separatorChar + href) ;
405
406 // then check in the xslt library directory
407 if (!file.canRead())
408 file = new File(GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "xslt" + File.separatorChar + href) ;
409
410 if (file.canRead()) {
411 Source source = new StreamSource(file) ;
412 return source ;
413 } else
414 return null ;
415 }
416
417 }
418
419
420}
421
Note: See TracBrowser for help on using the repository browser.