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

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

Changing how collection text is retrieved so that they can contain gsf elements. The downside is that it <fragment> elements turn up in the HTML. Possibly need a better solution in the future

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