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

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

Fixing Greenstone 3's use (or lack thereof) of generics, this was done automatically so we may want to change it over time. This change will also auto-format any files that have not already been formatted.

  • Property svn:keywords set to Author Date Id Revision
File size: 35.1 KB
RevLine 
[4258]1package org.greenstone.gsdl3.core;
2
[22085]3import org.greenstone.util.GlobalProperties;
[4258]4import org.greenstone.gsdl3.util.*;
5import org.greenstone.gsdl3.action.*;
6// XML classes
[24458]7import org.w3c.dom.Node;
8import org.w3c.dom.NodeList;
[23794]9import org.w3c.dom.Comment;
10import org.w3c.dom.Text;
[24458]11import org.w3c.dom.Document;
[18433]12import org.w3c.dom.Element;
13import org.xml.sax.InputSource;
[23794]14import org.w3c.dom.NamedNodeMap;
[4258]15
16// other java classes
[24884]17import java.io.ByteArrayInputStream;
[4258]18import java.io.File;
[25635]19import java.io.Serializable;
[24884]20import java.io.StringReader;
[18433]21import java.io.StringWriter;
22import java.io.FileReader;
23import java.io.FileNotFoundException;
[24509]24import java.util.ArrayList;
[4258]25import java.util.HashMap;
26import java.util.Enumeration;
27
[18433]28import javax.xml.parsers.*;
29import javax.xml.transform.*;
30import javax.xml.transform.dom.*;
31import javax.xml.transform.stream.*;
[13124]32import org.apache.log4j.*;
[24703]33import org.apache.tools.zip.ExtraFieldUtils;
[18433]34import org.apache.xerces.dom.*;
35import org.apache.xerces.parsers.DOMParser;
[13124]36
[23794]37import org.apache.commons.lang3.StringUtils;
38
[24458]39/**
40 * A receptionist that uses xslt to transform the page_data before returning it.
41 * . Receives requests consisting of an xml representation of cgi args, and
42 * returns the page of data - in html by default. The requests are processed by
43 * the appropriate action class
44 *
[4258]45 * @see Action
46 */
[24458]47public class TransformingReceptionist extends Receptionist
48{
[4258]49
[24458]50 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.TransformingReceptionist.class.getName());
[18433]51
[24458]52 /** The preprocess.xsl file is in a fixed location */
53 static final String preprocess_xsl_filename = GlobalProperties.getGSDL3Home() + File.separatorChar + "ui" + File.separatorChar + "xslt" + File.separatorChar + "preProcess.xsl";
[18433]54
[24458]55 /** the list of xslt to use for actions */
[25635]56 protected HashMap<String, String> xslt_map = null;
[8921]57
[24458]58 /** a transformer class to transform xml using xslt */
59 protected XMLTransformer transformer = null;
[4258]60
[24458]61 protected TransformerFactory transformerFactory = null;
62 protected DOMParser parser = null;
[4258]63
[24458]64 public TransformingReceptionist()
65 {
66 super();
[25635]67 this.xslt_map = new HashMap<String, String>();
[24458]68 this.transformer = new XMLTransformer();
69 try
70 {
71 transformerFactory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
72 this.converter = new XMLConverter();
73 //transformerFactory.setURIResolver(new MyUriResolver()) ;
[4258]74
[24458]75 parser = new DOMParser();
76 parser.setFeature("http://xml.org/sax/features/validation", false);
77 // 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.
78 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
79 // a performance test showed that having this on lead to increased
80 // memory use for small-medium docs, and not much gain for large
81 // docs.
82 // http://www.sosnoski.com/opensrc/xmlbench/conclusions.html
83 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
84 parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
85 // setting a handler for when fatal errors, errors or warnings happen during xml parsing
86 // call XMLConverter's getParseErrorMessage() to get the errorstring that can be rendered as web page
87 this.parser.setErrorHandler(new XMLConverter.ParseErrorHandler());
88 }
89 catch (Exception e)
90 {
91 e.printStackTrace();
92 }
[4258]93
[24458]94 }
[20149]95
[24458]96 /** configures the receptionist - overwrite this to set up the xslt map */
97 public boolean configure()
98 {
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();
[25301]151 ac.addActionParameters(this.params);
[24458]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 return true;
[22786]183 }
184
[24458]185 protected Node postProcessPage(Element page)
[22786]186 {
[24458]187 // might need to add some data to the page
188 addExtraInfo(page);
189 // transform the page using xslt
190 Node transformed_page = transformPage(page);
191
192 // if the user has specified they want only a part of the full page then subdivide it
193 boolean subdivide = false;
194 String excerptID = null;
195 String excerptTag = null;
196 Element request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
197 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
198 if (cgi_param_list != null)
[22786]199 {
[25635]200 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
[24458]201 if ((excerptID = (String) params.get(GSParams.EXCERPT_ID)) != null)
202 {
203 subdivide = true;
204 }
205 if ((excerptTag = (String) params.get(GSParams.EXCERPT_TAG)) != null)
206 {
207 subdivide = true;
208 }
[22786]209 }
[24458]210
211 if (subdivide)
212 {
213 Node subdivided_page = subdivide(transformed_page, excerptID, excerptTag);
214 if (subdivided_page != null)
215 {
216 return subdivided_page;
217 }
218 }
219
220 return transformed_page;
[22786]221 }
[24458]222
223 protected Node subdivide(Node transformed_page, String excerptID, String excerptTag)
[22786]224 {
[24458]225 if (excerptID != null)
226 {
227 Node selectedElement = getNodeByIdRecursive(transformed_page, excerptID);
228 modifyNodesByTagRecursive(selectedElement, "a");
229 return selectedElement;
230 }
231 else if (excerptTag != null)
232 {
233 /*
234 * // define a list
235 *
236 * Node selectedElement =
237 * modifyNodesByTagRecursive(transformed_page, excerptTag);
238 */
239
240 Node selectedElement = getNodeByTagRecursive(transformed_page, excerptTag);
241 return selectedElement;
242
243 }
244 return transformed_page;
[22786]245 }
[24458]246
247 protected Node getNodeByIdRecursive(Node parent, String id)
[22786]248 {
[24458]249 if (parent.hasAttributes() && ((Element) parent).getAttribute("id").equals(id))
250 {
251 return parent;
252 }
253
254 NodeList children = parent.getChildNodes();
255 for (int i = 0; i < children.getLength(); i++)
256 {
257 Node result = null;
258 if ((result = getNodeByIdRecursive(children.item(i), id)) != null)
259 {
260 return result;
261 }
262 }
263 return null;
[22786]264 }
[24458]265
266 protected Node getNodeByTagRecursive(Node parent, String tag)
[22786]267 {
[24458]268 if (parent.getNodeType() == Node.ELEMENT_NODE && ((Element) parent).getTagName().equals(tag))
269 {
270 return parent;
271 }
272
273 NodeList children = parent.getChildNodes();
274 for (int i = 0; i < children.getLength(); i++)
275 {
276 Node result = null;
277 if ((result = getNodeByTagRecursive(children.item(i), tag)) != null)
278 {
279 return result;
280 }
281 }
282 return null;
[22786]283 }
[24458]284
285 protected Node modifyNodesByTagRecursive(Node parent, String tag)
[22786]286 {
[24522]287 if (parent == null || (parent.getNodeType() == Node.ELEMENT_NODE && ((Element) parent).getTagName().equals(tag)))
[22786]288 {
[24458]289 return parent;
[22786]290 }
[24458]291
292 NodeList children = parent.getChildNodes();
293 for (int i = 0; i < children.getLength(); i++)
294 {
295 Node result = null;
296 if ((result = modifyNodesByTagRecursive(children.item(i), tag)) != null)
297 {
298 //return result;
299 //logger.error("Modify node value = "+result.getNodeValue()); //NamedItem("href"););
[24583]300 //logger.error("BEFORE Modify node attribute = " + result.getAttributes().getNamedItem("href").getNodeValue());
301 //String url = result.getAttributes().getNamedItem("href").getNodeValue();
[24458]302 //url = url + "&excerptid=results";
[24583]303 //result.getAttributes().getNamedItem("href").setNodeValue(url);
304 //logger.error("AFTER Modify node attribute = " + result.getAttributes().getNamedItem("href").getNodeValue());
[24458]305 }
306 }
307 return null;
[22786]308 }
[24458]309
310 /**
311 * overwrite this to add any extra info that might be needed in the page
312 * before transformation
313 */
314 protected void addExtraInfo(Element page)
[22786]315 {
316 }
[24458]317
318 /**
319 * transform the page using xslt we need to get any format element out of
320 * the page and add it to the xslt before transforming
321 */
322 protected Node transformPage(Element page)
[22786]323 {
[24458]324 boolean allowsClientXSLT = (Boolean) config_params.get(GSConstants.ALLOW_CLIENT_SIDE_XSLT);
325 //System.out.println("Client side transforms allowed? " + allowsClientXSLT);
326
327 String currentInterface = (String) config_params.get(GSConstants.INTERFACE_NAME);
328
329 Element request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
330 String output = request.getAttribute(GSXML.OUTPUT_ATT);
331
332 //System.out.println("Current output mode is: " + output + ", current interface name is: " + currentInterface);
333
334 if (allowsClientXSLT)
[22786]335 {
[24458]336 if (!currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX) && output.equals("html"))
337 {
338 System.out.println("output is html and we are not currently using a client side version, switching");
339 // Switch the interface
340 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.concat(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX));
341 }
342 else if ((currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX) && !output.equals("html")) || output.equals("server"))
343 {
344 // The reverse needs to happen too
345 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.substring(0, currentInterface.length() - GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX.length()));
346 }
[22786]347 }
[24458]348 else if (currentInterface.endsWith(GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX))
349 {
350 config_params.put(GSConstants.INTERFACE_NAME, currentInterface.substring(0, currentInterface.length() - GSConstants.CLIENT_SIDE_XSLT_INTERFACE_SUFFIX.length()));
351 }
[23298]352
[24458]353 // DocType defaults in case the skin doesn't have an "xsl:output" element
354 String qualifiedName = "html";
355 String publicID = "-//W3C//DTD HTML 4.01 Transitional//EN";
356 String systemID = "http://www.w3.org/TR/html4/loose.dtd";
[4258]357
[24458]358 // We need to create an empty document with a predefined DocType,
359 // that will then be used for the transformation by the DOMResult
360 Document docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
[23968]361
[24458]362 if (output.equals("xsltclient"))
363 {
364 // If you're just getting the client-side transform page, why bother with the rest of this?
365 Element html = docWithDoctype.createElement("html");
366 Element img = docWithDoctype.createElement("img");
367 img.setAttribute("src", "interfaces/default/images/loading.gif"); // Make it dynamic
368 img.setAttribute("alt", "Please wait...");
369 Text title_text = docWithDoctype.createTextNode("Please wait..."); // Make this language dependent
370 Element head = docWithDoctype.createElement("head");
371 Element title = docWithDoctype.createElement("title");
372 title.appendChild(title_text);
373 Element body = docWithDoctype.createElement("body");
374 Element script = docWithDoctype.createElement("script");
375 Element jquery = docWithDoctype.createElement("script");
376 jquery.setAttribute("src", "jquery.js");
377 jquery.setAttribute("type", "text/javascript");
378 Comment jquery_comment = docWithDoctype.createComment("jQuery");
379 Comment script_comment = docWithDoctype.createComment("Filler for browser");
380 script.setAttribute("src", "test.js");
381 script.setAttribute("type", "text/javascript");
382 Element pagevar = docWithDoctype.createElement("script");
383 Element style = docWithDoctype.createElement("style");
384 style.setAttribute("type", "text/css");
385 Text style_text = docWithDoctype.createTextNode("body { text-align: center; padding: 50px; font: 14pt Arial, sans-serif; font-weight: bold; }");
386 pagevar.setAttribute("type", "text/javascript");
387 Text page_var_text = docWithDoctype.createTextNode("var placeholder = true;");
[23968]388
[24458]389 html.appendChild(head);
390 head.appendChild(title);
391 head.appendChild(style);
392 style.appendChild(style_text);
393 html.appendChild(body);
394 head.appendChild(pagevar);
395 head.appendChild(jquery);
396 head.appendChild(script);
397 pagevar.appendChild(page_var_text);
398 jquery.appendChild(jquery_comment);
399 script.appendChild(script_comment);
400 body.appendChild(img);
401 docWithDoctype.appendChild(html);
[23968]402
[24458]403 return (Node) docWithDoctype;
404 }
[23968]405
[24458]406 // 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
407 logger.debug("page before transforming:");
408 logger.debug(this.converter.getPrettyStringLogger(page, logger));
409
410 String action = request.getAttribute(GSXML.ACTION_ATT);
411 String subaction = request.getAttribute(GSXML.SUBACTION_ATT);
412
413 // we should choose how to transform the data based on output, eg diff
414 // choice for html, and wml??
415 // for now, if output=xml, we don't transform the page, we just return
416 // the page xml
417 Document theXML = null;
418
419 if (output.equals("xml") || output.equals("clientside"))
[23968]420 {
[24458]421 // Append some bits and pieces first...
422 theXML = converter.newDOM();
423 // Import into new document first!
424 Node newPage = theXML.importNode(page, true);
425 theXML.appendChild(newPage);
426 Element root = theXML.createElement("xsltparams");
427 newPage.appendChild(root);
428
429 Element libname = theXML.createElement("param");
430 libname.setAttribute("name", "library_name");
431 Text libnametext = theXML.createTextNode((String) config_params.get(GSConstants.LIBRARY_NAME));
432 libname.appendChild(libnametext);
433
434 Element intname = theXML.createElement("param");
435 intname.setAttribute("name", "interface_name");
436 Text intnametext = theXML.createTextNode((String) config_params.get(GSConstants.INTERFACE_NAME));
437 intname.appendChild(intnametext);
[25253]438
439 Element siteName = theXML.createElement("param");
440 siteName.setAttribute("name", "site_name");
441 Text siteNameText = theXML.createTextNode((String) config_params.get(GSConstants.SITE_NAME));
442 siteName.appendChild(siteNameText);
[24458]443
444 Element filepath = theXML.createElement("param");
445 filepath.setAttribute("name", "filepath");
446 Text filepathtext = theXML.createTextNode(GlobalProperties.getGSDL3Home());
447 filepath.appendChild(filepathtext);
448
449 root.appendChild(libname);
450 root.appendChild(intname);
[25253]451 root.appendChild(siteName);
[24458]452 root.appendChild(filepath);
453
454 if (output.equals("xml"))
455 return theXML.getDocumentElement();
[23968]456 }
[24458]457
458 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
459 String collection = "";
[24884]460 String inlineTemplate = "";
[24458]461 if (cgi_param_list != null)
[23968]462 {
[24458]463 // Don't waste time getting all the parameters
[25635]464 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
[24458]465 collection = (String) params.get(GSParams.COLLECTION);
466 if (collection == null)
[24884]467 {
[24458]468 collection = "";
[24884]469 }
470
471 inlineTemplate = (String) params.get(GSParams.INLINE_TEMPLATE);
[23968]472 }
[4258]473
[24509]474 Document style_doc = getXSLTDocument(action, subaction, collection);
[24458]475 if (style_doc == null)
476 {
[24509]477 String errorPage = this.converter.getParseErrorMessage();
478 if (errorPage != null)
479 {
480 return XMLTransformer.constructErrorXHTMLPage("Cannot parse the xslt file\n" + errorPage);
481 }
[24458]482 return page;
483 }
[23794]484
[24458]485 // put the page into a document - this is necessary for xslt to get
486 // the paths right if you have paths relative to the document root
487 // eg /page.
488 Document doc = this.converter.newDOM();
489 doc.appendChild(doc.importNode(page, true));
490 Element page_response = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
491 Element format_elem = (Element) GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
492 if (output.equals("formatelem"))
493 {
494 return format_elem;
495 }
496 if (format_elem != null)
497 {
498 //page_response.removeChild(format_elem);
499 logger.debug("format elem=" + this.converter.getPrettyStringLogger(format_elem, logger));
500 // need to transform the format info
501 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");
502 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
[9405]503
[24458]504 if (configStylesheet_doc != null)
505 {
506 Document format_doc = this.converter.newDOM();
507 format_doc.appendChild(format_doc.importNode(format_elem, true));
508 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params); // Needs addressing <-
[23794]509
[24458]510 // Since we started creating documents with DocTypes, we can end up with
511 // Document objects here. But we will be working with an Element instead,
512 // so we grab the DocumentElement() of the Document object in such a case.
513 Element new_format;
514 if (result.getNodeType() == Node.DOCUMENT_NODE)
515 {
516 new_format = ((Document) result).getDocumentElement();
517 }
518 else
519 {
520 new_format = (Element) result;
521 }
522 logger.debug("new format elem=" + this.converter.getPrettyStringLogger(new_format, logger));
523 if (output.equals("newformat"))
524 {
525 return new_format;
526 }
[4258]527
[24458]528 // add extracted GSF statements in to the main stylesheet
529 GSXSLT.mergeStylesheets(style_doc, new_format);
530 //System.out.println("added extracted GSF statements into the main stylesheet") ;
[18433]531
[24458]532 // add extracted GSF statements in to the debug test stylesheet
533 //GSXSLT.mergeStylesheets(oldStyle_doc, new_format);
534 }
535 else
536 {
537 logger.error(" couldn't parse the config_format stylesheet, adding the format info as is");
538 GSXSLT.mergeStylesheets(style_doc, format_elem);
539 //GSXSLT.mergeStylesheets(oldStyle_doc, format_elem);
540 }
541 logger.debug("the converted stylesheet is:");
542 logger.debug(this.converter.getPrettyStringLogger(style_doc.getDocumentElement(), logger));
543 }
[18433]544
[24458]545 //for debug purposes only
546 Document oldStyle_doc = style_doc;
[18433]547
[24458]548 Document preprocessingXsl;
549 try
550 {
[24884]551 preprocessingXsl = getDoc(preprocess_xsl_filename);
[24458]552 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
553 if (errMsg != null)
554 {
555 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt file: " + preprocess_xsl_filename + "\n" + errMsg);
556 }
557 }
558 catch (java.io.FileNotFoundException e)
559 {
560 return fileNotFoundErrorPage(e.getMessage());
561 }
562 catch (Exception e)
563 {
564 e.printStackTrace();
565 System.out.println("error loading preprocess xslt");
566 return XMLTransformer.constructErrorXHTMLPage("error loading preprocess xslt\n" + e.getMessage());
567 }
[18433]568
[24458]569 Document libraryXsl = null;
570 try
571 {
[24884]572 libraryXsl = getDoc(this.getLibraryXSLFilename());
[24458]573 String errMsg = ((XMLConverter.ParseErrorHandler) parser.getErrorHandler()).getErrorMessage();
574 if (errMsg != null)
575 {
576 return XMLTransformer.constructErrorXHTMLPage("Error loading xslt file: " + this.getLibraryXSLFilename() + "\n" + errMsg);
577 }
578 }
579 catch (java.io.FileNotFoundException e)
580 {
581 return fileNotFoundErrorPage(e.getMessage());
582 }
583 catch (Exception e)
584 {
585 e.printStackTrace();
586 System.out.println("error loading library xslt");
587 return XMLTransformer.constructErrorXHTMLPage("error loading library xslt\n" + e.getMessage());
588 }
[16374]589
[24458]590 // Combine the skin file and library variables/templates into one document.
591 // Please note: We dont just use xsl:import because the preprocessing stage
592 // needs to know what's available in the library.
[16374]593
[24458]594 Document skinAndLibraryXsl = null;
595 Document skinAndLibraryDoc = converter.newDOM();
[25445]596
597 // Applying the preprocessing XSLT - in its own block {} to allow use of non-unique variable names
[24458]598 {
[16374]599
[24458]600 skinAndLibraryXsl = converter.newDOM();
601 Element root = skinAndLibraryXsl.createElement("skinAndLibraryXsl");
602 skinAndLibraryXsl.appendChild(root);
[4258]603
[24458]604 Element s = skinAndLibraryXsl.createElement("skinXsl");
605 s.appendChild(skinAndLibraryXsl.importNode(style_doc.getDocumentElement(), true));
606 root.appendChild(s);
[23794]607
[24458]608 Element l = skinAndLibraryXsl.createElement("libraryXsl");
609 Element libraryXsl_el = libraryXsl.getDocumentElement();
610 l.appendChild(skinAndLibraryXsl.importNode(libraryXsl_el, true));
611 root.appendChild(l);
612 //System.out.println("Skin and Library XSL are now together") ;
[4258]613
[24458]614 //System.out.println("Pre-processing the skin file...") ;
[18433]615
[24458]616 //pre-process the skin style sheet
617 //In other words, apply the preProcess.xsl to 'skinAndLibraryXsl' in order to
618 //expand all GS-Lib statements into complete XSL statements and also to create
[25445]619 //a valid xsl style sheet document.
[18433]620
[25445]621 XMLTransformer preProcessor = new XMLTransformer();
622 // Perform the transformation, by passing in:
623 // preprocess-stylesheet, source-xsl (skinAndLibraryXsl), and the node that should
624 // be in the result (skinAndLibraryDoc)
625 preProcessor.transform_withResultNode(preprocessingXsl, skinAndLibraryXsl, skinAndLibraryDoc);
626 //System.out.println("GS-Lib statements are now expanded") ;
[24458]627 }
[25445]628
[18433]629
[24458]630 //The following code is to be uncommented if we need to append the extracted GSF statements
631 //after having extracted the GSLib elements. In case of a problem during postprocessing.
632 /*
633 * // put the page into a document - this is necessary for xslt to get
634 * // the paths right if you have paths relative to the document root //
635 * eg /page. Document doc = this.converter.newDOM();
636 * doc.appendChild(doc.importNode(page, true)); Element page_response =
637 * (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
638 * Element format_elem = (Element)GSXML.getChildByTagName(page_response,
639 * GSXML.FORMAT_ELEM); if (output.equals("formatelem")) { return
640 * format_elem; } if (format_elem != null) {
641 * //page_response.removeChild(format_elem);
642 * logger.debug("format elem="+
643 * this.converter.getPrettyString(format_elem)); // need to transform
644 * the format info String configStylesheet_file =
645 * GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(),
646 * (String)this.config_params.get(GSConstants.SITE_NAME), collection,
647 * (String)this.config_params.get(GSConstants.INTERFACE_NAME),
648 * base_interfaces, "config_format.xsl"); Document configStylesheet_doc
649 * = this.converter.getDOM(new File(configStylesheet_file)); if
650 * (configStylesheet_doc != null) { Document format_doc =
651 * this.converter.newDOM();
652 * format_doc.appendChild(format_doc.importNode(format_elem, true));
653 * Node result = this.transformer.transform(configStylesheet_doc,
654 * format_doc);
655 *
656 * // Since we started creating documents with DocTypes, we can end up
657 * with // Document objects here. But we will be working with an Element
658 * instead, // so we grab the DocumentElement() of the Document object
659 * in such a case. Element new_format; if(result.getNodeType() ==
660 * Node.DOCUMENT_NODE) { new_format =
661 * ((Document)result).getDocumentElement(); } else { new_format =
662 * (Element)result; }
663 * logger.debug("new format elem="+this.converter.getPrettyString
664 * (new_format)); if (output.equals("newformat")) { return new_format; }
665 *
666 * // add extracted GSF statements in to the main stylesheet
667 * GSXSLT.mergeStylesheets(skinAndLibraryDoc, new_format);
668 * //System.out.println
669 * ("added extracted GSF statements into the main stylesheet") ;
670 *
671 * // add extracted GSF statements in to the debug test stylesheet
672 * //GSXSLT.mergeStylesheets(oldStyle_doc, new_format); } else {
673 * logger.error(
674 * " couldn't parse the config_format stylesheet, adding the format info as is"
675 * ); GSXSLT.mergeStylesheets(skinAndLibraryDoc, format_elem); //
676 * GSXSLT.mergeStylesheets(oldStyle_doc, format_elem); }
677 * logger.debug("the converted stylesheet is:");
678 * logger.debug(this.converter
679 * .getPrettyString(skinAndLibraryDoc.getDocumentElement())); }
680 */
[18433]681
[24458]682 // there is a thing called a URIResolver which you can set for a
683 // transformer or transformer factory. may be able to use this
684 // instead of this absoluteIncludepaths hack
[18433]685
[24458]686 GSXSLT.absoluteIncludePaths(skinAndLibraryDoc, GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.SITE_NAME), collection, (String) this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
[18433]687
[24458]688 //Same but for the debug version when we want the do the transformation like we use to do
689 //without any gslib elements.
690 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);
[18433]691
[24458]692 //Send different stages of the skin xslt to the browser for debug purposes only
693 //using &o=skindoc or &o=skinandlib etc...
694 if (output.equals("skindoc"))
695 {
696 return converter.getDOM(getStringFromDocument(style_doc));
697 }
698 if (output.equals("skinandlib"))
699 {
700 return converter.getDOM(getStringFromDocument(skinAndLibraryXsl));
701 }
702 if (output.equals("skinandlibdoc") || output.equals("clientside"))
703 {
[18433]704
[24458]705 Node skinAndLib = converter.getDOM(getStringFromDocument(skinAndLibraryDoc));
[4258]706
[24458]707 if (output.equals("skinandlibdoc"))
708 {
709 return skinAndLib;
710 }
711 else
712 {
713 // Send XML and skinandlibdoc down the line together
714 Document finalDoc = converter.newDOM();
715 Node finalDocSkin = finalDoc.importNode(skinAndLibraryDoc.getDocumentElement(), true);
716 Node finalDocXML = finalDoc.importNode(theXML.getDocumentElement(), true);
717 Element root = finalDoc.createElement("skinlibPlusXML");
718 root.appendChild(finalDocSkin);
719 root.appendChild(finalDocXML);
720 finalDoc.appendChild(root);
721 return (Node) finalDoc.getDocumentElement();
722 }
723 }
724 if (output.equals("oldskindoc"))
725 {
726 return converter.getDOM(getStringFromDocument(oldStyle_doc));
727 }
728
729 // Try to get the system and public ID from the current skin xsl document
730 // otherwise keep the default values.
731 Element root = skinAndLibraryDoc.getDocumentElement();
732 NodeList nodes = root.getElementsByTagName("xsl:output");
733 // If there is at least one "xsl:output" command in the final xsl then...
734 if (nodes.getLength() != 0)
735 {
736 // There should be only one element called xsl:output,
737 // but if this is not the case get the last one
738 Element xsl_output = (Element) nodes.item(nodes.getLength() - 1);
739 if (xsl_output != null)
740 {
741 // Qualified name will always be html even for xhtml pages
742 //String attrValue = xsl_output.getAttribute("method");
743 //qualifiedName = attrValue.equals("") ? qualifiedName : attrValue;
744
745 String attrValue = xsl_output.getAttribute("doctype-system");
746 systemID = attrValue.equals("") ? systemID : attrValue;
747
748 attrValue = xsl_output.getAttribute("doctype-public");
749 publicID = attrValue.equals("") ? publicID : attrValue;
750 }
751 }
752
753 //System.out.println(converter.getPrettyString(docWithDoctype));
754 //System.out.println("Doctype vals: " + qualifiedName + " " + publicID + " " + systemID) ;
755
756 docWithDoctype = converter.newDOM(qualifiedName, publicID, systemID);
757
758 //System.out.println("Generate final HTML from current skin") ;
759 //Transformation of the XML message from the receptionist to HTML with doctype
[24884]760
[24993]761 if (inlineTemplate != null)
[24884]762 {
763 try
764 {
765 Document inlineTemplateDoc = this.converter.getDOM("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:java=\"http://xml.apache.org/xslt/java\" xmlns:util=\"xalan://org.greenstone.gsdl3.util.XSLTUtil\" xmlns:gsf=\"http://www.greenstone.org/greenstone3/schema/ConfigFormat\">" + inlineTemplate + "</xsl:stylesheet>");
766 GSXSLT.mergeStylesheets(skinAndLibraryDoc, inlineTemplateDoc.getDocumentElement());
767 }
[24993]768 catch (Exception ex)
[24884]769 {
770 ex.printStackTrace();
771 }
772 }
[24993]773
[24884]774 if (skinAndLibraryDoc.getElementsByTagName("gsf:metadata").getLength() > 0)
[24703]775 {
[24993]776 secondConfigFormatPass(collection, skinAndLibraryDoc, doc, new UserContext(request));
[24703]777 }
[24884]778
[24703]779 if (output.equals("xmlfinal"))
780 {
781 return doc;
782 }
[24884]783
[24458]784 return this.transformer.transform(skinAndLibraryDoc, doc, config_params, docWithDoctype); // The default
785
786 // The line below will do the transformation like we use to do before having Skin++ implemented,
787 // it will not contain any GS-Lib statements expanded, and the result will not contain any doctype.
788
789 //return (Element)this.transformer.transform(style_doc, doc, config_params);
790 //return null; // For now - change later
791 }
[24884]792
[24993]793 protected void secondConfigFormatPass(String collection, Document skinAndLibraryDoc, Document doc, UserContext userContext)
[24703]794 {
795 String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve"); // Hard-wired?
796 Element metaMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
[24993]797 Element metaRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
[24703]798 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
799 Element docNodeList = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
[24884]800
[24703]801 NodeList metaNodes = skinAndLibraryDoc.getElementsByTagName("gsf:metadata");
[24458]802
[24884]803 for (int i = 0; i < metaNodes.getLength(); i++)
[24703]804 {
805 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
806 param.setAttribute(GSXML.NAME_ATT, "metadata");
[24884]807 param.setAttribute(GSXML.VALUE_ATT, ((Element) metaNodes.item(i)).getAttribute(GSXML.NAME_ATT));
[24703]808 paramList.appendChild(param);
809 }
810 metaRequest.appendChild(paramList);
[24884]811
[24703]812 NodeList docNodes = doc.getElementsByTagName("documentNode");
[24884]813 for (int i = 0; i < docNodes.getLength(); i++)
[24703]814 {
815 Element docNode = this.doc.createElement(GSXML.DOC_NODE_ELEM);
[24884]816 docNode.setAttribute(GSXML.NODE_ID_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_ID_ATT));
817 docNode.setAttribute(GSXML.NODE_TYPE_ATT, ((Element) docNodes.item(i)).getAttribute(GSXML.NODE_TYPE_ATT));
[24703]818 docNodeList.appendChild(docNode);
819 }
820 metaRequest.appendChild(docNodeList);
821
822 metaMessage.appendChild(metaRequest);
[24884]823 Element response = (Element) mr.process(metaMessage);
[24703]824
825 NodeList metaDocNodes = response.getElementsByTagName(GSXML.DOC_NODE_ELEM);
[24884]826 for (int i = 0; i < docNodes.getLength(); i++)
[24703]827 {
828 GSXML.mergeMetadataLists(docNodes.item(i), metaDocNodes.item(i));
829 }
[24884]830
[24703]831 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");
832 Document configStylesheet_doc = this.converter.getDOM(new File(configStylesheet_file));
833
834 if (configStylesheet_doc != null)
835 {
836 Document format_doc = this.converter.newDOM();
837 format_doc.appendChild(format_doc.importNode(skinAndLibraryDoc.getDocumentElement().cloneNode(true), true));
838 Node result = this.transformer.transform(configStylesheet_doc, format_doc, config_params);
[24884]839 GSXSLT.mergeStylesheets(skinAndLibraryDoc, ((Document) result).getDocumentElement());
[24703]840 }
841 }
842
[24458]843 // method to convert Document to a proper XML string for debug purposes only
844 protected String getStringFromDocument(Document doc)
845 {
846 String content = "";
847 try
848 {
849 DOMSource domSource = new DOMSource(doc);
850 StringWriter writer = new StringWriter();
851 StreamResult result = new StreamResult(writer);
852 TransformerFactory tf = TransformerFactory.newInstance();
853 Transformer transformer = tf.newTransformer();
854 transformer.transform(domSource, result);
855 content = writer.toString();
[25423]856 System.out.println("Change the & to &Amp; for proper debug display");
[24458]857 content = StringUtils.replace(content, "&", "&amp;");
858 writer.flush();
859 }
860 catch (TransformerException ex)
861 {
862 ex.printStackTrace();
863 return null;
864 }
865 return content;
866 }
867
[24884]868 protected synchronized Document getDoc(String docName) throws Exception
[24458]869 {
[24884]870 File xslt_file = new File(docName);
[24458]871
872 FileReader reader = new FileReader(xslt_file);
873 InputSource xml_source = new InputSource(reader);
874 this.parser.parse(xml_source);
875 Document doc = this.parser.getDocument();
876
877 return doc;
878 }
879
[24509]880 protected Document getXSLTDocument(String action, String subaction, String collection)
[24458]881 {
882 String name = null;
883 if (!subaction.equals(""))
884 {
885 String key = action + ":" + subaction;
[25635]886 name = this.xslt_map.get(key);
[24458]887 }
888 // try the action by itself
889 if (name == null)
890 {
[25635]891 name = this.xslt_map.get(action);
[24458]892 }
893 // now find the absolute path
[24509]894 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);
895
896 if (stylesheets.size() == 0)
[24458]897 {
[24583]898 logger.error(" Can't find stylesheet for " + name);
899 return null;
[24458]900 }
[24509]901 logger.debug("Stylesheet: " + name);
[24884]902
903 Document finalDoc = this.converter.getDOM(stylesheets.get(stylesheets.size() - 1), "UTF-8");
904 if (finalDoc == null)
[24509]905 {
906 return null;
907 }
[24884]908
909 for (int i = stylesheets.size() - 2; i >= 0; i--)
[24509]910 {
911 Document currentDoc = this.converter.getDOM(stylesheets.get(i), "UTF-8");
[24884]912 if (currentDoc == null)
[24509]913 {
914 return null;
915 }
[24884]916
[24509]917 GSXSLT.mergeStylesheets(finalDoc, currentDoc.getDocumentElement());
918 }
[24884]919
[24509]920 return finalDoc;
[24458]921 }
922
923 // returns the library.xsl path of the library file that is applicable for the current interface
924 protected String getLibraryXSLFilename()
925 {
926 return GSFile.xmlTransformDir(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String) this.config_params.get(GSConstants.INTERFACE_NAME))) + File.separatorChar + "library.xsl";
927 }
928
929 // Call this when a FileNotFoundException could be thrown when loading an xsl (xml) file.
930 // Returns an error xhtml page indicating which xsl (or other xml) file is missing.
931 protected Document fileNotFoundErrorPage(String filenameMessage)
932 {
933 String errorMessage = "ERROR missing file: " + filenameMessage;
934 Element errPage = XMLTransformer.constructErrorXHTMLPage(errorMessage);
935 logger.error(errorMessage);
936 return errPage.getOwnerDocument();
937 }
[4258]938}
Note: See TracBrowser for help on using the repository browser.