source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/core/TransformingReceptionist.java@ 25301

Last change on this file since 25301 was 25301, checked in by kjdon, 12 years ago

changed a method name to reflect better what it does

  • Property svn:keywords set to Author Date Id Revision
File size: 35.3 KB
Line 
1package org.greenstone.gsdl3.core;
2
3import org.greenstone.util.GlobalProperties;
4import org.greenstone.gsdl3.util.*;
5import org.greenstone.gsdl3.action.*;
6// XML classes
7import org.w3c.dom.Node;
8import org.w3c.dom.NodeList;
9import org.w3c.dom.Comment;
10import org.w3c.dom.Text;
11import org.w3c.dom.Document;
12import org.w3c.dom.Element;
13import org.xml.sax.InputSource;
14import org.w3c.dom.NamedNodeMap;
15
16// other java classes
17import java.io.ByteArrayInputStream;
18import java.io.File;
19import java.io.StringReader;
20import java.io.StringWriter;
21import java.io.FileReader;
22import java.io.FileNotFoundException;
23import java.util.ArrayList;
24import java.util.HashMap;
25import java.util.Enumeration;
26
27import javax.xml.parsers.*;
28import javax.xml.transform.*;
29import javax.xml.transform.dom.*;
30import javax.xml.transform.stream.*;
31import org.apache.log4j.*;
32import org.apache.tools.zip.ExtraFieldUtils;
33import org.apache.xerces.dom.*;
34import org.apache.xerces.parsers.DOMParser;
35
36import org.apache.commons.lang3.StringUtils;
37
38/**
39 * A receptionist that uses xslt to transform the page_data before returning it.
40 * . Receives requests consisting of an xml representation of cgi args, and
41 * returns the page of data - in html by default. The requests are processed by
42 * the appropriate action class
43 *
44 * @see Action
45 */
46public class TransformingReceptionist extends Receptionist
47{
48
49 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.TransformingReceptionist.class.getName());
50
51 /** The preprocess.xsl file is in a fixed location */
52 static final String preprocess_xsl_filename = GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "xslt" + File.separatorChar + "preProcess.xsl";
53
54 /** the list of xslt to use for actions */
55 protected HashMap xslt_map = null;
56
57 /** a transformer class to transform xml using xslt */
58 protected XMLTransformer transformer = null;
59
60 protected TransformerFactory transformerFactory = null;
61 protected DOMParser parser = null;
62
63 public TransformingReceptionist()
64 {
65 super();
66 this.xslt_map = new HashMap();
67 this.transformer = new XMLTransformer();
68 try
69 {
70 transformerFactory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
71 this.converter = new XMLConverter();
72 //transformerFactory.setURIResolver(new MyUriResolver()) ;
73
74 parser = new DOMParser();
75 parser.setFeature("http://xml.org/sax/features/validation", false);
76 // 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.
77 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
78 // a performance test showed that having this on lead to increased
79 // memory use for small-medium docs, and not much gain for large
80 // docs.
81 // http://www.sosnoski.com/opensrc/xmlbench/conclusions.html
82 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
83 parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
84 // setting a handler for when fatal errors, errors or warnings happen during xml parsing
85 // call XMLConverter's getParseErrorMessage() to get the errorstring that can be rendered as web page
86 this.parser.setErrorHandler(new XMLConverter.ParseErrorHandler());
87 }
88 catch (Exception e)
89 {
90 e.printStackTrace();
91 }
92
93 }
94
95 /** configures the receptionist - overwrite this to set up the xslt map */
96 public boolean configure()
97 {
98
99 if (this.config_params == null)
100 {
101 logger.error(" config variables must be set before calling configure");
102 return false;
103 }
104 if (this.mr == null)
105 {
106 logger.error(" message router must be set before calling configure");
107 return false;
108 }
109
110 // find the config file containing a list of actions
111 File interface_config_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))));
112 if (!interface_config_file.exists())
113 {
114 logger.error(" interface config file: " + interface_config_file.getPath() + " not found!");
115 return false;
116 }
117 Document config_doc = this.converter.getDOM(interface_config_file, "utf-8");
118 if (config_doc == null)
119 {
120 logger.error(" could not parse interface config file: " + interface_config_file.getPath());
121 return false;
122 }
123 Element config_elem = config_doc.getDocumentElement();
124 String base_interface = config_elem.getAttribute("baseInterface");
125 setUpBaseInterface(base_interface);
126 setUpInterfaceOptions(config_elem);
127
128 Element action_list = (Element) GSXML.getChildByTagName(config_elem, GSXML.ACTION_ELEM + GSXML.LIST_MODIFIER);
129 NodeList actions = action_list.getElementsByTagName(GSXML.ACTION_ELEM);
130
131 for (int i = 0; i < actions.getLength(); i++)
132 {
133 Element action = (Element) actions.item(i);
134 String class_name = action.getAttribute("class");
135 String action_name = action.getAttribute("name");
136 Action ac = null;
137 try
138 {
139 ac = (Action) Class.forName("org.greenstone.gsdl3.action." + class_name).newInstance();
140 }
141 catch (Exception e)
142 {
143 logger.error(" couldn't load in action " + class_name);
144 e.printStackTrace();
145 continue;
146 }
147 ac.setConfigParams(this.config_params);
148 ac.setMessageRouter(this.mr);
149 ac.configure();
150 ac.addActionParameters(this.params);
151 this.action_map.put(action_name, ac);
152
153 // now do the xslt map
154 String xslt = action.getAttribute("xslt");
155 if (!xslt.equals(""))
156 {
157 this.xslt_map.put(action_name, xslt);
158 }
159 NodeList subactions = action.getElementsByTagName(GSXML.SUBACTION_ELEM);
160 for (int j = 0; j < subactions.getLength(); j++)
161 {
162 Element subaction = (Element) subactions.item(j);
163 String subname = subaction.getAttribute(GSXML.NAME_ATT);
164 String subxslt = subaction.getAttribute("xslt");
165
166 String map_key = action_name + ":" + subname;
167 logger.debug("adding in to xslt map, " + map_key + "->" + subxslt);
168 this.xslt_map.put(map_key, subxslt);
169 }
170 }
171 Element lang_list = (Element) GSXML.getChildByTagName(config_elem, "languageList");
172 if (lang_list == null)
173 {
174 logger.error(" didn't find a language list in the config file!!");
175 }
176 else
177 {
178 this.language_list = (Element) this.doc.importNode(lang_list, true);
179 }
180
181 return true;
182 }
183
184 protected Node postProcessPage(Element page)
185 {
186 // might need to add some data to the page
187 addExtraInfo(page);
188 // transform the page using xslt
189 Node transformed_page = transformPage(page);
190
191 // if the user has specified they want only a part of the full page then subdivide it
192 boolean subdivide = false;
193 String excerptID = null;
194 String excerptTag = null;
195 Element request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
196 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
197 if (cgi_param_list != null)
198 {
199 HashMap params = GSXML.extractParams(cgi_param_list, false);
200 if ((excerptID = (String) params.get(GSParams.EXCERPT_ID)) != null)
201 {
202 subdivide = true;
203 }
204 if ((excerptTag = (String) params.get(GSParams.EXCERPT_TAG)) != null)
205 {
206 subdivide = true;
207 }
208 }
209
210 if (subdivide)
211 {
212 Node subdivided_page = subdivide(transformed_page, excerptID, excerptTag);
213 if (subdivided_page != null)
214 {
215 return subdivided_page;
216 }
217 }
218
219 return transformed_page;
220 }
221
222 protected Node subdivide(Node transformed_page, String excerptID, String excerptTag)
223 {
224 if (excerptID != null)
225 {
226 Node selectedElement = getNodeByIdRecursive(transformed_page, excerptID);
227 modifyNodesByTagRecursive(selectedElement, "a");
228 return selectedElement;
229 }
230 else if (excerptTag != null)
231 {
232 /*
233 * // define a list
234 *
235 * Node selectedElement =
236 * modifyNodesByTagRecursive(transformed_page, excerptTag);
237 */
238
239 Node selectedElement = getNodeByTagRecursive(transformed_page, excerptTag);
240 return selectedElement;
241
242 }
243 return transformed_page;
244 }
245
246 protected Node getNodeByIdRecursive(Node parent, String id)
247 {
248 if (parent.hasAttributes() && ((Element) parent).getAttribute("id").equals(id))
249 {
250 return parent;
251 }
252
253 NodeList children = parent.getChildNodes();
254 for (int i = 0; i < children.getLength(); i++)
255 {
256 Node result = null;
257 if ((result = getNodeByIdRecursive(children.item(i), id)) != null)
258 {
259 return result;
260 }
261 }
262 return null;
263 }
264
265 protected Node getNodeByTagRecursive(Node parent, String tag)
266 {
267 if (parent.getNodeType() == Node.ELEMENT_NODE && ((Element) parent).getTagName().equals(tag))
268 {
269 return parent;
270 }
271
272 NodeList children = parent.getChildNodes();
273 for (int i = 0; i < children.getLength(); i++)
274 {
275 Node result = null;
276 if ((result = getNodeByTagRecursive(children.item(i), tag)) != null)
277 {
278 return result;
279 }
280 }
281 return null;
282 }
283
284 protected Node modifyNodesByTagRecursive(Node parent, String tag)
285 {
286 if (parent == null || (parent.getNodeType() == Node.ELEMENT_NODE && ((Element) parent).getTagName().equals(tag)))
287 {
288 return parent;
289 }
290
291 NodeList children = parent.getChildNodes();
292 for (int i = 0; i < children.getLength(); i++)
293 {
294 Node result = null;
295 if ((result = modifyNodesByTagRecursive(children.item(i), tag)) != null)
296 {
297 //return result;
298 //logger.error("Modify node value = "+result.getNodeValue()); //NamedItem("href"););
299 //logger.error("BEFORE Modify node attribute = " + result.getAttributes().getNamedItem("href").getNodeValue());
300 //String url = result.getAttributes().getNamedItem("href").getNodeValue();
301 //url = url + "&excerptid=results";
302 //result.getAttributes().getNamedItem("href").setNodeValue(url);
303 //logger.error("AFTER Modify node attribute = " + result.getAttributes().getNamedItem("href").getNodeValue());
304 }
305 }
306 return null;
307 }
308
309 /**
310 * overwrite this to add any extra info that might be needed in the page
311 * before transformation
312 */
313 protected void addExtraInfo(Element page)
314 {
315 }
316
317 /**
318 * transform the page using xslt we need to get any format element out of
319 * the page and add it to the xslt before transforming
320 */
321 protected Node transformPage(Element page)
322 {
323 boolean allowsClientXSLT = (Boolean) config_params.get(GSConstants.ALLOW_CLIENT_SIDE_XSLT);
324 //System.out.println("Client side transforms allowed? " + allowsClientXSLT);
325
326 String currentInterface = (String) config_params.get(GSConstants.INTERFACE_NAME);
327
328 Element request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
329 String output = request.getAttribute(GSXML.OUTPUT_ATT);
330
331 //System.out.println("Current output mode is: " + output + ", current interface name is: " + currentInterface);
332
333 if (allowsClientXSLT)
334 {
335 if (!currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX) && output.equals("html"))
336 {
337 System.out.println("output is html and we are not currently using a client side version, switching");
338 // Switch the interface
339 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.concat(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX));
340 }
341 else if ((currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX) && !output.equals("html")) || output.equals("server"))
342 {
343 // The reverse needs to happen too
344 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.substring(0, currentInterface.length() - GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX.length()));
345 }
346 }
347 else if (currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX))
348 {
349 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.substring(0, currentInterface.length() - GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX.length()));
350 }
351
352 // DocType defaults in case the skin doesn't have an "xsl:output" element
353 String qualifiedName = "html";
354 String publicID = "-//W3C//DTD HTML 4.01 Transitional//EN";
355 String systemID = "http://www.w3.org/TR/html4/loose.dtd";
356
357 // We need to create an empty document with a predefined DocType,
358 // that will then be used for the transformation by the DOMResult
359 Document docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
360
361 if (output.equals("xsltclient"))
362 {
363 // If you're just getting the client-side transform page, why bother with the rest of this?
364 Element html = docWithDoctype.createElement("html");
365 Element img = docWithDoctype.createElement("img");
366 img.setAttribute("src", "interfaces/default/images/loading.gif"); // Make it dynamic
367 img.setAttribute("alt", "Please wait...");
368 Text title_text = docWithDoctype.createTextNode("Please wait..."); // Make this language dependent
369 Element head = docWithDoctype.createElement("head");
370 Element title = docWithDoctype.createElement("title");
371 title.appendChild(title_text);
372 Element body = docWithDoctype.createElement("body");
373 Element script = docWithDoctype.createElement("script");
374 Element jquery = docWithDoctype.createElement("script");
375 jquery.setAttribute("src", "jquery.js");
376 jquery.setAttribute("type", "text/javascript");
377 Comment jquery_comment = docWithDoctype.createComment("jQuery");
378 Comment script_comment = docWithDoctype.createComment("Filler for browser");
379 script.setAttribute("src", "test.js");
380 script.setAttribute("type", "text/javascript");
381 Element pagevar = docWithDoctype.createElement("script");
382 Element style = docWithDoctype.createElement("style");
383 style.setAttribute("type", "text/css");
384 Text style_text = docWithDoctype.createTextNode("body { text-align: center; padding: 50px; font: 14pt Arial, sans-serif; font-weight: bold; }");
385 pagevar.setAttribute("type", "text/javascript");
386 Text page_var_text = docWithDoctype.createTextNode("var placeholder = true;");
387
388 html.appendChild(head);
389 head.appendChild(title);
390 head.appendChild(style);
391 style.appendChild(style_text);
392 html.appendChild(body);
393 head.appendChild(pagevar);
394 head.appendChild(jquery);
395 head.appendChild(script);
396 pagevar.appendChild(page_var_text);
397 jquery.appendChild(jquery_comment);
398 script.appendChild(script_comment);
399 body.appendChild(img);
400 docWithDoctype.appendChild(html);
401
402 return (Node) docWithDoctype;
403 }
404
405 // Passing in the pretty string here means it needs to be generated even when not debugging; so use custom function to return blank when debug is off
406 logger.debug("page before transforming:");
407 logger.debug(this.converter.getPrettyStringLogger(page, logger));
408
409 String action = request.getAttribute(GSXML.ACTION_ATT);
410 String subaction = request.getAttribute(GSXML.SUBACTION_ATT);
411
412 // we should choose how to transform the data based on output, eg diff
413 // choice for html, and wml??
414 // for now, if output=xml, we don't transform the page, we just return
415 // the page xml
416 Document theXML = null;
417
418 if (output.equals("xml") || output.equals("clientside"))
419 {
420 // Append some bits and pieces first...
421 theXML = converter.newDOM();
422 // Import into new document first!
423 Node newPage = theXML.importNode(page, true);
424 theXML.appendChild(newPage);
425 Element root = theXML.createElement("xsltparams");
426 newPage.appendChild(root);
427
428 Element libname = theXML.createElement("param");
429 libname.setAttribute("name", "library_name");
430 Text libnametext = theXML.createTextNode((String) config_params.get(GSConstants.LIBRARY_NAME));
431 libname.appendChild(libnametext);
432
433 Element intname = theXML.createElement("param");
434 intname.setAttribute("name", "interface_name");
435 Text intnametext = theXML.createTextNode((String) config_params.get(GSConstants.INTERFACE_NAME));
436 intname.appendChild(intnametext);
437
438 Element siteName = theXML.createElement("param");
439 siteName.setAttribute("name", "site_name");
440 Text siteNameText = theXML.createTextNode((String) config_params.get(GSConstants.SITE_NAME));
441 siteName.appendChild(siteNameText);
442
443 Element filepath = theXML.createElement("param");
444 filepath.setAttribute("name", "filepath");
445 Text filepathtext = theXML.createTextNode(GlobalProperties.getGSDL3Home());
446 filepath.appendChild(filepathtext);
447
448 root.appendChild(libname);
449 root.appendChild(intname);
450 root.appendChild(siteName);
451 root.appendChild(filepath);
452
453 if (output.equals("xml"))
454 return theXML.getDocumentElement();
455 }
456
457 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
458 String collection = "";
459 String inlineTemplate = "";
460 if (cgi_param_list != null)
461 {
462 // Don't waste time getting all the parameters
463 HashMap params = GSXML.extractParams(cgi_param_list, false);
464 collection = (String) params.get(GSParams.COLLECTION);
465 if (collection == null)
466 {
467 collection = "";
468 }
469
470 inlineTemplate = (String) params.get(GSParams.INLINE_TEMPLATE);
471 }
472
473 Document style_doc = getXSLTDocument(action, subaction, collection);
474 if (style_doc == null)
475 {
476 String errorPage = this.converter.getParseErrorMessage();
477 if (errorPage != null)
478 {
479 return XMLTransformer.constructErrorXHTMLPage("Cannot parse the xslt file\n" + errorPage);
480 }
481 return page;
482 }
483
484 // put the page into a document - this is necessary for xslt to get
485 // the paths right if you have paths relative to the document root
486 // eg /page.
487 Document doc = this.converter.newDOM();
488 doc.appendChild(doc.importNode(page, true));
489 Element page_response = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
490 Element format_elem = (Element) GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
491 if (output.equals("formatelem"))
492 {
493 return format_elem;
494 }
495 if (format_elem != null)
496 {
497 //page_response.removeChild(format_elem);
498 logger.debug("format elem=" + this.converter.getPrettyStringLogger(format_elem, logger));
499 // need to transform the format info
500 String configStylesheet_file = GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces, "config_format.xsl");
501 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
502
503 if (configStylesheet_doc != null)
504 {
505 Document format_doc = this.converter.newDOM();
506 format_doc.appendChild(format_doc.importNode(format_elem, true));
507 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params); // Needs addressing <-
508
509 // Since we started creating documents with DocTypes, we can end up with
510 // Document objects here. But we will be working with an Element instead,
511 // so we grab the DocumentElement() of the Document object in such a case.
512 Element new_format;
513 if (result.getNodeType() == Node.DOCUMENT_NODE)
514 {
515 new_format = ((Document) result).getDocumentElement();
516 }
517 else
518 {
519 new_format = (Element) result;
520 }
521 logger.debug("new format elem=" + this.converter.getPrettyStringLogger(new_format, logger));
522 if (output.equals("newformat"))
523 {
524 return new_format;
525 }
526
527 // add extracted GSF statements in to the main stylesheet
528 GSXSLT.mergeStylesheets(style_doc, new_format);
529 //System.out.println("added extracted GSF statements into the main stylesheet") ;
530
531 // add extracted GSF statements in to the debug test stylesheet
532 //GSXSLT.mergeStylesheets(oldStyle_doc, new_format);
533 }
534 else
535 {
536 logger.error(" couldn't parse the config_format stylesheet, adding the format info as is");
537 GSXSLT.mergeStylesheets(style_doc, format_elem);
538 //GSXSLT.mergeStylesheets(oldStyle_doc, format_elem);
539 }
540 logger.debug("the converted stylesheet is:");
541 logger.debug(this.converter.getPrettyStringLogger(style_doc.getDocumentElement(), logger));
542 }
543
544 //for debug purposes only
545 Document oldStyle_doc = style_doc;
546
547 Document preprocessingXsl;
548 try
549 {
550 preprocessingXsl = getDoc(preprocess_xsl_filename);
551 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
552 if (errMsg != null)
553 {
554 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt file: " + preprocess_xsl_filename + "\n" + errMsg);
555 }
556 }
557 catch (java.io.FileNotFoundException e)
558 {
559 return fileNotFoundErrorPage(e.getMessage());
560 }
561 catch (Exception e)
562 {
563 e.printStackTrace();
564 System.out.println("error loading preprocess xslt");
565 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt\n" + e.getMessage());
566 }
567
568 Document libraryXsl = null;
569 try
570 {
571 libraryXsl = getDoc(this.getLibraryXSLFilename());
572 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
573 if (errMsg != null)
574 {
575 return XMLTransformer.constructErrorXHTMLPage("Error loading xslt file: " + this.getLibraryXSLFilename() + "\n" + errMsg);
576 }
577 }
578 catch (java.io.FileNotFoundException e)
579 {
580 return fileNotFoundErrorPage(e.getMessage());
581 }
582 catch (Exception e)
583 {
584 e.printStackTrace();
585 System.out.println("error loading library xslt");
586 return XMLTransformer.constructErrorXHTMLPage("error loading library xslt\n" + e.getMessage());
587 }
588
589 // Combine the skin file and library variables/templates into one document.
590 // Please note: We dont just use xsl:import because the preprocessing stage
591 // needs to know what's available in the library.
592
593 Document skinAndLibraryXsl = null;
594 Document skinAndLibraryDoc = converter.newDOM();
595 try
596 {
597
598 skinAndLibraryXsl = converter.newDOM();
599 Element root = skinAndLibraryXsl.createElement("skinAndLibraryXsl");
600 skinAndLibraryXsl.appendChild(root);
601
602 Element s = skinAndLibraryXsl.createElement("skinXsl");
603 s.appendChild(skinAndLibraryXsl.importNode(style_doc.getDocumentElement(), true));
604 root.appendChild(s);
605
606 Element l = skinAndLibraryXsl.createElement("libraryXsl");
607 Element libraryXsl_el = libraryXsl.getDocumentElement();
608 l.appendChild(skinAndLibraryXsl.importNode(libraryXsl_el, true));
609 root.appendChild(l);
610 //System.out.println("Skin and Library XSL are now together") ;
611
612 //System.out.println("Pre-processing the skin file...") ;
613
614 //pre-process the skin style sheet
615 //In other words, apply the preProcess.xsl to 'skinAndLibraryXsl' in order to
616 //expand all GS-Lib statements into complete XSL statements and also to create
617 //a valid xsl style sheet document.
618
619 Transformer preProcessor = transformerFactory.newTransformer(new DOMSource(preprocessingXsl));
620 preProcessor.setErrorListener(new XMLTransformer.TransformErrorListener());
621 DOMResult result = new DOMResult();
622 result.setNode(skinAndLibraryDoc);
623 preProcessor.transform(new DOMSource(skinAndLibraryXsl), result);
624 //System.out.println("GS-Lib statements are now expanded") ;
625
626 }
627 catch (TransformerException e)
628 {
629 e.printStackTrace();
630 System.out.println("TransformerException while preprocessing the skin xslt");
631 return XMLTransformer.constructErrorXHTMLPage(e.getMessage());
632 }
633 catch (Exception e)
634 {
635 e.printStackTrace();
636 System.out.println("Error while preprocessing the skin xslt");
637 return XMLTransformer.constructErrorXHTMLPage(e.getMessage());
638 }
639
640 //The following code is to be uncommented if we need to append the extracted GSF statements
641 //after having extracted the GSLib elements. In case of a problem during postprocessing.
642 /*
643 * // put the page into a document - this is necessary for xslt to get
644 * // the paths right if you have paths relative to the document root //
645 * eg /page. Document doc = this.converter.newDOM();
646 * doc.appendChild(doc.importNode(page, true)); Element page_response =
647 * (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
648 * Element format_elem = (Element)GSXML.getChildByTagName(page_response,
649 * GSXML.FORMAT_ELEM); if (output.equals("formatelem")) { return
650 * format_elem; } if (format_elem != null) {
651 * //page_response.removeChild(format_elem);
652 * logger.debug("format elem="+
653 * this.converter.getPrettyString(format_elem)); // need to transform
654 * the format info String configStylesheet_file =
655 * GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(),
656 * (String)this.config_params.get(GSConstants.SITE_NAME), collection,
657 * (String)this.config_params.get(GSConstants.INTERFACE_NAME),
658 * base_interfaces, "config_format.xsl"); Document configStylesheet_doc
659 * = this.converter.getDOM(new File(configStylesheet_file)); if
660 * (configStylesheet_doc != null) { Document format_doc =
661 * this.converter.newDOM();
662 * format_doc.appendChild(format_doc.importNode(format_elem, true));
663 * Node result = this.transformer.transform(configStylesheet_doc,
664 * format_doc);
665 *
666 * // Since we started creating documents with DocTypes, we can end up
667 * with // Document objects here. But we will be working with an Element
668 * instead, // so we grab the DocumentElement() of the Document object
669 * in such a case. Element new_format; if(result.getNodeType() ==
670 * Node.DOCUMENT_NODE) { new_format =
671 * ((Document)result).getDocumentElement(); } else { new_format =
672 * (Element)result; }
673 * logger.debug("new format elem="+this.converter.getPrettyString
674 * (new_format)); if (output.equals("newformat")) { return new_format; }
675 *
676 * // add extracted GSF statements in to the main stylesheet
677 * GSXSLT.mergeStylesheets(skinAndLibraryDoc, new_format);
678 * //System.out.println
679 * ("added extracted GSF statements into the main stylesheet") ;
680 *
681 * // add extracted GSF statements in to the debug test stylesheet
682 * //GSXSLT.mergeStylesheets(oldStyle_doc, new_format); } else {
683 * logger.error(
684 * " couldn't parse the config_format stylesheet, adding the format info as is"
685 * ); GSXSLT.mergeStylesheets(skinAndLibraryDoc, format_elem); //
686 * GSXSLT.mergeStylesheets(oldStyle_doc, format_elem); }
687 * logger.debug("the converted stylesheet is:");
688 * logger.debug(this.converter
689 * .getPrettyString(skinAndLibraryDoc.getDocumentElement())); }
690 */
691
692 // there is a thing called a URIResolver which you can set for a
693 // transformer or transformer factory. may be able to use this
694 // instead of this absoluteIncludepaths hack
695
696 GSXSLT.absoluteIncludePaths(skinAndLibraryDoc, GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
697
698 //Same but for the debug version when we want the do the transformation like we use to do
699 //without any gslib elements.
700 GSXSLT.absoluteIncludePaths(oldStyle_doc, GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
701
702 //Send different stages of the skin xslt to the browser for debug purposes only
703 //using &o=skindoc or &o=skinandlib etc...
704 if (output.equals("skindoc"))
705 {
706 return converter.getDOM(getStringFromDocument(style_doc));
707 }
708 if (output.equals("skinandlib"))
709 {
710 return converter.getDOM(getStringFromDocument(skinAndLibraryXsl));
711 }
712 if (output.equals("skinandlibdoc") || output.equals("clientside"))
713 {
714
715 Node skinAndLib = converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
716
717 if (output.equals("skinandlibdoc"))
718 {
719 return skinAndLib;
720 }
721 else
722 {
723 // Send XML and skinandlibdoc down the line together
724 Document finalDoc = converter.newDOM();
725 Node finalDocSkin = finalDoc.importNode(skinAndLibraryDoc.getDocumentElement(), true);
726 Node finalDocXML = finalDoc.importNode(theXML.getDocumentElement(), true);
727 Element root = finalDoc.createElement("skinlibPlusXML");
728 root.appendChild(finalDocSkin);
729 root.appendChild(finalDocXML);
730 finalDoc.appendChild(root);
731 return (Node) finalDoc.getDocumentElement();
732 }
733 }
734 if (output.equals("oldskindoc"))
735 {
736 return converter.getDOM(getStringFromDocument(oldStyle_doc));
737 }
738
739 // Try to get the system and public ID from the current skin xsl document
740 // otherwise keep the default values.
741 Element root = skinAndLibraryDoc.getDocumentElement();
742 NodeList nodes = root.getElementsByTagName("xsl:output");
743 // If there is at least one "xsl:output" command in the final xsl then...
744 if (nodes.getLength() != 0)
745 {
746 // There should be only one element called xsl:output,
747 // but if this is not the case get the last one
748 Element xsl_output = (Element) nodes.item(nodes.getLength() - 1);
749 if (xsl_output != null)
750 {
751 // Qualified name will always be html even for xhtml pages
752 //String attrValue = xsl_output.getAttribute("method");
753 //qualifiedName = attrValue.equals("") ? qualifiedName : attrValue;
754
755 String attrValue = xsl_output.getAttribute("doctype-system");
756 systemID = attrValue.equals("") ? systemID : attrValue;
757
758 attrValue = xsl_output.getAttribute("doctype-public");
759 publicID = attrValue.equals("") ? publicID : attrValue;
760 }
761 }
762
763 //System.out.println(converter.getPrettyString(docWithDoctype));
764 //System.out.println("Doctype vals: " + qualifiedName + " " + publicID + " " + systemID) ;
765
766 docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
767
768 //System.out.println("Generate final HTML from current skin") ;
769 //Transformation of the XML message from the receptionist to HTML with doctype
770
771 if (inlineTemplate != null)
772 {
773 try
774 {
775 Document inlineTemplateDoc = this.converter.getDOM("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:java=\"http://xml.apache.org/xslt/java\" xmlns:util=\"xalan://org.greenstone.gsdl3.util.XSLTUtil\" xmlns:gsf=\"http://www.greenstone.org/greenstone3/schema/ConfigFormat\">" + inlineTemplate + "</xsl:stylesheet>");
776 GSXSLT.mergeStylesheets(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement());
777 }
778 catch (Exception ex)
779 {
780 ex.printStackTrace();
781 }
782 }
783
784 if (skinAndLibraryDoc.getElementsByTagName("gsf:metadata").getLength() > 0)
785 {
786 secondConfigFormatPass(collection, skinAndLibraryDoc, doc, new UserContext(request));
787 }
788
789 if (output.equals("xmlfinal"))
790 {
791 return doc;
792 }
793
794 return this.transformer.transform(skinAndLibraryDoc, doc, config_params, docWithDoctype); // The default
795
796 // The line below will do the transformation like we use to do before having Skin++ implemented,
797 // it will not contain any GS-Lib statements expanded, and the result will not contain any doctype.
798
799 //return (Element)this.transformer.transform(style_doc, doc, config_params);
800 //return null; // For now - change later
801 }
802
803 protected void secondConfigFormatPass(String collection, Document skinAndLibraryDoc, Document doc, UserContext userContext)
804 {
805 String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve"); // Hard-wired?
806 Element metaMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
807 Element metaRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
808 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
809 Element docNodeList = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
810
811 NodeList metaNodes = skinAndLibraryDoc.getElementsByTagName("gsf:metadata");
812
813 for (int i = 0; i < metaNodes.getLength(); i++)
814 {
815 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
816 param.setAttribute(GSXML.NAME_ATT, "metadata");
817 param.setAttribute(GSXML.VALUE_ATT, ((Element) metaNodes.item(i)).getAttribute(GSXML.NAME_ATT));
818 paramList.appendChild(param);
819 }
820 metaRequest.appendChild(paramList);
821
822 NodeList docNodes = doc.getElementsByTagName("documentNode");
823 for (int i = 0; i < docNodes.getLength(); i++)
824 {
825 Element docNode = this.doc.createElement(GSXML.DOC_NODE_ELEM);
826 docNode.setAttribute(GSXML.NODE_ID_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_ID_ATT));
827 docNode.setAttribute(GSXML.NODE_TYPE_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_TYPE_ATT));
828 docNodeList.appendChild(docNode);
829 }
830 metaRequest.appendChild(docNodeList);
831
832 metaMessage.appendChild(metaRequest);
833 Element response = (Element) mr.process(metaMessage);
834
835 NodeList metaDocNodes = response.getElementsByTagName(GSXML.DOC_NODE_ELEM);
836 for (int i = 0; i < docNodes.getLength(); i++)
837 {
838 GSXML.mergeMetadataLists(docNodes.item(i), metaDocNodes.item(i));
839 }
840
841 String configStylesheet_file = GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces, "config_format.xsl");
842 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
843
844 if (configStylesheet_doc != null)
845 {
846 Document format_doc = this.converter.newDOM();
847 format_doc.appendChild(format_doc.importNode(skinAndLibraryDoc.getDocumentElement().cloneNode(true), true));
848 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params);
849 GSXSLT.mergeStylesheets(skinAndLibraryDoc, ((Document) result).getDocumentElement());
850 }
851 }
852
853 // method to convert Document to a proper XML string for debug purposes only
854 protected String getStringFromDocument(Document doc)
855 {
856 String content = "";
857 try
858 {
859 DOMSource domSource = new DOMSource(doc);
860 StringWriter writer = new StringWriter();
861 StreamResult result = new StreamResult(writer);
862 TransformerFactory tf = TransformerFactory.newInstance();
863 Transformer transformer = tf.newTransformer();
864 transformer.transform(domSource, result);
865 content = writer.toString();
866 System.out.println("Change the & to &Amp; for proper debug dispay");
867 content = StringUtils.replace(content, "&", "&amp;");
868 writer.flush();
869 }
870 catch (TransformerException ex)
871 {
872 ex.printStackTrace();
873 return null;
874 }
875 return content;
876 }
877
878 protected synchronized Document getDoc(String docName) throws Exception
879 {
880 File xslt_file = new File(docName);
881
882 FileReader reader = new FileReader(xslt_file);
883 InputSource xml_source = new InputSource(reader);
884 this.parser.parse(xml_source);
885 Document doc = this.parser.getDocument();
886
887 return doc;
888 }
889
890 protected Document getXSLTDocument(String action, String subaction, String collection)
891 {
892 String name = null;
893 if (!subaction.equals(""))
894 {
895 String key = action + ":" + subaction;
896 name = (String) this.xslt_map.get(key);
897 }
898 // try the action by itself
899 if (name == null)
900 {
901 name = (String) this.xslt_map.get(action);
902 }
903 // now find the absolute path
904 ArrayList<File> stylesheets = GSFile.getStylesheetFiles(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces, name);
905
906 if (stylesheets.size() == 0)
907 {
908 logger.error(" Can't find stylesheet for " + name);
909 return null;
910 }
911 logger.debug("Stylesheet: " + name);
912
913 Document finalDoc = this.converter.getDOM(stylesheets.get(stylesheets.size() - 1), "UTF-8");
914 if (finalDoc == null)
915 {
916 return null;
917 }
918
919 for (int i = stylesheets.size() - 2; i >= 0; i--)
920 {
921 Document currentDoc = this.converter.getDOM(stylesheets.get(i), "UTF-8");
922 if (currentDoc == null)
923 {
924 return null;
925 }
926
927 GSXSLT.mergeStylesheets(finalDoc, currentDoc.getDocumentElement());
928 }
929
930 return finalDoc;
931 }
932
933 // returns the library.xsl path of the library file that is applicable for the current interface
934 protected String getLibraryXSLFilename()
935 {
936 return GSFile.xmlTransformDir(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))) + File.separatorChar + "library.xsl";
937 }
938
939 // Call this when a FileNotFoundException could be thrown when loading an xsl (xml) file.
940 // Returns an error xhtml page indicating which xsl (or other xml) file is missing.
941 protected Document fileNotFoundErrorPage(String filenameMessage)
942 {
943 String errorMessage = "ERROR missing file: " + filenameMessage;
944 Element errPage = XMLTransformer.constructErrorXHTMLPage(errorMessage);
945 logger.error(errorMessage);
946 return errPage.getOwnerDocument();
947 }
948}
Note: See TracBrowser for help on using the repository browser.