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

Last change on this file since 25999 was 25999, checked in by xiao, 12 years ago

gslib file may be non-existent in some servlets (it's not there for flax and not necessary for it), therefore the code can't assume it exists and try to use it.

  • Property svn:keywords set to Author Date Id Revision
File size: 34.1 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 String gsLibFile = this.getGSLibXSLFilename();
585 if(new File(gsLibFile).exists()) {
586 libraryXsl = getDoc(gsLibFile);
587 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
588 if (errMsg != null)
589 {
590 return XMLTransformer.constructErrorXHTMLPage("Error loading xslt file: " + this.getGSLibXSLFilename() + "\n" + errMsg);
591 }
592 }
593 }
594 catch (java.io.FileNotFoundException e)
595 {
596 return fileNotFoundErrorPage(e.getMessage());
597 }
598 catch (Exception e)
599 {
600 e.printStackTrace();
601 System.out.println("error loading gslib xslt");
602 return XMLTransformer.constructErrorXHTMLPage("error loading gslib xslt\n" + e.getMessage());
603 }
604
605 // Combine the skin file and library variables/templates into one document.
606 // Please note: We dont just use xsl:import because the preprocessing stage
607 // needs to know what's available in the library.
608
609 Document skinAndLibraryXsl = null;
610 Document skinAndLibraryDoc = converter.newDOM();
611
612 // Applying the preprocessing XSLT - in its own block {} to allow use of non-unique variable names
613 {
614
615 skinAndLibraryXsl = converter.newDOM();
616 Element root = skinAndLibraryXsl.createElement("skinAndLibraryXsl");
617 skinAndLibraryXsl.appendChild(root);
618
619 Element s = skinAndLibraryXsl.createElement("skinXsl");
620 s.appendChild(skinAndLibraryXsl.importNode(style_doc.getDocumentElement(), true));
621 root.appendChild(s);
622
623 Element l = skinAndLibraryXsl.createElement("libraryXsl");
624 if(libraryXsl != null) {
625 Element libraryXsl_el = libraryXsl.getDocumentElement();
626 l.appendChild(skinAndLibraryXsl.importNode(libraryXsl_el, true));
627 }
628 root.appendChild(l);
629
630 //System.out.println("Skin and Library XSL are now together") ;
631
632 //System.out.println("Pre-processing the skin file...") ;
633
634 //pre-process the skin style sheet
635 //In other words, apply the preProcess.xsl to 'skinAndLibraryXsl' in order to
636 //expand all GS-Lib statements into complete XSL statements and also to create
637 //a valid xsl style sheet document.
638
639 XMLTransformer preProcessor = new XMLTransformer();
640 // Perform the transformation, by passing in:
641 // preprocess-stylesheet, source-xsl (skinAndLibraryXsl), and the node that should
642 // be in the result (skinAndLibraryDoc)
643 preProcessor.transform_withResultNode(preprocessingXsl, skinAndLibraryXsl, skinAndLibraryDoc);
644 //System.out.println("GS-Lib statements are now expanded") ;
645 }
646
647 // there is a thing called a URIResolver which you can set for a
648 // transformer or transformer factory. may be able to use this
649 // instead of this absoluteIncludepaths hack
650
651 //GSXSLT.absoluteIncludePaths(skinAndLibraryDoc, GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
652
653 //Same but for the debug version when we want the do the transformation like we use to do
654 //without any gslib elements.
655 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);
656
657 //Send different stages of the skin xslt to the browser for debug purposes only
658 //using &o=skindoc or &o=skinandlib etc...
659 if (output.equals("skindoc"))
660 {
661 return converter.getDOM(getStringFromDocument(style_doc));
662 }
663 if (output.equals("skinandlib"))
664 {
665 return converter.getDOM(getStringFromDocument(skinAndLibraryXsl));
666 }
667 if (output.equals("skinandlibdoc") || output.equals("clientside"))
668 {
669
670 Node skinAndLib = converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
671
672 if (output.equals("skinandlibdoc"))
673 {
674 return skinAndLib;
675 }
676 else
677 {
678 // Send XML and skinandlibdoc down the line together
679 Document finalDoc = converter.newDOM();
680 Node finalDocSkin = finalDoc.importNode(skinAndLibraryDoc.getDocumentElement(), true);
681 Node finalDocXML = finalDoc.importNode(theXML.getDocumentElement(), true);
682 Element root = finalDoc.createElement("skinlibPlusXML");
683 root.appendChild(finalDocSkin);
684 root.appendChild(finalDocXML);
685 finalDoc.appendChild(root);
686 return (Node) finalDoc.getDocumentElement();
687 }
688 }
689 if (output.equals("oldskindoc"))
690 {
691 return converter.getDOM(getStringFromDocument(oldStyle_doc));
692 }
693
694 // Try to get the system and public ID from the current skin xsl document
695 // otherwise keep the default values.
696 Element root = skinAndLibraryDoc.getDocumentElement();
697 NodeList nodes = root.getElementsByTagName("xsl:output");
698 // If there is at least one "xsl:output" command in the final xsl then...
699 if (nodes.getLength() != 0)
700 {
701 // There should be only one element called xsl:output,
702 // but if this is not the case get the last one
703 Element xsl_output = (Element) nodes.item(nodes.getLength() - 1);
704 if (xsl_output != null)
705 {
706 // Qualified name will always be html even for xhtml pages
707 //String attrValue = xsl_output.getAttribute("method");
708 //qualifiedName = attrValue.equals("") ? qualifiedName : attrValue;
709
710 String attrValue = xsl_output.getAttribute("doctype-system");
711 systemID = attrValue.equals("") ? systemID : attrValue;
712
713 attrValue = xsl_output.getAttribute("doctype-public");
714 publicID = attrValue.equals("") ? publicID : attrValue;
715 }
716 }
717
718 //System.out.println(converter.getPrettyString(docWithDoctype));
719 //System.out.println("Doctype vals: " + qualifiedName + " " + publicID + " " + systemID) ;
720
721 docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
722
723 //System.out.println("Generate final HTML from current skin") ;
724 //Transformation of the XML message from the receptionist to HTML with doctype
725
726 if (inlineTemplate != null)
727 {
728 try
729 {
730 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");
731
732 if (_debug)
733 {
734 GSXSLT.mergeStylesheetsDebug(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement(), true, true, "OTHER2", "INLINE");
735 }
736 else
737 {
738 GSXSLT.mergeStylesheets(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement(), true);
739 }
740 }
741 catch (Exception ex)
742 {
743 ex.printStackTrace();
744 }
745 }
746
747 GSXSLT.inlineImportAndIncludeFiles(skinAndLibraryDoc, null, (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
748 skinAndLibraryDoc = (Document) secondConfigFormatPass(collection, skinAndLibraryDoc, doc, new UserContext(request));
749
750 if (_debug)
751 {
752 GSXML.addDebugSpanTags(skinAndLibraryDoc);
753 }
754
755 if (output.equals("xmlfinal"))
756 {
757 return doc;
758 }
759
760 if (output.equals("skinandlibdocfinal"))
761 {
762 return converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
763 }
764
765 return this.transformer.transform(skinAndLibraryDoc, doc, config_params, docWithDoctype);
766
767 // The line below will do the transformation like we use to do before having Skin++ implemented,
768 // it will not contain any GS-Lib statements expanded, and the result will not contain any doctype.
769
770 //return (Element)this.transformer.transform(style_doc, doc, config_params);
771 //return null; // For now - change later
772 }
773
774 protected Node secondConfigFormatPass(String collection, Document skinAndLibraryDoc, Document doc, UserContext userContext)
775 {
776 String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve"); // Hard-wired?
777 Element metaMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
778 Element metaRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
779 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
780 Element docNodeList = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
781
782 NodeList metaNodes = skinAndLibraryDoc.getElementsByTagName("gsf:metadata");
783
784 for (int i = 0; i < metaNodes.getLength(); i++)
785 {
786 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
787 param.setAttribute(GSXML.NAME_ATT, "metadata");
788 param.setAttribute(GSXML.VALUE_ATT, ((Element) metaNodes.item(i)).getAttribute(GSXML.NAME_ATT));
789 paramList.appendChild(param);
790 }
791 metaRequest.appendChild(paramList);
792
793 NodeList docNodes = doc.getElementsByTagName("documentNode");
794 for (int i = 0; i < docNodes.getLength(); i++)
795 {
796 Element docNode = this.doc.createElement(GSXML.DOC_NODE_ELEM);
797 docNode.setAttribute(GSXML.NODE_ID_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_ID_ATT));
798 docNode.setAttribute(GSXML.NODE_TYPE_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_TYPE_ATT));
799 docNodeList.appendChild(docNode);
800 }
801 metaRequest.appendChild(docNodeList);
802
803 metaMessage.appendChild(metaRequest);
804 Element response = (Element) mr.process(metaMessage);
805
806 NodeList metaDocNodes = response.getElementsByTagName(GSXML.DOC_NODE_ELEM);
807 for (int i = 0; i < docNodes.getLength(); i++)
808 {
809 GSXML.mergeMetadataLists(docNodes.item(i), metaDocNodes.item(i));
810 }
811
812 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");
813 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
814
815 if (configStylesheet_doc != null)
816 {
817 return this.transformer.transform(configStylesheet_doc, skinAndLibraryDoc, config_params);
818 }
819 return skinAndLibraryDoc;
820 }
821
822 // method to convert Document to a proper XML string for debug purposes only
823 protected String getStringFromDocument(Document doc)
824 {
825 String content = "";
826 try
827 {
828 DOMSource domSource = new DOMSource(doc);
829 StringWriter writer = new StringWriter();
830 StreamResult result = new StreamResult(writer);
831 TransformerFactory tf = TransformerFactory.newInstance();
832 Transformer transformer = tf.newTransformer();
833 transformer.transform(domSource, result);
834 content = writer.toString();
835 System.out.println("Change the & to &Amp; for proper debug display");
836 content = StringUtils.replace(content, "&", "&amp;");
837 writer.flush();
838 }
839 catch (TransformerException ex)
840 {
841 ex.printStackTrace();
842 return null;
843 }
844 return content;
845 }
846
847 protected synchronized Document getDoc(String docName) throws Exception
848 {
849 File xslt_file = new File(docName);
850
851 FileReader reader = new FileReader(xslt_file);
852 InputSource xml_source = new InputSource(reader);
853 this.parser.parse(xml_source);
854 Document doc = this.parser.getDocument();
855
856 return doc;
857 }
858
859 protected Document getXSLTDocument(String action, String subaction, String collection)
860 {
861 String name = null;
862 if (!subaction.equals(""))
863 {
864 String key = action + ":" + subaction;
865 name = this.xslt_map.get(key);
866 }
867 // try the action by itself
868 if (name == null)
869 {
870 name = this.xslt_map.get(action);
871 }
872
873 Document finalDoc = GSXSLT.mergedXSLTDocumentCascade(name, (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces, _debug);
874 return finalDoc;
875 }
876 // // now find the absolute path
877 // 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);
878 // if (stylesheets.size() == 0)
879 // {
880 // logger.error(" Can't find stylesheet for " + name);
881 // return null;
882 // }
883 // logger.debug("Stylesheet: " + name);
884
885 // Document finalDoc = this.converter.getDOM(stylesheets.get(stylesheets.size() - 1), "UTF-8");
886 // if (finalDoc == null)
887 // {
888 // return null;
889 // }
890
891 // for (int i = stylesheets.size() - 2; i >= 0; i--)
892 // {
893 // Document currentDoc = this.converter.getDOM(stylesheets.get(i), "UTF-8");
894 // if (currentDoc == null)
895 // {
896 // return null;
897 // }
898
899 // if (_debug)
900 // {
901 // GSXSLT.mergeStylesheetsDebug(finalDoc, currentDoc.getDocumentElement(), true, true, stylesheets.get(stylesheets.size() - 1).getAbsolutePath(), stylesheets.get(i).getAbsolutePath());
902 // }
903 // else
904 // {
905 // GSXSLT.mergeStylesheets(finalDoc, currentDoc.getDocumentElement(), true);
906 // }
907 // }
908
909 // return finalDoc;
910 // }
911
912 // returns the path to the gslib.xsl file that is applicable for the current interface
913 protected String getGSLibXSLFilename()
914 {
915 return GSFile.xmlTransformDir(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))) + File.separatorChar + "gslib.xsl";
916 }
917
918 // Call this when a FileNotFoundException could be thrown when loading an xsl (xml) file.
919 // Returns an error xhtml page indicating which xsl (or other xml) file is missing.
920 protected Document fileNotFoundErrorPage(String filenameMessage)
921 {
922 String errorMessage = "ERROR missing file: " + filenameMessage;
923 Element errPage = XMLTransformer.constructErrorXHTMLPage(errorMessage);
924 logger.error(errorMessage);
925 return errPage.getOwnerDocument();
926 }
927}
Note: See TracBrowser for help on using the repository browser.