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

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

Fixing the language setting not working correctly when getting collection text. Also correcting missing macrons in Maori

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