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

Last change on this file since 24993 was 24993, checked in by sjm84, 12 years ago

Adding UserContext to replace the use of lang and uid

  • Property svn:keywords set to Author Date Id Revision
File size: 35.1 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.getActionParameters(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 filepath = theXML.createElement("param");
439 filepath.setAttribute("name", "filepath");
440 Text filepathtext = theXML.createTextNode(GlobalProperties.getGSDL3Home());
441 filepath.appendChild(filepathtext);
442
443 root.appendChild(libname);
444 root.appendChild(intname);
445 root.appendChild(filepath);
446
447 if (output.equals("xml"))
448 return theXML.getDocumentElement();
449 }
450
451 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
452 String collection = "";
453 String inlineTemplate = "";
454 if (cgi_param_list != null)
455 {
456 // Don't waste time getting all the parameters
457 HashMap params = GSXML.extractParams(cgi_param_list, false);
458 collection = (String) params.get(GSParams.COLLECTION);
459 if (collection == null)
460 {
461 collection = "";
462 }
463
464 inlineTemplate = (String) params.get(GSParams.INLINE_TEMPLATE);
465 }
466
467 Document style_doc = getXSLTDocument(action, subaction, collection);
468 if (style_doc == null)
469 {
470 String errorPage = this.converter.getParseErrorMessage();
471 if (errorPage != null)
472 {
473 return XMLTransformer.constructErrorXHTMLPage("Cannot parse the xslt file\n" + errorPage);
474 }
475 return page;
476 }
477
478 // put the page into a document - this is necessary for xslt to get
479 // the paths right if you have paths relative to the document root
480 // eg /page.
481 Document doc = this.converter.newDOM();
482 doc.appendChild(doc.importNode(page, true));
483 Element page_response = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
484 Element format_elem = (Element) GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
485 if (output.equals("formatelem"))
486 {
487 return format_elem;
488 }
489 if (format_elem != null)
490 {
491 //page_response.removeChild(format_elem);
492 logger.debug("format elem=" + this.converter.getPrettyStringLogger(format_elem, logger));
493 // need to transform the format info
494 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");
495 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
496
497 if (configStylesheet_doc != null)
498 {
499 Document format_doc = this.converter.newDOM();
500 format_doc.appendChild(format_doc.importNode(format_elem, true));
501 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params); // Needs addressing <-
502
503 // Since we started creating documents with DocTypes, we can end up with
504 // Document objects here. But we will be working with an Element instead,
505 // so we grab the DocumentElement() of the Document object in such a case.
506 Element new_format;
507 if (result.getNodeType() == Node.DOCUMENT_NODE)
508 {
509 new_format = ((Document) result).getDocumentElement();
510 }
511 else
512 {
513 new_format = (Element) result;
514 }
515 logger.debug("new format elem=" + this.converter.getPrettyStringLogger(new_format, logger));
516 if (output.equals("newformat"))
517 {
518 return new_format;
519 }
520
521 // add extracted GSF statements in to the main stylesheet
522 GSXSLT.mergeStylesheets(style_doc, new_format);
523 //System.out.println("added extracted GSF statements into the main stylesheet") ;
524
525 // add extracted GSF statements in to the debug test stylesheet
526 //GSXSLT.mergeStylesheets(oldStyle_doc, new_format);
527 }
528 else
529 {
530 logger.error(" couldn't parse the config_format stylesheet, adding the format info as is");
531 GSXSLT.mergeStylesheets(style_doc, format_elem);
532 //GSXSLT.mergeStylesheets(oldStyle_doc, format_elem);
533 }
534 logger.debug("the converted stylesheet is:");
535 logger.debug(this.converter.getPrettyStringLogger(style_doc.getDocumentElement(), logger));
536 }
537
538 //for debug purposes only
539 Document oldStyle_doc = style_doc;
540
541 Document preprocessingXsl;
542 try
543 {
544 preprocessingXsl = getDoc(preprocess_xsl_filename);
545 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
546 if (errMsg != null)
547 {
548 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt file: " + preprocess_xsl_filename + "\n" + errMsg);
549 }
550 }
551 catch (java.io.FileNotFoundException e)
552 {
553 return fileNotFoundErrorPage(e.getMessage());
554 }
555 catch (Exception e)
556 {
557 e.printStackTrace();
558 System.out.println("error loading preprocess xslt");
559 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt\n" + e.getMessage());
560 }
561
562 Document libraryXsl = null;
563 try
564 {
565 libraryXsl = getDoc(this.getLibraryXSLFilename());
566 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
567 if (errMsg != null)
568 {
569 return XMLTransformer.constructErrorXHTMLPage("Error loading xslt file: " + this.getLibraryXSLFilename() + "\n" + errMsg);
570 }
571 }
572 catch (java.io.FileNotFoundException e)
573 {
574 return fileNotFoundErrorPage(e.getMessage());
575 }
576 catch (Exception e)
577 {
578 e.printStackTrace();
579 System.out.println("error loading library xslt");
580 return XMLTransformer.constructErrorXHTMLPage("error loading library xslt\n" + e.getMessage());
581 }
582
583 // Combine the skin file and library variables/templates into one document.
584 // Please note: We dont just use xsl:import because the preprocessing stage
585 // needs to know what's available in the library.
586
587 Document skinAndLibraryXsl = null;
588 Document skinAndLibraryDoc = converter.newDOM();
589 try
590 {
591
592 skinAndLibraryXsl = converter.newDOM();
593 Element root = skinAndLibraryXsl.createElement("skinAndLibraryXsl");
594 skinAndLibraryXsl.appendChild(root);
595
596 Element s = skinAndLibraryXsl.createElement("skinXsl");
597 s.appendChild(skinAndLibraryXsl.importNode(style_doc.getDocumentElement(), true));
598 root.appendChild(s);
599
600 Element l = skinAndLibraryXsl.createElement("libraryXsl");
601 Element libraryXsl_el = libraryXsl.getDocumentElement();
602 l.appendChild(skinAndLibraryXsl.importNode(libraryXsl_el, true));
603 root.appendChild(l);
604 //System.out.println("Skin and Library XSL are now together") ;
605
606 //System.out.println("Pre-processing the skin file...") ;
607
608 //pre-process the skin style sheet
609 //In other words, apply the preProcess.xsl to 'skinAndLibraryXsl' in order to
610 //expand all GS-Lib statements into complete XSL statements and also to create
611 //a valid xsl style sheet document.
612
613 Transformer preProcessor = transformerFactory.newTransformer(new DOMSource(preprocessingXsl));
614 preProcessor.setErrorListener(new XMLTransformer.TransformErrorListener());
615 DOMResult result = new DOMResult();
616 result.setNode(skinAndLibraryDoc);
617 preProcessor.transform(new DOMSource(skinAndLibraryXsl), result);
618 //System.out.println("GS-Lib statements are now expanded") ;
619
620 }
621 catch (TransformerException e)
622 {
623 e.printStackTrace();
624 System.out.println("TransformerException while preprocessing the skin xslt");
625 return XMLTransformer.constructErrorXHTMLPage(e.getMessage());
626 }
627 catch (Exception e)
628 {
629 e.printStackTrace();
630 System.out.println("Error while preprocessing the skin xslt");
631 return XMLTransformer.constructErrorXHTMLPage(e.getMessage());
632 }
633
634 //The following code is to be uncommented if we need to append the extracted GSF statements
635 //after having extracted the GSLib elements. In case of a problem during postprocessing.
636 /*
637 * // put the page into a document - this is necessary for xslt to get
638 * // the paths right if you have paths relative to the document root //
639 * eg /page. Document doc = this.converter.newDOM();
640 * doc.appendChild(doc.importNode(page, true)); Element page_response =
641 * (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
642 * Element format_elem = (Element)GSXML.getChildByTagName(page_response,
643 * GSXML.FORMAT_ELEM); if (output.equals("formatelem")) { return
644 * format_elem; } if (format_elem != null) {
645 * //page_response.removeChild(format_elem);
646 * logger.debug("format elem="+
647 * this.converter.getPrettyString(format_elem)); // need to transform
648 * the format info String configStylesheet_file =
649 * GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(),
650 * (String)this.config_params.get(GSConstants.SITE_NAME), collection,
651 * (String)this.config_params.get(GSConstants.INTERFACE_NAME),
652 * base_interfaces, "config_format.xsl"); Document configStylesheet_doc
653 * = this.converter.getDOM(new File(configStylesheet_file)); if
654 * (configStylesheet_doc != null) { Document format_doc =
655 * this.converter.newDOM();
656 * format_doc.appendChild(format_doc.importNode(format_elem, true));
657 * Node result = this.transformer.transform(configStylesheet_doc,
658 * format_doc);
659 *
660 * // Since we started creating documents with DocTypes, we can end up
661 * with // Document objects here. But we will be working with an Element
662 * instead, // so we grab the DocumentElement() of the Document object
663 * in such a case. Element new_format; if(result.getNodeType() ==
664 * Node.DOCUMENT_NODE) { new_format =
665 * ((Document)result).getDocumentElement(); } else { new_format =
666 * (Element)result; }
667 * logger.debug("new format elem="+this.converter.getPrettyString
668 * (new_format)); if (output.equals("newformat")) { return new_format; }
669 *
670 * // add extracted GSF statements in to the main stylesheet
671 * GSXSLT.mergeStylesheets(skinAndLibraryDoc, new_format);
672 * //System.out.println
673 * ("added extracted GSF statements into the main stylesheet") ;
674 *
675 * // add extracted GSF statements in to the debug test stylesheet
676 * //GSXSLT.mergeStylesheets(oldStyle_doc, new_format); } else {
677 * logger.error(
678 * " couldn't parse the config_format stylesheet, adding the format info as is"
679 * ); GSXSLT.mergeStylesheets(skinAndLibraryDoc, format_elem); //
680 * GSXSLT.mergeStylesheets(oldStyle_doc, format_elem); }
681 * logger.debug("the converted stylesheet is:");
682 * logger.debug(this.converter
683 * .getPrettyString(skinAndLibraryDoc.getDocumentElement())); }
684 */
685
686 // there is a thing called a URIResolver which you can set for a
687 // transformer or transformer factory. may be able to use this
688 // instead of this absoluteIncludepaths hack
689
690 GSXSLT.absoluteIncludePaths(skinAndLibraryDoc, GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
691
692 //Same but for the debug version when we want the do the transformation like we use to do
693 //without any gslib elements.
694 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);
695
696 //Send different stages of the skin xslt to the browser for debug purposes only
697 //using &o=skindoc or &o=skinandlib etc...
698 if (output.equals("skindoc"))
699 {
700 return converter.getDOM(getStringFromDocument(style_doc));
701 }
702 if (output.equals("skinandlib"))
703 {
704 return converter.getDOM(getStringFromDocument(skinAndLibraryXsl));
705 }
706 if (output.equals("skinandlibdoc") || output.equals("clientside"))
707 {
708
709 Node skinAndLib = converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
710
711 if (output.equals("skinandlibdoc"))
712 {
713 return skinAndLib;
714 }
715 else
716 {
717 // Send XML and skinandlibdoc down the line together
718 Document finalDoc = converter.newDOM();
719 Node finalDocSkin = finalDoc.importNode(skinAndLibraryDoc.getDocumentElement(), true);
720 Node finalDocXML = finalDoc.importNode(theXML.getDocumentElement(), true);
721 Element root = finalDoc.createElement("skinlibPlusXML");
722 root.appendChild(finalDocSkin);
723 root.appendChild(finalDocXML);
724 finalDoc.appendChild(root);
725 return (Node) finalDoc.getDocumentElement();
726 }
727 }
728 if (output.equals("oldskindoc"))
729 {
730 return converter.getDOM(getStringFromDocument(oldStyle_doc));
731 }
732
733 // Try to get the system and public ID from the current skin xsl document
734 // otherwise keep the default values.
735 Element root = skinAndLibraryDoc.getDocumentElement();
736 NodeList nodes = root.getElementsByTagName("xsl:output");
737 // If there is at least one "xsl:output" command in the final xsl then...
738 if (nodes.getLength() != 0)
739 {
740 // There should be only one element called xsl:output,
741 // but if this is not the case get the last one
742 Element xsl_output = (Element) nodes.item(nodes.getLength() - 1);
743 if (xsl_output != null)
744 {
745 // Qualified name will always be html even for xhtml pages
746 //String attrValue = xsl_output.getAttribute("method");
747 //qualifiedName = attrValue.equals("") ? qualifiedName : attrValue;
748
749 String attrValue = xsl_output.getAttribute("doctype-system");
750 systemID = attrValue.equals("") ? systemID : attrValue;
751
752 attrValue = xsl_output.getAttribute("doctype-public");
753 publicID = attrValue.equals("") ? publicID : attrValue;
754 }
755 }
756
757 //System.out.println(converter.getPrettyString(docWithDoctype));
758 //System.out.println("Doctype vals: " + qualifiedName + " " + publicID + " " + systemID) ;
759
760 docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
761
762 //System.out.println("Generate final HTML from current skin") ;
763 //Transformation of the XML message from the receptionist to HTML with doctype
764
765 if (inlineTemplate != null)
766 {
767 try
768 {
769 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>");
770 GSXSLT.mergeStylesheets(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement());
771 }
772 catch (Exception ex)
773 {
774 ex.printStackTrace();
775 }
776 }
777
778 if (skinAndLibraryDoc.getElementsByTagName("gsf:metadata").getLength() > 0)
779 {
780 secondConfigFormatPass(collection, skinAndLibraryDoc, doc, new UserContext(request));
781 }
782
783 if (output.equals("xmlfinal"))
784 {
785 return doc;
786 }
787
788 return this.transformer.transform(skinAndLibraryDoc, doc, config_params, docWithDoctype); // The default
789
790 // The line below will do the transformation like we use to do before having Skin++ implemented,
791 // it will not contain any GS-Lib statements expanded, and the result will not contain any doctype.
792
793 //return (Element)this.transformer.transform(style_doc, doc, config_params);
794 //return null; // For now - change later
795 }
796
797 protected void secondConfigFormatPass(String collection, Document skinAndLibraryDoc, Document doc, UserContext userContext)
798 {
799 String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve"); // Hard-wired?
800 Element metaMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
801 Element metaRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
802 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
803 Element docNodeList = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
804
805 NodeList metaNodes = skinAndLibraryDoc.getElementsByTagName("gsf:metadata");
806
807 for (int i = 0; i < metaNodes.getLength(); i++)
808 {
809 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
810 param.setAttribute(GSXML.NAME_ATT, "metadata");
811 param.setAttribute(GSXML.VALUE_ATT, ((Element) metaNodes.item(i)).getAttribute(GSXML.NAME_ATT));
812 paramList.appendChild(param);
813 }
814 metaRequest.appendChild(paramList);
815
816 NodeList docNodes = doc.getElementsByTagName("documentNode");
817 for (int i = 0; i < docNodes.getLength(); i++)
818 {
819 Element docNode = this.doc.createElement(GSXML.DOC_NODE_ELEM);
820 docNode.setAttribute(GSXML.NODE_ID_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_ID_ATT));
821 docNode.setAttribute(GSXML.NODE_TYPE_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_TYPE_ATT));
822 docNodeList.appendChild(docNode);
823 }
824 metaRequest.appendChild(docNodeList);
825
826 metaMessage.appendChild(metaRequest);
827 Element response = (Element) mr.process(metaMessage);
828
829 NodeList metaDocNodes = response.getElementsByTagName(GSXML.DOC_NODE_ELEM);
830 for (int i = 0; i < docNodes.getLength(); i++)
831 {
832 GSXML.mergeMetadataLists(docNodes.item(i), metaDocNodes.item(i));
833 }
834
835 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");
836 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
837
838 if (configStylesheet_doc != null)
839 {
840 Document format_doc = this.converter.newDOM();
841 format_doc.appendChild(format_doc.importNode(skinAndLibraryDoc.getDocumentElement().cloneNode(true), true));
842 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params);
843 GSXSLT.mergeStylesheets(skinAndLibraryDoc, ((Document) result).getDocumentElement());
844 }
845 }
846
847 // method to convert Document to a proper XML string for debug purposes only
848 protected String getStringFromDocument(Document doc)
849 {
850 String content = "";
851 try
852 {
853 DOMSource domSource = new DOMSource(doc);
854 StringWriter writer = new StringWriter();
855 StreamResult result = new StreamResult(writer);
856 TransformerFactory tf = TransformerFactory.newInstance();
857 Transformer transformer = tf.newTransformer();
858 transformer.transform(domSource, result);
859 content = writer.toString();
860 System.out.println("Change the & to &Amp; for proper debug dispay");
861 content = StringUtils.replace(content, "&", "&amp;");
862 writer.flush();
863 }
864 catch (TransformerException ex)
865 {
866 ex.printStackTrace();
867 return null;
868 }
869 return content;
870 }
871
872 protected synchronized Document getDoc(String docName) throws Exception
873 {
874 File xslt_file = new File(docName);
875
876 FileReader reader = new FileReader(xslt_file);
877 InputSource xml_source = new InputSource(reader);
878 this.parser.parse(xml_source);
879 Document doc = this.parser.getDocument();
880
881 return doc;
882 }
883
884 protected Document getXSLTDocument(String action, String subaction, String collection)
885 {
886 String name = null;
887 if (!subaction.equals(""))
888 {
889 String key = action + ":" + subaction;
890 name = (String) this.xslt_map.get(key);
891 }
892 // try the action by itself
893 if (name == null)
894 {
895 name = (String) this.xslt_map.get(action);
896 }
897 // now find the absolute path
898 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);
899
900 if (stylesheets.size() == 0)
901 {
902 logger.error(" Can't find stylesheet for " + name);
903 return null;
904 }
905 logger.debug("Stylesheet: " + name);
906
907 Document finalDoc = this.converter.getDOM(stylesheets.get(stylesheets.size() - 1), "UTF-8");
908 if (finalDoc == null)
909 {
910 return null;
911 }
912
913 for (int i = stylesheets.size() - 2; i >= 0; i--)
914 {
915 Document currentDoc = this.converter.getDOM(stylesheets.get(i), "UTF-8");
916 if (currentDoc == null)
917 {
918 return null;
919 }
920
921 GSXSLT.mergeStylesheets(finalDoc, currentDoc.getDocumentElement());
922 }
923
924 return finalDoc;
925 }
926
927 // returns the library.xsl path of the library file that is applicable for the current interface
928 protected String getLibraryXSLFilename()
929 {
930 return GSFile.xmlTransformDir(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))) + File.separatorChar + "library.xsl";
931 }
932
933 // Call this when a FileNotFoundException could be thrown when loading an xsl (xml) file.
934 // Returns an error xhtml page indicating which xsl (or other xml) file is missing.
935 protected Document fileNotFoundErrorPage(String filenameMessage)
936 {
937 String errorMessage = "ERROR missing file: " + filenameMessage;
938 Element errPage = XMLTransformer.constructErrorXHTMLPage(errorMessage);
939 logger.error(errorMessage);
940 return errPage.getOwnerDocument();
941 }
942}
Note: See TracBrowser for help on using the repository browser.