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

Last change on this file since 29421 was 29421, checked in by kjdon, 9 years ago

adding in debug stuff for a collection, eg so that can run greenbug. Now the user can be all-collections-editor or collname-collection-editor. They are more likely to be one of these and want to use greenbug than they are to be an administrator

  • Property svn:keywords set to Author Date Id Revision
File size: 39.8 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 String debug_p = (String) params.get(GSParams.DEBUG);
681 if (debug_p != null && (debug_p.equals("on") || debug_p.equals("1") || debug_p.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 break;
692 }
693 if (!collection.equals("")) {
694 if (g.equals("all-collections-editor")) {
695 found = true;
696 break;
697 }
698
699 if (g.equals(collection+"-collection-editor")) {
700 found = true;
701 break;
702 }
703 }
704 }
705 if (found)
706 {
707 _debug = true;
708 }
709 }
710 }
711
712 config_params.put("collName", collection);
713
714 Document style_doc = getXSLTDocument(action, subaction, collection);
715 if (style_doc == null)
716 {
717 // this getParseErrorMessage may have originally worked, but now it doesn't.
718 // //String errorPage = this.converter.getParseErrorMessage();
719 // if (errorPage != null)
720 // {
721 // return XMLTransformer.constructErrorXHTMLPage("Cannot parse the xslt file\n");// + errorPage);
722 // }
723 return page;
724 }
725
726 // put the page into a document - this is necessary for xslt to get
727 // the paths right if you have paths relative to the document root
728 // eg /page.
729 Document doc = XMLConverter.newDOM();
730 doc.appendChild(doc.importNode(page, true));
731 Element page_response = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
732 Element format_elem = (Element) GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
733
734 NodeList pageElems = doc.getElementsByTagName("page");
735 if (pageElems.getLength() > 0)
736 {
737 Element pageElem = (Element) pageElems.item(0);
738 String langAtt = pageElem.getAttribute(GSXML.LANG_ATT);
739
740 if (langAtt != null && langAtt.length() > 0)
741 {
742 config_params.put("lang", langAtt);
743 }
744 }
745
746 if (output.equals("formatelem"))
747 {
748 return format_elem;
749 }
750 if (format_elem != null)
751 {
752 //page_response.removeChild(format_elem);
753 logger.debug("format elem=" + this.converter.getPrettyStringLogger(format_elem, logger));
754 // need to transform the format info
755 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");
756 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
757
758 if (configStylesheet_doc != null)
759 {
760 Document format_doc = XMLConverter.newDOM();
761 format_doc.appendChild(format_doc.importNode(format_elem, true));
762
763 if (_debug)
764 {
765 String siteHome = GSFile.siteHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME));
766 GSXSLT.insertDebugElements(format_doc, GSFile.collectionConfigFile(siteHome, collection));
767 }
768
769 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params); // Needs addressing <-
770
771 // Since we started creating documents with DocTypes, we can end up with
772 // Document objects here. But we will be working with an Element instead,
773 // so we grab the DocumentElement() of the Document object in such a case.
774 Element new_format;
775 if (result.getNodeType() == Node.DOCUMENT_NODE)
776 {
777 new_format = ((Document) result).getDocumentElement();
778 }
779 else
780 {
781 new_format = (Element) result;
782 }
783 logger.debug("new format elem=" + this.converter.getPrettyStringLogger(new_format, logger));
784 if (output.equals("newformat"))
785 {
786 return new_format;
787 }
788
789 // add extracted GSF statements in to the main stylesheet
790 if (_debug)
791 {
792 String siteHome = GSFile.siteHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME));
793 GSXSLT.mergeStylesheetsDebug(style_doc, new_format, true, true, "OTHER1", GSFile.collectionConfigFile(siteHome, collection));
794 }
795 else
796 {
797 GSXSLT.mergeStylesheets(style_doc, new_format, true);
798 }
799 //System.out.println("added extracted GSF statements into the main stylesheet") ;
800
801 // add extracted GSF statements in to the debug test stylesheet
802 //GSXSLT.mergeStylesheets(oldStyle_doc, new_format);
803 }
804 else
805 {
806 logger.error(" couldn't parse the config_format stylesheet, adding the format info as is");
807 GSXSLT.mergeStylesheets(style_doc, format_elem, true);
808 //GSXSLT.mergeStylesheets(oldStyle_doc, format_elem);
809 }
810 logger.debug("the converted stylesheet is:");
811 logger.debug(this.converter.getPrettyStringLogger(style_doc.getDocumentElement(), logger));
812 }
813
814 //for debug purposes only
815 Document oldStyle_doc = style_doc;
816 Document preprocessingXsl;
817 try
818 {
819 preprocessingXsl = getDoc(preprocess_xsl_filename);
820 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
821 if (errMsg != null)
822 {
823 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt file: " + preprocess_xsl_filename + "\n" + errMsg);
824 }
825 }
826 catch (java.io.FileNotFoundException e)
827 {
828 return fileNotFoundErrorPage(e.getMessage());
829 }
830 catch (Exception e)
831 {
832 e.printStackTrace();
833 System.out.println("error loading preprocess xslt");
834 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt\n" + e.getMessage());
835 }
836
837 Document libraryXsl = null;
838 try
839 {
840 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);
841 }
842 catch (Exception e)
843 {
844 e.printStackTrace();
845 System.out.println("error loading gslib xslt");
846 return XMLTransformer.constructErrorXHTMLPage("error loading gslib xslt\n" + e.getMessage());
847 }
848
849 // Combine the skin file and library variables/templates into one document.
850 // Please note: We dont just use xsl:import because the preprocessing stage
851 // needs to know what's available in the library.
852
853 Document skinAndLibraryXsl = null;
854 Document skinAndLibraryDoc = converter.newDOM();
855
856 // Applying the preprocessing XSLT - in its own block {} to allow use of non-unique variable names
857 {
858
859 skinAndLibraryXsl = converter.newDOM();
860 Element root = skinAndLibraryXsl.createElement("skinAndLibraryXsl");
861 skinAndLibraryXsl.appendChild(root);
862
863 Element s = skinAndLibraryXsl.createElement("skinXsl");
864 s.appendChild(skinAndLibraryXsl.importNode(style_doc.getDocumentElement(), true));
865 root.appendChild(s);
866
867 Element l = skinAndLibraryXsl.createElement("libraryXsl");
868 if (libraryXsl != null)
869 {
870 Element libraryXsl_el = libraryXsl.getDocumentElement();
871 l.appendChild(skinAndLibraryXsl.importNode(libraryXsl_el, true));
872 }
873 root.appendChild(l);
874
875 //System.out.println("Skin and Library XSL are now together") ;
876
877 //System.out.println("Pre-processing the skin file...") ;
878
879 //pre-process the skin style sheet
880 //In other words, apply the preProcess.xsl to 'skinAndLibraryXsl' in order to
881 //expand all GS-Lib statements into complete XSL statements and also to create
882 //a valid xsl style sheet document.
883
884 XMLTransformer preProcessor = new XMLTransformer();
885 // Perform the transformation, by passing in:
886 // preprocess-stylesheet, source-xsl (skinAndLibraryXsl), and the node that should
887 // be in the result (skinAndLibraryDoc)
888 preProcessor.transform_withResultNode(preprocessingXsl, skinAndLibraryXsl, skinAndLibraryDoc);
889 //System.out.println("GS-Lib statements are now expanded") ;
890 }
891
892 // there is a thing called a URIResolver which you can set for a
893 // transformer or transformer factory. may be able to use this
894 // instead of this absoluteIncludepaths hack
895
896 //GSXSLT.absoluteIncludePaths(skinAndLibraryDoc, GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
897
898 //Same but for the debug version when we want the do the transformation like we use to do
899 //without any gslib elements.
900 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);
901
902 //Send different stages of the skin xslt to the browser for debug purposes only
903 //using &o=skindoc or &o=skinandlib etc...
904 if (output.equals("skindoc"))
905 {
906 return converter.getDOM(getStringFromDocument(style_doc));
907 }
908 if (output.equals("skinandlib"))
909 {
910 return converter.getDOM(getStringFromDocument(skinAndLibraryXsl));
911 }
912 if (output.equals("skinandlibdoc") || output.equals("clientside"))
913 {
914
915 Node skinAndLib = converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
916
917 if (output.equals("skinandlibdoc"))
918 {
919 return skinAndLib;
920 }
921 else
922 {
923 // Send XML and skinandlibdoc down the line together
924 Document finalDoc = converter.newDOM();
925 Node finalDocSkin = finalDoc.importNode(skinAndLibraryDoc.getDocumentElement(), true);
926 Node finalDocXML = finalDoc.importNode(theXML.getDocumentElement(), true);
927 Element root = finalDoc.createElement("skinlibPlusXML");
928 root.appendChild(finalDocSkin);
929 root.appendChild(finalDocXML);
930 finalDoc.appendChild(root);
931 return (Node) finalDoc.getDocumentElement();
932 }
933 }
934 if (output.equals("oldskindoc"))
935 {
936 return converter.getDOM(getStringFromDocument(oldStyle_doc));
937 }
938
939 // We now no longer create a document with doctype before the transformation
940 // We let the XMLTransformer do the work of first working out the doctype from any
941 // that may be set in the (merged) stylesheets and then setting the doctype when transforming
942
943 /*
944 // Try to get the system and public ID from the current skin xsl document
945 // otherwise keep the default values.
946 Element root = skinAndLibraryDoc.getDocumentElement();
947 NodeList nodes = root.getElementsByTagName("xsl:output");
948 // If there is at least one "xsl:output" command in the final xsl then...
949 if (nodes.getLength() != 0)
950 {
951 // There should be only one element called xsl:output,
952 // but if this is not the case get the last one
953 Element xsl_output = (Element) nodes.item(nodes.getLength() - 1);
954 if (xsl_output != null)
955 {
956 // Qualified name will always be html even for xhtml pages
957 //String attrValue = xsl_output.getAttribute("method");
958 //qualifiedName = attrValue.equals("") ? qualifiedName : attrValue;
959
960 String attrValue = xsl_output.getAttribute("doctype-system");
961 systemID = attrValue.equals("") ? systemID : attrValue;
962
963 attrValue = xsl_output.getAttribute("doctype-public");
964 publicID = attrValue.equals("") ? publicID : attrValue;
965 }
966 }
967
968 //System.out.println(converter.getPrettyString(docWithDoctype));
969 //System.out.println("Doctype vals: " + qualifiedName + " " + publicID + " " + systemID) ;
970
971 docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
972 */
973
974 //System.out.println("Generate final HTML from current skin") ;
975 //Transformation of the XML message from the receptionist to HTML with doctype
976
977 if (inlineTemplate != null)
978 {
979 try
980 {
981 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");
982
983 if (_debug)
984 {
985 GSXSLT.mergeStylesheetsDebug(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement(), true, true, "OTHER2", "INLINE");
986 }
987 else
988 {
989 GSXSLT.mergeStylesheets(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement(), true);
990 }
991 }
992 catch (Exception ex)
993 {
994 ex.printStackTrace();
995 }
996 }
997
998 if (_debug)
999 {
1000 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);
1001 }
1002 else
1003 {
1004 GSXSLT.inlineImportAndIncludeFiles(skinAndLibraryDoc, null, (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
1005 }
1006 skinAndLibraryDoc = (Document) performFormatPass(collection, skinAndLibraryDoc, doc, new UserContext(request), TEXT_PASS);
1007 skinAndLibraryDoc = (Document) performFormatPass(collection, skinAndLibraryDoc, doc, new UserContext(request), CONFIG_PASS);
1008
1009 if (output.equals("xmlfinal"))
1010 {
1011 return doc;
1012 }
1013
1014 if (output.equals("skinandlibdocfinal"))
1015 {
1016 return converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
1017 }
1018
1019 // The transformer will now work out the resulting doctype from any set in the (merged) stylesheets and
1020 // will set this in the output document it creates. So don't pass in any docWithDocType to the transformer
1021 //Node finalResult = this.transformer.transform(skinAndLibraryDoc, doc, config_params, docWithDoctype);
1022 Node finalResult = this.transformer.transform(skinAndLibraryDoc, doc, config_params);
1023
1024 if (_debug)
1025 {
1026 GSXSLT.fixTables((Document) finalResult);
1027 }
1028
1029 return finalResult;
1030
1031 // The line below will do the transformation like we use to do before having Skin++ implemented,
1032 // it will not contain any GS-Lib statements expanded, and the result will not contain any doctype.
1033
1034 //return (Element)this.transformer.transform(style_doc, doc, config_params);
1035 //return null; // For now - change later
1036 }
1037
1038 protected Node performFormatPass(String collection, Document skinAndLibraryDoc, Document doc, UserContext userContext, int pass)
1039 {
1040 String formatFile;
1041 if (pass == CONFIG_PASS)
1042 {
1043 formatFile = "config_format.xsl";
1044 }
1045 else
1046 {
1047 formatFile = "text_fragment_format.xsl";
1048 }
1049
1050 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);
1051 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
1052
1053 if (configStylesheet_doc != null)
1054 {
1055 return this.transformer.transform(configStylesheet_doc, skinAndLibraryDoc, config_params);
1056 }
1057 return skinAndLibraryDoc;
1058 }
1059
1060 // method to convert Document to a proper XML string for debug purposes only
1061 protected String getStringFromDocument(Document doc)
1062 {
1063 String content = "";
1064 try
1065 {
1066 DOMSource domSource = new DOMSource(doc);
1067 StringWriter writer = new StringWriter();
1068 StreamResult result = new StreamResult(writer);
1069 TransformerFactory tf = TransformerFactory.newInstance();
1070 Transformer transformer = tf.newTransformer();
1071 transformer.transform(domSource, result);
1072 content = writer.toString();
1073 System.out.println("Change the & to &Amp; for proper debug display");
1074 content = StringUtils.replace(content, "&", "&amp;");
1075 writer.flush();
1076 }
1077 catch (TransformerException ex)
1078 {
1079 ex.printStackTrace();
1080 return null;
1081 }
1082 return content;
1083 }
1084
1085 protected synchronized Document getDoc(String docName) throws Exception
1086 {
1087 File xslt_file = new File(docName);
1088
1089 FileReader reader = new FileReader(xslt_file);
1090 InputSource xml_source = new InputSource(reader);
1091 this.parser.parse(xml_source);
1092 Document doc = this.parser.getDocument();
1093
1094 return doc;
1095 }
1096
1097 protected Document getXSLTDocument(String action, String subaction, String collection)
1098 {
1099 String name = null;
1100 if (!subaction.equals(""))
1101 {
1102 String key = action + ":" + subaction;
1103 name = this.xslt_map.get(key);
1104 }
1105 // try the action by itself
1106 if (name == null)
1107 {
1108 name = this.xslt_map.get(action);
1109 }
1110 if (name == null)
1111 {
1112 // so we can reandomly create any named page
1113 if (action.equals("p") && !subaction.equals(""))
1114 {
1115 // TODO: pages/ won't work for interface other than default!!
1116 name = "pages/" + subaction + ".xsl";
1117 }
1118
1119 }
1120
1121 Document finalDoc = null;
1122 if(name != null)
1123 {
1124 finalDoc = GSXSLT.mergedXSLTDocumentCascade(name, (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces, _debug);
1125 }
1126 return finalDoc;
1127 }
1128
1129 // returns the path to the gslib.xsl file that is applicable for the current interface
1130 protected String getGSLibXSLFilename()
1131 {
1132 return GSFile.xmlTransformDir(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))) + File.separatorChar + "gslib.xsl";
1133 }
1134
1135 // Call this when a FileNotFoundException could be thrown when loading an xsl (xml) file.
1136 // Returns an error xhtml page indicating which xsl (or other xml) file is missing.
1137 protected Document fileNotFoundErrorPage(String filenameMessage)
1138 {
1139 String errorMessage = "ERROR missing file: " + filenameMessage;
1140 Element errPage = XMLTransformer.constructErrorXHTMLPage(errorMessage);
1141 logger.error(errorMessage);
1142 return errPage.getOwnerDocument();
1143 }
1144}
Note: See TracBrowser for help on using the repository browser.