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

Last change on this file since 27127 was 27127, checked in by sjm84, 11 years ago

The debug information will no longer be inserted if the user is not an admin

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