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

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

Adding in some unfinished code that will help us view the XML a page was generated with

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