1 /* 2 * Copyright 2002-2007 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.web.servlet.view.xslt; 18 19 import java.util.ArrayList; 20 import java.util.HashMap; 21 import java.util.Iterator; 22 import java.util.List; 23 import java.util.Map; 24 import java.util.Properties; 25 26 import javax.servlet.http.HttpServletRequest; 27 import javax.servlet.http.HttpServletResponse; 28 import javax.xml.parsers.DocumentBuilderFactory; 29 import javax.xml.transform.ErrorListener; 30 import javax.xml.transform.Source; 31 import javax.xml.transform.TransformerException; 32 import javax.xml.transform.dom.DOMSource; 33 34 import junit.framework.TestCase; 35 import org.w3c.dom.Document; 36 import org.w3c.dom.Element; 37 import org.w3c.dom.Text; 38 39 import org.springframework.context.ApplicationContextException; 40 import org.springframework.core.JdkVersion; 41 import org.springframework.core.io.ClassPathResource; 42 import org.springframework.core.io.FileSystemResource; 43 import org.springframework.mock.web.MockHttpServletRequest; 44 import org.springframework.mock.web.MockHttpServletResponse; 45 import org.springframework.web.servlet.ModelAndView; 46 47 /** 48 * Unit tests for the {@link AbstractXsltView} class. 49 * 50 * @author Darren Davison 51 * @author Rick Evans 52 * @author Juergen Hoeller 53 * @since 11.03.2005 54 */ 55 public class TestXsltViewTests extends TestCase { 56 57 private TestXsltView view; 58 59 private int warnings = 0; 60 61 private int errors = 0; 62 63 private int fatal = 0; 64 65 setUp()66 public void setUp() { 67 this.view = new TestXsltView(); 68 } 69 70 testNoSuchStylesheet()71 public void testNoSuchStylesheet() { 72 view.setStylesheetLocation(new FileSystemResource("/does/not/exist.xsl")); 73 try { 74 view.initApplicationContext(); 75 fail("Must have thrown ApplicationContextException"); 76 } 77 catch (ApplicationContextException expected) { 78 } 79 } 80 testCustomErrorListener()81 public void testCustomErrorListener() { 82 view.setErrorListener(new ErrorListener() { 83 public void warning(TransformerException ex) { 84 incWarnings(); 85 } 86 public void error(TransformerException ex) { 87 incErrors(); 88 } 89 public void fatalError(TransformerException ex) { 90 incFatals(); 91 } 92 }); 93 94 // loaded stylesheet is not well formed 95 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/errors.xsl")); 96 try { 97 view.initApplicationContext(); 98 } 99 catch (ApplicationContextException ex) { 100 // shouldn't really happen, but can be let through by XSLT engine 101 assertTrue(ex.getCause() instanceof TransformerException); 102 } 103 assertEquals(1, fatal); 104 assertEquals(1, errors); 105 assertEquals(0, warnings); 106 } 107 testRender()108 public void testRender() throws Exception { 109 MockHttpServletRequest request = new MockHttpServletRequest(); 110 MockHttpServletResponse response = new MockHttpServletResponse(); 111 112 AbstractXsltView view = new AbstractXsltView() { 113 protected Source createXsltSource(Map model, String root, HttpServletRequest request, HttpServletResponse response) throws Exception { 114 Hero hero = (Hero) model.get("hero"); 115 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 116 Element node = document.createElement(root); 117 node.setAttribute("name", hero.getName()); 118 node.setAttribute("age", hero.getAge() + ""); 119 node.setAttribute("catchphrase", hero.getCatchphrase()); 120 return new DOMSource(node); 121 } 122 }; 123 124 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/sunnyDay.xsl")); 125 view.setIndent(true); 126 view.initApplicationContext(); 127 128 view.render(new ModelAndView().addObject("hero", new Hero("Jet", 24, "BOOM")).getModel(), request, response); 129 assertEquals("text/html;charset=ISO-8859-1", response.getContentType()); 130 String text = response.getContentAsString(); 131 assertEquals("<hero name=\"Jet\" age=\"24\" catchphrase=\"BOOM\" sex=\"Female\"/>", text.trim()); 132 } 133 testRenderWithCustomContentType()134 public void testRenderWithCustomContentType() throws Exception { 135 MockHttpServletRequest request = new MockHttpServletRequest(); 136 MockHttpServletResponse response = new MockHttpServletResponse(); 137 138 AbstractXsltView view = new AbstractXsltView() { 139 protected Source createXsltSource(Map model, String root, HttpServletRequest request, HttpServletResponse response) throws Exception { 140 Hero hero = (Hero) model.get("hero"); 141 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 142 Element node = document.createElement(root); 143 node.setAttribute("name", hero.getName()); 144 node.setAttribute("age", hero.getAge() + ""); 145 node.setAttribute("catchphrase", hero.getCatchphrase()); 146 return new DOMSource(node); 147 } 148 }; 149 150 view.setContentType("text/plain"); 151 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/sunnyDay.xsl")); 152 view.setIndent(true); 153 view.initApplicationContext(); 154 155 view.render(new ModelAndView().addObject("hero", new Hero("Jet", 24, "BOOM")).getModel(), request, response); 156 assertEquals("text/plain", response.getContentType()); 157 String text = response.getContentAsString(); 158 assertEquals("<hero name=\"Jet\" age=\"24\" catchphrase=\"BOOM\" sex=\"Female\"/>", text.trim()); 159 } 160 testRenderWithSingleSourceInModel()161 public void testRenderWithSingleSourceInModel() throws Exception { 162 MockHttpServletRequest request = new MockHttpServletRequest(); 163 MockHttpServletResponse response = new MockHttpServletResponse(); 164 165 AbstractXsltView view = new AbstractXsltView() { 166 protected Map getParameters(HttpServletRequest request) { 167 Map parameters = new HashMap(); 168 parameters.put("sex", "Male"); 169 return parameters; 170 } 171 }; 172 173 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/sunnyDay.xsl")); 174 Properties outputProperties = new Properties(); 175 outputProperties.setProperty("indent", "false"); 176 view.setOutputProperties(outputProperties); 177 view.initApplicationContext(); 178 179 Hero hero = new Hero("Jet", 24, "BOOM"); 180 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 181 Element node = document.createElement("hero"); 182 node.setAttribute("name", hero.getName()); 183 node.setAttribute("age", hero.getAge() + ""); 184 node.setAttribute("catchphrase", hero.getCatchphrase()); 185 186 view.render(new ModelAndView().addObject("hero", new DOMSource(node)).getModel(), request, response); 187 assertEquals("text/html;charset=ISO-8859-1", response.getContentType()); 188 String text = response.getContentAsString(); 189 assertEquals("<hero name=\"Jet\" age=\"24\" catchphrase=\"BOOM\" sex=\"Male\"/>", text.trim()); 190 } 191 testRenderWithSingleNodeInModel()192 public void testRenderWithSingleNodeInModel() throws Exception { 193 MockHttpServletRequest request = new MockHttpServletRequest(); 194 MockHttpServletResponse response = new MockHttpServletResponse(); 195 response.setWriterAccessAllowed(false); 196 197 AbstractXsltView view = new AbstractXsltView() { 198 protected Map getParameters(HttpServletRequest request) { 199 Map parameters = new HashMap(); 200 parameters.put("sex", "Male"); 201 return parameters; 202 } 203 }; 204 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/sunnyDay.xsl")); 205 view.initApplicationContext(); 206 207 Hero hero = new Hero("Jet", 24, "BOOM"); 208 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 209 Element node = document.createElement("hero"); 210 node.setAttribute("name", hero.getName()); 211 node.setAttribute("age", hero.getAge() + ""); 212 node.setAttribute("catchphrase", hero.getCatchphrase()); 213 214 view.render(new ModelAndView().addObject("hero", node).getModel(), request, response); 215 String text = response.getContentAsString(); 216 assertEquals("<hero name=\"Jet\" age=\"24\" catchphrase=\"BOOM\" sex=\"Male\"/>", text.trim()); 217 } 218 testRenderWithNoStylesheetSpecified()219 public void testRenderWithNoStylesheetSpecified() throws Exception { 220 MockHttpServletRequest request = new MockHttpServletRequest(); 221 MockHttpServletResponse response = new MockHttpServletResponse(); 222 223 AbstractXsltView view = new AbstractXsltView() { 224 protected Map getParameters(HttpServletRequest request) { 225 Map parameters = new HashMap(); 226 parameters.put("sex", "Male"); 227 return parameters; 228 } 229 }; 230 231 Properties outputProperties = new Properties(); 232 outputProperties.setProperty("indent", "false"); 233 view.setOutputProperties(outputProperties); 234 view.initApplicationContext(); 235 236 Hero hero = new Hero("Jet", 24, "BOOM"); 237 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 238 Element node = document.createElement("hero"); 239 node.setAttribute("name", hero.getName()); 240 node.setAttribute("age", hero.getAge() + ""); 241 node.setAttribute("catchphrase", hero.getCatchphrase()); 242 243 view.render(new ModelAndView().addObject("hero", new DOMSource(node)).getModel(), request, response); 244 assertEquals("text/xml;charset=ISO-8859-1", response.getContentType()); 245 String text = response.getContentAsString().trim(); 246 assertTrue(text.startsWith("<?xml")); 247 assertTrue(text.indexOf("<hero") != -1); 248 assertTrue(text.indexOf("age=\"24\"") != -1); 249 assertTrue(text.indexOf("catchphrase=\"BOOM\"") != -1); 250 assertTrue(text.indexOf("name=\"Jet\"") != -1); 251 } 252 testRenderSingleNodeInModelWithExplicitDocRootName()253 public void testRenderSingleNodeInModelWithExplicitDocRootName() throws Exception { 254 MockHttpServletRequest request = new MockHttpServletRequest(); 255 MockHttpServletResponse response = new MockHttpServletResponse(); 256 response.setOutputStreamAccessAllowed(false); 257 258 AbstractXsltView view = new AbstractXsltView() { 259 protected Source createXsltSource(Map model, String root, HttpServletRequest request, HttpServletResponse response) throws Exception { 260 Hero hero = (Hero) model.get("hero"); 261 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 262 Element node = document.createElement(root); 263 node.setAttribute("name", hero.getName()); 264 node.setAttribute("age", hero.getAge() + ""); 265 node.setAttribute("catchphrase", hero.getCatchphrase()); 266 return new DOMSource(node); 267 } 268 protected Map getParameters(HttpServletRequest request) { 269 Map parameters = new HashMap(); 270 parameters.put("sex", "Male"); 271 return parameters; 272 } 273 protected boolean useWriter() { 274 return true; 275 } 276 }; 277 278 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/sunnyDayExplicitRoot.xsl")); 279 view.setUseSingleModelNameAsRoot(false); 280 view.setRoot("baddie"); 281 view.initApplicationContext(); 282 view.render(new ModelAndView().addObject("hero", new Hero("Jet", 24, "BOOM")).getModel(), request, response); 283 String text = response.getContentAsString(); 284 assertTrue(text.trim().startsWith("<baddie ")); 285 } 286 287 /** 288 * Not a test per-se, but rather only here to validate the example 289 * given in the reference documentation. 290 */ testMyFirstWordsExampleFromTheReferenceDocumentation()291 public void testMyFirstWordsExampleFromTheReferenceDocumentation() throws Exception { 292 // TODO: Why does this test not even work on JDK 1.4? 293 // Maybe because of the Xalan version there? 294 if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { 295 return; 296 } 297 298 MockHttpServletRequest request = new MockHttpServletRequest(); 299 MockHttpServletResponse response = new MockHttpServletResponse(); 300 301 AbstractXsltView view = new AbstractXsltView() { 302 protected Source createXsltSource( 303 Map model, String rootName, HttpServletRequest request, HttpServletResponse response) 304 throws Exception { 305 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 306 Element root = document.createElement(rootName); 307 List words = (List) model.get("wordList"); 308 for (Iterator it = words.iterator(); it.hasNext();) { 309 String nextWord = (String) it.next(); 310 Element wordNode = document.createElement("word"); 311 Text textNode = document.createTextNode(nextWord); 312 wordNode.appendChild(textNode); 313 root.appendChild(wordNode); 314 } 315 return new DOMSource(root); 316 } 317 }; 318 319 view.setStylesheetLocation(new ClassPathResource("org/springframework/web/servlet/view/xslt/firstWords.xsl")); 320 view.setIndent(true); 321 view.initApplicationContext(); 322 323 Map map = new HashMap(); 324 List wordList = new ArrayList(); 325 wordList.add("hello"); 326 wordList.add("world"); 327 map.put("wordList", wordList); 328 329 view.render(new ModelAndView("home", map).getModel(), request, response); 330 String text = response.getContentAsString(); 331 assertTrue(text.trim().startsWith("<html")); 332 } 333 334 incWarnings()335 private void incWarnings() { 336 warnings++; 337 } 338 incErrors()339 private void incErrors() { 340 errors++; 341 } 342 incFatals()343 private void incFatals() { 344 fatal++; 345 } 346 347 348 private static final class TestXsltView extends AbstractXsltView { 349 } 350 351 352 private static final class Hero { 353 354 private String name; 355 private int age; 356 private String catchphrase; 357 Hero()358 public Hero() { 359 } 360 Hero(String name, int age, String catchphrase)361 public Hero(String name, int age, String catchphrase) { 362 this.name = name; 363 this.age = age; 364 this.catchphrase = catchphrase; 365 } 366 getCatchphrase()367 public String getCatchphrase() { 368 return catchphrase; 369 } 370 setCatchphrase(String catchphrase)371 public void setCatchphrase(String catchphrase) { 372 this.catchphrase = catchphrase; 373 } 374 getName()375 public String getName() { 376 return name; 377 } 378 setName(String name)379 public void setName(String name) { 380 this.name = name; 381 } 382 getAge()383 public int getAge() { 384 return age; 385 } 386 setAge(int age)387 public void setAge(int age) { 388 this.age = age; 389 } 390 } 391 392 } 393