| 1 4 package com.tctest.spring.integrationtests.framework; 5 6 import org.apache.commons.logging.Log; 7 import org.apache.commons.logging.LogFactory; 8 import org.apache.log4j.Logger; 9 import org.apache.tools.ant.taskdefs.War; 10 import org.apache.tools.ant.types.ZipFileSet; 11 import org.codehaus.cargo.util.AntUtils; 12 import org.codehaus.plexus.util.StringUtils; 13 import org.springframework.beans.factory.BeanFactory; 14 import org.springframework.remoting.rmi.RmiRegistryFactoryBean; 15 import org.springframework.web.context.ContextLoader; 16 import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; 17 18 import com.tc.test.TestConfigObject; 19 import com.tctest.spring.integrationtests.framework.web.RemoteContextListener; 20 21 import java.io.File ; 22 import java.io.FileOutputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.PrintWriter ; 26 import java.io.StringWriter ; 27 import java.net.URL ; 28 import java.net.URLClassLoader ; 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Map ; 35 import java.util.Set ; 36 import java.util.StringTokenizer ; 37 38 import junit.framework.Assert; 39 40 42 public class WARBuilder implements DeploymentBuilder { 43 44 Log logger = LogFactory.getLog(getClass()); 45 46 private FileSystemPath warDirectoryPath; 47 48 private String warFileName; 49 50 private Set classDirectories = new HashSet (); 51 52 private Set libs = new HashSet (); 53 54 private List resources = new ArrayList (); 55 56 private List remoteServices = new ArrayList (); 57 58 private Set beanDefinitionFiles = new HashSet (); 59 60 private Map contextParams = new HashMap (); 61 62 private List listeners = new ArrayList (); 63 64 private List servlets = new ArrayList (); 65 66 private Map taglibs = new HashMap (); 67 68 private StringBuffer remoteSvcDefBlock = new StringBuffer (); 69 70 private final FileSystemPath tempDirPath; 71 72 private String dispatcherServletName = null; 73 74 private final TestConfigObject testConfig; 75 76 77 public WARBuilder(File tempDir, TestConfigObject config) throws IOException { 78 this(File.createTempFile("test", ".war", tempDir).getAbsolutePath(), tempDir, config); 79 } 80 81 public WARBuilder(String warFileName, File tempDir, TestConfigObject config) { 82 this.warFileName = warFileName; 83 this.tempDirPath = new FileSystemPath(tempDir); 84 this.testConfig = config; 85 86 addDirectoryOrJARContainingClass(RemoteContextListener.class); addDirectoryOrJARContainingClass(LogFactory.class); addDirectoryOrJARContainingClass(Logger.class); 90 addDirectoryOrJARContainingClassOfSelectedVersion(BeanFactory.class, new String []{TestConfigObject.SPRING_VARIANT}); } 95 96 public DeploymentBuilder addClassesDirectory(FileSystemPath path) { 97 classDirectories.add(path); 98 return this; 99 } 100 101 public Deployment makeDeployment() throws Exception { 102 createWARDirectory(); 103 104 FileSystemPath warFile = makeWARFileName(); 105 logger.debug("Creating war file: " + warFile); 106 warFile.delete(); 107 108 War warTask = makeWarTask(); 109 warTask.setUpdate(false); 110 warTask.setDestFile(warFile.getFile()); 111 warTask.setWebxml(warDirectoryPath.existingFile("WEB-INF/web.xml").getFile()); 112 addWEBINFDirectory(warTask); 113 addClassesDirectories(warTask); 114 addLibs(warTask); 115 addResources(warTask); 116 warTask.execute(); 117 118 return new WARDeployment(warFile); 119 } 120 121 private FileSystemPath makeWARFileName() { 122 File f = new File (warFileName); 123 if (f.isAbsolute()) { 124 return FileSystemPath.makeNewFile(warFileName); 125 } else { 126 return tempDirPath.file(warFileName); 127 } 128 } 129 130 private void addLibs(War warTask) { 131 for (Iterator it = libs.iterator(); it.hasNext();) { 132 FileSystemPath lib = (FileSystemPath) it.next(); 133 ZipFileSet zipFileSet = new ZipFileSet(); 134 zipFileSet.setFile(lib.getFile()); 135 warTask.addLib(zipFileSet); 136 } 137 } 138 139 private War makeWarTask() { 140 return (War) new AntUtils().createAntTask("war"); 141 } 142 143 private void addClassesDirectories(War warTask) { 144 for (Iterator it = classDirectories.iterator(); it.hasNext();) { 145 FileSystemPath path = (FileSystemPath) it.next(); 146 ZipFileSet zipFileSet = new ZipFileSet(); 147 zipFileSet.setDir(path.getFile()); 148 warTask.addClasses(zipFileSet); 149 } 150 } 151 152 private void addResources(War warTask) { 153 for(Iterator it = resources.iterator(); it.hasNext(); ) { 154 ResourceDefinition definition = (ResourceDefinition) it.next(); 155 ZipFileSet zipfileset = new ZipFileSet(); 156 zipfileset.setDir(definition.location); 157 zipfileset.setIncludes(definition.includes); 158 zipfileset.setPrefix(definition.prefix); 159 warTask.addZipfileset(zipfileset); 160 } 161 } 162 163 private void addWEBINFDirectory(War warTask) { 164 ZipFileSet zipFileSet = new ZipFileSet(); 165 zipFileSet.setDir(warDirectoryPath.getFile()); 166 warTask.addFileset(zipFileSet); 167 } 168 169 public DeploymentBuilder addClassesDirectory(String directory) { 170 return addClassesDirectory(FileSystemPath.existingDir(directory)); 171 } 172 173 void createWARDirectory() throws IOException { 174 this.warDirectoryPath = tempDirPath.mkdir("tempwar"); 175 FileSystemPath webInfDir = warDirectoryPath.mkdir("WEB-INF"); 176 createWebXML(webInfDir); 177 if (this.dispatcherServletName == null) { 178 createRemotingContext(webInfDir); 179 } else { 180 createDispatcherServletContext(webInfDir); 181 } 182 } 183 184 private void createDispatcherServletContext(FileSystemPath webInfDir) throws IOException { 185 FileSystemPath springRemotingAppCtx = webInfDir.file(this.dispatcherServletName + "-servlet.xml"); 186 FileOutputStream fos = new FileOutputStream (springRemotingAppCtx.getFile()); 187 188 try { 189 appendFile(fos, "/dispatcherServletContextHeader.txt"); 190 PrintWriter pw = new PrintWriter (fos); 191 pw.println(remoteSvcDefBlock.toString()); 192 193 writeHandlerMappingBean(pw); 194 195 for (Iterator it = remoteServices.iterator(); it.hasNext();) { 196 RemoteService remoteService = (RemoteService) it.next(); 197 writeRemoteService(pw, remoteService); 198 } 199 pw.flush(); 200 writeFooter(fos); 201 } finally { 202 fos.close(); 203 } 204 } 205 206 private void createRemotingContext(FileSystemPath webInfDir) throws IOException { 207 FileSystemPath springRemotingAppCtx = webInfDir.mkdir("classes/com/tctest/spring").file("spring-remoting.xml"); 208 FileOutputStream fos = new FileOutputStream (springRemotingAppCtx.getFile()); 209 210 try { 211 appendFile(fos, "/remoteContextHeader.txt"); 212 PrintWriter pw = new PrintWriter (fos); 213 pw.println(remoteSvcDefBlock.toString()); 214 215 writeRegistryFactoryBean(pw); 216 217 for (Iterator it = remoteServices.iterator(); it.hasNext();) { 218 RemoteService remoteService = (RemoteService) it.next(); 219 writeRemoteService(pw, remoteService); 220 } 221 pw.flush(); 222 writeFooter(fos); 223 } finally { 224 fos.close(); 225 } 226 } 227 228 private void writeHandlerMappingBean(PrintWriter pw) { 229 pw.println("<bean id=\"defaultHandlerMapping\" class=\"" + BeanNameUrlHandlerMapping.class.getName() + "\"/>"); 230 } 231 232 private void writeRegistryFactoryBean(PrintWriter pw) { 233 pw.println("<bean class=\"" + RmiRegistryFactoryBean.class.getName() + "\" name=\"registry\" >"); 234 pw.println("<property name=\"port\" value=\"${rmi.registry.port}\" />"); 235 pw.println("</bean>"); 236 } 237 238 private void writeRemoteService(PrintWriter pw, RemoteService remoteService) { 239 if (this.dispatcherServletName == null) { 240 pw.println("<bean class=\"" + remoteService.getExporterType().getName() + "\">"); 241 printProperty(pw, "serviceName", remoteService.getRemoteName()); 242 printPropertyRef(pw, "service", remoteService.getBeanName()); 243 printProperty(pw, "serviceInterface", remoteService.getInterfaceType().getName()); 244 printPropertyRef(pw, "registry", "registry"); 245 pw.println("</bean>"); 246 } else { 247 pw.println("<bean name=\"/" + remoteService.getRemoteName() + "\" class=\"" + remoteService.getExporterType().getName() + "\">"); 248 printPropertyRef(pw, "service", remoteService.getBeanName()); 249 printProperty(pw, "serviceInterface", remoteService.getInterfaceType().getName()); 250 pw.println("</bean>"); 251 } 252 } 253 254 private void printProperty(PrintWriter pw, String propertyName, String propertyValue) { 255 pw.println("<property name=\"" + propertyName + "\" value=\"" + propertyValue + "\" />"); 256 } 257 258 private void printPropertyRef(PrintWriter pw, String propertyName, String propertyValue) { 259 pw.println("<property name=\"" + propertyName + "\" ref=\"" + propertyValue + "\" />"); 260 } 261 262 private void writeFooter(FileOutputStream fos) throws IOException { 263 appendFile(fos, "/remoteContextFooter.txt"); 264 } 265 266 private void appendFile(FileOutputStream fos, String fragmentName) throws IOException { 267 InputStream is = getClass().getResourceAsStream(fragmentName); 268 try { 269 int i; 271 while ((i = is.read()) != -1) 272 fos.write(i); 273 } finally { 274 is.close(); 275 } 276 277 } 278 279 private void createWebXML(FileSystemPath webInfDir) throws IOException { 280 FileSystemPath webXML = webInfDir.file("web.xml"); 281 FileOutputStream fos = new FileOutputStream (webXML.getFile()); 282 try { 283 PrintWriter pw = new PrintWriter (fos); 284 285 286 pw.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"); 287 288 pw.println("<!DOCTYPE web-app PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\" \"http://java.sun.com/dtd/web-app_2_3.dtd\">"); 290 pw.println("<web-app>\n"); 291 298 if(!beanDefinitionFiles.isEmpty()) { 299 writeContextParam(pw, ContextLoader.CONFIG_LOCATION_PARAM, generateContextConfigLocationValue()); 300 } 301 302 for (Iterator it = contextParams.entrySet().iterator(); it.hasNext();) { 303 Map.Entry param = (Map.Entry ) it.next(); 304 writeContextParam(pw, (String ) param.getKey(), (String ) param.getValue()); 305 } 306 307 if(!beanDefinitionFiles.isEmpty()) { 308 writeListener(pw, org.springframework.web.context.ContextLoaderListener.class.getName()); 309 if (this.dispatcherServletName == null) { 310 writeListener(pw, com.tctest.spring.integrationtests.framework.web.RemoteContextListener.class.getName()); 311 } 312 } 313 for (Iterator it = listeners.iterator(); it.hasNext();) { 314 writeListener(pw, ((Class ) it.next()).getName()); 315 } 316 317 for (Iterator it = servlets.iterator(); it.hasNext();) { 318 ServletDefinition definition = (ServletDefinition) it.next(); 319 writeServlet(pw, definition); 320 } 321 for (Iterator it = servlets.iterator(); it.hasNext();) { 322 ServletDefinition definition = (ServletDefinition) it.next(); 323 pw.println(" <servlet-mapping>"); 324 pw.println(" <servlet-name>"+definition.name+"</servlet-name>"); 325 pw.println(" <url-pattern>"+definition.mapping+"</url-pattern>"); 326 pw.println(" </servlet-mapping>"); 327 } 328 329 if(!taglibs.isEmpty()) { 330 pw.println(" <jsp-config>"); 331 for (Iterator it = taglibs.entrySet().iterator(); it.hasNext();) { 332 Map.Entry taglib = (Map.Entry ) it.next(); 333 pw.println(" <taglib-uri>"+taglib.getKey()+"</taglib-uri>"); 334 pw.println(" <taglib-location>"+taglib.getValue()+"</taglib-location>"); 335 } 336 pw.println(" </jsp-config>"); 337 } 338 339 pw.println("</web-app>"); 340 pw.flush(); 341 342 } finally { 343 fos.close(); 344 } 345 } 346 347 private void writeContextParam(PrintWriter pw, String name, String value) { 348 pw.println(" <context-param>"); 349 pw.println(" <param-name>"+name+"</param-name>"); 350 pw.println(" <param-value>"+value+"</param-value>"); 351 pw.println(" </context-param>"); 352 } 353 354 private void writeListener(PrintWriter pw, String className) { 355 pw.println(" <listener>"); 356 pw.println(" <listener-class>"+className+"</listener-class>"); 357 pw.println(" </listener>"); 358 } 359 360 private void writeServlet(PrintWriter pw, ServletDefinition definition) { 361 pw.println(" <servlet>"); 362 pw.println(" <servlet-name>"+definition.name+"</servlet-name>"); 363 pw.println(" <servlet-class>"+definition.servletClass.getName()+"</servlet-class>"); 364 365 if(definition.initParameters!=null) { 366 for (Iterator it = definition.initParameters.entrySet().iterator(); it.hasNext();) { 367 Map.Entry param = (Map.Entry ) it.next(); 368 pw.println(" <init-param>"); 369 pw.println(" <param-name>"+param.getKey()+"</param-name>"); 370 pw.println(" <param-value>"+param.getValue()+"</param-value>"); 371 pw.println(" </init-param>"); 372 } 373 } 374 375 if(definition.loadOnStartup) { 376 pw.println(" <load-on-startup>1</load-on-startup>"); 377 } 378 379 pw.println(" </servlet>"); 380 } 381 382 private String generateContextConfigLocationValue() { 383 StringWriter sw = new StringWriter (); 384 PrintWriter pw = new PrintWriter (sw); 385 for (Iterator it = beanDefinitionFiles.iterator(); it.hasNext();) { 386 String beanDefinitionFile = (String ) it.next(); 387 pw.println(beanDefinitionFile); 388 } 389 pw.flush(); 390 return sw.toString(); 391 } 392 393 public DeploymentBuilder addBeanDefinitionFile(String beanDefinition) { 394 beanDefinitionFiles.add(beanDefinition); 395 return this; 396 } 397 398 public DeploymentBuilder addRemoteService(String remoteName, String beanName, Class interfaceType) { 399 remoteServices.add(new RemoteService(remoteName, beanName, interfaceType)); 400 return this; 401 } 402 403 public DeploymentBuilder addRemoteService(Class exporterType, String remoteName, String beanName, Class interfaceType) { 404 remoteServices.add(new RemoteService(exporterType, remoteName, beanName, interfaceType)); 405 return this; 406 } 407 408 public DeploymentBuilder addRemoteService(String beanName, Class interfaceType) { 409 addRemoteService(StringUtils.capitaliseAllWords(beanName), beanName, interfaceType); 410 return this; 411 } 412 413 public DeploymentBuilder addRemoteServiceBlock(String block) { 414 remoteSvcDefBlock.append(block + "\n"); 415 return this; 416 } 417 418 public void setParentApplicationContextRef(String locatorFactorySelector, String parentContextKey) { 419 this.contextParams.put(ContextLoader.LOCATOR_FACTORY_SELECTOR_PARAM, locatorFactorySelector); 420 this.contextParams.put(ContextLoader.LOCATOR_FACTORY_KEY_PARAM, parentContextKey); 421 } 422 423 public DeploymentBuilder addDirectoryOrJARContainingClass(Class type) { 424 return addDirectoryOrJar(calculatePathToClass(type)); 425 } 426 427 public DeploymentBuilder addDirectoryOrJARContainingClassOfSelectedVersion(Class type, String [] variantNames) { 428 String pathSeparator = System.getProperty("path.separator"); 429 430 for (int i = 0; i < variantNames.length; i++) { 431 String selectedVariant = testConfig.selectedVariantFor(variantNames[i]); 432 String path = testConfig.variantLibraryClasspathFor(variantNames[i], selectedVariant); 433 String [] paths = path.split(pathSeparator); 434 for (int j = 0; j < paths.length; j++) { 435 addDirectoryOrJar(new FileSystemPath(new File (paths[j]))); 436 } 437 } 438 439 return this; 440 } 441 442 public DeploymentBuilder addDirectoryContainingResource(String resource) { 443 return addDirectoryOrJar(calculatePathToResource(resource)); 444 } 445 446 public DeploymentBuilder addResource(String location, String includes, String prefix) { 447 String resource = location + "/" + includes; 448 URL url = getClass().getResource(resource); 449 Assert.assertNotNull("Not found: " + resource, url); 450 FileSystemPath path = calculateDirectory(url, includes); 451 resources.add(new ResourceDefinition(path.getFile(), includes, prefix)); 452 return this; 453 } 454 455 public DeploymentBuilder addContextParameter(String name, String value) { 456 contextParams.put(name, value); 457 return this; 458 } 459 460 public DeploymentBuilder addListener(Class listenerClass) { 461 listeners.add(listenerClass); 462 return this; 463 } 464 465 public DeploymentBuilder setDispatcherServlet(String name, String mapping, Class servletClass, Map params, boolean loadOnStartup) { 466 Assert.assertNull(this.dispatcherServletName); 467 this.dispatcherServletName = name; 468 addServlet(name, mapping, servletClass, params, loadOnStartup); 469 return this; 470 } 471 472 public DeploymentBuilder addServlet(String name, String mapping, Class servletClass, Map params, boolean loadOnStartup) { 473 servlets.add(new ServletDefinition(name, mapping, servletClass, params, loadOnStartup)); 474 return this; 475 } 476 477 public DeploymentBuilder addTaglib(String uri, String location) { 478 taglibs.put(uri, location); 479 return this; 480 } 481 482 private DeploymentBuilder addDirectoryOrJar(FileSystemPath path) { 483 if (path.isDirectory()) { 484 classDirectories.add(path); 485 } else { 486 libs.add(path); 487 } 488 return this; 489 } 490 491 public static FileSystemPath calculatePathToClass(Class type) { 492 URL url = type.getResource("/" + classToPath(type)); 493 Assert.assertNotNull("Not found: " + type, url); 494 FileSystemPath filepath = calculateDirectory(url, "/" + classToPath(type)); 495 return filepath; 496 } 497 498 static public FileSystemPath calculatePathToClass(Class type, String pathString) { 499 String pathSeparator = System.getProperty("path.separator"); 500 StringTokenizer st = new StringTokenizer (pathString, pathSeparator); 501 URL [] urls = new URL [st.countTokens()]; 502 for (int i = 0; st.hasMoreTokens(); i++) { 503 String token = st.nextToken(); 504 if (token.startsWith("/")) { 505 token = "/" + token; 506 } 507 URL u = null; 508 try { 509 if (token.endsWith(".jar")) { 510 u = new URL ("jar", "", "file:/" + token + "!/"); 511 } else { 512 u = new URL ("file", "", token + "/"); 513 } 514 urls[i] = u; 515 } catch (Exception ex) { 516 throw new RuntimeException (ex); 517 } 518 } 519 URL url = new URLClassLoader (urls, null).getResource(classToPath(type)); 520 Assert.assertNotNull("Not found: " + type, url); 521 FileSystemPath filepath = calculateDirectory(url, "/" + classToPath(type)); 522 return filepath; 523 } 524 525 public static FileSystemPath calculateDirectory(URL url, String classNameAsPath) { 526 527 String urlAsString = null; 528 try { 529 urlAsString = java.net.URLDecoder.decode(url.toString(), "UTF-8"); 530 } catch (Exception ex ) { throw new RuntimeException (ex); } 531 Assert.assertTrue("URL should end with: " + classNameAsPath, urlAsString.endsWith(classNameAsPath)); 532 if (urlAsString.startsWith("file:")) { 533 return FileSystemPath.existingDir(urlAsString.substring("file:".length(), urlAsString.length() 534 - classNameAsPath.length())); 535 } else if (urlAsString.startsWith("jar:file:")) { 536 int n = urlAsString.indexOf('!'); 537 return FileSystemPath.makeExistingFile(urlAsString.substring("jar:file:".length(), n )); 538 } else throw new RuntimeException ("unsupported protocol: " + url); 539 } 540 541 private static String classToPath(Class type) { 542 return type.getName().replace('.', '/') + ".class"; 543 } 544 545 private FileSystemPath calculatePathToResource(String resource) { 546 URL url = getClass().getResource(resource); 547 Assert.assertNotNull("Not found: " + resource, url); 548 return calculateDirectory(url, resource); 549 } 550 551 552 private static class ResourceDefinition { 553 public final File location; 554 public final String prefix; 555 public final String includes; 556 557 public ResourceDefinition(File location, String includes, String prefix) { 558 this.location = location; 559 this.includes = includes; 560 this.prefix = prefix; 561 } 562 } 563 564 565 private static class ServletDefinition { 566 public final String name; 567 public final String mapping; 568 public final Class servletClass; 569 public final Map initParameters; 570 public final boolean loadOnStartup; 571 572 public ServletDefinition(String name, String mapping, Class servletClass, Map initParameters, boolean loadOnStartup) { 573 this.name = name; 574 this.mapping = mapping; 575 this.servletClass = servletClass; 576 this.initParameters = initParameters; 577 this.loadOnStartup = loadOnStartup; 578 } 579 } 580 581 } 582 | Popular Tags |