View Javadoc

1   /* Copyright (2007) Schibsted Søk AS
2    * This file is part of SESAT.
3    *
4    *   SESAT is free software: you can redistribute it and/or modify
5    *   it under the terms of the GNU Affero General Public License as published by
6    *   the Free Software Foundation, either version 3 of the License, or
7    *   (at your option) any later version.
8    *
9    *   SESAT is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU Affero General Public License for more details.
13   *
14   *   You should have received a copy of the GNU Affero General Public License
15   *   along with SESAT.  If not, see <http://www.gnu.org/licenses/>.
16   */
17  package no.sesat.search.view.velocity;
18  
19  import java.io.*;
20  
21  import javax.xml.parsers.DocumentBuilderFactory;
22  import javax.xml.parsers.ParserConfigurationException;
23  import javax.xml.transform.OutputKeys;
24  import javax.xml.transform.Transformer;
25  import javax.xml.transform.TransformerConfigurationException;
26  import javax.xml.transform.TransformerException;
27  import javax.xml.transform.TransformerFactory;
28  import javax.xml.transform.dom.DOMSource;
29  import javax.xml.transform.stream.StreamResult;
30  import org.apache.log4j.Logger;
31  
32  import org.apache.velocity.exception.ResourceNotFoundException;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Element;
35  
36  /**
37   *
38   * Load templates and adds debuginformation if VELOCITY_DEBUG is set to true.
39   *
40   * @see URLResourceLoader
41   *
42   *
43   *
44   *
45   */
46  public class URLVelocityTemplateLoader extends URLResourceLoader {
47  
48      private static final Logger LOG = Logger.getLogger(URLVelocityTemplateLoader.class);
49  
50  	private static final String DIV_TAG = "div";
51  	private static final String STYLE_ATTRIB = "style";
52  	private static final String STYLE_BORDER = "margin:3px;border:1px solid #C0C0C0";
53  	private static final String STYLE_HEADING="text-decoration:underline;font-size:10px";
54  	private static final String ONMOUSEOVER = "this.style.border='1px solid #C0C0C0';this.style.margin='4px'";
55  	private static final String ONMOUSEOUT = "this.style.border='none'";
56  
57  	/**
58  	 * getResourceStream() loads resource from url. Then add border around the
59  	 * template so its easy to see wich templates are loaded.
60  	 * @throws org.apache.velocity.exception.ResourceNotFoundException
61       */
62  	@Override
63  	public InputStream getResourceStream(final String url) throws ResourceNotFoundException {
64  
65          // Enable/disable velocity debug
66  		final boolean velocityDebug = Boolean.getBoolean("VELOCITY_DEBUG");
67          // Activate debug (Show borders/debuginfo)
68  		final boolean velocityDebugOn = Boolean.getBoolean("VELOCITY_DEBUG_ON");
69          // Onmouseover style
70  		final boolean styleOnmouseover ="onmouseover".equals(System.getProperty("VELOCITY_DEBUG_STYLE"));
71          // Silent style
72  		final boolean styleSilent ="silent".equals(System.getProperty("VELOCITY_DEBUG_STYLE"));
73          // Indicates if we found file local.(Can be edited)
74  		boolean foundLocal = false;
75  
76  		if(velocityDebug) {
77  
78              final String templatesDir = System.getProperty("VELOCITY_DEVELOP_BASEDIR");
79  
80              // Get the file equivalece of the URL by removing the host as well as the web application context path.
81              final String filePath = url.replaceAll("http://(.*?)/[^/]+/", "/").replace("localhost/", "");
82              final File file = getFile(templatesDir, filePath);
83  
84              foundLocal = file.exists();
85  
86              final InputStream stream = file.exists() ? getStream(file) : super.getResourceStream(url);
87  
88              if(velocityDebugOn && -1 == url.indexOf("rss")){
89                  StringBuilder  content = this.readTemplateFrom(stream);
90  
91                  // Create html
92                  final StringBuilder template= new  StringBuilder();
93                  template.append("\n");
94                  template.append(content);
95                  template.append("\n");
96  
97                  final StringWriter writer = new StringWriter();
98                  final Document doc = createDocument();
99  
100                 final Element div = doc.createElement(DIV_TAG);
101 
102                 if(styleOnmouseover) {
103 
104                     div.setAttribute("onmouseover", ONMOUSEOVER);
105                     div.setAttribute("onmouseout", ONMOUSEOUT);
106 
107                 }else if(styleSilent){
108 
109                         // Just print title as popup.
110                 }else {
111 
112                     final Element divHeader = doc.createElement(DIV_TAG);
113                     divHeader.setAttribute(STYLE_ATTRIB, STYLE_HEADING);
114                     divHeader.appendChild(doc.createTextNode(filePath));
115                     div.appendChild(divHeader);
116                     div.setAttribute("style", STYLE_BORDER);
117                 }
118 
119                 div.setAttribute("title", file.getName() + (foundLocal ? "(Editable)" : "(Not editable)"));
120                 div.appendChild(doc.createCDATASection(template.toString()));
121                 doc.appendChild(div);
122 
123                 internalWriteDocument(doc, writer);
124 
125                 final String result = writer.getBuffer().toString()
126                         .replace("<![CDATA[", "")
127                         .replace("]]>", "");
128 
129                 return new ByteArrayInputStream(result.getBytes());
130 
131             }else{
132                 // If debug is not currently activated OR If rss, means the output is xml.
133                 return stream;
134             }
135         }
136 		return super.getResourceStream(url);
137 	}
138 
139     /**
140      * Read template utf8.
141      * @param is to read from
142      * @return template as StringBuilder object
143      */
144     private StringBuilder readTemplateFrom(final InputStream is) {
145         StringBuilder builder = new StringBuilder();
146 
147         try {
148             InputStreamReader isr = new InputStreamReader(is, "UTF8");
149             Reader in = new BufferedReader(isr);
150             int ch;
151             while ((ch = in.read()) > -1) {
152                 builder.append((char)ch);
153             }
154             in.close();
155         } catch (IOException e) {
156             LOG.error(e);
157         }
158         return builder;
159     }
160 
161     /**
162 	 * Create file object
163 	 */
164 	private File getFile(final String templatesDir, final String filePath) {
165 
166         File result = null;
167 
168 		if(null == templatesDir) {
169             result = new File("null" + filePath);
170 
171 		}else{
172             for(String p : templatesDir.split(",")) {
173 
174                 final File file = new File(p + filePath);
175                 if(file.exists()) {
176                     result = file;
177                     break;
178                 }
179             }
180         }
181 
182 		return null == result ? new File(filePath) : result;
183 	}
184 
185 	/*
186 	 * Get stream from file of or url.
187 	 */
188 	private InputStream getStream(final File file) {
189 
190 		if (file.exists()) {
191 
192 			try {
193 				FileInputStream fileStream = new FileInputStream(file);
194                 return fileStream;
195 
196             } catch (FileNotFoundException ignore) {
197 				throw new IllegalStateException("File exist but filenotfoundexception thrown: " + ignore);
198 			}
199 
200 		} else {
201 			throw new IllegalArgumentException("File does not exist");
202 		}
203 	}
204 
205     // -- Write the document to the writer
206     private void internalWriteDocument(final Document d, final Writer w) {
207 
208         final DOMSource source = new DOMSource(d);
209         final StreamResult result = new StreamResult(w);
210 
211         final TransformerFactory factory = TransformerFactory.newInstance();
212 
213         try {
214             final Transformer transformer = factory.newTransformer();
215             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
216             transformer.transform(source, result);
217 
218         } catch (TransformerConfigurationException e) {
219             throw new RuntimeException("Xml Parser: " + e);
220 
221         } catch (TransformerException ignore) {
222             LOG.debug("Ingoring the following ", ignore);
223         }
224     }
225 
226     // -- Create a DOM document
227     private Document createDocument() {
228 
229         final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
230 
231         try {
232             return docFactory.newDocumentBuilder().newDocument();
233 
234         } catch (ParserConfigurationException e) {
235             throw new RuntimeException(e);
236         }
237     }
238 }