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

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

Switching to managing imports and includes ourselves as well as some tidying

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