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

Last change on this file since 27090 was 27090, checked in by ak19, 11 years ago

Now XMLTransformer sets the doctype of the document generated from what the transformer object has worked this out to be from (merged) stylesheets. Now TransformingReceptionist no longer generates a new document with a doctype (that it has to work out from merged stylesheets) to pass into XMLTransformer.transform().

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