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

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

Phase one of commiting the improved debugging system

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