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

Last change on this file since 28966 was 28966, checked in by kjdon, 10 years ago

Lots of changes. Mainly to do with removing this.doc from everywhere. Document is not thread safe. Now we tend to create a new Document everytime we are starting a new page/message etc. in service this.desc_doc is available as teh document to create service info stuff. But it should only be used for this and not for other messages. newDOM is now static for XMLConverter. method param changes for some GSXML methods.

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