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

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

Reformatting this file and reorganising imports

  • Property svn:keywords set to Author Date Id Revision
File size: 36.8 KB
Line 
1package org.greenstone.gsdl3.core;
2
3import java.io.File;
4import java.io.FileReader;
5import java.io.Serializable;
6import java.io.StringWriter;
7import java.util.ArrayList;
8import java.util.HashMap;
9
10import javax.xml.transform.Transformer;
11import javax.xml.transform.TransformerException;
12import javax.xml.transform.TransformerFactory;
13import javax.xml.transform.dom.DOMSource;
14import javax.xml.transform.stream.StreamResult;
15
16import org.apache.commons.lang3.StringUtils;
17import org.apache.log4j.Logger;
18import org.apache.xerces.parsers.DOMParser;
19import org.greenstone.gsdl3.action.Action;
20import org.greenstone.gsdl3.util.GSConstants;
21import org.greenstone.gsdl3.util.GSFile;
22import org.greenstone.gsdl3.util.GSParams;
23import org.greenstone.gsdl3.util.GSPath;
24import org.greenstone.gsdl3.util.GSXML;
25import org.greenstone.gsdl3.util.GSXSLT;
26import org.greenstone.gsdl3.util.UserContext;
27import org.greenstone.gsdl3.util.XMLConverter;
28import org.greenstone.gsdl3.util.XMLTransformer;
29import org.greenstone.util.GlobalProperties;
30import org.w3c.dom.Comment;
31import org.w3c.dom.Document;
32import org.w3c.dom.Element;
33import org.w3c.dom.Node;
34import org.w3c.dom.NodeList;
35import org.w3c.dom.Text;
36import org.xml.sax.InputSource;
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 + "interfaces" + File.separatorChar + "core" + File.separatorChar + "transform" + File.separatorChar + "preProcess.xsl";
53
54 /** the list of xslt to use for actions */
55 protected HashMap<String, String> 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 boolean _debug = false;
64
65 public TransformingReceptionist()
66 {
67 super();
68 this.xslt_map = new HashMap<String, String>();
69 this.transformer = new XMLTransformer();
70 try
71 {
72 transformerFactory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
73 this.converter = new XMLConverter();
74 //transformerFactory.setURIResolver(new MyUriResolver()) ;
75
76 parser = new DOMParser();
77 parser.setFeature("http://xml.org/sax/features/validation", false);
78 // 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.
79 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
80 // a performance test showed that having this on lead to increased
81 // memory use for small-medium docs, and not much gain for large
82 // docs.
83 // http://www.sosnoski.com/opensrc/xmlbench/conclusions.html
84 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
85 parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
86 // setting a handler for when fatal errors, errors or warnings happen during xml parsing
87 // call XMLConverter's getParseErrorMessage() to get the errorstring that can be rendered as web page
88 this.parser.setErrorHandler(new XMLConverter.ParseErrorHandler());
89 }
90 catch (Exception e)
91 {
92 e.printStackTrace();
93 }
94
95 }
96
97 /** configures the receptionist - overwrite this to set up the xslt map */
98 public boolean configure()
99 {
100
101 if (this.config_params == null)
102 {
103 logger.error(" config variables must be set before calling configure");
104 return false;
105 }
106 if (this.mr == null)
107 {
108 logger.error(" message router must be set before calling configure");
109 return false;
110 }
111
112 // find the config file containing a list of actions
113 File interface_config_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))));
114 if (!interface_config_file.exists())
115 {
116 logger.error(" interface config file: " + interface_config_file.getPath() + " not found!");
117 return false;
118 }
119 Document config_doc = this.converter.getDOM(interface_config_file, "utf-8");
120 if (config_doc == null)
121 {
122 logger.error(" could not parse interface config file: " + interface_config_file.getPath());
123 return false;
124 }
125 Element config_elem = config_doc.getDocumentElement();
126 String base_interface = config_elem.getAttribute("baseInterface");
127 setUpBaseInterface(base_interface);
128 setUpInterfaceOptions(config_elem);
129
130 Element action_list = (Element) GSXML.getChildByTagName(config_elem, GSXML.ACTION_ELEM + GSXML.LIST_MODIFIER);
131 NodeList actions = action_list.getElementsByTagName(GSXML.ACTION_ELEM);
132
133 for (int i = 0; i < actions.getLength(); i++)
134 {
135 Element action = (Element) actions.item(i);
136 String class_name = action.getAttribute("class");
137 String action_name = action.getAttribute("name");
138 Action ac = null;
139 try
140 {
141 ac = (Action) Class.forName("org.greenstone.gsdl3.action." + class_name).newInstance();
142 }
143 catch (Exception e)
144 {
145 logger.error(" couldn't load in action " + class_name);
146 e.printStackTrace();
147 continue;
148 }
149 ac.setConfigParams(this.config_params);
150 ac.setMessageRouter(this.mr);
151 ac.configure();
152 ac.addActionParameters(this.params);
153 this.action_map.put(action_name, ac);
154
155 // now do the xslt map
156 String xslt = action.getAttribute("xslt");
157 if (!xslt.equals(""))
158 {
159 this.xslt_map.put(action_name, xslt);
160 }
161 NodeList subactions = action.getElementsByTagName(GSXML.SUBACTION_ELEM);
162 for (int j = 0; j < subactions.getLength(); j++)
163 {
164 Element subaction = (Element) subactions.item(j);
165 String subname = subaction.getAttribute(GSXML.NAME_ATT);
166 String subxslt = subaction.getAttribute("xslt");
167
168 String map_key = action_name + ":" + subname;
169 logger.debug("adding in to xslt map, " + map_key + "->" + subxslt);
170 this.xslt_map.put(map_key, subxslt);
171 }
172 }
173 Element lang_list = (Element) GSXML.getChildByTagName(config_elem, "languageList");
174 if (lang_list == null)
175 {
176 logger.error(" didn't find a language list in the config file!!");
177 }
178 else
179 {
180 this.language_list = (Element) this.doc.importNode(lang_list, true);
181 }
182
183 return true;
184 }
185
186 protected Node postProcessPage(Element page)
187 {
188 // might need to add some data to the page
189 addExtraInfo(page);
190 // transform the page using xslt
191 Node transformed_page = transformPage(page);
192
193 // if the user has specified they want only a part of the full page then subdivide it
194 boolean subdivide = false;
195 String excerptID = null;
196 String excerptTag = null;
197 Element request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
198 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
199 if (cgi_param_list != null)
200 {
201 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
202 if ((excerptID = (String) params.get(GSParams.EXCERPT_ID)) != null)
203 {
204 subdivide = true;
205 }
206 if ((excerptTag = (String) params.get(GSParams.EXCERPT_TAG)) != null)
207 {
208 subdivide = true;
209 }
210 }
211
212 if (subdivide)
213 {
214 Node subdivided_page = subdivide(transformed_page, excerptID, excerptTag);
215 if (subdivided_page != null)
216 {
217 return subdivided_page;
218 }
219 }
220
221 return transformed_page;
222 }
223
224 protected Node subdivide(Node transformed_page, String excerptID, String excerptTag)
225 {
226 if (excerptID != null)
227 {
228 Node selectedElement = getNodeByIdRecursive(transformed_page, excerptID);
229 modifyNodesByTagRecursive(selectedElement, "a");
230 return selectedElement;
231 }
232 else if (excerptTag != null)
233 {
234 /*
235 * // define a list
236 *
237 * Node selectedElement =
238 * modifyNodesByTagRecursive(transformed_page, excerptTag);
239 */
240
241 Node selectedElement = getNodeByTagRecursive(transformed_page, excerptTag);
242 return selectedElement;
243
244 }
245 return transformed_page;
246 }
247
248 protected Node getNodeByIdRecursive(Node parent, String id)
249 {
250 if (parent.hasAttributes() && ((Element) parent).getAttribute("id").equals(id))
251 {
252 return parent;
253 }
254
255 NodeList children = parent.getChildNodes();
256 for (int i = 0; i < children.getLength(); i++)
257 {
258 Node result = null;
259 if ((result = getNodeByIdRecursive(children.item(i), id)) != null)
260 {
261 return result;
262 }
263 }
264 return null;
265 }
266
267 protected Node getNodeByTagRecursive(Node parent, String tag)
268 {
269 if (parent.getNodeType() == Node.ELEMENT_NODE && ((Element) parent).getTagName().equals(tag))
270 {
271 return parent;
272 }
273
274 NodeList children = parent.getChildNodes();
275 for (int i = 0; i < children.getLength(); i++)
276 {
277 Node result = null;
278 if ((result = getNodeByTagRecursive(children.item(i), tag)) != null)
279 {
280 return result;
281 }
282 }
283 return null;
284 }
285
286 protected Node modifyNodesByTagRecursive(Node parent, String tag)
287 {
288 if (parent == null || (parent.getNodeType() == Node.ELEMENT_NODE && ((Element) parent).getTagName().equals(tag)))
289 {
290 return parent;
291 }
292
293 NodeList children = parent.getChildNodes();
294 for (int i = 0; i < children.getLength(); i++)
295 {
296 Node result = null;
297 if ((result = modifyNodesByTagRecursive(children.item(i), tag)) != null)
298 {
299 //return result;
300 //logger.error("Modify node value = "+result.getNodeValue()); //NamedItem("href"););
301 //logger.error("BEFORE Modify node attribute = " + result.getAttributes().getNamedItem("href").getNodeValue());
302 //String url = result.getAttributes().getNamedItem("href").getNodeValue();
303 //url = url + "&excerptid=results";
304 //result.getAttributes().getNamedItem("href").setNodeValue(url);
305 //logger.error("AFTER Modify node attribute = " + result.getAttributes().getNamedItem("href").getNodeValue());
306 }
307 }
308 return null;
309 }
310
311 /**
312 * overwrite this to add any extra info that might be needed in the page
313 * before transformation
314 */
315 protected void addExtraInfo(Element page)
316 {
317 }
318
319 /**
320 * transform the page using xslt we need to get any format element out of
321 * the page and add it to the xslt before transforming
322 */
323 protected Node transformPage(Element page)
324 {
325 boolean allowsClientXSLT = (Boolean) config_params.get(GSConstants.ALLOW_CLIENT_SIDE_XSLT);
326 //System.out.println("Client side transforms allowed? " + allowsClientXSLT);
327
328 String currentInterface = (String) config_params.get(GSConstants.INTERFACE_NAME);
329
330 Element request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
331 String output = request.getAttribute(GSXML.OUTPUT_ATT);
332
333 //System.out.println("Current output mode is: " + output + ", current interface name is: " + currentInterface);
334
335 if (allowsClientXSLT)
336 {
337 if (!currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX) && output.equals("html"))
338 {
339 System.out.println("output is html and we are not currently using a client side version, switching");
340 // Switch the interface
341 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.concat(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX));
342 }
343 else if ((currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX) && !output.equals("html")) || output.equals("server"))
344 {
345 // The reverse needs to happen too
346 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.substring(0, currentInterface.length() - GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX.length()));
347 }
348 }
349 else if (currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX))
350 {
351 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.substring(0, currentInterface.length() - GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX.length()));
352 }
353
354 // DocType defaults in case the skin doesn't have an "xsl:output" element
355 String qualifiedName = "html";
356 String publicID = "-//W3C//DTD HTML 4.01 Transitional//EN";
357 String systemID = "http://www.w3.org/TR/html4/loose.dtd";
358
359 // We need to create an empty document with a predefined DocType,
360 // that will then be used for the transformation by the DOMResult
361 Document docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
362
363 if (output.equals("xsltclient"))
364 {
365 // If you're just getting the client-side transform page, why bother with the rest of this?
366 Element html = docWithDoctype.createElement("html");
367 Element img = docWithDoctype.createElement("img");
368 img.setAttribute("src", "interfaces/default/images/loading.gif"); // Make it dynamic
369 img.setAttribute("alt", "Please wait...");
370 Text title_text = docWithDoctype.createTextNode("Please wait..."); // Make this language dependent
371 Element head = docWithDoctype.createElement("head");
372 Element title = docWithDoctype.createElement("title");
373 title.appendChild(title_text);
374 Element body = docWithDoctype.createElement("body");
375 Element script = docWithDoctype.createElement("script");
376 Element jquery = docWithDoctype.createElement("script");
377 jquery.setAttribute("src", "jquery.js");
378 jquery.setAttribute("type", "text/javascript");
379 Comment jquery_comment = docWithDoctype.createComment("jQuery");
380 Comment script_comment = docWithDoctype.createComment("Filler for browser");
381 script.setAttribute("src", "test.js");
382 script.setAttribute("type", "text/javascript");
383 Element pagevar = docWithDoctype.createElement("script");
384 Element style = docWithDoctype.createElement("style");
385 style.setAttribute("type", "text/css");
386 Text style_text = docWithDoctype.createTextNode("body { text-align: center; padding: 50px; font: 14pt Arial, sans-serif; font-weight: bold; }");
387 pagevar.setAttribute("type", "text/javascript");
388 Text page_var_text = docWithDoctype.createTextNode("var placeholder = true;");
389
390 html.appendChild(head);
391 head.appendChild(title);
392 head.appendChild(style);
393 style.appendChild(style_text);
394 html.appendChild(body);
395 head.appendChild(pagevar);
396 head.appendChild(jquery);
397 head.appendChild(script);
398 pagevar.appendChild(page_var_text);
399 jquery.appendChild(jquery_comment);
400 script.appendChild(script_comment);
401 body.appendChild(img);
402 docWithDoctype.appendChild(html);
403
404 return (Node) docWithDoctype;
405 }
406
407 // 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
408 logger.debug("page before transforming:");
409 logger.debug(this.converter.getPrettyStringLogger(page, logger));
410
411 String action = request.getAttribute(GSXML.ACTION_ATT);
412 String subaction = request.getAttribute(GSXML.SUBACTION_ATT);
413
414 // we should choose how to transform the data based on output, eg diff
415 // choice for html, and wml??
416 // for now, if output=xml, we don't transform the page, we just return
417 // the page xml
418 Document theXML = null;
419
420 if (output.equals("xml") || output.equals("clientside"))
421 {
422 // Append some bits and pieces first...
423 theXML = converter.newDOM();
424 // Import into new document first!
425 Node newPage = theXML.importNode(page, true);
426 theXML.appendChild(newPage);
427 Element root = theXML.createElement("xsltparams");
428 newPage.appendChild(root);
429
430 Element libname = theXML.createElement("param");
431 libname.setAttribute("name", "library_name");
432 Text libnametext = theXML.createTextNode((String) config_params.get(GSConstants.LIBRARY_NAME));
433 libname.appendChild(libnametext);
434
435 Element intname = theXML.createElement("param");
436 intname.setAttribute("name", "interface_name");
437 Text intnametext = theXML.createTextNode((String) config_params.get(GSConstants.INTERFACE_NAME));
438 intname.appendChild(intnametext);
439
440 Element siteName = theXML.createElement("param");
441 siteName.setAttribute("name", "site_name");
442 Text siteNameText = theXML.createTextNode((String) config_params.get(GSConstants.SITE_NAME));
443 siteName.appendChild(siteNameText);
444
445 Element filepath = theXML.createElement("param");
446 filepath.setAttribute("name", "filepath");
447 Text filepathtext = theXML.createTextNode(GlobalProperties.getGSDL3Home());
448 filepath.appendChild(filepathtext);
449
450 root.appendChild(libname);
451 root.appendChild(intname);
452 root.appendChild(siteName);
453 root.appendChild(filepath);
454
455 if (output.equals("xml"))
456 return theXML.getDocumentElement();
457 }
458
459 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
460 String collection = "";
461 String inlineTemplate = "";
462 if (cgi_param_list != null)
463 {
464 // Don't waste time getting all the parameters
465 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
466 collection = (String) params.get(GSParams.COLLECTION);
467 if (collection == null)
468 {
469 collection = "";
470 }
471
472 inlineTemplate = (String) params.get(GSParams.INLINE_TEMPLATE);
473 }
474
475 Document style_doc = getXSLTDocument(action, subaction, collection);
476 if (style_doc == null)
477 {
478 String errorPage = this.converter.getParseErrorMessage();
479 if (errorPage != null)
480 {
481 return XMLTransformer.constructErrorXHTMLPage("Cannot parse the xslt file\n" + errorPage);
482 }
483 return page;
484 }
485
486 // put the page into a document - this is necessary for xslt to get
487 // the paths right if you have paths relative to the document root
488 // eg /page.
489 Document doc = this.converter.newDOM();
490 doc.appendChild(doc.importNode(page, true));
491 Element page_response = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
492 Element format_elem = (Element) GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
493
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);
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.