aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java438
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java357
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java543
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java513
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java328
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java1042
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java726
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java146
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java533
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java364
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java529
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Script.java133
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java650
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java764
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XSLTTraceSupport.java32
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Xalan2TraceSupport.java54
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java208
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java39
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java38
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java35
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java335
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java159
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java144
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java343
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java516
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java378
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java425
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java365
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java237
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java424
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java402
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java440
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java373
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java141
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java260
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java331
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java242
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java144
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java121
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java33
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java52
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java917
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java164
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java89
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java93
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java63
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java358
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java242
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java58
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java130
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java56
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java56
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java137
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InvokeDynamicCPInfo.java85
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java56
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodHandleCPInfo.java107
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java133
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodTypeCPInfo.java82
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java112
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java74
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java67
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java559
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java313
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java390
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java61
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java630
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java953
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java403
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java1495
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java321
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java54
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java111
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java835
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java932
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java113
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java897
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java57
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java57
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java54
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java690
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java215
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java43
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java153
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java215
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java83
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java157
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java119
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java296
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java268
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java117
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java150
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java605
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java117
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java65
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java133
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java632
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java421
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java193
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java140
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java61
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java252
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java153
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java247
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java226
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java416
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java579
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Gcjh.java89
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java38
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java120
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java94
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java123
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java684
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java139
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java183
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java458
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java93
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java709
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java47
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java155
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java334
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java153
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java182
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java64
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java122
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java346
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java241
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java202
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java300
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java46
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java90
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java228
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java177
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java448
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java401
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java52
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java99
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java193
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java65
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java2283
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java190
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java109
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java542
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java1297
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java179
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java36
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java317
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java213
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TearDownOnVmCrash.java144
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java35
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java63
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java141
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java366
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java329
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java106
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java88
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java44
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java116
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java71
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java2725
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java99
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTask.java965
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskConfig.java28
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirror.java24
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirrorImpl.java1951
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java43
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java479
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java283
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java397
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java675
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java49
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java397
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java132
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java479
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java101
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java85
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java81
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java116
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java91
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html29
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java251
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java193
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java181
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java297
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java272
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java196
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java30
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java236
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java519
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java333
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java217
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java486
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java311
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java205
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java331
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java277
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java71
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java114
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java577
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java110
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java84
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java84
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java600
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java784
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java122
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java114
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java165
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java69
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java91
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java127
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java172
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java199
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java108
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java196
213 files changed, 62092 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java
new file mode 100644
index 00000000..605b3368
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java
@@ -0,0 +1,438 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+/**
+ * Invokes the ANTLR Translator generator on a grammar file.
+ *
+ */
+public class ANTLR extends Task {
+
+ private CommandlineJava commandline = new CommandlineJava();
+
+ /** the file to process */
+ private File targetFile;
+
+ /** where to output the result */
+ private File outputDirectory;
+
+ /** an optional super grammar file */
+ private File superGrammar;
+
+ /** optional flag to enable html output */
+ private boolean html;
+
+ /** optional flag to print out a diagnostic file */
+ private boolean diagnostic;
+
+ /** optional flag to add trace methods */
+ private boolean trace;
+
+ /** optional flag to add trace methods to the parser only */
+ private boolean traceParser;
+
+ /** optional flag to add trace methods to the lexer only */
+ private boolean traceLexer;
+
+ /** optional flag to add trace methods to the tree walker only */
+ private boolean traceTreeWalker;
+
+ /** working directory */
+ private File workingdir = null;
+
+ /** captures ANTLR's output */
+ private ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ /** The debug attribute */
+ private boolean debug;
+
+
+ /** Instance of a utility class to use for file operations. */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /** Constructor for ANTLR task. */
+ public ANTLR() {
+ commandline.setVm(JavaEnvUtils.getJreExecutable("java"));
+ commandline.setClassname("antlr.Tool");
+ }
+
+ /**
+ * The grammar file to process.
+ * @param target the gramer file
+ */
+ public void setTarget(File target) {
+ log("Setting target to: " + target.toString(), Project.MSG_VERBOSE);
+ this.targetFile = target;
+ }
+
+ /**
+ * The directory to write the generated files to.
+ * @param outputDirectory the output directory
+ */
+ public void setOutputdirectory(File outputDirectory) {
+ log("Setting output directory to: " + outputDirectory.toString(), Project.MSG_VERBOSE);
+ this.outputDirectory = outputDirectory;
+ }
+
+ /**
+ * Sets an optional super grammar file.
+ * Use setGlib(File superGrammar) instead.
+ * @param superGrammar the super grammar filename
+ * @deprecated since ant 1.6
+ */
+ public void setGlib(String superGrammar) {
+ String sg = null;
+ if (Os.isFamily("dos")) {
+ sg = superGrammar.replace('\\', '/');
+ } else {
+ sg = superGrammar;
+ }
+ setGlib(FILE_UTILS.resolveFile(getProject().getBaseDir(), sg));
+ }
+ /**
+ * Sets an optional super grammar file
+ * @param superGrammar the super grammar file
+ * @since ant 1.6
+ */
+ public void setGlib(File superGrammar) {
+ this.superGrammar = superGrammar;
+ }
+ /**
+ * Sets a flag to enable ParseView debugging
+ * @param enable a <code>boolean</code> value
+ */
+ public void setDebug(boolean enable) {
+ this.debug = enable;
+ }
+
+ /**
+ * If true, emit html
+ * @param enable a <code>boolean</code> value
+ */
+ public void setHtml(boolean enable) {
+ html = enable;
+ }
+
+ /**
+ * Sets a flag to emit diagnostic text
+ * @param enable a <code>boolean</code> value
+ */
+ public void setDiagnostic(boolean enable) {
+ diagnostic = enable;
+ }
+
+ /**
+ * If true, enables all tracing.
+ * @param enable a <code>boolean</code> value
+ */
+ public void setTrace(boolean enable) {
+ trace = enable;
+ }
+
+ /**
+ * If true, enables parser tracing.
+ * @param enable a <code>boolean</code> value
+ */
+ public void setTraceParser(boolean enable) {
+ traceParser = enable;
+ }
+
+ /**
+ * If true, enables lexer tracing.
+ * @param enable a <code>boolean</code> value
+ */
+ public void setTraceLexer(boolean enable) {
+ traceLexer = enable;
+ }
+
+ /**
+ * Sets a flag to allow the user to enable tree walker tracing
+ * @param enable a <code>boolean</code> value
+ */
+ public void setTraceTreeWalker(boolean enable) {
+ traceTreeWalker = enable;
+ }
+
+ // we are forced to fork ANTLR since there is a call
+ // to System.exit() and there is nothing we can do
+ // right now to avoid this. :-( (SBa)
+ // I'm not removing this method to keep backward compatibility
+ /**
+ * @ant.attribute ignore="true"
+ * @param s a <code>boolean</code> value
+ */
+ public void setFork(boolean s) {
+ //this.fork = s;
+ }
+
+ /**
+ * The working directory of the process
+ * @param d the working directory
+ */
+ public void setDir(File d) {
+ this.workingdir = d;
+ }
+
+ /**
+ * Adds a classpath to be set
+ * because a directory might be given for Antlr debug.
+ * @return a path to be configured
+ */
+ public Path createClasspath() {
+ return commandline.createClasspath(getProject()).createPath();
+ }
+
+ /**
+ * Adds a new JVM argument.
+ * @return create a new JVM argument so that any argument can be passed to the JVM.
+ * @see #setFork(boolean)
+ */
+ public Commandline.Argument createJvmarg() {
+ return commandline.createVmArgument();
+ }
+
+ /**
+ * Adds the jars or directories containing Antlr
+ * this should make the forked JVM work without having to
+ * specify it directly.
+ * @throws BuildException on error
+ */
+ public void init() throws BuildException {
+ addClasspathEntry("/antlr/ANTLRGrammarParseBehavior.class");
+ }
+
+ /**
+ * Search for the given resource and add the directory or archive
+ * that contains it to the classpath.
+ *
+ * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+ * getResource doesn't contain the name of the archive.</p>
+ * @param resource the resource name to search for
+ */
+ protected void addClasspathEntry(String resource) {
+ /*
+ * pre Ant 1.6 this method used to call getClass().getResource
+ * while Ant 1.6 will call ClassLoader.getResource().
+ *
+ * The difference is that Class.getResource expects a leading
+ * slash for "absolute" resources and will strip it before
+ * delegating to ClassLoader.getResource - so we now have to
+ * emulate Class's behavior.
+ */
+ if (resource.startsWith("/")) {
+ resource = resource.substring(1);
+ } else {
+ resource = "org/apache/tools/ant/taskdefs/optional/"
+ + resource;
+ }
+
+ File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
+ resource);
+ if (f != null) {
+ log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
+ createClasspath().setLocation(f);
+ } else {
+ log("Couldn\'t find " + resource, Project.MSG_VERBOSE);
+ }
+ }
+
+ /**
+ * Execute the task.
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+ validateAttributes();
+
+ //TODO: use ANTLR to parse the grammar file to do this.
+ File generatedFile = getGeneratedFile();
+ boolean targetIsOutOfDate =
+ targetFile.lastModified() > generatedFile.lastModified();
+ boolean superGrammarIsOutOfDate = superGrammar != null
+ && (superGrammar.lastModified() > generatedFile.lastModified());
+ if (targetIsOutOfDate || superGrammarIsOutOfDate) {
+ if (targetIsOutOfDate) {
+ log("Compiling " + targetFile + " as it is newer than "
+ + generatedFile, Project.MSG_VERBOSE);
+ } else {
+ log("Compiling " + targetFile + " as " + superGrammar
+ + " is newer than " + generatedFile, Project.MSG_VERBOSE);
+ }
+ populateAttributes();
+ commandline.createArgument().setValue(targetFile.toString());
+
+ log(commandline.describeCommand(), Project.MSG_VERBOSE);
+ int err = run(commandline.getCommandline());
+ if (err != 0) {
+ throw new BuildException("ANTLR returned: " + err, getLocation());
+ } else {
+ String output = bos.toString();
+ if (output.indexOf("error:") > -1) {
+ throw new BuildException("ANTLR signaled an error: "
+ + output, getLocation());
+ }
+ }
+ } else {
+ log("Skipped grammar file. Generated file " + generatedFile
+ + " is newer.", Project.MSG_VERBOSE);
+ }
+ }
+
+ /**
+ * A refactored method for populating all the command line arguments based
+ * on the user-specified attributes.
+ */
+ private void populateAttributes() {
+ commandline.createArgument().setValue("-o");
+ commandline.createArgument().setValue(outputDirectory.toString());
+ if (superGrammar != null) {
+ commandline.createArgument().setValue("-glib");
+ commandline.createArgument().setValue(superGrammar.toString());
+ }
+ if (html) {
+ commandline.createArgument().setValue("-html");
+ }
+ if (diagnostic) {
+ commandline.createArgument().setValue("-diagnostic");
+ }
+ if (trace) {
+ commandline.createArgument().setValue("-trace");
+ }
+ if (traceParser) {
+ commandline.createArgument().setValue("-traceParser");
+ }
+ if (traceLexer) {
+ commandline.createArgument().setValue("-traceLexer");
+ }
+ if (traceTreeWalker) {
+ if (is272()) {
+ commandline.createArgument().setValue("-traceTreeParser");
+ } else {
+ commandline.createArgument().setValue("-traceTreeWalker");
+ }
+ }
+ if (debug) {
+ commandline.createArgument().setValue("-debug");
+ }
+ }
+
+ private void validateAttributes() throws BuildException {
+ if (targetFile == null || !targetFile.isFile()) {
+ throw new BuildException("Invalid target: " + targetFile);
+ }
+
+ // if no output directory is specified, used the target's directory
+ if (outputDirectory == null) {
+ setOutputdirectory(new File(targetFile.getParent()));
+ }
+ if (!outputDirectory.isDirectory()) {
+ throw new BuildException("Invalid output directory: " + outputDirectory);
+ }
+ }
+
+ private File getGeneratedFile() throws BuildException {
+ String generatedFileName = null;
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(targetFile));
+ String line;
+ while ((line = in.readLine()) != null) {
+ int extendsIndex = line.indexOf(" extends ");
+ if (line.startsWith("class ") && extendsIndex > -1) {
+ generatedFileName = line.substring(
+ "class ".length(), extendsIndex).trim();
+ break;
+ }
+ }
+ in.close();
+ } catch (Exception e) {
+ throw new BuildException("Unable to determine generated class", e);
+ }
+ if (generatedFileName == null) {
+ throw new BuildException("Unable to determine generated class");
+ }
+ return new File(outputDirectory, generatedFileName
+ + (html ? ".html" : ".java"));
+ }
+
+ /** execute in a forked VM */
+ private int run(String[] command) throws BuildException {
+ PumpStreamHandler psh =
+ new PumpStreamHandler(new LogOutputStream(this, Project.MSG_INFO),
+ new TeeOutputStream(
+ new LogOutputStream(this,
+ Project.MSG_WARN),
+ bos)
+ );
+ Execute exe = new Execute(psh, null);
+ exe.setAntRun(getProject());
+ if (workingdir != null) {
+ exe.setWorkingDirectory(workingdir);
+ }
+ exe.setCommandline(command);
+ try {
+ return exe.execute();
+ } catch (IOException e) {
+ throw new BuildException(e, getLocation());
+ } finally {
+ FileUtils.close(bos);
+ }
+ }
+
+ /**
+ * Whether the antlr version is 2.7.2 (or higher).
+ *
+ * @return true if the version of Antlr present is 2.7.2 or later.
+ * @since Ant 1.6
+ */
+ protected boolean is272() {
+ AntClassLoader l = null;
+ try {
+ l = getProject().createClassLoader(commandline.getClasspath());
+ l.loadClass("antlr.Version");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ } finally {
+ if (l != null) {
+ l.cleanup();
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java
new file mode 100644
index 00000000..11c091a8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java
@@ -0,0 +1,357 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.StreamPumper;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ * Create a CAB archive.
+ *
+ */
+
+public class Cab extends MatchingTask {
+ private static final int DEFAULT_RESULT = -99;
+ private File cabFile;
+ private File baseDir;
+ private Vector filesets = new Vector();
+ private boolean doCompress = true;
+ private boolean doVerbose = false;
+ private String cmdOptions;
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected String archiveType = "cab";
+ // CheckStyle:VisibilityModifier ON
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * The name/location of where to create the .cab file.
+ * @param cabFile the location of the cab file.
+ */
+ public void setCabfile(File cabFile) {
+ this.cabFile = cabFile;
+ }
+
+ /**
+ * Base directory to look in for files to CAB.
+ * @param baseDir base directory for files to cab.
+ */
+ public void setBasedir(File baseDir) {
+ this.baseDir = baseDir;
+ }
+
+ /**
+ * If true, compress the files otherwise only store them.
+ * @param compress a <code>boolean</code> value.
+ */
+ public void setCompress(boolean compress) {
+ doCompress = compress;
+ }
+
+ /**
+ * If true, display cabarc output.
+ * @param verbose a <code>boolean</code> value.
+ */
+ public void setVerbose(boolean verbose) {
+ doVerbose = verbose;
+ }
+
+ /**
+ * Sets additional cabarc options that are not supported directly.
+ * @param options cabarc command line options.
+ */
+ public void setOptions(String options) {
+ cmdOptions = options;
+ }
+
+ /**
+ * Adds a set of files to archive.
+ * @param set a set of files to archive.
+ */
+ public void addFileset(FileSet set) {
+ if (filesets.size() > 0) {
+ throw new BuildException("Only one nested fileset allowed");
+ }
+ filesets.addElement(set);
+ }
+
+ /*
+ * I'm not fond of this pattern: "sub-method expected to throw
+ * task-cancelling exceptions". It feels too much like programming
+ * for side-effects to me...
+ */
+ /**
+ * Check if the attributes and nested elements are correct.
+ * @throws BuildException on error.
+ */
+ protected void checkConfiguration() throws BuildException {
+ if (baseDir == null && filesets.size() == 0) {
+ throw new BuildException("basedir attribute or one "
+ + "nested fileset is required!",
+ getLocation());
+ }
+ if (baseDir != null && !baseDir.exists()) {
+ throw new BuildException("basedir does not exist!", getLocation());
+ }
+ if (baseDir != null && filesets.size() > 0) {
+ throw new BuildException(
+ "Both basedir attribute and a nested fileset is not allowed");
+ }
+ if (cabFile == null) {
+ throw new BuildException("cabfile attribute must be set!",
+ getLocation());
+ }
+ }
+
+ /**
+ * Create a new exec delegate. The delegate task is populated so that
+ * it appears in the logs to be the same task as this one.
+ * @return the delegate.
+ * @throws BuildException on error.
+ */
+ protected ExecTask createExec() throws BuildException {
+ ExecTask exec = new ExecTask(this);
+ return exec;
+ }
+
+ /**
+ * Check to see if the target is up to date with respect to input files.
+ * @param files the list of files to check.
+ * @return true if the cab file is newer than its dependents.
+ */
+ protected boolean isUpToDate(Vector files) {
+ boolean upToDate = true;
+ final int size = files.size();
+ for (int i = 0; i < size && upToDate; i++) {
+ String file = files.elementAt(i).toString();
+ if (FILE_UTILS.resolveFile(baseDir, file).lastModified()
+ > cabFile.lastModified()) {
+ upToDate = false;
+ }
+ }
+ return upToDate;
+ }
+
+ /**
+ * Creates a list file. This temporary file contains a list of all files
+ * to be included in the cab, one file per line.
+ *
+ * <p>This method expects to only be called on Windows and thus
+ * quotes the file names.</p>
+ * @param files the list of files to use.
+ * @return the list file created.
+ * @throws IOException if there is an error.
+ */
+ protected File createListFile(Vector files)
+ throws IOException {
+ File listFile = FILE_UTILS.createTempFile("ant", "", null, true, true);
+
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(listFile));
+
+ final int size = files.size();
+ for (int i = 0; i < size; i++) {
+ writer.write('\"' + files.elementAt(i).toString() + '\"');
+ writer.newLine();
+ }
+ } finally {
+ FileUtils.close(writer);
+ }
+
+ return listFile;
+ }
+
+ /**
+ * Append all files found by a directory scanner to a vector.
+ * @param files the vector to append the files to.
+ * @param ds the scanner to get the files from.
+ */
+ protected void appendFiles(Vector files, DirectoryScanner ds) {
+ String[] dsfiles = ds.getIncludedFiles();
+
+ for (int i = 0; i < dsfiles.length; i++) {
+ files.addElement(dsfiles[i]);
+ }
+ }
+
+ /**
+ * Get the complete list of files to be included in the cab. Filenames
+ * are gathered from the fileset if it has been added, otherwise from the
+ * traditional include parameters.
+ * @return the list of files.
+ * @throws BuildException if there is an error.
+ */
+ protected Vector getFileList() throws BuildException {
+ Vector files = new Vector();
+
+ if (baseDir != null) {
+ // get files from old methods - includes and nested include
+ appendFiles(files, super.getDirectoryScanner(baseDir));
+ } else {
+ FileSet fs = (FileSet) filesets.elementAt(0);
+ baseDir = fs.getDir();
+ appendFiles(files, fs.getDirectoryScanner(getProject()));
+ }
+
+ return files;
+ }
+
+ /**
+ * execute this task.
+ * @throws BuildException on error.
+ */
+ public void execute() throws BuildException {
+
+ checkConfiguration();
+
+ Vector files = getFileList();
+
+ // quick exit if the target is up to date
+ if (isUpToDate(files)) {
+ return;
+ }
+
+ log("Building " + archiveType + ": " + cabFile.getAbsolutePath());
+
+ if (!Os.isFamily("windows")) {
+ log("Using listcab/libcabinet", Project.MSG_VERBOSE);
+
+ StringBuffer sb = new StringBuffer();
+
+ Enumeration fileEnum = files.elements();
+
+ while (fileEnum.hasMoreElements()) {
+ sb.append(fileEnum.nextElement()).append("\n");
+ }
+ sb.append("\n").append(cabFile.getAbsolutePath()).append("\n");
+
+ try {
+ Process p = Execute.launch(getProject(),
+ new String[] {"listcab"}, null,
+ baseDir != null ? baseDir
+ : getProject().getBaseDir(),
+ true);
+ OutputStream out = p.getOutputStream();
+
+ // Create the stream pumpers to forward listcab's stdout and stderr to the log
+ // note: listcab is an interactive program, and issues prompts for every new line.
+ // Therefore, make it show only with verbose logging turned on.
+ LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE);
+ LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR);
+ StreamPumper outPump = new StreamPumper(p.getInputStream(), outLog);
+ StreamPumper errPump = new StreamPumper(p.getErrorStream(), errLog);
+
+ // Pump streams asynchronously
+ (new Thread(outPump)).start();
+ (new Thread(errPump)).start();
+
+ out.write(sb.toString().getBytes());
+ out.flush();
+ out.close();
+
+ // A wild default for when the thread is interrupted
+ int result = DEFAULT_RESULT;
+
+ try {
+ // Wait for the process to finish
+ result = p.waitFor();
+
+ // Wait for the end of output and error streams
+ outPump.waitFor();
+ outLog.close();
+ errPump.waitFor();
+ errLog.close();
+ } catch (InterruptedException ie) {
+ log("Thread interrupted: " + ie);
+ }
+
+ // Informative summary message in case of errors
+ if (Execute.isFailure(result)) {
+ log("Error executing listcab; error code: " + result);
+ }
+ } catch (IOException ex) {
+ String msg = "Problem creating " + cabFile + " " + ex.getMessage();
+ throw new BuildException(msg, getLocation());
+ }
+ } else {
+ try {
+ File listFile = createListFile(files);
+ ExecTask exec = createExec();
+ File outFile = null;
+
+ // die if cabarc fails
+ exec.setFailonerror(true);
+ exec.setDir(baseDir);
+
+ if (!doVerbose) {
+ outFile = FILE_UTILS.createTempFile("ant", "", null, true, true);
+ exec.setOutput(outFile);
+ }
+
+ exec.setExecutable("cabarc");
+ exec.createArg().setValue("-r");
+ exec.createArg().setValue("-p");
+
+ if (!doCompress) {
+ exec.createArg().setValue("-m");
+ exec.createArg().setValue("none");
+ }
+
+ if (cmdOptions != null) {
+ exec.createArg().setLine(cmdOptions);
+ }
+
+ exec.createArg().setValue("n");
+ exec.createArg().setFile(cabFile);
+ exec.createArg().setValue("@" + listFile.getAbsolutePath());
+
+ exec.execute();
+
+ if (outFile != null) {
+ outFile.delete();
+ }
+
+ listFile.delete();
+ } catch (IOException ioe) {
+ String msg = "Problem creating " + cabFile + " " + ioe.getMessage();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java
new file mode 100644
index 00000000..b63ef933
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java
@@ -0,0 +1,543 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.util.CollectionUtils;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Displays all the current properties in the build. The output can be sent to
+ * a file if desired. <P>
+ *
+ * Attribute "destfile" defines a file to send the properties to. This can be
+ * processed as a standard property file later. <P>
+ *
+ * Attribute "prefix" defines a prefix which is used to filter the properties
+ * only those properties starting with this prefix will be echoed. <P>
+ *
+ * By default, the "failonerror" attribute is enabled. If an error occurs while
+ * writing the properties to a file, and this attribute is enabled, then a
+ * BuildException will be thrown. If disabled, then IO errors will be reported
+ * as a log statement, but no error will be thrown. <P>
+ *
+ * Examples: <pre>
+ * &lt;echoproperties /&gt;
+ * </pre> Report the current properties to the log. <P>
+ *
+ * <pre>
+ * &lt;echoproperties destfile="my.properties" /&gt;
+ * </pre> Report the current properties to the file "my.properties", and will
+ * fail the build if the file could not be created or written to. <P>
+ *
+ * <pre>
+ * &lt;echoproperties destfile="my.properties" failonerror="false"
+ * prefix="ant" /&gt;
+ * </pre> Report all properties beginning with 'ant' to the file
+ * "my.properties", and will log a message if the file could not be created or
+ * written to, but will still allow the build to continue.
+ *
+ *@since Ant 1.5
+ */
+public class EchoProperties extends Task {
+
+ /**
+ * the properties element.
+ */
+ private static final String PROPERTIES = "properties";
+
+ /**
+ * the property element.
+ */
+ private static final String PROPERTY = "property";
+
+ /**
+ * name attribute for property, testcase and testsuite elements.
+ */
+ private static final String ATTR_NAME = "name";
+
+ /**
+ * value attribute for property elements.
+ */
+ private static final String ATTR_VALUE = "value";
+
+ /**
+ * the input file.
+ */
+ private File inFile = null;
+
+ /**
+ * File object pointing to the output file. If this is null, then
+ * we output to the project log, not to a file.
+ */
+ private File destfile = null;
+
+ /**
+ * If this is true, then errors generated during file output will become
+ * build errors, and if false, then such errors will be logged, but not
+ * thrown.
+ */
+ private boolean failonerror = true;
+
+ private Vector propertySets = new Vector();
+
+ private String format = "text";
+
+ private String prefix;
+
+ /**
+ * @since Ant 1.7
+ */
+ private String regex;
+
+ /**
+ * Sets the input file.
+ *
+ * @param file the input file
+ */
+ public void setSrcfile(File file) {
+ inFile = file;
+ }
+
+ /**
+ * Set a file to store the property output. If this is never specified,
+ * then the output will be sent to the Ant log.
+ *
+ *@param destfile file to store the property output
+ */
+ public void setDestfile(File destfile) {
+ this.destfile = destfile;
+ }
+
+
+ /**
+ * If true, the task will fail if an error occurs writing the properties
+ * file, otherwise errors are just logged.
+ *
+ *@param failonerror <tt>true</tt> if IO exceptions are reported as build
+ * exceptions, or <tt>false</tt> if IO exceptions are ignored.
+ */
+ public void setFailOnError(boolean failonerror) {
+ this.failonerror = failonerror;
+ }
+
+
+ /**
+ * If the prefix is set, then only properties which start with this
+ * prefix string will be recorded. If regex is not set and if this
+ * is never set, or it is set to an empty string or <tt>null</tt>,
+ * then all properties will be recorded. <P>
+ *
+ * For example, if the attribute is set as:
+ * <PRE>&lt;echoproperties prefix="ant." /&gt;</PRE>
+ * then the property "ant.home" will be recorded, but "ant-example"
+ * will not.
+ *
+ * @param prefix The new prefix value
+ */
+ public void setPrefix(String prefix) {
+ if (prefix != null && prefix.length() != 0) {
+ this.prefix = prefix;
+ PropertySet ps = new PropertySet();
+ ps.setProject(getProject());
+ ps.appendPrefix(prefix);
+ addPropertyset(ps);
+ }
+ }
+
+ /**
+ * If the regex is set, then only properties whose names match it
+ * will be recorded. If prefix is not set and if this is never set,
+ * or it is set to an empty string or <tt>null</tt>, then all
+ * properties will be recorded.<P>
+ *
+ * For example, if the attribute is set as:
+ * <PRE>&lt;echoproperties prefix=".*ant.*" /&gt;</PRE>
+ * then the properties "ant.home" and "user.variant" will be recorded,
+ * but "ant-example" will not.
+ *
+ * @param regex The new regex value
+ *
+ * @since Ant 1.7
+ */
+ public void setRegex(String regex) {
+ if (regex != null && regex.length() != 0) {
+ this.regex = regex;
+ PropertySet ps = new PropertySet();
+ ps.setProject(getProject());
+ ps.appendRegex(regex);
+ addPropertyset(ps);
+ }
+ }
+
+ /**
+ * A set of properties to write.
+ * @param ps the property set to write
+ * @since Ant 1.6
+ */
+ public void addPropertyset(PropertySet ps) {
+ propertySets.addElement(ps);
+ }
+
+ /**
+ * Set the output format - xml or text.
+ * @param ea an enumerated <code>FormatAttribute</code> value
+ */
+ public void setFormat(FormatAttribute ea) {
+ format = ea.getValue();
+ }
+
+ /**
+ * A enumerated type for the format attribute.
+ * The values are "xml" and "text".
+ */
+ public static class FormatAttribute extends EnumeratedAttribute {
+ private String [] formats = new String[]{"xml", "text"};
+
+ /**
+ * @see EnumeratedAttribute#getValues()
+ * @return accepted values
+ */
+ public String[] getValues() {
+ return formats;
+ }
+ }
+
+ /**
+ * Run the task.
+ *
+ *@exception BuildException trouble, probably file IO
+ */
+ public void execute() throws BuildException {
+ if (prefix != null && regex != null) {
+ throw new BuildException("Please specify either prefix"
+ + " or regex, but not both", getLocation());
+ }
+ //copy the properties file
+ Hashtable allProps = new Hashtable();
+
+ /* load properties from file if specified, otherwise
+ use Ant's properties */
+ if (inFile == null && propertySets.size() == 0) {
+ // add ant properties
+ allProps.putAll(getProject().getProperties());
+ } else if (inFile != null) {
+ if (inFile.exists() && inFile.isDirectory()) {
+ String message = "srcfile is a directory!";
+ if (failonerror) {
+ throw new BuildException(message, getLocation());
+ } else {
+ log(message, Project.MSG_ERR);
+ }
+ return;
+ }
+
+ if (inFile.exists() && !inFile.canRead()) {
+ String message = "Can not read from the specified srcfile!";
+ if (failonerror) {
+ throw new BuildException(message, getLocation());
+ } else {
+ log(message, Project.MSG_ERR);
+ }
+ return;
+ }
+
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(inFile);
+ Properties props = new Properties();
+ props.load(in);
+ allProps.putAll(props);
+ } catch (FileNotFoundException fnfe) {
+ String message =
+ "Could not find file " + inFile.getAbsolutePath();
+ if (failonerror) {
+ throw new BuildException(message, fnfe, getLocation());
+ } else {
+ log(message, Project.MSG_WARN);
+ }
+ return;
+ } catch (IOException ioe) {
+ String message =
+ "Could not read file " + inFile.getAbsolutePath();
+ if (failonerror) {
+ throw new BuildException(message, ioe, getLocation());
+ } else {
+ log(message, Project.MSG_WARN);
+ }
+ return;
+ } finally {
+ FileUtils.close(in);
+ }
+ }
+
+ Enumeration e = propertySets.elements();
+ while (e.hasMoreElements()) {
+ PropertySet ps = (PropertySet) e.nextElement();
+ allProps.putAll(ps.getProperties());
+ }
+
+ OutputStream os = null;
+ try {
+ if (destfile == null) {
+ os = new ByteArrayOutputStream();
+ saveProperties(allProps, os);
+ log(os.toString(), Project.MSG_INFO);
+ } else {
+ if (destfile.exists() && destfile.isDirectory()) {
+ String message = "destfile is a directory!";
+ if (failonerror) {
+ throw new BuildException(message, getLocation());
+ } else {
+ log(message, Project.MSG_ERR);
+ }
+ return;
+ }
+
+ if (destfile.exists() && !destfile.canWrite()) {
+ String message =
+ "Can not write to the specified destfile!";
+ if (failonerror) {
+ throw new BuildException(message, getLocation());
+ } else {
+ log(message, Project.MSG_ERR);
+ }
+ return;
+ }
+ os = new FileOutputStream(this.destfile);
+ saveProperties(allProps, os);
+ }
+ } catch (IOException ioe) {
+ if (failonerror) {
+ throw new BuildException(ioe, getLocation());
+ } else {
+ log(ioe.getMessage(), Project.MSG_INFO);
+ }
+ } finally {
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException ex) {
+ //ignore
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Send the key/value pairs in the hashtable to the given output stream.
+ * Only those properties matching the <tt>prefix</tt> constraint will be
+ * sent to the output stream.
+ * The output stream will be closed when this method returns.
+ *
+ * @param allProps propfile to save
+ * @param os output stream
+ * @throws IOException on output errors
+ * @throws BuildException on other errors
+ */
+ protected void saveProperties(Hashtable allProps, OutputStream os)
+ throws IOException, BuildException {
+ final List keyList = new ArrayList(allProps.keySet());
+ Collections.sort(keyList);
+ Properties props = new Properties() {
+ private static final long serialVersionUID = 5090936442309201654L;
+ public Enumeration keys() {
+ return CollectionUtils.asEnumeration(keyList.iterator());
+ }
+ public Set entrySet() {
+ Set result = super.entrySet();
+ if (JavaEnvUtils.isKaffe()) {
+ TreeSet t = new TreeSet(new Comparator() {
+ public int compare(Object o1, Object o2) {
+ String key1 = (String) ((Map.Entry) o1).getKey();
+ String key2 = (String) ((Map.Entry) o2).getKey();
+ return key1.compareTo(key2);
+ }
+ });
+ t.addAll(result);
+ result = t;
+ }
+ return result;
+ }
+ };
+ final int size = keyList.size();
+ for (int i = 0; i < size; i++) {
+ String name = keyList.get(i).toString();
+ String value = allProps.get(name).toString();
+ props.setProperty(name, value);
+ }
+ if ("text".equals(format)) {
+ jdkSaveProperties(props, os, "Ant properties");
+ } else if ("xml".equals(format)) {
+ xmlSaveProperties(props, os);
+ }
+ }
+
+ /**
+ * a tuple for the sort list.
+ */
+ private static final class Tuple implements Comparable {
+ private String key;
+ private String value;
+
+ private Tuple(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Compares this object with the specified object for order.
+ * @param o the Object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object is
+ * less than, equal to, or greater than the specified object.
+ * @throws ClassCastException if the specified object's type prevents it
+ * from being compared to this Object.
+ */
+ public int compareTo(Object o) {
+ Tuple that = (Tuple) o;
+ return key.compareTo(that.key);
+ }
+ }
+
+ private List sortProperties(Properties props) {
+ //sort the list. Makes SCM and manual diffs easier.
+ List sorted = new ArrayList(props.size());
+ Enumeration e = props.propertyNames();
+ while (e.hasMoreElements()) {
+ String name = (String) e.nextElement();
+ sorted.add(new Tuple(name, props.getProperty(name)));
+ }
+ Collections.sort(sorted);
+ return sorted;
+ }
+
+ /**
+ * Output the properties as xml output.
+ * @param props the properties to save
+ * @param os the output stream to write to (Note this gets closed)
+ * @throws IOException on error in writing to the stream
+ */
+ protected void xmlSaveProperties(Properties props,
+ OutputStream os) throws IOException {
+ // create XML document
+ Document doc = getDocumentBuilder().newDocument();
+ Element rootElement = doc.createElement(PROPERTIES);
+
+ List sorted = sortProperties(props);
+
+
+ // output properties
+ Iterator iten = sorted.iterator();
+ while (iten.hasNext()) {
+ Tuple tuple = (Tuple) iten.next();
+ Element propElement = doc.createElement(PROPERTY);
+ propElement.setAttribute(ATTR_NAME, tuple.key);
+ propElement.setAttribute(ATTR_VALUE, tuple.value);
+ rootElement.appendChild(propElement);
+ }
+
+ Writer wri = null;
+ try {
+ wri = new OutputStreamWriter(os, "UTF8");
+ wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ (new DOMElementWriter()).write(rootElement, wri, 0, "\t");
+ wri.flush();
+ } catch (IOException ioe) {
+ throw new BuildException("Unable to write XML file", ioe);
+ } finally {
+ FileUtils.close(wri);
+ }
+ }
+
+ /**
+ * JDK 1.2 allows for the safer method
+ * <tt>Properties.store(OutputStream, String)</tt>, which throws an
+ * <tt>IOException</tt> on an output error.
+ *
+ *@param props the properties to record
+ *@param os record the properties to this output stream
+ *@param header prepend this header to the property output
+ *@exception IOException on an I/O error during a write.
+ */
+ protected void jdkSaveProperties(Properties props, OutputStream os,
+ String header) throws IOException {
+ try {
+ props.store(os, header);
+
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ } finally {
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException ioex) {
+ log("Failed to close output stream");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Uses the DocumentBuilderFactory to get a DocumentBuilder instance.
+ *
+ * @return The DocumentBuilder instance
+ */
+ private static DocumentBuilder getDocumentBuilder() {
+ try {
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java
new file mode 100644
index 00000000..aaed7832
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java
@@ -0,0 +1,513 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.javah.JavahAdapter;
+import org.apache.tools.ant.taskdefs.optional.javah.JavahAdapterFactory;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.facade.FacadeTaskHelper;
+import org.apache.tools.ant.util.facade.ImplementationSpecificArgument;
+
+/**
+ * Generates JNI header files using javah.
+ *
+ * This task can take the following arguments:
+ * <ul>
+ * <li>classname - the fully-qualified name of a class</li>
+ * <li>outputFile - Concatenates the resulting header or source files for all
+ * the classes listed into this file</li>
+ * <li>destdir - Sets the directory where javah saves the header files or the
+ * stub files</li>
+ * <li>classpath</li>
+ * <li>bootclasspath</li>
+ * <li>force - Specifies that output files should always be written
+ (JDK1.2 only)</li>
+ * <li>old - Specifies that old JDK1.0-style header files should be generated
+ * (otherwise output file contain JNI-style native method
+ * function prototypes) (JDK1.2 only)</li>
+ * <li>stubs - generate C declarations from the Java object file (used with old)</li>
+ * <li>verbose - causes javah to print a message to stdout concerning the status
+ * of the generated files</li>
+ * <li>extdirs - Override location of installed extensions</li>
+ * </ul>
+ * Of these arguments, either <b>outputFile</b> or <b>destdir</b> is required,
+ * but not both. More than one classname may be specified, using a comma-separated
+ * list or by using <code>&lt;class name="xxx"&gt;</code> elements within the task.
+ * <p>
+ * When this task executes, it will generate C header and source files that
+ * are needed to implement native methods.
+ *
+ */
+
+public class Javah extends Task {
+
+ private Vector classes = new Vector(2);
+ private String cls;
+ private File destDir;
+ private Path classpath = null;
+ private File outputFile = null;
+ private boolean verbose = false;
+ private boolean force = false;
+ private boolean old = false;
+ private boolean stubs = false;
+ private Path bootclasspath;
+ //private Path extdirs;
+ private FacadeTaskHelper facade = null;
+ private Vector files = new Vector();
+ private JavahAdapter nestedAdapter = null;
+
+ /**
+ * No arg constructor.
+ */
+ public Javah() {
+ facade = new FacadeTaskHelper(JavahAdapterFactory.getDefault());
+ }
+
+ /**
+ * the fully-qualified name of the class (or classes, separated by commas).
+ * @param cls the classname (or classnames).
+ */
+ public void setClass(String cls) {
+ this.cls = cls;
+ }
+
+ /**
+ * Adds class to process.
+ * @return a <code>ClassArgument</code> to be configured.
+ */
+ public ClassArgument createClass() {
+ ClassArgument ga = new ClassArgument();
+ classes.addElement(ga);
+ return ga;
+ }
+
+ /**
+ * A class corresponding the the nested "class" element.
+ * It contains a "name" attribute.
+ */
+ public class ClassArgument {
+ private String name;
+
+ /** Constructor for ClassArgument. */
+ public ClassArgument() {
+ }
+
+ /**
+ * Set the name attribute.
+ * @param name the name attribute.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the name attribute.
+ * @return the name attribute.
+ */
+ public String getName() {
+ return name;
+ }
+ }
+
+ /**
+ * Add a fileset.
+ * @param fs the fileset to add.
+ */
+ public void addFileSet(FileSet fs) {
+ files.add(fs);
+ }
+
+ /**
+ * Names of the classes to process.
+ * @return the array of classes.
+ * @since Ant 1.6.3
+ */
+ public String[] getClasses() {
+ ArrayList al = new ArrayList();
+ if (cls != null) {
+ StringTokenizer tok = new StringTokenizer(cls, ",", false);
+ while (tok.hasMoreTokens()) {
+ al.add(tok.nextToken().trim());
+ }
+ }
+
+ if (files.size() > 0) {
+ for (Enumeration e = files.elements(); e.hasMoreElements();) {
+ FileSet fs = (FileSet) e.nextElement();
+ String[] includedClasses = fs.getDirectoryScanner(
+ getProject()).getIncludedFiles();
+ for (int i = 0; i < includedClasses.length; i++) {
+ String className =
+ includedClasses[i].replace('\\', '.').replace('/', '.')
+ .substring(0, includedClasses[i].length() - 6);
+ al.add(className);
+ }
+ }
+ }
+ Enumeration e = classes.elements();
+ while (e.hasMoreElements()) {
+ ClassArgument arg = (ClassArgument) e.nextElement();
+ al.add(arg.getName());
+ }
+ return (String[]) al.toArray(new String[al.size()]);
+ }
+
+ /**
+ * Set the destination directory into which the Java source
+ * files should be compiled.
+ * @param destDir the destination directory.
+ */
+ public void setDestdir(File destDir) {
+ this.destDir = destDir;
+ }
+
+ /**
+ * The destination directory, if any.
+ * @return the destination directory.
+ * @since Ant 1.6.3
+ */
+ public File getDestdir() {
+ return destDir;
+ }
+
+ /**
+ * the classpath to use.
+ * @param src the classpath.
+ */
+ public void setClasspath(Path src) {
+ if (classpath == null) {
+ classpath = src;
+ } else {
+ classpath.append(src);
+ }
+ }
+
+ /**
+ * Path to use for classpath.
+ * @return a path to be configured.
+ */
+ public Path createClasspath() {
+ if (classpath == null) {
+ classpath = new Path(getProject());
+ }
+ return classpath.createPath();
+ }
+
+ /**
+ * Adds a reference to a classpath defined elsewhere.
+ * @param r a reference to a classpath.
+ * @todo this needs to be documented in the HTML docs.
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * The classpath to use.
+ * @return the classpath.
+ * @since Ant 1.6.3
+ */
+ public Path getClasspath() {
+ return classpath;
+ }
+
+ /**
+ * location of bootstrap class files.
+ * @param src the bootstrap classpath.
+ */
+ public void setBootclasspath(Path src) {
+ if (bootclasspath == null) {
+ bootclasspath = src;
+ } else {
+ bootclasspath.append(src);
+ }
+ }
+
+ /**
+ * Adds path to bootstrap class files.
+ * @return a path to be configured.
+ */
+ public Path createBootclasspath() {
+ if (bootclasspath == null) {
+ bootclasspath = new Path(getProject());
+ }
+ return bootclasspath.createPath();
+ }
+
+ /**
+ * To the bootstrap path, this adds a reference to a classpath defined elsewhere.
+ * @param r a reference to a classpath
+ * @todo this needs to be documented in the HTML.
+ */
+ public void setBootClasspathRef(Reference r) {
+ createBootclasspath().setRefid(r);
+ }
+
+ /**
+ * The bootclasspath to use.
+ * @return the bootclass path.
+ * @since Ant 1.6.3
+ */
+ public Path getBootclasspath() {
+ return bootclasspath;
+ }
+
+ /**
+ * Concatenates the resulting header or source files for all
+ * the classes listed into this file.
+ * @param outputFile the output file.
+ */
+ public void setOutputFile(File outputFile) {
+ this.outputFile = outputFile;
+ }
+
+ /**
+ * The destination file, if any.
+ * @return the destination file.
+ * @since Ant 1.6.3
+ */
+ public File getOutputfile() {
+ return outputFile;
+ }
+
+ /**
+ * If true, output files should always be written (JDK1.2 only).
+ * @param force the value to use.
+ */
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+
+ /**
+ * Whether output files should always be written.
+ * @return the force attribute.
+ * @since Ant 1.6.3
+ */
+ public boolean getForce() {
+ return force;
+ }
+
+ /**
+ * If true, specifies that old JDK1.0-style header files should be
+ * generated.
+ * (otherwise output file contain JNI-style native method function
+ * prototypes) (JDK1.2 only).
+ * @param old if true use old 1.0 style header files.
+ */
+ public void setOld(boolean old) {
+ this.old = old;
+ }
+
+ /**
+ * Whether old JDK1.0-style header files should be generated.
+ * @return the old attribute.
+ * @since Ant 1.6.3
+ */
+ public boolean getOld() {
+ return old;
+ }
+
+ /**
+ * If true, generate C declarations from the Java object file (used with old).
+ * @param stubs if true, generated C declarations.
+ */
+ public void setStubs(boolean stubs) {
+ this.stubs = stubs;
+ }
+
+ /**
+ * Whether C declarations from the Java object file should be generated.
+ * @return the stubs attribute.
+ * @since Ant 1.6.3
+ */
+ public boolean getStubs() {
+ return stubs;
+ }
+
+ /**
+ * If true, causes Javah to print a message concerning
+ * the status of the generated files.
+ * @param verbose if true, do verbose printing.
+ */
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ /**
+ * Whether verbose output should get generated.
+ * @return the verbose attribute.
+ * @since Ant 1.6.3
+ */
+ public boolean getVerbose() {
+ return verbose;
+ }
+
+ /**
+ * Choose the implementation for this particular task.
+ * @param impl the name of the implementation.
+ * @since Ant 1.6.3
+ */
+ public void setImplementation(String impl) {
+ if ("default".equals(impl)) {
+ facade.setImplementation(JavahAdapterFactory.getDefault());
+ } else {
+ facade.setImplementation(impl);
+ }
+ }
+
+ /**
+ * Adds an implementation specific command-line argument.
+ * @return a ImplementationSpecificArgument to be configured.
+ *
+ * @since Ant 1.6.3
+ */
+ public ImplementationSpecificArgument createArg() {
+ ImplementationSpecificArgument arg =
+ new ImplementationSpecificArgument();
+ facade.addImplementationArgument(arg);
+ return arg;
+ }
+
+ /**
+ * Returns the (implementation specific) settings given as nested
+ * arg elements.
+ * @return the arguments.
+ * @since Ant 1.6.3
+ */
+ public String[] getCurrentArgs() {
+ return facade.getArgs();
+ }
+
+ /**
+ * The classpath to use when loading the javah implementation
+ * if it is not a built-in one.
+ *
+ * @since Ant 1.8.0
+ */
+ public Path createImplementationClasspath() {
+ return facade.getImplementationClasspath(getProject());
+ }
+
+ /**
+ * Set the adapter explicitly.
+ * @since Ant 1.8.0
+ */
+ public void add(JavahAdapter adapter) {
+ if (nestedAdapter != null) {
+ throw new BuildException("Can't have more than one javah"
+ + " adapter");
+ }
+ nestedAdapter = adapter;
+ }
+
+ /**
+ * Execute the task
+ *
+ * @throws BuildException is there is a problem in the task execution.
+ */
+ public void execute() throws BuildException {
+ // first off, make sure that we've got a srcdir
+
+ if ((cls == null) && (classes.size() == 0) && (files.size() == 0)) {
+ throw new BuildException("class attribute must be set!",
+ getLocation());
+ }
+
+ if ((cls != null) && (classes.size() > 0) && (files.size() > 0)) {
+ throw new BuildException("set class attribute OR class element OR fileset, "
+ + "not 2 or more of them.", getLocation());
+ }
+
+ if (destDir != null) {
+ if (!destDir.isDirectory()) {
+ throw new BuildException("destination directory \"" + destDir
+ + "\" does not exist or is not a directory", getLocation());
+ }
+ if (outputFile != null) {
+ throw new BuildException("destdir and outputFile are mutually "
+ + "exclusive", getLocation());
+ }
+ }
+
+ if (classpath == null) {
+ classpath = (new Path(getProject())).concatSystemClasspath("last");
+ } else {
+ classpath = classpath.concatSystemClasspath("ignore");
+ }
+
+ JavahAdapter ad =
+ nestedAdapter != null ? nestedAdapter :
+ JavahAdapterFactory.getAdapter(facade.getImplementation(),
+ this,
+ createImplementationClasspath());
+ if (!ad.compile(this)) {
+ throw new BuildException("compilation failed");
+ }
+ }
+
+ /**
+ * Logs the compilation parameters, adds the files to compile and logs the
+ * &quot;niceSourceList&quot;
+ * @param cmd the command line.
+ */
+ public void logAndAddFiles(Commandline cmd) {
+ logAndAddFilesToCompile(cmd);
+ }
+
+ /**
+ * Logs the compilation parameters, adds the files to compile and logs the
+ * &quot;niceSourceList&quot;
+ * @param cmd the command line to add parameters to.
+ */
+ protected void logAndAddFilesToCompile(Commandline cmd) {
+ log("Compilation " + cmd.describeArguments(),
+ Project.MSG_VERBOSE);
+
+ StringBuffer niceClassList = new StringBuffer();
+ String[] c = getClasses();
+ for (int i = 0; i < c.length; i++) {
+ cmd.createArgument().setValue(c[i]);
+ niceClassList.append(" ");
+ niceClassList.append(c[i]);
+ niceClassList.append(StringUtils.LINE_SEP);
+ }
+
+ StringBuffer prefix = new StringBuffer("Class");
+ if (c.length > 1) {
+ prefix.append("es");
+ }
+ prefix.append(" to be compiled:");
+ prefix.append(StringUtils.LINE_SEP);
+
+ log(prefix.toString() + niceClassList.toString(), Project.MSG_VERBOSE);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java
new file mode 100644
index 00000000..81a386fd
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.optional.native2ascii.Native2AsciiAdapter;
+import org.apache.tools.ant.taskdefs.optional.native2ascii.Native2AsciiAdapterFactory;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.apache.tools.ant.util.facade.FacadeTaskHelper;
+import org.apache.tools.ant.util.facade.ImplementationSpecificArgument;
+
+/**
+ * Converts files from native encodings to ASCII.
+ *
+ * @since Ant 1.2
+ */
+public class Native2Ascii extends MatchingTask {
+
+ private boolean reverse = false; // convert from ascii back to native
+ private String encoding = null; // encoding to convert to/from
+ private File srcDir = null; // Where to find input files
+ private File destDir = null; // Where to put output files
+ private String extension = null; // Extension of output files if different
+
+ private Mapper mapper;
+ private FacadeTaskHelper facade = null;
+ private Native2AsciiAdapter nestedAdapter = null;
+
+ /** No args constructor */
+ public Native2Ascii() {
+ facade = new FacadeTaskHelper(Native2AsciiAdapterFactory.getDefault());
+ }
+
+ /**
+ * Flag the conversion to run in the reverse sense,
+ * that is Ascii to Native encoding.
+ *
+ * @param reverse True if the conversion is to be reversed,
+ * otherwise false;
+ */
+ public void setReverse(boolean reverse) {
+ this.reverse = reverse;
+ }
+
+ /**
+ * The value of the reverse attribute.
+ * @return the reverse attribute.
+ * @since Ant 1.6.3
+ */
+ public boolean getReverse() {
+ return reverse;
+ }
+
+ /**
+ * Set the encoding to translate to/from.
+ * If unset, the default encoding for the JVM is used.
+ *
+ * @param encoding String containing the name of the Native
+ * encoding to convert from or to.
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * The value of the encoding attribute.
+ * @return the encoding attribute.
+ * @since Ant 1.6.3
+ */
+ public String getEncoding() {
+ return encoding;
+ }
+
+ /**
+ * Set the source directory in which to find files to convert.
+ *
+ * @param srcDir directory to find input file in.
+ */
+ public void setSrc(File srcDir) {
+ this.srcDir = srcDir;
+ }
+
+
+ /**
+ * Set the destination directory to place converted files into.
+ *
+ * @param destDir directory to place output file into.
+ */
+ public void setDest(File destDir) {
+ this.destDir = destDir;
+ }
+
+ /**
+ * Set the extension which converted files should have.
+ * If unset, files will not be renamed.
+ *
+ * @param ext File extension to use for converted files.
+ */
+ public void setExt(String ext) {
+ this.extension = ext;
+ }
+
+ /**
+ * Choose the implementation for this particular task.
+ * @param impl the name of the implementation
+ * @since Ant 1.6.3
+ */
+ public void setImplementation(String impl) {
+ if ("default".equals(impl)) {
+ facade.setImplementation(Native2AsciiAdapterFactory.getDefault());
+ } else {
+ facade.setImplementation(impl);
+ }
+ }
+
+ /**
+ * Defines the FileNameMapper to use (nested mapper element).
+ *
+ * @return the mapper to use for file name translations.
+ *
+ * @throws BuildException if more than one mapper is defined.
+ */
+ public Mapper createMapper() throws BuildException {
+ if (mapper != null) {
+ throw new BuildException("Cannot define more than one mapper",
+ getLocation());
+ }
+ mapper = new Mapper(getProject());
+ return mapper;
+ }
+
+ /**
+ * A nested filenamemapper
+ * @param fileNameMapper the mapper to add
+ * @since Ant 1.6.3
+ */
+ public void add(FileNameMapper fileNameMapper) {
+ createMapper().add(fileNameMapper);
+ }
+
+ /**
+ * Adds an implementation specific command-line argument.
+ * @return a ImplementationSpecificArgument to be configured
+ *
+ * @since Ant 1.6.3
+ */
+ public ImplementationSpecificArgument createArg() {
+ ImplementationSpecificArgument arg =
+ new ImplementationSpecificArgument();
+ facade.addImplementationArgument(arg);
+ return arg;
+ }
+
+ /**
+ * The classpath to use when loading the native2ascii
+ * implementation if it is not a built-in one.
+ *
+ * @since Ant 1.8.0
+ */
+ public Path createImplementationClasspath() {
+ return facade.getImplementationClasspath(getProject());
+ }
+
+ /**
+ * Set the adapter explicitly.
+ * @since Ant 1.8.0
+ */
+ public void add(Native2AsciiAdapter adapter) {
+ if (nestedAdapter != null) {
+ throw new BuildException("Can't have more than one native2ascii"
+ + " adapter");
+ }
+ nestedAdapter = adapter;
+ }
+
+ /**
+ * Execute the task
+ *
+ * @throws BuildException is there is a problem in the task execution.
+ */
+ public void execute() throws BuildException {
+
+ DirectoryScanner scanner = null; // Scanner to find our inputs
+ String[] files; // list of files to process
+
+ // default srcDir to basedir
+ if (srcDir == null) {
+ srcDir = getProject().resolveFile(".");
+ }
+
+ // Require destDir
+ if (destDir == null) {
+ throw new BuildException("The dest attribute must be set.");
+ }
+
+ // if src and dest dirs are the same, require the extension
+ // to be set, so we don't stomp every file. One could still
+ // include a file with the same extension, but ....
+ if (srcDir.equals(destDir) && extension == null && mapper == null) {
+ throw new BuildException("The ext attribute or a mapper must be set if"
+ + " src and dest dirs are the same.");
+ }
+
+ FileNameMapper m = null;
+ if (mapper == null) {
+ if (extension == null) {
+ m = new IdentityMapper();
+ } else {
+ m = new ExtMapper();
+ }
+ } else {
+ m = mapper.getImplementation();
+ }
+
+ scanner = getDirectoryScanner(srcDir);
+ files = scanner.getIncludedFiles();
+ SourceFileScanner sfs = new SourceFileScanner(this);
+ files = sfs.restrict(files, srcDir, destDir, m);
+ int count = files.length;
+ if (count == 0) {
+ return;
+ }
+ String message = "Converting " + count + " file"
+ + (count != 1 ? "s" : "") + " from ";
+ log(message + srcDir + " to " + destDir);
+ for (int i = 0; i < files.length; i++) {
+ convert(files[i], m.mapFileName(files[i])[0]);
+ }
+ }
+
+ /**
+ * Convert a single file.
+ *
+ * @param srcName name of the input file.
+ * @param destName name of the input file.
+ */
+ private void convert(String srcName, String destName)
+ throws BuildException {
+ File srcFile; // File to convert
+ File destFile; // where to put the results
+
+ // Build the full file names
+ srcFile = new File(srcDir, srcName);
+ destFile = new File(destDir, destName);
+
+ // Make sure we're not about to clobber something
+ if (srcFile.equals(destFile)) {
+ throw new BuildException("file " + srcFile
+ + " would overwrite its self");
+ }
+
+ // Make intermediate directories if needed
+ // TODO JDK 1.1 doesn't have File.getParentFile,
+ String parentName = destFile.getParent();
+ if (parentName != null) {
+ File parentFile = new File(parentName);
+
+ if (!parentFile.exists()
+ && !(parentFile.mkdirs() || parentFile.isDirectory())) {
+ throw new BuildException("cannot create parent directory "
+ + parentName);
+ }
+ }
+
+ log("converting " + srcName, Project.MSG_VERBOSE);
+ Native2AsciiAdapter ad =
+ nestedAdapter != null ? nestedAdapter :
+ Native2AsciiAdapterFactory.getAdapter(facade.getImplementation(),
+ this,
+ createImplementationClasspath());
+ if (!ad.convert(this, srcFile, destFile)) {
+ throw new BuildException("conversion failed");
+ }
+ }
+
+ /**
+ * Returns the (implementation specific) settings given as nested
+ * arg elements.
+ * @return the arguments.
+ * @since Ant 1.6.3
+ */
+ public String[] getCurrentArgs() {
+ return facade.getArgs();
+ }
+
+ private class ExtMapper implements FileNameMapper {
+
+ public void setFrom(String s) {
+ }
+ public void setTo(String s) {
+ }
+
+ public String[] mapFileName(String fileName) {
+ int lastDot = fileName.lastIndexOf('.');
+ if (lastDot >= 0) {
+ return new String[] {fileName.substring(0, lastDot)
+ + extension};
+ } else {
+ return new String[] {fileName + extension};
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java
new file mode 100644
index 00000000..5ba2a760
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java
@@ -0,0 +1,1042 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netrexx.lang.Rexx;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+
+// CheckStyle:InnerAssignmentCheck OFF - used too much in the file to be removed
+/**
+ * Compiles NetRexx source files.
+ * This task can take the following
+ * arguments:
+ * <ul>
+ * <li>binary</li>
+ * <li>classpath</li>
+ * <li>comments</li>
+ * <li>compile</li>
+ * <li>console</li>
+ * <li>crossref</li>
+ * <li>decimal</li>
+ * <li>destdir</li>
+ * <li>diag</li>
+ * <li>explicit</li>
+ * <li>format</li>
+ * <li>keep</li>
+ * <li>logo</li>
+ * <li>replace</li>
+ * <li>savelog</li>
+ * <li>srcdir</li>
+ * <li>sourcedir</li>
+ * <li>strictargs</li>
+ * <li>strictassign</li>
+ * <li>strictcase</li>
+ * <li>strictimport</li>
+ * <li>symbols</li>
+ * <li>time</li>
+ * <li>trace</li>
+ * <li>utf8</li>
+ * <li>verbose</li>
+ * <li>suppressMethodArgumentNotUsed</li>
+ * <li>suppressPrivatePropertyNotUsed</li>
+ * <li>suppressVariableNotUsed</li>
+ * <li>suppressExceptionNotSignalled</li>
+ * <li>suppressDeprecation</li>
+ * <li>removeKeepExtension</li>
+ * </ul>
+ * Of these arguments, the <b>srcdir</b> argument is required.
+ *
+ * <p>When this task executes, it will recursively scan the srcdir
+ * looking for NetRexx source files to compile. This task makes its
+ * compile decision based on timestamp.
+ * <p>Before files are compiled they and any other file in the
+ * srcdir will be copied to the destdir allowing support files to be
+ * located properly in the classpath. The reason for copying the source files
+ * before the compile is that NetRexxC has only two destinations for classfiles:
+ * <ol>
+ * <li>The current directory, and,</li>
+ * <li>The directory the source is in (see sourcedir option)
+ * </ol>
+ *
+ */
+public class NetRexxC extends MatchingTask {
+
+ // variables to hold arguments
+ private boolean binary;
+ private String classpath;
+ private boolean comments;
+ private boolean compact = true; // should be the default, as it integrates better in ant.
+ private boolean compile = true;
+ private boolean console;
+ private boolean crossref;
+ private boolean decimal = true;
+ private File destDir;
+ private boolean diag;
+ private boolean explicit;
+ private boolean format;
+ private boolean keep;
+ private boolean logo = true;
+ private boolean replace;
+ private boolean savelog;
+ private File srcDir;
+ private boolean sourcedir = true; // ?? Should this be the default for ant?
+ private boolean strictargs;
+ private boolean strictassign;
+ private boolean strictcase;
+ private boolean strictimport;
+ private boolean strictprops;
+ private boolean strictsignal;
+ private boolean symbols;
+ private boolean time;
+ private String trace = "trace2";
+ private boolean utf8;
+ private String verbose = "verbose3";
+ private boolean suppressMethodArgumentNotUsed = false;
+ private boolean suppressPrivatePropertyNotUsed = false;
+ private boolean suppressVariableNotUsed = false;
+ private boolean suppressExceptionNotSignalled = false;
+ private boolean suppressDeprecation = false;
+ private boolean removeKeepExtension = false;
+
+ // constants for the messages to suppress by flags and their corresponding properties
+ static final String MSG_METHOD_ARGUMENT_NOT_USED
+ = "Warning: Method argument is not used";
+ static final String MSG_PRIVATE_PROPERTY_NOT_USED
+ = "Warning: Private property is defined but not used";
+ static final String MSG_VARIABLE_NOT_USED
+ = "Warning: Variable is set but not used";
+ static final String MSG_EXCEPTION_NOT_SIGNALLED
+ = "is in SIGNALS list but is not signalled within the method";
+ static final String MSG_DEPRECATION = "has been deprecated";
+
+ // other implementation variables
+ private Vector compileList = new Vector();
+ private Hashtable filecopyList = new Hashtable();
+
+ /**
+ * Set whether literals are treated as binary, rather than NetRexx types.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default is false.
+ * @param binary a <code>boolean</code> value.
+ */
+ public void setBinary(boolean binary) {
+ this.binary = binary;
+ }
+
+
+ /**
+ * Set the classpath used for NetRexx compilation.
+ * @param classpath the classpath to use.
+ */
+ public void setClasspath(String classpath) {
+ this.classpath = classpath;
+ }
+
+
+ /**
+ * Set whether comments are passed through to the generated java source.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param comments a <code>boolean</code> value.
+ */
+ public void setComments(boolean comments) {
+ this.comments = comments;
+ }
+
+
+ /**
+ * Set whether error messages come out in compact or verbose format.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is true.
+ * @param compact a <code>boolean</code> value.
+ */
+ public void setCompact(boolean compact) {
+ this.compact = compact;
+ }
+
+
+ /**
+ * Set whether the NetRexx compiler should compile the generated java code.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is true.
+ * Setting this flag to false, will automatically set the keep flag to true.
+ * @param compile a <code>boolean</code> value.
+ */
+ public void setCompile(boolean compile) {
+ this.compile = compile;
+ if (!this.compile && !this.keep) {
+ this.keep = true;
+ }
+ }
+
+
+ /**
+ * Set whether or not compiler messages should be displayed on the 'console'.
+ * Note that this task will rely on the default value for filtering compile messages.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param console a <code>boolean</code> value.
+ */
+ public void setConsole(boolean console) {
+ this.console = console;
+ }
+
+
+ /**
+ * Whether variable cross references are generated.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param crossref a <code>boolean</code> value.
+ */
+ public void setCrossref(boolean crossref) {
+ this.crossref = crossref;
+ }
+
+
+ /**
+ * Set whether decimal arithmetic should be used for the netrexx code.
+ * Setting this to off will report decimal arithmetic as an error, for
+ * performance critical applications.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is true.
+ * @param decimal a <code>boolean</code> value.
+ */
+ public void setDecimal(boolean decimal) {
+ this.decimal = decimal;
+ }
+
+
+ /**
+ * Set the destination directory into which the NetRexx source files
+ * should be copied and then compiled.
+ * @param destDirName the destination directory.
+ */
+ public void setDestDir(File destDirName) {
+ destDir = destDirName;
+ }
+
+
+ /**
+ * Whether diagnostic information about the compile is generated
+ * @param diag a <code>boolean</code> value.
+ */
+ public void setDiag(boolean diag) {
+ this.diag = diag;
+ }
+
+
+ /**
+ * Sets whether variables must be declared explicitly before use.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param explicit a <code>boolean</code> value.
+ */
+ public void setExplicit(boolean explicit) {
+ this.explicit = explicit;
+ }
+
+
+ /**
+ * Whether the generated java code is formatted nicely or left to match
+ * NetRexx line numbers for call stack debugging.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value false.
+ * @param format a <code>boolean</code> value.
+ */
+ public void setFormat(boolean format) {
+ this.format = format;
+ }
+
+
+ /**
+ * Whether the generated java code is produced.
+ * This is not implemented yet.
+ * @param java a <code>boolean</code> value.
+ */
+ public void setJava(boolean java) {
+ log("The attribute java is currently unused.", Project.MSG_WARN);
+ }
+
+
+ /**
+ * Sets whether the generated java source file should be kept after
+ * compilation. The generated files will have an extension of .java.keep,
+ * <b>not</b> .java. See setRemoveKeepExtension
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param keep a <code>boolean</code> value.
+ * @see #setRemoveKeepExtension(boolean)
+ */
+ public void setKeep(boolean keep) {
+ this.keep = keep;
+ }
+
+
+ /**
+ * Whether the compiler text logo is displayed when compiling.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param logo a <code>boolean</code> value.
+ */
+ public void setLogo(boolean logo) {
+ this.logo = logo;
+ }
+
+
+ /**
+ * Whether the generated .java file should be replaced when compiling.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param replace a <code>boolean</code> value.
+ */
+ public void setReplace(boolean replace) {
+ this.replace = replace;
+ }
+
+
+ /**
+ * Sets whether the compiler messages will be written to NetRexxC.log as
+ * well as to the console.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param savelog a <code>boolean</code> value.
+ */
+ public void setSavelog(boolean savelog) {
+ this.savelog = savelog;
+ }
+
+
+ /**
+ * Tells the NetRexx compiler to store the class files in the same
+ * directory as the source files. The alternative is the working directory.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is true.
+ * @param sourcedir a <code>boolean</code> value.
+ */
+ public void setSourcedir(boolean sourcedir) {
+ this.sourcedir = sourcedir;
+ }
+
+
+ /**
+ * Set the source dir to find the source Java files.
+ * @param srcDirName the source directory.
+ */
+ public void setSrcDir(File srcDirName) {
+ srcDir = srcDirName;
+ }
+
+
+ /**
+ * Tells the NetRexx compiler that method calls always need parentheses,
+ * even if no arguments are needed, e.g. <code>aStringVar.getBytes</code>
+ * vs. <code>aStringVar.getBytes()</code>.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param strictargs a <code>boolean</code> value.
+ */
+ public void setStrictargs(boolean strictargs) {
+ this.strictargs = strictargs;
+ }
+
+
+ /**
+ * Tells the NetRexx compile that assignments must match exactly on type.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param strictassign a <code>boolean</code> value.
+ */
+ public void setStrictassign(boolean strictassign) {
+ this.strictassign = strictassign;
+ }
+
+
+ /**
+ * Specifies whether the NetRexx compiler should be case sensitive or not.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param strictcase a <code>boolean</code> value.
+ */
+ public void setStrictcase(boolean strictcase) {
+ this.strictcase = strictcase;
+ }
+
+
+ /**
+ * Sets whether classes need to be imported explicitly using an <code>import</code>
+ * statement. By default the NetRexx compiler will import certain packages
+ * automatically.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param strictimport a <code>boolean</code> value.
+ */
+ public void setStrictimport(boolean strictimport) {
+ this.strictimport = strictimport;
+ }
+
+
+ /**
+ * Sets whether local properties need to be qualified explicitly using
+ * <code>this</code>.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param strictprops a <code>boolean</code> value.
+ */
+ public void setStrictprops(boolean strictprops) {
+ this.strictprops = strictprops;
+ }
+
+
+ /**
+ * Whether the compiler should force catching of exceptions by explicitly
+ * named types.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false
+ * @param strictsignal a <code>boolean</code> value.
+ */
+ public void setStrictsignal(boolean strictsignal) {
+ this.strictsignal = strictsignal;
+ }
+
+
+ /**
+ * Sets whether debug symbols should be generated into the class file.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param symbols a <code>boolean</code> value.
+ */
+ public void setSymbols(boolean symbols) {
+ this.symbols = symbols;
+ }
+
+
+ /**
+ * Asks the NetRexx compiler to print compilation times to the console
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param time a <code>boolean</code> value.
+ */
+ public void setTime(boolean time) {
+ this.time = time;
+ }
+
+ /**
+ * Turns on or off tracing and directs the resultant trace output Valid
+ * values are: "trace", "trace1", "trace2" and "notrace". "trace" and
+ * "trace2".
+ * @param trace the value to set.
+ */
+ public void setTrace(TraceAttr trace) {
+ this.trace = trace.getValue();
+ }
+
+ /**
+ * Turns on or off tracing and directs the resultant trace output Valid
+ * values are: "trace", "trace1", "trace2" and "notrace". "trace" and
+ * "trace2".
+ * @param trace the value to set.
+ */
+ public void setTrace(String trace) {
+ TraceAttr t = new TraceAttr();
+
+ t.setValue(trace);
+ setTrace(t);
+ }
+
+
+ /**
+ * Tells the NetRexx compiler that the source is in UTF8.
+ * Valid true values are "yes", "on" or "true". Anything else sets the flag to false.
+ * The default value is false.
+ * @param utf8 a <code>boolean</code> value.
+ */
+ public void setUtf8(boolean utf8) {
+ this.utf8 = utf8;
+ }
+
+
+ /**
+ * Whether lots of warnings and error messages should be generated
+ * @param verbose the value to set - verbose&lt;level&gt; or noverbose.
+ */
+ public void setVerbose(VerboseAttr verbose) {
+ this.verbose = verbose.getValue();
+ }
+
+
+ /**
+ * Whether lots of warnings and error messages should be generated
+ * @param verbose the value to set - verbose&lt;level&gt; or noverbose.
+ */
+ public void setVerbose(String verbose) {
+ VerboseAttr v = new VerboseAttr();
+
+ v.setValue(verbose);
+ setVerbose(v);
+ }
+
+ /**
+ * Whether the task should suppress the "Method argument is not used" in
+ * strictargs-Mode, which can not be suppressed by the compiler itself.
+ * The warning is logged as verbose message, though.
+ * @param suppressMethodArgumentNotUsed a <code>boolean</code> value.
+ */
+ public void setSuppressMethodArgumentNotUsed(boolean suppressMethodArgumentNotUsed) {
+ this.suppressMethodArgumentNotUsed = suppressMethodArgumentNotUsed;
+ }
+
+
+ /**
+ * Whether the task should suppress the "Private property is defined but
+ * not used" in strictargs-Mode, which can be quite annoying while
+ * developing. The warning is logged as verbose message, though.
+ * @param suppressPrivatePropertyNotUsed a <code>boolean</code> value.
+ */
+ public void setSuppressPrivatePropertyNotUsed(boolean suppressPrivatePropertyNotUsed) {
+ this.suppressPrivatePropertyNotUsed = suppressPrivatePropertyNotUsed;
+ }
+
+
+ /**
+ * Whether the task should suppress the "Variable is set but not used" in
+ * strictargs-Mode. Be careful with this one! The warning is logged as
+ * verbose message, though.
+ * @param suppressVariableNotUsed a <code>boolean</code> value.
+ */
+ public void setSuppressVariableNotUsed(boolean suppressVariableNotUsed) {
+ this.suppressVariableNotUsed = suppressVariableNotUsed;
+ }
+
+
+ /**
+ * Whether the task should suppress the "FooException is in SIGNALS list
+ * but is not signalled within the method", which is sometimes rather
+ * useless. The warning is logged as verbose message, though.
+ * @param suppressExceptionNotSignalled a <code>boolean</code> value.
+ */
+ public void setSuppressExceptionNotSignalled(boolean suppressExceptionNotSignalled) {
+ this.suppressExceptionNotSignalled = suppressExceptionNotSignalled;
+ }
+
+
+ /**
+ * Tells whether we should filter out any deprecation-messages
+ * of the compiler out.
+ * @param suppressDeprecation a <code>boolean</code> value.
+ */
+ public void setSuppressDeprecation(boolean suppressDeprecation) {
+ this.suppressDeprecation = suppressDeprecation;
+ }
+
+
+ /**
+ * Tells whether the trailing .keep in nocompile-mode should be removed
+ * so that the resulting java source really ends on .java.
+ * This facilitates the use of the javadoc tool lateron.
+ */
+ public void setRemoveKeepExtension(boolean removeKeepExtension) {
+ this.removeKeepExtension = removeKeepExtension;
+ }
+
+
+ /**
+ * init-Method sets defaults from Properties. That way, when ant is called
+ * with arguments like -Dant.netrexxc.verbose=verbose5 one can easily take
+ * control of all netrexxc-tasks.
+ */
+ public void init() {
+ String p;
+
+ if ((p = getProject().getProperty("ant.netrexxc.binary")) != null) {
+ this.binary = Project.toBoolean(p);
+ }
+ // classpath makes no sense
+ if ((p = getProject().getProperty("ant.netrexxc.comments")) != null) {
+ this.comments = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.compact")) != null) {
+ this.compact = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.compile")) != null) {
+ this.compile = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.console")) != null) {
+ this.console = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.crossref")) != null) {
+ this.crossref = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.decimal")) != null) {
+ this.decimal = Project.toBoolean(p);
+ // destDir
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.diag")) != null) {
+ this.diag = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.explicit")) != null) {
+ this.explicit = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.format")) != null) {
+ this.format = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.keep")) != null) {
+ this.keep = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.logo")) != null) {
+ this.logo = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.replace")) != null) {
+ this.replace = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.savelog")) != null) {
+ this.savelog = Project.toBoolean(p);
+ // srcDir
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.sourcedir")) != null) {
+ this.sourcedir = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.strictargs")) != null) {
+ this.strictargs = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.strictassign")) != null) {
+ this.strictassign = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.strictcase")) != null) {
+ this.strictcase = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.strictimport")) != null) {
+ this.strictimport = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.strictprops")) != null) {
+ this.strictprops = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.strictsignal")) != null) {
+ this.strictsignal = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.symbols")) != null) {
+ this.symbols = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.time")) != null) {
+ this.time = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.trace")) != null) {
+ setTrace(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.utf8")) != null) {
+ this.utf8 = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.verbose")) != null) {
+ setVerbose(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.suppressMethodArgumentNotUsed")) != null) {
+ this.suppressMethodArgumentNotUsed = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.suppressPrivatePropertyNotUsed")) != null) {
+ this.suppressPrivatePropertyNotUsed = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.suppressVariableNotUsed")) != null) {
+ this.suppressVariableNotUsed = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.suppressExceptionNotSignalled")) != null) {
+ this.suppressExceptionNotSignalled = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.suppressDeprecation")) != null) {
+ this.suppressDeprecation = Project.toBoolean(p);
+ }
+ if ((p = getProject().getProperty("ant.netrexxc.removeKeepExtension")) != null) {
+ this.removeKeepExtension = Project.toBoolean(p);
+ }
+ }
+
+
+ /**
+ * Executes the task - performs the actual compiler call.
+ * @throws BuildException on error.
+ */
+ public void execute() throws BuildException {
+
+ // first off, make sure that we've got a srcdir and destdir
+ if (srcDir == null || destDir == null) {
+ throw new BuildException("srcDir and destDir attributes must be set!");
+ }
+
+ // scan source and dest dirs to build up both copy lists and
+ // compile lists
+ // scanDir(srcDir, destDir);
+ DirectoryScanner ds = getDirectoryScanner(srcDir);
+
+ String[] files = ds.getIncludedFiles();
+
+ scanDir(srcDir, destDir, files);
+
+ // copy the source and support files
+ copyFilesToDestination();
+
+ // compile the source files
+ if (compileList.size() > 0) {
+ log("Compiling " + compileList.size() + " source file"
+ + (compileList.size() == 1 ? "" : "s")
+ + " to " + destDir);
+ doNetRexxCompile();
+ if (removeKeepExtension && (!compile || keep)) {
+ removeKeepExtensions();
+ }
+ }
+ }
+
+
+ /**
+ * Scans the directory looking for source files to be compiled and support
+ * files to be copied.
+ */
+ private void scanDir(File srcDir, File destDir, String[] files) {
+ for (int i = 0; i < files.length; i++) {
+ File srcFile = new File(srcDir, files[i]);
+ File destFile = new File(destDir, files[i]);
+ String filename = files[i];
+ // if it's a non source file, copy it if a later date than the
+ // dest
+ // if it's a source file, see if the destination class file
+ // needs to be recreated via compilation
+ if (filename.toLowerCase().endsWith(".nrx")) {
+ File classFile =
+ new File(destDir,
+ filename.substring(0, filename.lastIndexOf('.')) + ".class");
+ File javaFile =
+ new File(destDir,
+ filename.substring(0, filename.lastIndexOf('.'))
+ + (removeKeepExtension ? ".java" : ".java.keep"));
+
+ // nocompile case tests against .java[.keep] file
+ if (!compile && srcFile.lastModified() > javaFile.lastModified()) {
+ filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath());
+ compileList.addElement(destFile.getAbsolutePath());
+ } else if (compile && srcFile.lastModified() > classFile.lastModified()) {
+ // compile case tests against .class file
+ filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath());
+ compileList.addElement(destFile.getAbsolutePath());
+ }
+ } else {
+ if (srcFile.lastModified() > destFile.lastModified()) {
+ filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+
+ /** Copy eligible files from the srcDir to destDir */
+ private void copyFilesToDestination() {
+ if (filecopyList.size() > 0) {
+ log("Copying " + filecopyList.size() + " file"
+ + (filecopyList.size() == 1 ? "" : "s")
+ + " to " + destDir.getAbsolutePath());
+
+ Enumeration e = filecopyList.keys();
+
+ while (e.hasMoreElements()) {
+ String fromFile = (String) e.nextElement();
+ String toFile = (String) filecopyList.get(fromFile);
+
+ try {
+ FileUtils.getFileUtils().copyFile(fromFile, toFile);
+ } catch (IOException ioe) {
+ String msg = "Failed to copy " + fromFile + " to " + toFile
+ + " due to " + ioe.getMessage();
+
+ throw new BuildException(msg, ioe);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Rename .java.keep files (back) to .java. The netrexxc renames all
+ * .java files to .java.keep if either -keep or -nocompile option is set.
+ */
+ private void removeKeepExtensions() {
+ if (compileList.size() > 0) {
+ log("Removing .keep extension on " + compileList.size() + " file"
+ + (compileList.size() == 1 ? "" : "s"));
+ Enumeration e = compileList.elements();
+ while (e.hasMoreElements()) {
+ String nrxName = (String) e.nextElement();
+ String baseName = nrxName.substring(0, nrxName.lastIndexOf('.'));
+ File fromFile = new File(baseName + ".java.keep");
+ File toFile = new File(baseName + ".java");
+ if (fromFile.renameTo(toFile)) {
+ log("Successfully renamed " + fromFile + " to " + toFile, Project.MSG_VERBOSE);
+ } else {
+ log("Failed to rename " + fromFile + " to " + toFile);
+ }
+ }
+ }
+ }
+
+
+ /** Performs a compile using the NetRexx 1.1.x compiler */
+ private void doNetRexxCompile() throws BuildException {
+ log("Using NetRexx compiler", Project.MSG_VERBOSE);
+
+ String classpath = getCompileClasspath();
+ StringBuffer compileOptions = new StringBuffer();
+
+ // create an array of strings for input to the compiler: one array
+ // comes from the compile options, the other from the compileList
+ String[] compileOptionsArray = getCompileOptionsAsArray();
+ String[] fileListArray = new String[compileList.size()];
+ Enumeration e = compileList.elements();
+ int j = 0;
+
+ while (e.hasMoreElements()) {
+ fileListArray[j] = (String) e.nextElement();
+ j++;
+ }
+ // create a single array of arguments for the compiler
+ String[] compileArgs = new String[compileOptionsArray.length + fileListArray.length];
+
+ for (int i = 0; i < compileOptionsArray.length; i++) {
+ compileArgs[i] = compileOptionsArray[i];
+ }
+ for (int i = 0; i < fileListArray.length; i++) {
+ compileArgs[i + compileOptionsArray.length] = fileListArray[i];
+ }
+
+ // print nice output about what we are doing for the log
+ compileOptions.append("Compilation args: ");
+ for (int i = 0; i < compileOptionsArray.length; i++) {
+ compileOptions.append(compileOptionsArray[i]);
+ compileOptions.append(" ");
+ }
+ log(compileOptions.toString(), Project.MSG_VERBOSE);
+
+ String eol = System.getProperty("line.separator");
+ StringBuffer niceSourceList = new StringBuffer("Files to be compiled:" + eol);
+
+ final int size = compileList.size();
+ for (int i = 0; i < size; i++) {
+ niceSourceList.append(" ");
+ niceSourceList.append(compileList.elementAt(i).toString());
+ niceSourceList.append(eol);
+ }
+
+ log(niceSourceList.toString(), Project.MSG_VERBOSE);
+
+ // need to set java.class.path property and restore it later
+ // since the NetRexx compiler has no option for the classpath
+ String currentClassPath = System.getProperty("java.class.path");
+ Properties currentProperties = System.getProperties();
+
+ currentProperties.put("java.class.path", classpath);
+
+ try {
+ StringWriter out = new StringWriter();
+ PrintWriter w = null;
+ int rc =
+ COM.ibm.netrexx.process.NetRexxC.main(new Rexx(compileArgs),
+ w = new PrintWriter(out));
+ String sdir = srcDir.getAbsolutePath();
+ String ddir = destDir.getAbsolutePath();
+ boolean doReplace = !(sdir.equals(ddir));
+ int dlen = ddir.length();
+ String l;
+ BufferedReader in = new BufferedReader(new StringReader(out.toString()));
+
+ log("replacing destdir '" + ddir + "' through sourcedir '"
+ + sdir + "'", Project.MSG_VERBOSE);
+ while ((l = in.readLine()) != null) {
+ int idx;
+
+ while (doReplace && ((idx = l.indexOf(ddir)) != -1)) {
+ // path is mentioned in the message
+ l = (new StringBuffer(l)).replace(idx, idx + dlen, sdir).toString();
+ }
+ // verbose level logging for suppressed messages
+ if (suppressMethodArgumentNotUsed
+ && l.indexOf(MSG_METHOD_ARGUMENT_NOT_USED) != -1) {
+ log(l, Project.MSG_VERBOSE);
+ } else if (suppressPrivatePropertyNotUsed
+ && l.indexOf(MSG_PRIVATE_PROPERTY_NOT_USED) != -1) {
+ log(l, Project.MSG_VERBOSE);
+ } else if (suppressVariableNotUsed
+ && l.indexOf(MSG_VARIABLE_NOT_USED) != -1) {
+ log(l, Project.MSG_VERBOSE);
+ } else if (suppressExceptionNotSignalled
+ && l.indexOf(MSG_EXCEPTION_NOT_SIGNALLED) != -1) {
+ log(l, Project.MSG_VERBOSE);
+ } else if (suppressDeprecation
+ && l.indexOf(MSG_DEPRECATION) != -1) {
+ log(l, Project.MSG_VERBOSE);
+ } else if (l.indexOf("Error:") != -1) {
+ // error level logging for compiler errors
+ log(l, Project.MSG_ERR);
+ } else if (l.indexOf("Warning:") != -1) {
+ // warning for all warning messages
+ log(l, Project.MSG_WARN);
+ } else {
+ log(l, Project.MSG_INFO); // info level for the rest.
+ }
+ }
+ if (rc > 1) {
+ throw new BuildException("Compile failed, messages should "
+ + "have been provided.");
+ }
+ if (w.checkError()) {
+ throw new IOException("Encountered an error");
+ }
+ } catch (IOException ioe) {
+ throw new BuildException("Unexpected IOException while "
+ + "playing with Strings", ioe);
+ } finally {
+ // need to reset java.class.path property
+ // since the NetRexx compiler has no option for the classpath
+ currentProperties = System.getProperties();
+ currentProperties.put("java.class.path", currentClassPath);
+ }
+
+ }
+
+
+ /** Builds the compilation classpath. */
+ private String getCompileClasspath() {
+ StringBuffer classpath = new StringBuffer();
+
+ // add dest dir to classpath so that previously compiled and
+ // untouched classes are on classpath
+ classpath.append(destDir.getAbsolutePath());
+
+ // add our classpath to the mix
+ if (this.classpath != null) {
+ addExistingToClasspath(classpath, this.classpath);
+ }
+
+ // add the system classpath
+ // addExistingToClasspath(classpath,System.getProperty("java.class.path"));
+ return classpath.toString();
+ }
+
+
+ /** This */
+ private String[] getCompileOptionsAsArray() {
+ Vector options = new Vector();
+
+ options.addElement(binary ? "-binary" : "-nobinary");
+ options.addElement(comments ? "-comments" : "-nocomments");
+ options.addElement(compile ? "-compile" : "-nocompile");
+ options.addElement(compact ? "-compact" : "-nocompact");
+ options.addElement(console ? "-console" : "-noconsole");
+ options.addElement(crossref ? "-crossref" : "-nocrossref");
+ options.addElement(decimal ? "-decimal" : "-nodecimal");
+ options.addElement(diag ? "-diag" : "-nodiag");
+ options.addElement(explicit ? "-explicit" : "-noexplicit");
+ options.addElement(format ? "-format" : "-noformat");
+ options.addElement(keep ? "-keep" : "-nokeep");
+ options.addElement(logo ? "-logo" : "-nologo");
+ options.addElement(replace ? "-replace" : "-noreplace");
+ options.addElement(savelog ? "-savelog" : "-nosavelog");
+ options.addElement(sourcedir ? "-sourcedir" : "-nosourcedir");
+ options.addElement(strictargs ? "-strictargs" : "-nostrictargs");
+ options.addElement(strictassign ? "-strictassign" : "-nostrictassign");
+ options.addElement(strictcase ? "-strictcase" : "-nostrictcase");
+ options.addElement(strictimport ? "-strictimport" : "-nostrictimport");
+ options.addElement(strictprops ? "-strictprops" : "-nostrictprops");
+ options.addElement(strictsignal ? "-strictsignal" : "-nostrictsignal");
+ options.addElement(symbols ? "-symbols" : "-nosymbols");
+ options.addElement(time ? "-time" : "-notime");
+ options.addElement("-" + trace);
+ options.addElement(utf8 ? "-utf8" : "-noutf8");
+ options.addElement("-" + verbose);
+
+ String[] results = new String[options.size()];
+
+ options.copyInto(results);
+ return results;
+ }
+
+
+ /**
+ * Takes a classpath-like string, and adds each element of this string to
+ * a new classpath, if the components exist. Components that don't exist,
+ * aren't added. We do this, because jikes issues warnings for
+ * non-existent files/dirs in his classpath, and these warnings are pretty
+ * annoying.
+ *
+ * @param target - target classpath
+ * @param source - source classpath to get file objects.
+ */
+ private void addExistingToClasspath(StringBuffer target, String source) {
+ StringTokenizer tok = new StringTokenizer(source,
+ System.getProperty("path.separator"), false);
+
+ while (tok.hasMoreTokens()) {
+ File f = getProject().resolveFile(tok.nextToken());
+
+ if (f.exists()) {
+ target.append(File.pathSeparator);
+ target.append(f.getAbsolutePath());
+ } else {
+ log("Dropping from classpath: "
+ + f.getAbsolutePath(), Project.MSG_VERBOSE);
+ }
+ }
+
+ }
+
+
+ /**
+ * Enumerated class corresponding to the trace attribute.
+ */
+ public static class TraceAttr extends EnumeratedAttribute {
+ /** {@inheritDoc}. */
+ public String[] getValues() {
+ return new String[]{"trace", "trace1", "trace2", "notrace"};
+ }
+ }
+
+ /**
+ * Enumerated class corresponding to the verbose attribute.
+ */
+ public static class VerboseAttr extends EnumeratedAttribute {
+ /** {@inheritDoc}. */
+ public String[] getValues() {
+ return new String[]{"verbose", "verbose0", "verbose1",
+ "verbose2", "verbose3", "verbose4",
+ "verbose5", "noverbose"};
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
new file mode 100644
index 00000000..162cab1a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
@@ -0,0 +1,726 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LayoutPreservingProperties;
+
+/**
+ * Modifies settings in a property file.
+ *
+ * <p>The following is an example of its usage:</p>
+ * <pre>
+ * &lt;target name="setState"&gt;
+ * &lt;property
+ * name="header"
+ * value="##Generated file - do not modify!"/&gt;
+ * &lt;propertyfile file="apropfile.properties" comment="${header}"&gt;
+ * &lt;entry key="product.version.major" type="int" value="5"/&gt;
+ * &lt;entry key="product.version.minor" type="int" value="0"/&gt;
+ * &lt;entry key="product.build.major" type="int" value="0" /&gt;
+ * &lt;entry key="product.build.minor" type="int" operation="+" /&gt;
+ * &lt;entry key="product.build.date" type="date" value="now" /&gt;
+ * &lt;entry key="intSet" type="int" operation="=" value="681"/&gt;
+ * &lt;entry key="intDec" type="int" operation="-"/&gt;
+ * &lt;entry key="StringEquals" type="string" value="testValue"/&gt;
+ * &lt;/propertyfile&gt;
+ * &lt;/target&gt;
+ * </pre>
+ *
+ * The &lt;propertyfile&gt; task must have:
+ * <ul>
+ * <li>file</li>
+ * </ul>
+ * Other parameters are:
+ * <ul>
+ * <li>comment</li>
+ * <li>key</li>
+ * <li>operation</li>
+ * <li>type</li>
+ * <li>value (the final four being eliminated shortly)</li>
+ * </ul>
+ *
+ * The &lt;entry&gt; task must have:
+ * <ul>
+ * <li>key</li>
+ * </ul>
+ * Other parameters are:
+ * <ul>
+ * <li>operation</li>
+ * <li>type</li>
+ * <li>value</li>
+ * <li>default</li>
+ * <li>unit</li>
+ * </ul>
+ *
+ * If type is unspecified, it defaults to string.
+ *
+ * Parameter values:
+ * <ul>
+ * <li>operation:</li>
+ * <ul>
+ * <li>"=" (set -- default)</li>
+ * <li>"-" (dec)</li>
+ * <li>"+" (inc)</li>
+ * </ul>
+ * <li>type:</li>
+ * <ul>
+ * <li>"int"</li>
+ * <li>"date"</li>
+ * <li>"string"</li>
+ * </ul>
+ * <li>value:</li>
+ * <ul>
+ * <li>holds the default value, if the property
+ * was not found in property file</li>
+ * <li>"now" In case of type "date", the
+ * value "now" will be replaced by the current
+ * date/time and used even if a valid date was
+ * found in the property file.</li>
+ * </ul>
+ * </ul>
+ *
+ * <p>String property types can only use the "=" operation.
+ * Int property types can only use the "=", "-" or "+" operations.<p>
+ *
+ * The message property is used for the property file header, with "\\" being
+ * a newline delimiter character.
+ *
+ */
+public class PropertyFile extends Task {
+
+ /* ========================================================================
+ *
+ * Instance variables.
+ */
+
+ // Use this to prepend a message to the properties file
+ private String comment;
+
+ private Properties properties;
+ private File propertyfile;
+ private boolean useJDKProperties;
+
+ private Vector entries = new Vector();
+
+ /* ========================================================================
+ *
+ * Constructors
+ */
+
+ /* ========================================================================
+ *
+ * Methods
+ */
+
+ /**
+ * Execute the task.
+ * @throws BuildException on error.
+ */
+ @Override
+ public void execute() throws BuildException {
+ checkParameters();
+ readFile();
+ executeOperation();
+ writeFile();
+ }
+
+ /**
+ * The entry nested element.
+ * @return an entry nested element to be configured.
+ */
+ public Entry createEntry() {
+ Entry e = new Entry();
+ entries.addElement(e);
+ return e;
+ }
+
+ private void executeOperation() throws BuildException {
+ for (Enumeration e = entries.elements(); e.hasMoreElements();) {
+ Entry entry = (Entry) e.nextElement();
+ entry.executeOn(properties);
+ }
+ }
+
+ private void readFile() throws BuildException {
+ if (useJDKProperties) {
+ // user chose to use standard Java properties, which loose
+ // comments and layout
+ properties = new Properties();
+ } else {
+ properties = new LayoutPreservingProperties();
+ }
+ try {
+ if (propertyfile.exists()) {
+ log("Updating property file: "
+ + propertyfile.getAbsolutePath());
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(propertyfile);
+ BufferedInputStream bis = new BufferedInputStream(fis);
+ properties.load(bis);
+ } finally {
+ if (fis != null) {
+ fis.close();
+ }
+ }
+ } else {
+ log("Creating new property file: "
+ + propertyfile.getAbsolutePath());
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(propertyfile.getAbsolutePath());
+ out.flush();
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ throw new BuildException(ioe.toString());
+ }
+ }
+
+ private void checkParameters() throws BuildException {
+ if (!checkParam(propertyfile)) {
+ throw new BuildException("file token must not be null.",
+ getLocation());
+ }
+ }
+
+ /**
+ * Location of the property file to be edited; required.
+ * @param file the property file.
+ */
+ public void setFile(File file) {
+ propertyfile = file;
+ }
+
+ /**
+ * optional header comment for the file
+ * @param hdr the string to use for the comment.
+ */
+ public void setComment(String hdr) {
+ comment = hdr;
+ }
+
+ /**
+ * optional flag to use original Java properties (as opposed to
+ * layout preserving properties)
+ */
+ public void setJDKProperties(boolean val) {
+ useJDKProperties = val;
+ }
+
+ private void writeFile() throws BuildException {
+ // Write to RAM first, as an OOME could otherwise produce a truncated file:
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ properties.store(baos, comment);
+ } catch (IOException x) { // should not happen
+ throw new BuildException(x, getLocation());
+ }
+ try {
+ OutputStream os = new FileOutputStream(propertyfile);
+ try {
+ try {
+ os.write(baos.toByteArray());
+ } finally {
+ os.close();
+ }
+ } catch (IOException x) { // possibly corrupt
+ FileUtils.getFileUtils().tryHardToDelete(propertyfile);
+ throw x;
+ }
+ } catch (IOException x) { // opening, writing, or closing
+ throw new BuildException(x, getLocation());
+ }
+ }
+
+ private boolean checkParam(File param) {
+ return !(param == null);
+ }
+
+ /**
+ * Instance of this class represents nested elements of
+ * a task propertyfile.
+ */
+ public static class Entry {
+ private static final int DEFAULT_INT_VALUE = 0;
+ private static final String DEFAULT_DATE_VALUE = "now";
+ private static final String DEFAULT_STRING_VALUE = "";
+
+ private String key = null;
+ private int type = Type.STRING_TYPE;
+ private int operation = Operation.EQUALS_OPER;
+ private String value = null;
+ private String defaultValue = null;
+ private String newValue = null;
+ private String pattern = null;
+ private int field = Calendar.DATE;
+
+ /**
+ * Name of the property name/value pair
+ * @param value the key.
+ */
+ public void setKey(String value) {
+ this.key = value;
+ }
+
+ /**
+ * Value to set (=), to add (+) or subtract (-)
+ * @param value the value.
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * operation to apply.
+ * &quot;+&quot; or &quot;=&quot;
+ *(default) for all datatypes; &quot;-&quot; for date and int only)\.
+ * @param value the operation enumerated value.
+ */
+ public void setOperation(Operation value) {
+ this.operation = Operation.toOperation(value.getValue());
+ }
+
+ /**
+ * Regard the value as : int, date or string (default)
+ * @param value the type enumerated value.
+ */
+ public void setType(Type value) {
+ this.type = Type.toType(value.getValue());
+ }
+
+ /**
+ * Initial value to set for a property if it is not
+ * already defined in the property file.
+ * For type date, an additional keyword is allowed: &quot;now&quot;
+ * @param value the default value.
+ */
+ public void setDefault(String value) {
+ this.defaultValue = value;
+ }
+
+ /**
+ * For int and date type only. If present, Values will
+ * be parsed and formatted accordingly.
+ * @param value the pattern to use.
+ */
+ public void setPattern(String value) {
+ this.pattern = value;
+ }
+
+ /**
+ * The unit of the value to be applied to date +/- operations.
+ * Valid Values are:
+ * <ul>
+ * <li>millisecond</li>
+ * <li>second</li>
+ * <li>minute</li>
+ * <li>hour</li>
+ * <li>day (default)</li>
+ * <li>week</li>
+ * <li>month</li>
+ * <li>year</li>
+ * </ul>
+ * This only applies to date types using a +/- operation.
+ * @param unit the unit enumerated value.
+ * @since Ant 1.5
+ */
+ public void setUnit(PropertyFile.Unit unit) {
+ field = unit.getCalendarField();
+ }
+
+ /**
+ * Apply the nested element to the properties.
+ * @param props the properties to apply the entry on.
+ * @throws BuildException if there is an error.
+ */
+ protected void executeOn(Properties props) throws BuildException {
+ checkParameters();
+
+ if (operation == Operation.DELETE_OPER) {
+ props.remove(key);
+ return;
+ }
+
+ // type may be null because it wasn't set
+ String oldValue = (String) props.get(key);
+ try {
+ if (type == Type.INTEGER_TYPE) {
+ executeInteger(oldValue);
+ } else if (type == Type.DATE_TYPE) {
+ executeDate(oldValue);
+ } else if (type == Type.STRING_TYPE) {
+ executeString(oldValue);
+ } else {
+ throw new BuildException("Unknown operation type: "
+ + type);
+ }
+ } catch (NullPointerException npe) {
+ // Default to string type
+ // which means do nothing
+ npe.printStackTrace();
+ }
+
+ if (newValue == null) {
+ newValue = "";
+ }
+
+ // Insert as a string by default
+ props.put(key, newValue);
+ }
+
+ /**
+ * Handle operations for type <code>date</code>.
+ *
+ * @param oldValue the current value read from the property file or
+ * <code>null</code> if the <code>key</code> was
+ * not contained in the property file.
+ */
+ private void executeDate(String oldValue) throws BuildException {
+ Calendar currentValue = Calendar.getInstance();
+
+ if (pattern == null) {
+ pattern = "yyyy/MM/dd HH:mm";
+ }
+ DateFormat fmt = new SimpleDateFormat(pattern);
+
+ String currentStringValue = getCurrentValue(oldValue);
+ if (currentStringValue == null) {
+ currentStringValue = DEFAULT_DATE_VALUE;
+ }
+
+ if ("now".equals(currentStringValue)) {
+ currentValue.setTime(new Date());
+ } else {
+ try {
+ currentValue.setTime(fmt.parse(currentStringValue));
+ } catch (ParseException pe) {
+ // swallow
+ }
+ }
+
+ if (operation != Operation.EQUALS_OPER) {
+ int offset = 0;
+ try {
+ offset = Integer.parseInt(value);
+ if (operation == Operation.DECREMENT_OPER) {
+ offset = -1 * offset;
+ }
+ } catch (NumberFormatException e) {
+ throw new BuildException("Value not an integer on " + key);
+ }
+ currentValue.add(field, offset);
+ }
+
+ newValue = fmt.format(currentValue.getTime());
+ }
+
+
+ /**
+ * Handle operations for type <code>int</code>.
+ *
+ * @param oldValue the current value read from the property file or
+ * <code>null</code> if the <code>key</code> was
+ * not contained in the property file.
+ */
+ private void executeInteger(String oldValue) throws BuildException {
+ int currentValue = DEFAULT_INT_VALUE;
+ int newV = DEFAULT_INT_VALUE;
+
+
+ DecimalFormat fmt = (pattern != null) ? new DecimalFormat(pattern)
+ : new DecimalFormat();
+ try {
+ String curval = getCurrentValue(oldValue);
+ if (curval != null) {
+ currentValue = fmt.parse(curval).intValue();
+ } else {
+ currentValue = 0;
+ }
+ } catch (NumberFormatException nfe) {
+ // swallow
+ } catch (ParseException pe) {
+ // swallow
+ }
+
+ if (operation == Operation.EQUALS_OPER) {
+ newV = currentValue;
+ } else {
+ int operationValue = 1;
+ if (value != null) {
+ try {
+ operationValue = fmt.parse(value).intValue();
+ } catch (NumberFormatException nfe) {
+ // swallow
+ } catch (ParseException pe) {
+ // swallow
+ }
+ }
+
+ if (operation == Operation.INCREMENT_OPER) {
+ newV = currentValue + operationValue;
+ } else if (operation == Operation.DECREMENT_OPER) {
+ newV = currentValue - operationValue;
+ }
+ }
+
+ this.newValue = fmt.format(newV);
+ }
+
+ /**
+ * Handle operations for type <code>string</code>.
+ *
+ * @param oldValue the current value read from the property file or
+ * <code>null</code> if the <code>key</code> was
+ * not contained in the property file.
+ */
+ private void executeString(String oldValue) throws BuildException {
+ String newV = DEFAULT_STRING_VALUE;
+
+ String currentValue = getCurrentValue(oldValue);
+
+ if (currentValue == null) {
+ currentValue = DEFAULT_STRING_VALUE;
+ }
+
+ if (operation == Operation.EQUALS_OPER) {
+ newV = currentValue;
+ } else if (operation == Operation.INCREMENT_OPER) {
+ newV = currentValue + value;
+ }
+ this.newValue = newV;
+ }
+
+ /**
+ * Check if parameter combinations can be supported
+ * @todo make sure the 'unit' attribute is only specified on date
+ * fields
+ */
+ private void checkParameters() throws BuildException {
+ if (type == Type.STRING_TYPE
+ && operation == Operation.DECREMENT_OPER) {
+ throw new BuildException("- is not supported for string "
+ + "properties (key:" + key + ")");
+ }
+ if (value == null && defaultValue == null && operation != Operation.DELETE_OPER) {
+ throw new BuildException("\"value\" and/or \"default\" "
+ + "attribute must be specified (key:" + key + ")");
+ }
+ if (key == null) {
+ throw new BuildException("key is mandatory");
+ }
+ if (type == Type.STRING_TYPE && pattern != null) {
+ throw new BuildException("pattern is not supported for string "
+ + "properties (key:" + key + ")");
+ }
+ }
+
+ private String getCurrentValue(String oldValue) {
+ String ret = null;
+ if (operation == Operation.EQUALS_OPER) {
+ // If only value is specified, the property is set to it
+ // regardless of its previous value.
+ if (value != null && defaultValue == null) {
+ ret = value;
+ }
+
+ // If only default is specified and the property previously
+ // existed in the property file, it is unchanged.
+ if (value == null && defaultValue != null && oldValue != null) {
+ ret = oldValue;
+ }
+
+ // If only default is specified and the property did not
+ // exist in the property file, the property is set to default.
+ if (value == null && defaultValue != null && oldValue == null) {
+ ret = defaultValue;
+ }
+
+ // If value and default are both specified and the property
+ // previously existed in the property file, the property
+ // is set to value.
+ if (value != null && defaultValue != null && oldValue != null) {
+ ret = value;
+ }
+
+ // If value and default are both specified and the property
+ // did not exist in the property file, the property is set
+ // to default.
+ if (value != null && defaultValue != null && oldValue == null) {
+ ret = defaultValue;
+ }
+ } else {
+ ret = (oldValue == null) ? defaultValue : oldValue;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Enumerated attribute with the values "+", "-", "="
+ */
+ public static class Operation extends EnumeratedAttribute {
+
+ // Property type operations
+ /** + */
+ public static final int INCREMENT_OPER = 0;
+ /** - */
+ public static final int DECREMENT_OPER = 1;
+ /** = */
+ public static final int EQUALS_OPER = 2;
+ /** del */
+ public static final int DELETE_OPER = 3;
+
+ /** {@inheritDoc}. */
+ @Override
+ public String[] getValues() {
+ return new String[] {"+", "-", "=", "del"};
+ }
+
+ /**
+ * Convert string to index.
+ * @param oper the string to convert.
+ * @return the index.
+ */
+ public static int toOperation(String oper) {
+ if ("+".equals(oper)) {
+ return INCREMENT_OPER;
+ } else if ("-".equals(oper)) {
+ return DECREMENT_OPER;
+ } else if ("del".equals(oper)) {
+ return DELETE_OPER;
+ }
+ return EQUALS_OPER;
+ }
+ }
+
+ /**
+ * Enumerated attribute with the values "int", "date" and "string".
+ */
+ public static class Type extends EnumeratedAttribute {
+
+ // Property types
+ /** int */
+ public static final int INTEGER_TYPE = 0;
+ /** date */
+ public static final int DATE_TYPE = 1;
+ /** string */
+ public static final int STRING_TYPE = 2;
+
+ /** {@inheritDoc} */
+ @Override
+ public String[] getValues() {
+ return new String[] {"int", "date", "string"};
+ }
+
+ /**
+ * Convert string to index.
+ * @param type the string to convert.
+ * @return the index.
+ */
+ public static int toType(String type) {
+ if ("int".equals(type)) {
+ return INTEGER_TYPE;
+ } else if ("date".equals(type)) {
+ return DATE_TYPE;
+ }
+ return STRING_TYPE;
+ }
+ }
+ }
+
+ /**
+ * Borrowed from Tstamp
+ * @todo share all this time stuff across many tasks as a datetime datatype
+ * @since Ant 1.5
+ */
+ public static class Unit extends EnumeratedAttribute {
+
+ private static final String MILLISECOND = "millisecond";
+ private static final String SECOND = "second";
+ private static final String MINUTE = "minute";
+ private static final String HOUR = "hour";
+ private static final String DAY = "day";
+ private static final String WEEK = "week";
+ private static final String MONTH = "month";
+ private static final String YEAR = "year";
+
+ private static final String[] UNITS
+ = {MILLISECOND, SECOND, MINUTE, HOUR,
+ DAY, WEEK, MONTH, YEAR };
+
+ private Map calendarFields = new HashMap();
+
+ /** no arg constructor */
+ public Unit() {
+ calendarFields.put(MILLISECOND,
+ new Integer(Calendar.MILLISECOND));
+ calendarFields.put(SECOND, new Integer(Calendar.SECOND));
+ calendarFields.put(MINUTE, new Integer(Calendar.MINUTE));
+ calendarFields.put(HOUR, new Integer(Calendar.HOUR_OF_DAY));
+ calendarFields.put(DAY, new Integer(Calendar.DATE));
+ calendarFields.put(WEEK, new Integer(Calendar.WEEK_OF_YEAR));
+ calendarFields.put(MONTH, new Integer(Calendar.MONTH));
+ calendarFields.put(YEAR, new Integer(Calendar.YEAR));
+ }
+
+ /**
+ * Convert the value to a Calendar field index.
+ * @return the calendar value.
+ */
+ public int getCalendarField() {
+ String key = getValue().toLowerCase();
+ Integer i = (Integer) calendarFields.get(key);
+ return i.intValue();
+ }
+
+ /** {@inheritDoc}. */
+ @Override
+ public String[] getValues() {
+ return UNITS;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java
new file mode 100644
index 00000000..c4acadb2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+/*
+ * Task to rename files based on extension. This task has the following
+ * properties which can be set:
+ * <ul>
+ * <li>fromExtension: </li>
+ * <li>toExtension: </li>
+ * <li>srcDir: </li>
+ * <li>replace: </li>
+ * </ul>
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.Move;
+import org.apache.tools.ant.types.Mapper;
+
+/**
+ *
+ * @version 1.2
+ *
+ * @deprecated since 1.5.x.
+ * Use &lt;move&gt; instead
+ */
+public class RenameExtensions extends MatchingTask {
+
+ private String fromExtension = "";
+ private String toExtension = "";
+ private boolean replace = false;
+ private File srcDir;
+
+ private Mapper.MapperType globType;
+
+
+ /** Creates new RenameExtensions */
+ public RenameExtensions() {
+ super();
+ globType = new Mapper.MapperType();
+ globType.setValue("glob");
+ }
+
+ /**
+ * The string that files must end in to be renamed
+ *
+ * @param from the extension of files being renamed.
+ */
+ public void setFromExtension(String from) {
+ fromExtension = from;
+ }
+
+ /**
+ * The string that renamed files will end with on
+ * completion
+ *
+ * @param to the extension of the renamed files.
+ */
+ public void setToExtension(String to) {
+ toExtension = to;
+ }
+
+ /**
+ * store replace attribute - this determines whether the target file
+ * should be overwritten if present
+ *
+ * @param replace if true overwrite any target files that exist.
+ */
+ public void setReplace(boolean replace) {
+ this.replace = replace;
+ }
+
+ /**
+ * Set the source dir to find the files to be renamed.
+ *
+ * @param srcDir the source directory.
+ */
+ public void setSrcDir(File srcDir) {
+ this.srcDir = srcDir;
+ }
+
+ /**
+ * Executes the task.
+ *
+ * @throws BuildException is there is a problem in the task execution.
+ */
+ public void execute() throws BuildException {
+
+ // first off, make sure that we've got a from and to extension
+ if (fromExtension == null || toExtension == null || srcDir == null) {
+ throw new BuildException("srcDir, fromExtension and toExtension "
+ + "attributes must be set!");
+ }
+
+ log("DEPRECATED - The renameext task is deprecated. Use move instead.",
+ Project.MSG_WARN);
+ log("Replace this with:", Project.MSG_INFO);
+ log("<move todir=\"" + srcDir + "\" overwrite=\"" + replace + "\">",
+ Project.MSG_INFO);
+ log(" <fileset dir=\"" + srcDir + "\" />", Project.MSG_INFO);
+ log(" <mapper type=\"glob\"", Project.MSG_INFO);
+ log(" from=\"*" + fromExtension + "\"", Project.MSG_INFO);
+ log(" to=\"*" + toExtension + "\" />", Project.MSG_INFO);
+ log("</move>", Project.MSG_INFO);
+ log("using the same patterns on <fileset> as you\'ve used here",
+ Project.MSG_INFO);
+
+ Move move = new Move();
+ move.bindToOwner(this);
+ move.setOwningTarget(getOwningTarget());
+ move.setTaskName(getTaskName());
+ move.setLocation(getLocation());
+ move.setTodir(srcDir);
+ move.setOverwrite(replace);
+
+ fileset.setDir(srcDir);
+ move.addFileset(fileset);
+
+ Mapper me = move.createMapper();
+ me.setType(globType);
+ me.setFrom("*" + fromExtension);
+ me.setTo("*" + toExtension);
+
+ move.execute();
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
new file mode 100644
index 00000000..d088096a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
@@ -0,0 +1,533 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.RegularExpression;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.Substitution;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.regexp.Regexp;
+import org.apache.tools.ant.util.regexp.RegexpUtil;
+
+/**
+ * Performs regular expression string replacements in a text
+ * file. The input file(s) must be able to be properly processed by
+ * a Reader instance. That is, they must be text only, no binary.
+ *
+ * The syntax of the regular expression depends on the implementation that
+ * you choose to use. The system property <code>ant.regexp.regexpimpl</code>
+ * will be the classname of the implementation that will be used (the default
+ * is <code>org.apache.tools.ant.util.regexp.JakartaOroRegexp</code> and
+ * requires the Jakarta Oro Package).
+ *
+ * <pre>
+ * Available implementations:
+ *
+ * org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp (default)
+ * Uses Java's built-in regular expression package
+ *
+ * org.apache.tools.ant.util.regexp.JakartaOroRegexp
+ * Requires the jakarta-oro package
+ *
+ * org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
+ * Requires the jakarta-regexp package
+ *
+ * Usage:
+ *
+ * Call Syntax:
+ *
+ * &lt;replaceregexp file="file"
+ * match="pattern"
+ * replace="pattern"
+ * flags="options"?
+ * byline="true|false"? &gt;
+ * regexp?
+ * substitution?
+ * fileset*
+ * &lt;/replaceregexp&gt;
+ *
+ * NOTE: You must have either the file attribute specified, or at least one fileset subelement
+ * to operation on. You may not have the file attribute specified if you nest fileset elements
+ * inside this task. Also, you cannot specify both match and a regular expression subelement at
+ * the same time, nor can you specify the replace attribute and the substitution subelement at
+ * the same time.
+ *
+ * Attributes:
+ *
+ * file --&gt; A single file to operation on (mutually exclusive
+ * with the fileset subelements)
+ * match --&gt; The Regular expression to match
+ * replace --&gt; The Expression replacement string
+ * flags --&gt; The options to give to the replacement
+ * g = Substitute all occurrences. default is to replace only the first one
+ * i = Case insensitive match
+ *
+ * byline --&gt; Should this file be processed a single line at a time (default is false)
+ * "true" indicates to perform replacement on a line by line basis
+ * "false" indicates to perform replacement on the whole file at once.
+ *
+ * Example:
+ *
+ * The following call could be used to replace an old property name in a ".properties"
+ * file with a new name. In the replace attribute, you can refer to any part of the
+ * match expression in parenthesis using backslash followed by a number like '\1'.
+ *
+ * &lt;replaceregexp file="test.properties"
+ * match="MyProperty=(.*)"
+ * replace="NewProperty=\1"
+ * byline="true" /&gt;
+ *
+ * </pre>
+ *
+ */
+public class ReplaceRegExp extends Task {
+
+ private File file;
+ private String flags;
+ private boolean byline;
+ private Union resources;
+ private RegularExpression regex;
+ private Substitution subs;
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ private boolean preserveLastModified = false;
+
+ /**
+ * Encoding to assume for the files
+ */
+ private String encoding = null;
+
+ /** Default Constructor */
+ public ReplaceRegExp() {
+ super();
+ this.file = null;
+ this.flags = "";
+ this.byline = false;
+
+ this.regex = null;
+ this.subs = null;
+ }
+
+
+ /**
+ * file for which the regular expression should be replaced;
+ * required unless a nested fileset is supplied.
+ * @param file The file for which the reg exp should be replaced.
+ */
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+
+ /**
+ * the regular expression pattern to match in the file(s);
+ * required if no nested &lt;regexp&gt; is used
+ * @param match the match attribute.
+ */
+ public void setMatch(String match) {
+ if (regex != null) {
+ throw new BuildException("Only one regular expression is allowed");
+ }
+
+ regex = new RegularExpression();
+ regex.setPattern(match);
+ }
+
+
+ /**
+ * The substitution pattern to place in the file(s) in place
+ * of the regular expression.
+ * Required if no nested &lt;substitution&gt; is used
+ * @param replace the replace attribute
+ */
+
+ public void setReplace(String replace) {
+ if (subs != null) {
+ throw new BuildException("Only one substitution expression is "
+ + "allowed");
+ }
+
+ subs = new Substitution();
+ subs.setExpression(replace);
+ }
+
+ /**
+ * The flags to use when matching the regular expression. For more
+ * information, consult the Perl5 syntax.
+ * <ul>
+ * <li>g : Global replacement. Replace all occurrences found
+ * <li>i : Case Insensitive. Do not consider case in the match
+ * <li>m : Multiline. Treat the string as multiple lines of input,
+ * using "^" and "$" as the start or end of any line, respectively,
+ * rather than start or end of string.
+ * <li> s : Singleline. Treat the string as a single line of input, using
+ * "." to match any character, including a newline, which normally,
+ * it would not match.
+ *</ul>
+ * @param flags the flags attribute
+ */
+ public void setFlags(String flags) {
+ this.flags = flags;
+ }
+
+
+ /**
+ * Process the file(s) one line at a time, executing the replacement
+ * on one line at a time. This is useful if you
+ * want to only replace the first occurrence of a regular expression on
+ * each line, which is not easy to do when processing the file as a whole.
+ * Defaults to <i>false</i>.
+ *
+ * @param byline the byline attribute as a string
+ * @deprecated since 1.6.x.
+ * Use setByLine(boolean).
+ */
+ @Deprecated
+ public void setByLine(String byline) {
+ Boolean res = Boolean.valueOf(byline);
+
+ if (res == null) {
+ res = Boolean.FALSE;
+ }
+ this.byline = res.booleanValue();
+ }
+
+ /**
+ * Process the file(s) one line at a time, executing the replacement
+ * on one line at a time. This is useful if you
+ * want to only replace the first occurrence of a regular expression on
+ * each line, which is not easy to do when processing the file as a whole.
+ * Defaults to <i>false</i>.
+ *
+ * @param byline the byline attribute
+ */
+ public void setByLine(boolean byline) {
+ this.byline = byline;
+ }
+
+ /**
+ * Specifies the encoding Ant expects the files to be in -
+ * defaults to the platforms default encoding.
+ * @param encoding the encoding attribute
+ *
+ * @since Ant 1.6
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * list files to apply the replacement to
+ * @param set the fileset element
+ */
+ public void addFileset(FileSet set) {
+ addConfigured(set);
+ }
+
+ /**
+ * Support arbitrary file system based resource collections.
+ *
+ * @since Ant 1.8.0
+ */
+ public void addConfigured(ResourceCollection rc) {
+ if (!rc.isFilesystemOnly()) {
+ throw new BuildException("only filesystem resources are supported");
+ }
+ if (resources == null) {
+ resources = new Union();
+ }
+ resources.add(rc);
+ }
+
+ /**
+ * A regular expression.
+ * You can use this element to refer to a previously
+ * defined regular expression datatype instance
+ * @return the regular expression object to be configured as an element
+ */
+ public RegularExpression createRegexp() {
+ if (regex != null) {
+ throw new BuildException("Only one regular expression is allowed.");
+ }
+
+ regex = new RegularExpression();
+ return regex;
+ }
+
+
+ /**
+ * A substitution pattern. You can use this element to refer to a previously
+ * defined substitution pattern datatype instance.
+ * @return the substitution pattern object to be configured as an element
+ */
+ public Substitution createSubstitution() {
+ if (subs != null) {
+ throw new BuildException("Only one substitution expression is "
+ + "allowed");
+ }
+
+ subs = new Substitution();
+ return subs;
+ }
+
+ /**
+ * Whether the file timestamp shall be preserved even if the file
+ * is modified.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setPreserveLastModified(boolean b) {
+ preserveLastModified = b;
+ }
+
+ /**
+ * Invoke a regular expression (r) on a string (input) using
+ * substitutions (s) for a matching regex.
+ *
+ * @param r a regular expression
+ * @param s a Substitution
+ * @param input the string to do the replacement on
+ * @param options The options for the regular expression
+ * @return the replacement result
+ */
+ protected String doReplace(RegularExpression r,
+ Substitution s,
+ String input,
+ int options) {
+ String res = input;
+ Regexp regexp = r.getRegexp(getProject());
+
+ if (regexp.matches(input, options)) {
+ log("Found match; substituting", Project.MSG_DEBUG);
+ res = regexp.substitute(input, s.getExpression(getProject()),
+ options);
+ }
+
+ return res;
+ }
+
+
+ /**
+ * Perform the replacement on a file
+ *
+ * @param f the file to perform the replacement on
+ * @param options the regular expressions options
+ * @exception IOException if an error occurs
+ */
+ protected void doReplace(File f, int options)
+ throws IOException {
+ File temp = FILE_UTILS.createTempFile("replace", ".txt", null, true, true);
+ try {
+ boolean changes = false;
+
+ InputStream is = new FileInputStream(f);
+ try {
+ Reader r = encoding != null ? new InputStreamReader(is, encoding) : new InputStreamReader(is);
+ OutputStream os = new FileOutputStream(temp);
+ try {
+ Writer w = encoding != null ? new OutputStreamWriter(os, encoding) : new OutputStreamWriter(os);
+
+ log("Replacing pattern '" + regex.getPattern(getProject())
+ + "' with '" + subs.getExpression(getProject())
+ + "' in '" + f.getPath() + "'" + (byline ? " by line" : "")
+ + (flags.length() > 0 ? " with flags: '" + flags + "'" : "")
+ + ".", Project.MSG_VERBOSE);
+
+ if (byline) {
+ r = new BufferedReader(r);
+ w = new BufferedWriter(w);
+
+ StringBuffer linebuf = new StringBuffer();
+ int c;
+ boolean hasCR = false;
+
+ do {
+ c = r.read();
+
+ if (c == '\r') {
+ if (hasCR) {
+ // second CR -> EOL + possibly empty line
+ changes |= replaceAndWrite(linebuf.toString(),
+ w, options);
+ w.write('\r');
+
+ linebuf = new StringBuffer();
+ // hasCR is still true (for the second one)
+ } else {
+ // first CR in this line
+ hasCR = true;
+ }
+ } else if (c == '\n') {
+ // LF -> EOL
+ changes |= replaceAndWrite(linebuf.toString(),
+ w, options);
+ if (hasCR) {
+ w.write('\r');
+ hasCR = false;
+ }
+ w.write('\n');
+
+ linebuf = new StringBuffer();
+ } else { // any other char
+ if ((hasCR) || (c < 0)) {
+ // Mac-style linebreak or EOF (or both)
+ changes |= replaceAndWrite(linebuf.toString(),
+ w, options);
+ if (hasCR) {
+ w.write('\r');
+ hasCR = false;
+ }
+
+ linebuf = new StringBuffer();
+ }
+
+ if (c >= 0) {
+ linebuf.append((char) c);
+ }
+ }
+ } while (c >= 0);
+
+ } else {
+ changes = multilineReplace(r, w, options);
+ }
+
+ r.close();
+ w.close();
+
+ } finally {
+ os.close();
+ }
+ } finally {
+ is.close();
+ }
+ if (changes) {
+ log("File has changed; saving the updated file", Project.MSG_VERBOSE);
+ try {
+ long origLastModified = f.lastModified();
+ FILE_UTILS.rename(temp, f);
+ if (preserveLastModified) {
+ FILE_UTILS.setFileLastModified(f, origLastModified);
+ }
+ temp = null;
+ } catch (IOException e) {
+ throw new BuildException("Couldn't rename temporary file "
+ + temp, e, getLocation());
+ }
+ } else {
+ log("No change made", Project.MSG_DEBUG);
+ }
+ } finally {
+ if (temp != null) {
+ temp.delete();
+ }
+ }
+ }
+
+
+ /**
+ * Execute the task
+ *
+ * @throws BuildException is there is a problem in the task execution.
+ */
+ @Override
+ public void execute() throws BuildException {
+ if (regex == null) {
+ throw new BuildException("No expression to match.");
+ }
+ if (subs == null) {
+ throw new BuildException("Nothing to replace expression with.");
+ }
+
+ if (file != null && resources != null) {
+ throw new BuildException("You cannot supply the 'file' attribute "
+ + "and resource collections at the same "
+ + "time.");
+ }
+
+ int options = RegexpUtil.asOptions(flags);
+
+ if (file != null && file.exists()) {
+ try {
+ doReplace(file, options);
+ } catch (IOException e) {
+ log("An error occurred processing file: '"
+ + file.getAbsolutePath() + "': " + e.toString(),
+ Project.MSG_ERR);
+ }
+ } else if (file != null) {
+ log("The following file is missing: '"
+ + file.getAbsolutePath() + "'", Project.MSG_ERR);
+ }
+
+ if (resources != null) {
+ for (Resource r : resources) {
+ FileProvider fp =
+ r.as(FileProvider.class);
+ File f = fp.getFile();
+
+ if (f.exists()) {
+ try {
+ doReplace(f, options);
+ } catch (Exception e) {
+ log("An error occurred processing file: '"
+ + f.getAbsolutePath() + "': " + e.toString(),
+ Project.MSG_ERR);
+ }
+ } else {
+ log("The following file is missing: '"
+ + f.getAbsolutePath() + "'", Project.MSG_ERR);
+ }
+ }
+ }
+ }
+
+ private boolean multilineReplace(Reader r, Writer w, int options)
+ throws IOException {
+ return replaceAndWrite(FileUtils.safeReadFully(r), w, options);
+ }
+
+ private boolean replaceAndWrite(String s, Writer w, int options)
+ throws IOException {
+ String res = doReplace(regex, subs, s, options);
+ w.write(res);
+ return !res.equals(s);
+ }
+}
+
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java
new file mode 100644
index 00000000..b395a16c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java
@@ -0,0 +1,364 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Map;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Invokes the rpm tool to build a Linux installation file.
+ *
+ */
+public class Rpm extends Task {
+
+ private static final String PATH1 = "PATH";
+ private static final String PATH2 = "Path";
+ private static final String PATH3 = "path";
+
+ /**
+ * the spec file
+ */
+ private String specFile;
+
+ /**
+ * the rpm top dir
+ */
+ private File topDir;
+
+ /**
+ * the rpm command to use
+ */
+ private String command = "-bb";
+
+ /**
+ * The executable to use for building the packages.
+ * @since Ant 1.6
+ */
+ private String rpmBuildCommand = null;
+
+ /**
+ * clean BUILD directory
+ */
+ private boolean cleanBuildDir = false;
+
+ /**
+ * remove spec file
+ */
+ private boolean removeSpec = false;
+
+ /**
+ * remove sources
+ */
+ private boolean removeSource = false;
+
+ /**
+ * the file to direct standard output from the command
+ */
+ private File output;
+
+ /**
+ * the file to direct standard error from the command
+ */
+ private File error;
+
+ /**
+ * Halt on error return value from rpm build.
+ */
+ private boolean failOnError = false;
+
+ /**
+ * Don't show output of RPM build command on console. This does not affect
+ * the printing of output and error messages to files.
+ */
+ private boolean quiet = false;
+
+ /**
+ * Execute the task
+ *
+ * @throws BuildException is there is a problem in the task execution.
+ */
+ public void execute() throws BuildException {
+
+ Commandline toExecute = new Commandline();
+
+ toExecute.setExecutable(rpmBuildCommand == null
+ ? guessRpmBuildCommand()
+ : rpmBuildCommand);
+ if (topDir != null) {
+ toExecute.createArgument().setValue("--define");
+ toExecute.createArgument().setValue("_topdir " + topDir);
+ }
+
+ toExecute.createArgument().setLine(command);
+
+ if (cleanBuildDir) {
+ toExecute.createArgument().setValue("--clean");
+ }
+ if (removeSpec) {
+ toExecute.createArgument().setValue("--rmspec");
+ }
+ if (removeSource) {
+ toExecute.createArgument().setValue("--rmsource");
+ }
+
+ toExecute.createArgument().setValue("SPECS/" + specFile);
+
+ ExecuteStreamHandler streamhandler = null;
+ OutputStream outputstream = null;
+ OutputStream errorstream = null;
+ if (error == null && output == null) {
+ if (!quiet) {
+ streamhandler = new LogStreamHandler(this, Project.MSG_INFO,
+ Project.MSG_WARN);
+ } else {
+ streamhandler = new LogStreamHandler(this, Project.MSG_DEBUG,
+ Project.MSG_DEBUG);
+ }
+ } else {
+ if (output != null) {
+ try {
+ BufferedOutputStream bos
+ = new BufferedOutputStream(new FileOutputStream(output));
+ outputstream = new PrintStream(bos);
+ } catch (IOException e) {
+ throw new BuildException(e, getLocation());
+ }
+ } else if (!quiet) {
+ outputstream = new LogOutputStream(this, Project.MSG_INFO);
+ } else {
+ outputstream = new LogOutputStream(this, Project.MSG_DEBUG);
+ }
+ if (error != null) {
+ try {
+ BufferedOutputStream bos
+ = new BufferedOutputStream(new FileOutputStream(error));
+ errorstream = new PrintStream(bos);
+ } catch (IOException e) {
+ throw new BuildException(e, getLocation());
+ }
+ } else if (!quiet) {
+ errorstream = new LogOutputStream(this, Project.MSG_WARN);
+ } else {
+ errorstream = new LogOutputStream(this, Project.MSG_DEBUG);
+ }
+ streamhandler = new PumpStreamHandler(outputstream, errorstream);
+ }
+
+ Execute exe = getExecute(toExecute, streamhandler);
+ try {
+ log("Building the RPM based on the " + specFile + " file");
+ int returncode = exe.execute();
+ if (Execute.isFailure(returncode)) {
+ String msg = "'" + toExecute.getExecutable()
+ + "' failed with exit code " + returncode;
+ if (failOnError) {
+ throw new BuildException(msg);
+ }
+ log(msg, Project.MSG_ERR);
+ }
+ } catch (IOException e) {
+ throw new BuildException(e, getLocation());
+ } finally {
+ FileUtils.close(outputstream);
+ FileUtils.close(errorstream);
+ }
+ }
+
+ /**
+ * The directory which will have the expected
+ * subdirectories, SPECS, SOURCES, BUILD, SRPMS ; optional.
+ * If this isn't specified,
+ * the <tt>baseDir</tt> value is used
+ *
+ * @param td the directory containing the normal RPM directories.
+ */
+ public void setTopDir(File td) {
+ this.topDir = td;
+ }
+
+ /**
+ * What command to issue to the rpm build tool; optional.
+ * The default is "-bb"
+ * @param c the command to use.
+ */
+ public void setCommand(String c) {
+ this.command = c;
+ }
+
+ /**
+ * The name of the spec File to use; required.
+ * @param sf the spec file name to use.
+ */
+ public void setSpecFile(String sf) {
+ if ((sf == null) || (sf.trim().length() == 0)) {
+ throw new BuildException("You must specify a spec file", getLocation());
+ }
+ this.specFile = sf;
+ }
+
+ /**
+ * Flag (optional, default=false) to remove
+ * the generated files in the BUILD directory
+ * @param cbd a <code>boolean</code> value.
+ */
+ public void setCleanBuildDir(boolean cbd) {
+ cleanBuildDir = cbd;
+ }
+
+ /**
+ * Flag (optional, default=false) to remove the spec file from SPECS
+ * @param rs a <code>boolean</code> value.
+ */
+ public void setRemoveSpec(boolean rs) {
+ removeSpec = rs;
+ }
+
+ /**
+ * Flag (optional, default=false)
+ * to remove the sources after the build.
+ * See the <tt>--rmsource</tt> option of rpmbuild.
+ * @param rs a <code>boolean</code> value.
+ */
+ public void setRemoveSource(boolean rs) {
+ removeSource = rs;
+ }
+
+ /**
+ * Optional file to save stdout to.
+ * @param output the file to save stdout to.
+ */
+ public void setOutput(File output) {
+ this.output = output;
+ }
+
+ /**
+ * Optional file to save stderr to
+ * @param error the file to save error output to.
+ */
+ public void setError(File error) {
+ this.error = error;
+ }
+
+ /**
+ * The executable to run when building; optional.
+ * The default is <code>rpmbuild</code>.
+ *
+ * @since Ant 1.6
+ * @param c the rpm build executable
+ */
+ public void setRpmBuildCommand(String c) {
+ this.rpmBuildCommand = c;
+ }
+
+ /**
+ * If <code>true</code>, stop the build process when the rpmbuild command
+ * exits with an error status.
+ * @param value <code>true</code> if it should halt, otherwise
+ * <code>false</code>. The default is <code>false</code>.
+ *
+ * @since Ant 1.6.3
+ */
+ public void setFailOnError(boolean value) {
+ failOnError = value;
+ }
+
+ /**
+ * If true, output from the RPM build command will only be logged to DEBUG.
+ * @param value <code>false</code> if output should be logged, otherwise
+ * <code>true</code>. The default is <code>false</code>.
+ *
+ * @since Ant 1.6.3
+ */
+ public void setQuiet(boolean value) {
+ quiet = value;
+ }
+
+ /**
+ * Checks whether <code>rpmbuild</code> is on the PATH and returns
+ * the absolute path to it - falls back to <code>rpm</code>
+ * otherwise.
+ *
+ * @return the command used to build RPM's
+ *
+ * @since 1.6
+ */
+ protected String guessRpmBuildCommand() {
+ Map/*<String, String>*/ env = Execute.getEnvironmentVariables();
+ String path = (String) env.get(PATH1);
+ if (path == null) {
+ path = (String) env.get(PATH2);
+ if (path == null) {
+ path = (String) env.get(PATH3);
+ }
+ }
+
+ if (path != null) {
+ Path p = new Path(getProject(), path);
+ String[] pElements = p.list();
+ for (int i = 0; i < pElements.length; i++) {
+ File f = new File(pElements[i],
+ "rpmbuild"
+ + (Os.isFamily("dos") ? ".exe" : ""));
+ if (f.canRead()) {
+ return f.getAbsolutePath();
+ }
+ }
+ }
+
+ return "rpm";
+ }
+
+ /**
+ * Get the execute object.
+ * @param toExecute the command line to use.
+ * @param streamhandler the stream handler to use.
+ * @return the execute object.
+ * @since Ant 1.6.3
+ */
+ protected Execute getExecute(Commandline toExecute,
+ ExecuteStreamHandler streamhandler) {
+ Execute exe = new Execute(streamhandler, null);
+
+ exe.setAntRun(getProject());
+ if (topDir == null) {
+ topDir = getProject().getBaseDir();
+ }
+ exe.setWorkingDirectory(topDir);
+
+ exe.setCommandline(toExecute.getCommandline());
+ return exe;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java
new file mode 100644
index 00000000..e57d6d22
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java
@@ -0,0 +1,529 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.XmlConstants;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Validate XML Schema documents.
+ * This task validates XML schema documents. It requires an XML parser
+ * that handles the relevant SAX, Xerces or JAXP options.
+ *
+ * To resolve remote referencies, Ant may need its proxy set up, using the
+ * setproxy task.
+ *
+ * Hands off most of the work to its parent, {@link XMLValidateTask}
+ * @since Ant1.7
+ */
+
+public class SchemaValidate extends XMLValidateTask {
+
+ /** map of all declared schemas; we catch and complain about redefinitions */
+ private HashMap schemaLocations = new HashMap();
+
+ /** full checking of a schema */
+ private boolean fullChecking = true;
+
+ /**
+ * flag to disable DTD support. Best left enabled.
+ */
+ private boolean disableDTD = false;
+
+ /**
+ * default URL for nonamespace schemas
+ */
+ private SchemaLocation anonymousSchema;
+
+ // Error strings
+ /** SAX1 not supported */
+ public static final String ERROR_SAX_1 = "SAX1 parsers are not supported";
+
+ /** schema features not supported */
+ public static final String ERROR_NO_XSD_SUPPORT
+ = "Parser does not support Xerces or JAXP schema features";
+
+ /** too many default schemas */
+ public static final String ERROR_TOO_MANY_DEFAULT_SCHEMAS
+ = "Only one of defaultSchemaFile and defaultSchemaURL allowed";
+
+ /** unable to create parser */
+ public static final String ERROR_PARSER_CREATION_FAILURE
+ = "Could not create parser";
+
+ /** adding schema */
+ public static final String MESSAGE_ADDING_SCHEMA = "Adding schema ";
+
+ /** Duplicate declaration of schema */
+ public static final String ERROR_DUPLICATE_SCHEMA
+ = "Duplicate declaration of schema ";
+
+ /**
+ * Called by the project to let the task initialize properly. The default
+ * implementation is a no-op.
+ *
+ * @throws BuildException if something goes wrong with the build
+ */
+ public void init() throws BuildException {
+ super.init();
+ //validating
+ setLenient(false);
+ }
+
+ /**
+ * Turn on XSD support in Xerces.
+ * @return true on success, false on failure
+ */
+ public boolean enableXercesSchemaValidation() {
+ try {
+ setFeature(XmlConstants.FEATURE_XSD, true);
+ //set the schema source for the doc
+ setNoNamespaceSchemaProperty(XmlConstants.PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION);
+ } catch (BuildException e) {
+ log(e.toString(), Project.MSG_VERBOSE);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * set nonamespace handling up for xerces or other parsers
+ * @param property name of the property to set
+ */
+ private void setNoNamespaceSchemaProperty(String property) {
+ String anonSchema = getNoNamespaceSchemaURL();
+ if (anonSchema != null) {
+ setProperty(property, anonSchema);
+ }
+ }
+
+ /**
+ * Set schema attributes in a JAXP 1.2 engine.
+ * @see <A href="http://java.sun.com/xml/jaxp/change-requests-11.html">
+ * JAXP 1.2 Approved CHANGES</A>
+ * @return true on success, false on failure
+ */
+ public boolean enableJAXP12SchemaValidation() {
+ try {
+ //enable XSD
+ setProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_LANGUAGE, XmlConstants.URI_XSD);
+ //set the schema source for the doc
+ setNoNamespaceSchemaProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_SOURCE);
+ } catch (BuildException e) {
+ log(e.toString(), Project.MSG_VERBOSE);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * add the schema
+ * @param location the schema location.
+ * @throws BuildException if there is no namespace, or if there already
+ * is a declaration of this schema with a different value
+ */
+ public void addConfiguredSchema(SchemaLocation location) {
+ log("adding schema " + location, Project.MSG_DEBUG);
+ location.validateNamespace();
+ SchemaLocation old = (SchemaLocation) schemaLocations.get(location.getNamespace());
+ if (old != null && !old.equals(location)) {
+ throw new BuildException(ERROR_DUPLICATE_SCHEMA + location);
+ }
+ schemaLocations.put(location.getNamespace(), location);
+ }
+
+ /**
+ * enable full schema checking. Slower but better.
+ * @param fullChecking a <code>boolean</code> value.
+ */
+ public void setFullChecking(boolean fullChecking) {
+ this.fullChecking = fullChecking;
+ }
+
+ /**
+ * create a schema location to hold the anonymous
+ * schema
+ */
+ protected void createAnonymousSchema() {
+ if (anonymousSchema == null) {
+ anonymousSchema = new SchemaLocation();
+ }
+ anonymousSchema.setNamespace("(no namespace)");
+ }
+
+ /**
+ * identify the URL of the default schema
+ * @param defaultSchemaURL the URL of the default schema.
+ */
+ public void setNoNamespaceURL(String defaultSchemaURL) {
+ createAnonymousSchema();
+ this.anonymousSchema.setUrl(defaultSchemaURL);
+ }
+
+ /**
+ * identify a file containing the default schema
+ * @param defaultSchemaFile the location of the default schema.
+ */
+ public void setNoNamespaceFile(File defaultSchemaFile) {
+ createAnonymousSchema();
+ this.anonymousSchema.setFile(defaultSchemaFile);
+ }
+
+ /**
+ * flag to disable DTD support.
+ * @param disableDTD a <code>boolean</code> value.
+ */
+ public void setDisableDTD(boolean disableDTD) {
+ this.disableDTD = disableDTD;
+ }
+
+ /**
+ * init the parser : load the parser class, and set features if necessary It
+ * is only after this that the reader is valid
+ *
+ * @throws BuildException if something went wrong
+ */
+ protected void initValidator() {
+ super.initValidator();
+ //validate the parser type
+ if (isSax1Parser()) {
+ throw new BuildException(ERROR_SAX_1);
+ }
+
+ //enable schema
+ //setFeature(XmlConstants.FEATURE_VALIDATION, false);
+ setFeature(XmlConstants.FEATURE_NAMESPACES, true);
+ if (!enableXercesSchemaValidation() && !enableJAXP12SchemaValidation()) {
+ //couldnt use the xerces or jaxp calls
+ throw new BuildException(ERROR_NO_XSD_SUPPORT);
+ }
+
+ //enable schema checking
+ setFeature(XmlConstants.FEATURE_XSD_FULL_VALIDATION, fullChecking);
+
+ //turn off DTDs if desired
+ setFeatureIfSupported(XmlConstants.FEATURE_DISALLOW_DTD, disableDTD);
+
+ //schema declarations go in next
+ addSchemaLocations();
+ }
+
+ /**
+ * Create a reader if the use of the class did not specify another one.
+ * The reason to not use {@link org.apache.tools.ant.util.JAXPUtils#getXMLReader()} was to
+ * create our own factory with our own options.
+ * @return a default XML parser
+ */
+ protected XMLReader createDefaultReader() {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setValidating(true);
+ factory.setNamespaceAware(true);
+ XMLReader reader = null;
+ try {
+ SAXParser saxParser = factory.newSAXParser();
+ reader = saxParser.getXMLReader();
+ } catch (ParserConfigurationException e) {
+ throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
+ } catch (SAXException e) {
+ throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
+ }
+ return reader;
+ }
+
+ /**
+ * build a string list of all schema locations, then set the relevant
+ * property.
+ */
+ protected void addSchemaLocations() {
+ Iterator it = schemaLocations.values().iterator();
+ StringBuffer buffer = new StringBuffer();
+ int count = 0;
+ while (it.hasNext()) {
+ if (count > 0) {
+ buffer.append(' ');
+ }
+ SchemaLocation schemaLocation = (SchemaLocation) it.next();
+ String tuple = schemaLocation.getURIandLocation();
+ buffer.append(tuple);
+ log("Adding schema " + tuple, Project.MSG_VERBOSE);
+ count++;
+ }
+ if (count > 0) {
+ setProperty(XmlConstants.PROPERTY_SCHEMA_LOCATION, buffer.toString());
+ }
+
+ }
+
+ /**
+ * get the URL of the no namespace schema
+ * @return the schema URL
+ */
+ protected String getNoNamespaceSchemaURL() {
+ if (anonymousSchema == null) {
+ return null;
+ } else {
+ return anonymousSchema.getSchemaLocationURL();
+ }
+ }
+
+ /**
+ * set a feature if it is supported, log at verbose level if
+ * not
+ * @param feature the feature.
+ * @param value a <code>boolean</code> value.
+ */
+ protected void setFeatureIfSupported(String feature, boolean value) {
+ try {
+ getXmlReader().setFeature(feature, value);
+ } catch (SAXNotRecognizedException e) {
+ log("Not recognizied: " + feature, Project.MSG_VERBOSE);
+ } catch (SAXNotSupportedException e) {
+ log("Not supported: " + feature, Project.MSG_VERBOSE);
+ }
+ }
+
+ /**
+ * handler called on successful file validation.
+ *
+ * @param fileProcessed number of files processed.
+ */
+ protected void onSuccessfulValidation(int fileProcessed) {
+ log(fileProcessed + MESSAGE_FILES_VALIDATED, Project.MSG_VERBOSE);
+ }
+
+ /**
+ * representation of a schema location. This is a URI plus either a file or
+ * a url
+ */
+ public static class SchemaLocation {
+ private String namespace;
+
+ private File file;
+
+ private String url;
+
+ /** No namespace URI */
+ public static final String ERROR_NO_URI = "No namespace URI";
+
+ /** Both URL and File were given for schema */
+ public static final String ERROR_TWO_LOCATIONS
+ = "Both URL and File were given for schema ";
+
+ /** File not found */
+ public static final String ERROR_NO_FILE = "File not found: ";
+
+ /** Cannot make URL */
+ public static final String ERROR_NO_URL_REPRESENTATION
+ = "Cannot make a URL of ";
+
+ /** No location provided */
+ public static final String ERROR_NO_LOCATION
+ = "No file or URL supplied for the schema ";
+
+ /** No arg constructor */
+ public SchemaLocation() {
+ }
+
+ /**
+ * Get the namespace.
+ * @return the namespace.
+ */
+ public String getNamespace() {
+ return namespace;
+ }
+
+ /**
+ * set the namespace of this schema. Any URI
+ * @param namespace the namespace to use.
+ */
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * Get the file.
+ * @return the file containing the schema.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * identify a file that contains this namespace's schema.
+ * The file must exist.
+ * @param file the file contains the schema.
+ */
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+ /**
+ * The URL containing the schema.
+ * @return the URL string.
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * identify a URL that hosts the schema.
+ * @param url the URL string.
+ */
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ /**
+ * get the URL of the schema
+ * @return a URL to the schema
+ * @throws BuildException if not
+ */
+ public String getSchemaLocationURL() {
+ boolean hasFile = file != null;
+ boolean hasURL = isSet(url);
+ //error if both are empty, or both are set
+ if (!hasFile && !hasURL) {
+ throw new BuildException(ERROR_NO_LOCATION + namespace);
+ }
+ if (hasFile && hasURL) {
+ throw new BuildException(ERROR_TWO_LOCATIONS + namespace);
+ }
+ String schema = url;
+ if (hasFile) {
+ if (!file.exists()) {
+ throw new BuildException(ERROR_NO_FILE + file);
+ }
+
+ try {
+ schema = FileUtils.getFileUtils().getFileURL(file).toString();
+ } catch (MalformedURLException e) {
+ //this is almost implausible, but required handling
+ throw new BuildException(ERROR_NO_URL_REPRESENTATION + file, e);
+ }
+ }
+ return schema;
+ }
+
+ /**
+ * validate the fields then create a "uri location" string
+ *
+ * @return string of uri and location
+ * @throws BuildException if there is an error.
+ */
+ public String getURIandLocation() throws BuildException {
+ validateNamespace();
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(namespace);
+ buffer.append(' ');
+ buffer.append(getSchemaLocationURL());
+ return new String(buffer);
+ }
+
+ /**
+ * assert that a namespace is valid
+ * @throws BuildException if not
+ */
+ public void validateNamespace() {
+ if (!isSet(getNamespace())) {
+ throw new BuildException(ERROR_NO_URI);
+ }
+ }
+
+ /**
+ * check that a property is set
+ * @param property string to check
+ * @return true if it is not null or empty
+ */
+ private boolean isSet(String property) {
+ return property != null && property.length() != 0;
+ }
+
+ /**
+ * equality test checks namespace, location and filename. All must match,
+ * @param o object to compare against
+ * @return true iff the objects are considered equal in value
+ */
+
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SchemaLocation)) {
+ return false;
+ }
+
+ final SchemaLocation schemaLocation = (SchemaLocation) o;
+
+ if (file != null ? !file.equals(schemaLocation.file) : schemaLocation.file != null) {
+ return false;
+ }
+ if (namespace != null ? !namespace.equals(schemaLocation.namespace)
+ : schemaLocation.namespace != null) {
+ return false;
+ }
+ if (url != null ? !url.equals(schemaLocation.url) : schemaLocation.url != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Generate a hashcode depending on the namespace, url and file name.
+ * @return the hashcode.
+ */
+ public int hashCode() {
+ int result;
+ // CheckStyle:MagicNumber OFF
+ result = (namespace != null ? namespace.hashCode() : 0);
+ result = 29 * result + (file != null ? file.hashCode() : 0);
+ result = 29 * result + (url != null ? url.hashCode() : 0);
+ // CheckStyle:MagicNumber OFF
+ return result;
+ }
+
+ /**
+ * Returns a string representation of the object for error messages
+ * and the like
+ * @return a string representation of the object.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(namespace != null ? namespace : "(anonymous)");
+ buffer.append(' ');
+ buffer.append(url != null ? (url + " ") : "");
+ buffer.append(file != null ? file.getAbsolutePath() : "");
+ return buffer.toString();
+ }
+ } //SchemaLocation
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Script.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Script.java
new file mode 100644
index 00000000..2b8d9f65
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Script.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+
+/**
+ * Executes a script.
+ *
+ * @ant.task name="script"
+ */
+public class Script extends Task {
+
+ private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+
+ /**
+ * Set the project.
+ * @param project the project that this task belongs to.
+ */
+ public void setProject(Project project) {
+ super.setProject(project);
+ helper.setProjectComponent(this);
+ }
+
+ /**
+ * Run the script using the helper object.
+ *
+ * @exception BuildException if something goes wrong with the build
+ */
+ public void execute() throws BuildException {
+ helper.getScriptRunner().executeScript("ANT");
+ }
+
+ /**
+ * Defines the manager.
+ *
+ * @param manager the scripting manager.
+ */
+ public void setManager(String manager) {
+ helper.setManager(manager);
+ }
+
+ /**
+ * Defines the language (required).
+ *
+ * @param language the scripting language name for the script.
+ */
+ public void setLanguage(String language) {
+ helper.setLanguage(language);
+ }
+
+ /**
+ * Load the script from an external file ; optional.
+ *
+ * @param fileName the name of the file containing the script source.
+ */
+ public void setSrc(String fileName) {
+ helper.setSrc(new File(fileName));
+ }
+
+ /**
+ * Set the script text.
+ *
+ * @param text a component of the script text to be added.
+ */
+ public void addText(String text) {
+ helper.addText(text);
+ }
+
+ /**
+ * Set the classpath to be used when searching for classes and resources.
+ *
+ * @param classpath an Ant Path object containing the search path.
+ */
+ public void setClasspath(Path classpath) {
+ helper.setClasspath(classpath);
+ }
+
+ /**
+ * Classpath to be used when searching for classes and resources.
+ *
+ * @return an empty Path instance to be configured by Ant.
+ */
+ public Path createClasspath() {
+ return helper.createClasspath();
+ }
+
+ /**
+ * Set the classpath by reference.
+ *
+ * @param r a Reference to a Path instance to be used as the classpath
+ * value.
+ */
+ public void setClasspathRef(Reference r) {
+ helper.setClasspathRef(r);
+ }
+
+ /**
+ * Set the setbeans attribute.
+ * If this is true, &lt;script&gt; will create variables in the
+ * script instance for all
+ * properties, targets and references of the current project.
+ * It this is false, only the project and self variables will
+ * be set.
+ * The default is true.
+ * @param setBeans the value to set.
+ */
+ public void setSetBeans(boolean setBeans) {
+ helper.setSetBeans(setBeans);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
new file mode 100644
index 00000000..8d9a44a6
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
@@ -0,0 +1,650 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.XSLTLiaison4;
+import org.apache.tools.ant.taskdefs.XSLTLogger;
+import org.apache.tools.ant.taskdefs.XSLTLoggerAware;
+import org.apache.tools.ant.taskdefs.XSLTProcess;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.URLProvider;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1)
+ *
+ * @since Ant 1.3
+ */
+public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware {
+
+ /**
+ * Helper for transforming filenames to URIs.
+ *
+ * @since Ant 1.7
+ */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * The current <code>Project</code>
+ */
+ private Project project;
+
+ /**
+ * the name of the factory implementation class to use
+ * or null for default JAXP lookup.
+ */
+ private String factoryName = null;
+
+ /** The trax TransformerFactory */
+ private TransformerFactory tfactory = null;
+
+ /** stylesheet to use for transformation */
+ private Resource stylesheet;
+
+ private XSLTLogger logger;
+
+ /** possible resolver for publicIds */
+ private EntityResolver entityResolver;
+
+ /** transformer to use for processing files */
+ private Transformer transformer;
+
+ /** The In memory version of the stylesheet */
+ private Templates templates;
+
+ /**
+ * The modification time of the stylesheet from which the templates
+ * are read
+ */
+ private long templatesModTime;
+
+ /** possible resolver for URIs */
+ private URIResolver uriResolver;
+
+ /** transformer output properties */
+ private final Vector outputProperties = new Vector();
+
+ /** stylesheet parameters */
+ private final Hashtable<String, Object> params = new Hashtable<String, Object>();
+
+ /** factory attributes */
+ private final Vector attributes = new Vector();
+
+ /** whether to suppress warnings */
+ private boolean suppressWarnings = false;
+
+ /** optional trace configuration. */
+ private XSLTProcess.TraceConfiguration traceConfiguration = null;
+
+ /**
+ * Constructor for TraXLiaison.
+ * @throws Exception never
+ */
+ public TraXLiaison() throws Exception {
+ }
+
+ /**
+ * Set the stylesheet file.
+ * @param stylesheet a <code>File</code> value
+ * @throws Exception on error
+ */
+ public void setStylesheet(final File stylesheet) throws Exception {
+ final FileResource fr = new FileResource();
+ fr.setProject(project);
+ fr.setFile(stylesheet);
+ setStylesheet(fr);
+ }
+
+ /**
+ * Set the stylesheet file.
+ * @param stylesheet a {@link org.apache.tools.ant.types.Resource} value
+ * @throws Exception on error
+ */
+ public void setStylesheet(final Resource stylesheet) throws Exception {
+ if (this.stylesheet != null) {
+ // resetting the stylesheet - reset transformer
+ transformer = null;
+
+ // do we need to reset templates as well
+ if (!this.stylesheet.equals(stylesheet)
+ || (stylesheet.getLastModified() != templatesModTime)) {
+ templates = null;
+ }
+ }
+ this.stylesheet = stylesheet;
+ }
+
+ /**
+ * Transform an input file.
+ * @param infile the file to transform
+ * @param outfile the result file
+ * @throws Exception on error
+ */
+ public void transform(final File infile, final File outfile) throws Exception {
+ if (transformer == null) {
+ createTransformer();
+ }
+
+ InputStream fis = null;
+ OutputStream fos = null;
+ try {
+ fis = new BufferedInputStream(new FileInputStream(infile));
+ fos = new BufferedOutputStream(new FileOutputStream(outfile));
+ final StreamResult res = new StreamResult(fos);
+ // not sure what could be the need of this...
+ res.setSystemId(JAXPUtils.getSystemId(outfile));
+ final Source src = getSource(fis, infile);
+
+ // set parameters on each transformation, maybe something has changed
+ //(e.g. value of file name parameter)
+ setTransformationParameters();
+
+ transformer.transform(src, res);
+ } finally {
+ // make sure to close all handles, otherwise the garbage
+ // collector will close them...whenever possible and
+ // Windows may complain about not being able to delete files.
+ FileUtils.close(fis);
+ FileUtils.close(fos);
+ }
+ }
+
+ /**
+ * Get the source instance from the stream and id of the file.
+ * @param is the stream containing the stylesheet data.
+ * @param infile the file that will be used for the systemid.
+ * @return the configured source instance matching the stylesheet.
+ * @throws ParserConfigurationException if a parser cannot be created which
+ * satisfies the requested configuration.
+ * @throws SAXException in case of problem detected by the SAX parser.
+ */
+ private Source getSource(final InputStream is, final File infile)
+ throws ParserConfigurationException, SAXException {
+ // todo: is this comment still relevant ??
+ // FIXME: need to use a SAXSource as the source for the transform
+ // so we can plug in our own entity resolver
+ Source src = null;
+ if (entityResolver != null) {
+ if (getFactory().getFeature(SAXSource.FEATURE)) {
+ final SAXParserFactory spFactory = SAXParserFactory.newInstance();
+ spFactory.setNamespaceAware(true);
+ final XMLReader reader = spFactory.newSAXParser().getXMLReader();
+ reader.setEntityResolver(entityResolver);
+ src = new SAXSource(reader, new InputSource(is));
+ } else {
+ throw new IllegalStateException("xcatalog specified, but "
+ + "parser doesn't support SAX");
+ }
+ } else {
+ // WARN: Don't use the StreamSource(File) ctor. It won't work with
+ // xalan prior to 2.2 because of systemid bugs.
+ src = new StreamSource(is);
+ }
+ src.setSystemId(JAXPUtils.getSystemId(infile));
+ return src;
+ }
+
+ private Source getSource(final InputStream is, final Resource resource)
+ throws ParserConfigurationException, SAXException {
+ // todo: is this comment still relevant ??
+ // FIXME: need to use a SAXSource as the source for the transform
+ // so we can plug in our own entity resolver
+ Source src = null;
+ if (entityResolver != null) {
+ if (getFactory().getFeature(SAXSource.FEATURE)) {
+ final SAXParserFactory spFactory = SAXParserFactory.newInstance();
+ spFactory.setNamespaceAware(true);
+ final XMLReader reader = spFactory.newSAXParser().getXMLReader();
+ reader.setEntityResolver(entityResolver);
+ src = new SAXSource(reader, new InputSource(is));
+ } else {
+ throw new IllegalStateException("xcatalog specified, but "
+ + "parser doesn't support SAX");
+ }
+ } else {
+ // WARN: Don't use the StreamSource(File) ctor. It won't work with
+ // xalan prior to 2.2 because of systemid bugs.
+ src = new StreamSource(is);
+ }
+ // The line below is a hack: the system id must an URI, but it is not
+ // cleat to get the URI of an resource, so just set the name of the
+ // resource as a system id
+ src.setSystemId(resourceToURI(resource));
+ return src;
+ }
+
+ private String resourceToURI(final Resource resource) {
+ final FileProvider fp = resource.as(FileProvider.class);
+ if (fp != null) {
+ return FILE_UTILS.toURI(fp.getFile().getAbsolutePath());
+ }
+ final URLProvider up = resource.as(URLProvider.class);
+ if (up != null) {
+ final URL u = up.getURL();
+ return String.valueOf(u);
+ } else {
+ return resource.getName();
+ }
+ }
+
+ /**
+ * Read in templates from the stylesheet
+ */
+ private void readTemplates()
+ throws IOException, TransformerConfigurationException,
+ ParserConfigurationException, SAXException {
+
+ // Use a stream so that you can close it yourself quickly
+ // and avoid keeping the handle until the object is garbaged.
+ // (always keep control), otherwise you won't be able to delete
+ // the file quickly on windows.
+ InputStream xslStream = null;
+ try {
+ xslStream
+ = new BufferedInputStream(stylesheet.getInputStream());
+ templatesModTime = stylesheet.getLastModified();
+ final Source src = getSource(xslStream, stylesheet);
+ templates = getFactory().newTemplates(src);
+ } finally {
+ if (xslStream != null) {
+ xslStream.close();
+ }
+ }
+ }
+
+ /**
+ * Create a new transformer based on the liaison settings
+ * @throws Exception thrown if there is an error during creation.
+ * @see #setStylesheet(java.io.File)
+ * @see #addParam(java.lang.String, java.lang.String)
+ * @see #setOutputProperty(java.lang.String, java.lang.String)
+ */
+ private void createTransformer() throws Exception {
+ if (templates == null) {
+ readTemplates();
+ }
+
+ transformer = templates.newTransformer();
+
+ // configure the transformer...
+ transformer.setErrorListener(this);
+ if (uriResolver != null) {
+ transformer.setURIResolver(uriResolver);
+ }
+ final int size = outputProperties.size();
+ for (int i = 0; i < size; i++) {
+ final String[] pair = (String[]) outputProperties.elementAt(i);
+ transformer.setOutputProperty(pair[0], pair[1]);
+ }
+
+ if (traceConfiguration != null) {
+ if ("org.apache.xalan.transformer.TransformerImpl"
+ .equals(transformer.getClass().getName())) {
+ try {
+ final Class traceSupport =
+ Class.forName("org.apache.tools.ant.taskdefs.optional."
+ + "Xalan2TraceSupport", true,
+ Thread.currentThread()
+ .getContextClassLoader());
+ final XSLTTraceSupport ts =
+ (XSLTTraceSupport) traceSupport.newInstance();
+ ts.configureTrace(transformer, traceConfiguration);
+ } catch (final Exception e) {
+ final String msg = "Failed to enable tracing because of " + e;
+ if (project != null) {
+ project.log(msg, Project.MSG_WARN);
+ } else {
+ System.err.println(msg);
+ }
+ }
+ } else {
+ final String msg = "Not enabling trace support for transformer"
+ + " implementation" + transformer.getClass().getName();
+ if (project != null) {
+ project.log(msg, Project.MSG_WARN);
+ } else {
+ System.err.println(msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the parameters for the transformer.
+ */
+ private void setTransformationParameters() {
+ for (final Enumeration enumeration = params.keys();
+ enumeration.hasMoreElements();) {
+ final String name = (String) enumeration.nextElement();
+ final Object value = params.get(name);
+ transformer.setParameter(name, value);
+ }
+ }
+
+ /**
+ * return the Transformer factory associated to this liaison.
+ * @return the Transformer factory associated to this liaison.
+ * @throws BuildException thrown if there is a problem creating
+ * the factory.
+ * @see #setFactory(String)
+ * @since Ant 1.5.2
+ */
+ private TransformerFactory getFactory() throws BuildException {
+ if (tfactory != null) {
+ return tfactory;
+ }
+ // not initialized yet, so create the factory
+ if (factoryName == null) {
+ tfactory = TransformerFactory.newInstance();
+ } else {
+ try {
+ Class clazz = null;
+ try {
+ clazz =
+ Class.forName(factoryName, true,
+ Thread.currentThread()
+ .getContextClassLoader());
+ } catch (final ClassNotFoundException cnfe) {
+ final String msg = "Failed to load " + factoryName
+ + " via the configured classpath, will try"
+ + " Ant's classpath instead.";
+ if (logger != null) {
+ logger.log(msg);
+ } else if (project != null) {
+ project.log(msg, Project.MSG_WARN);
+ } else {
+ System.err.println(msg);
+ }
+ }
+
+ if (clazz == null) {
+ clazz = Class.forName(factoryName);
+ }
+ tfactory = (TransformerFactory) clazz.newInstance();
+ } catch (final Exception e) {
+ throw new BuildException(e);
+ }
+ }
+
+ try { // #51668, #52382
+ final Field _isNotSecureProcessing = tfactory.getClass().getDeclaredField("_isNotSecureProcessing");
+ _isNotSecureProcessing.setAccessible(true);
+ _isNotSecureProcessing.set(tfactory, Boolean.TRUE);
+ } catch (final Exception x) {
+ if (project != null) {
+ project.log(x.toString(), Project.MSG_DEBUG);
+ }
+ }
+
+ tfactory.setErrorListener(this);
+
+ // specific attributes for the transformer
+ final int size = attributes.size();
+ for (int i = 0; i < size; i++) {
+ final Object[] pair = (Object[]) attributes.elementAt(i);
+ tfactory.setAttribute((String) pair[0], pair[1]);
+ }
+
+ if (uriResolver != null) {
+ tfactory.setURIResolver(uriResolver);
+ }
+ return tfactory;
+ }
+
+
+ /**
+ * Set the factory name to use instead of JAXP default lookup.
+ * @param name the fully qualified class name of the factory to use
+ * or null for the default JAXP look up mechanism.
+ * @since Ant 1.6
+ */
+ public void setFactory(final String name) {
+ factoryName = name;
+ }
+
+ /**
+ * Set a custom attribute for the JAXP factory implementation.
+ * @param name the attribute name.
+ * @param value the value of the attribute, usually a boolean
+ * string or object.
+ * @since Ant 1.6
+ */
+ public void setAttribute(final String name, final Object value) {
+ final Object[] pair = new Object[]{name, value};
+ attributes.addElement(pair);
+ }
+
+ /**
+ * Set the output property for the current transformer.
+ * Note that the stylesheet must be set prior to calling
+ * this method.
+ * @param name the output property name.
+ * @param value the output property value.
+ * @since Ant 1.5
+ * @since Ant 1.5
+ */
+ public void setOutputProperty(final String name, final String value) {
+ final String[] pair = new String[]{name, value};
+ outputProperties.addElement(pair);
+ }
+
+ /**
+ * Set the class to resolve entities during the transformation.
+ * @param aResolver the resolver class.
+ */
+ public void setEntityResolver(final EntityResolver aResolver) {
+ entityResolver = aResolver;
+ }
+
+ /**
+ * Set the class to resolve URIs during the transformation
+ * @param aResolver a <code>EntityResolver</code> value
+ */
+ public void setURIResolver(final URIResolver aResolver) {
+ uriResolver = aResolver;
+ }
+
+ /**
+ * Add a parameter.
+ * @param name the name of the parameter
+ * @param value the value of the parameter
+ */
+ public void addParam(final String name, final String value) {
+ params.put(name, value);
+ }
+
+ /**
+ * Add a parameter.
+ * @param name the name of the parameter
+ * @param value the value of the parameter
+ * @since Ant 1.9.3
+ */
+ public void addParam(final String name, final Object value) {
+ params.put(name, value);
+ }
+
+ /**
+ * Set a logger.
+ * @param l a logger.
+ */
+ public void setLogger(final XSLTLogger l) {
+ logger = l;
+ }
+
+ /**
+ * Log an error.
+ * @param e the exception to log.
+ */
+ public void error(final TransformerException e) {
+ logError(e, "Error");
+ }
+
+ /**
+ * Log a fatal error.
+ * @param e the exception to log.
+ */
+ public void fatalError(final TransformerException e) {
+ logError(e, "Fatal Error");
+ throw new BuildException("Fatal error during transformation using " + stylesheet + ": " + e.getMessageAndLocation(), e);
+ }
+
+ /**
+ * Log a warning.
+ * @param e the exception to log.
+ */
+ public void warning(final TransformerException e) {
+ if (!suppressWarnings) {
+ logError(e, "Warning");
+ }
+ }
+
+ private void logError(final TransformerException e, final String type) {
+ if (logger == null) {
+ return;
+ }
+
+ final StringBuffer msg = new StringBuffer();
+ final SourceLocator locator = e.getLocator();
+ if (locator != null) {
+ final String systemid = locator.getSystemId();
+ if (systemid != null) {
+ String url = systemid;
+ if (url.startsWith("file:")) {
+ url = FileUtils.getFileUtils().fromURI(url);
+ }
+ msg.append(url);
+ } else {
+ msg.append("Unknown file");
+ }
+ final int line = locator.getLineNumber();
+ if (line != -1) {
+ msg.append(":");
+ msg.append(line);
+ final int column = locator.getColumnNumber();
+ if (column != -1) {
+ msg.append(":");
+ msg.append(column);
+ }
+ }
+ }
+ msg.append(": ");
+ msg.append(type);
+ msg.append("! ");
+ msg.append(e.getMessage());
+ if (e.getCause() != null) {
+ msg.append(" Cause: ");
+ msg.append(e.getCause());
+ }
+
+ logger.log(msg.toString());
+ }
+
+ // kept for backwards compatibility
+ /**
+ * @param file the filename to use for the systemid
+ * @return the systemid
+ * @deprecated since 1.5.x.
+ * Use org.apache.tools.ant.util.JAXPUtils#getSystemId instead.
+ */
+ @Deprecated
+ protected String getSystemId(final File file) {
+ return JAXPUtils.getSystemId(file);
+ }
+
+
+ /**
+ * Specific configuration for the TRaX liaison.
+ * @param xsltTask the XSLTProcess task instance from which this liaison
+ * is to be configured.
+ */
+ public void configure(final XSLTProcess xsltTask) {
+ project = xsltTask.getProject();
+ final XSLTProcess.Factory factory = xsltTask.getFactory();
+ if (factory != null) {
+ setFactory(factory.getName());
+
+ // configure factory attributes
+ for (final Enumeration attrs = factory.getAttributes();
+ attrs.hasMoreElements();) {
+ final XSLTProcess.Factory.Attribute attr =
+ (XSLTProcess.Factory.Attribute) attrs.nextElement();
+ setAttribute(attr.getName(), attr.getValue());
+ }
+ }
+
+ final XMLCatalog xmlCatalog = xsltTask.getXMLCatalog();
+ // use XMLCatalog as the entity resolver and URI resolver
+ if (xmlCatalog != null) {
+ setEntityResolver(xmlCatalog);
+ setURIResolver(xmlCatalog);
+ }
+
+
+ // configure output properties
+ for (final Enumeration props = xsltTask.getOutputProperties();
+ props.hasMoreElements();) {
+ final XSLTProcess.OutputProperty prop
+ = (XSLTProcess.OutputProperty) props.nextElement();
+ setOutputProperty(prop.getName(), prop.getValue());
+ }
+
+ suppressWarnings = xsltTask.getSuppressWarnings();
+
+ traceConfiguration = xsltTask.getTraceConfiguration();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
new file mode 100644
index 00000000..05c043df
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
@@ -0,0 +1,764 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.DTDLocation;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.apache.tools.ant.util.XmlConstants;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.ParserAdapter;
+
+/**
+ * Checks XML files are valid (or only well formed). The
+ * task uses the SAX2 parser implementation provided by JAXP by default
+ * (probably the one that is used by Ant itself), but one can specify any
+ * SAX1/2 parser if needed.
+ *
+ */
+public class XMLValidateTask extends Task {
+
+ /**
+ * helper for path -> URI and URI -> path conversions.
+ */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ protected static final String INIT_FAILED_MSG =
+ "Could not start xml validation: ";
+
+ // ant task properties
+ // defaults
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected boolean failOnError = true;
+ protected boolean warn = true;
+ protected boolean lenient = false;
+ protected String readerClassName = null;
+
+ /** file to be validated */
+ protected File file = null;
+ /** sets of file to be validated */
+ protected Vector filesets = new Vector();
+ protected Path classpath;
+
+ /**
+ * the parser is viewed as a SAX2 XMLReader. If a SAX1 parser is specified,
+ * it's wrapped in an adapter that make it behave as a XMLReader.
+ * a more 'standard' way of doing this would be to use the JAXP1.1 SAXParser
+ * interface.
+ */
+ protected XMLReader xmlReader = null;
+ // XMLReader used to validation process
+ protected ValidatorErrorHandler errorHandler = new ValidatorErrorHandler();
+ // to report sax parsing errors
+ // CheckStyle:VisibilityModifier ON
+
+ /** The vector to store all attributes (features) to be set on the parser. **/
+ private Vector attributeList = new Vector();
+
+ /**
+ * List of properties.
+ */
+ private final Vector propertyList = new Vector();
+
+ private XMLCatalog xmlCatalog = new XMLCatalog();
+ /** Message for successful validation */
+ public static final String MESSAGE_FILES_VALIDATED
+ = " file(s) have been successfully validated.";
+
+ private AntClassLoader readerLoader = null;
+
+ /**
+ * Specify how parser error are to be handled.
+ * Optional, default is <code>true</code>.
+ * <p>
+ * If set to <code>true</code> (default), throw a buildException if the
+ * parser yields an error.
+ * @param fail if set to <code>false</code> do not fail on error
+ */
+ public void setFailOnError(boolean fail) {
+ failOnError = fail;
+ }
+
+ /**
+ * Specify how parser error are to be handled.
+ * <p>
+ * If set to <code>true</code> (default), log a warn message for each SAX warn event.
+ * @param bool if set to <code>false</code> do not send warnings
+ */
+ public void setWarn(boolean bool) {
+ warn = bool;
+ }
+
+ /**
+ * Specify whether the parser should be validating. Default
+ * is <code>true</code>.
+ * <p>
+ * If set to false, the validation will fail only if the parsed document
+ * is not well formed XML.
+ * <p>
+ * this option is ignored if the specified class
+ * with {@link #setClassName(String)} is not a SAX2 XMLReader.
+ * @param bool if set to <code>false</code> only fail on malformed XML
+ */
+ public void setLenient(boolean bool) {
+ lenient = bool;
+ }
+
+ /**
+ * Specify the class name of the SAX parser to be used. (optional)
+ * @param className should be an implementation of SAX2
+ * <code>org.xml.sax.XMLReader</code> or SAX2 <code>org.xml.sax.Parser</code>.
+ * <p> if className is an implementation of
+ * <code>org.xml.sax.Parser</code>, {@link #setLenient(boolean)},
+ * will be ignored.
+ * <p> if not set, the default will be used.
+ * @see org.xml.sax.XMLReader
+ * @see org.xml.sax.Parser
+ */
+ public void setClassName(String className) {
+ readerClassName = className;
+ }
+
+ /**
+ * Specify the classpath to be searched to load the parser (optional)
+ * @param classpath the classpath to load the parser
+ */
+ public void setClasspath(Path classpath) {
+ if (this.classpath == null) {
+ this.classpath = classpath;
+ } else {
+ this.classpath.append(classpath);
+ }
+ }
+
+ /**
+ * @see #setClasspath
+ * @return the classpath created
+ */
+ public Path createClasspath() {
+ if (this.classpath == null) {
+ this.classpath = new Path(getProject());
+ }
+ return this.classpath.createPath();
+ }
+
+ /**
+ * Where to find the parser class; optional.
+ * @see #setClasspath
+ * @param r reference to a classpath defined elsewhere
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * specify the file to be checked; optional.
+ * @param file the file to be checked
+ */
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+ /**
+ * add an XMLCatalog as a nested element; optional.
+ * @param catalog XMLCatalog to use
+ */
+ public void addConfiguredXMLCatalog(XMLCatalog catalog) {
+ xmlCatalog.addConfiguredXMLCatalog(catalog);
+ }
+
+ /**
+ * specify a set of file to be checked
+ * @param set the fileset to check
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ /**
+ * Add an attribute nested element. This is used for setting arbitrary
+ * features of the SAX parser.
+ * Valid attributes
+ * <a href=
+ * "http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"
+ * >include</a>
+ * @return attribute created
+ * @since ant1.6
+ */
+ public Attribute createAttribute() {
+ final Attribute feature = new Attribute();
+ attributeList.addElement(feature);
+ return feature;
+ }
+
+ /**
+ * Creates a property.
+ *
+ * @return a property.
+ * @since ant 1.6.2
+ */
+ public Property createProperty() {
+ final Property prop = new Property();
+ propertyList.addElement(prop);
+ return prop;
+ }
+
+ /**
+ * Called by the project to let the task initialize properly.
+ *
+ * @exception BuildException if something goes wrong with the build
+ */
+ public void init() throws BuildException {
+ super.init();
+ xmlCatalog.setProject(getProject());
+ }
+
+ /**
+ * Create a DTD location record; optional.
+ * This stores the location of a DTD. The DTD is identified
+ * by its public Id.
+ * @return created DTD location
+ */
+ public DTDLocation createDTD() {
+ DTDLocation dtdLocation = new DTDLocation();
+ xmlCatalog.addDTD(dtdLocation);
+ return dtdLocation;
+ }
+ /**
+ * accessor to the xmlCatalog used in the task
+ * @return xmlCatalog reference
+ */
+ protected EntityResolver getEntityResolver() {
+ return xmlCatalog;
+ }
+
+ /**
+ * get the XML reader. Non-null only after {@link #initValidator()}.
+ * If the reader is an instance of {@link ParserAdapter} then
+ * the parser is a SAX1 parser, and you cannot call
+ * {@link #setFeature(String, boolean)} or {@link #setProperty(String, String)}
+ * on it.
+ * @return the XML reader or null.
+ */
+ protected XMLReader getXmlReader() {
+ return xmlReader;
+ }
+
+ /**
+ * execute the task
+ * @throws BuildException if <code>failonerror</code> is true and an error happens
+ */
+ public void execute() throws BuildException {
+ try {
+ int fileProcessed = 0;
+ if (file == null && (filesets.size() == 0)) {
+ throw new BuildException(
+ "Specify at least one source - " + "a file or a fileset.");
+ }
+
+
+
+ if (file != null) {
+ if (file.exists() && file.canRead() && file.isFile()) {
+ doValidate(file);
+ fileProcessed++;
+ } else {
+ String errorMsg = "File " + file + " cannot be read";
+ if (failOnError) {
+ throw new BuildException(errorMsg);
+ } else {
+ log(errorMsg, Project.MSG_ERR);
+ }
+ }
+ }
+
+ final int size = filesets.size();
+ for (int i = 0; i < size; i++) {
+
+ FileSet fs = (FileSet) filesets.elementAt(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ String[] files = ds.getIncludedFiles();
+
+ for (int j = 0; j < files.length; j++) {
+ File srcFile = new File(fs.getDir(getProject()), files[j]);
+ doValidate(srcFile);
+ fileProcessed++;
+ }
+ }
+ onSuccessfulValidation(fileProcessed);
+ } finally {
+ cleanup();
+ }
+ }
+
+ /**
+ * handler called on successful file validation.
+ * @param fileProcessed number of files processed.
+ */
+ protected void onSuccessfulValidation(int fileProcessed) {
+ log(fileProcessed + MESSAGE_FILES_VALIDATED);
+ }
+
+ /**
+ * init the parser :
+ * load the parser class, and set features if necessary
+ * It is only after this that the reader is valid
+ * @throws BuildException if something went wrong
+ */
+ protected void initValidator() {
+
+ xmlReader = createXmlReader();
+
+ xmlReader.setEntityResolver(getEntityResolver());
+ xmlReader.setErrorHandler(errorHandler);
+
+ if (!isSax1Parser()) {
+ // turn validation on
+ if (!lenient) {
+ setFeature(XmlConstants.FEATURE_VALIDATION, true);
+ }
+ // set the feature from the attribute list
+ final int attSize = attributeList.size();
+ for (int i = 0; i < attSize; i++) {
+ Attribute feature = (Attribute) attributeList.elementAt(i);
+ setFeature(feature.getName(), feature.getValue());
+
+ }
+ // Sets properties
+ final int propSize = propertyList.size();
+ for (int i = 0; i < propSize; i++) {
+ final Property prop = (Property) propertyList.elementAt(i);
+ setProperty(prop.getName(), prop.getValue());
+ }
+ }
+ }
+
+ /**
+ * test that returns true if we are using a SAX1 parser.
+ * @return true when a SAX1 parser is in use
+ */
+ protected boolean isSax1Parser() {
+ return (xmlReader instanceof ParserAdapter);
+ }
+
+ /**
+ * create the XML reader.
+ * This is one by instantiating anything specified by {@link #readerClassName},
+ * falling back to a default reader if not.
+ * If the returned reader is an instance of {@link ParserAdapter} then
+ * we have created and wrapped a SAX1 parser.
+ * @return the new XMLReader.
+ */
+ protected XMLReader createXmlReader() {
+ Object reader = null;
+ if (readerClassName == null) {
+ reader = createDefaultReaderOrParser();
+ } else {
+
+ Class readerClass = null;
+ try {
+ // load the parser class
+ if (classpath != null) {
+ readerLoader = getProject().createClassLoader(classpath);
+ readerClass = Class.forName(readerClassName, true,
+ readerLoader);
+ } else {
+ readerClass = Class.forName(readerClassName);
+ }
+
+ reader = readerClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ throw new BuildException(INIT_FAILED_MSG + readerClassName, e);
+ } catch (InstantiationException e) {
+ throw new BuildException(INIT_FAILED_MSG + readerClassName, e);
+ } catch (IllegalAccessException e) {
+ throw new BuildException(INIT_FAILED_MSG + readerClassName, e);
+ }
+ }
+
+ // then check it implements XMLReader
+ XMLReader newReader;
+ if (reader instanceof XMLReader) {
+ newReader = (XMLReader) reader;
+ log(
+ "Using SAX2 reader " + reader.getClass().getName(),
+ Project.MSG_VERBOSE);
+ } else {
+
+ // see if it is a SAX1 Parser
+ if (reader instanceof Parser) {
+ newReader = new ParserAdapter((Parser) reader);
+ log(
+ "Using SAX1 parser " + reader.getClass().getName(),
+ Project.MSG_VERBOSE);
+ } else {
+ throw new BuildException(
+ INIT_FAILED_MSG
+ + reader.getClass().getName()
+ + " implements nor SAX1 Parser nor SAX2 XMLReader.");
+ }
+ }
+ return newReader;
+ }
+
+ /**
+ * Cleans up resources.
+ *
+ * @since Ant 1.8.0
+ */
+ protected void cleanup() {
+ if (readerLoader != null) {
+ readerLoader.cleanup();
+ readerLoader = null;
+ }
+ }
+
+ /**
+ * Returns a SAX-based XMLReader or a SAX-based Parser.
+ * @return reader or parser
+ */
+ private Object createDefaultReaderOrParser() {
+ Object reader;
+ try {
+ reader = createDefaultReader();
+ } catch (BuildException exc) {
+ reader = JAXPUtils.getParser();
+ }
+ return reader;
+ }
+
+ /**
+ * Create a reader if the use of the class did not specify another one.
+ * If a BuildException is thrown, the caller may revert to an alternate
+ * reader.
+ * @return a new reader.
+ * @throws BuildException if something went wrong
+ */
+ protected XMLReader createDefaultReader() {
+ return JAXPUtils.getXMLReader();
+ }
+
+ /**
+ * Set a feature on the parser.
+ * @param feature the name of the feature to set
+ * @param value the value of the feature
+ * @throws BuildException if the feature was not supported
+ */
+ protected void setFeature(String feature, boolean value)
+ throws BuildException {
+ log("Setting feature " + feature + "=" + value, Project.MSG_DEBUG);
+ try {
+ xmlReader.setFeature(feature, value);
+ } catch (SAXNotRecognizedException e) {
+ throw new BuildException(
+ "Parser "
+ + xmlReader.getClass().getName()
+ + " doesn't recognize feature "
+ + feature,
+ e,
+ getLocation());
+ } catch (SAXNotSupportedException e) {
+ throw new BuildException(
+ "Parser "
+ + xmlReader.getClass().getName()
+ + " doesn't support feature "
+ + feature,
+ e,
+ getLocation());
+ }
+ }
+
+ /**
+ * Sets a property.
+ *
+ * @param name a property name
+ * @param value a property value.
+ * @throws BuildException if an error occurs.
+ * @throws BuildException if the property was not supported
+ */
+ protected void setProperty(String name, String value) throws BuildException {
+ // Validates property
+ if (name == null || value == null) {
+ throw new BuildException("Property name and value must be specified.");
+ }
+
+ try {
+ xmlReader.setProperty(name, value);
+ } catch (SAXNotRecognizedException e) {
+ throw new BuildException(
+ "Parser "
+ + xmlReader.getClass().getName()
+ + " doesn't recognize property "
+ + name,
+ e,
+ getLocation());
+ } catch (SAXNotSupportedException e) {
+ throw new BuildException(
+ "Parser "
+ + xmlReader.getClass().getName()
+ + " doesn't support property "
+ + name,
+ e,
+ getLocation());
+ }
+ }
+
+ /**
+ * parse the file
+ * @param afile the file to validate.
+ * @return true if the file validates.
+ */
+ protected boolean doValidate(File afile) {
+ //for every file, we have a new instance of the validator
+ initValidator();
+ boolean result = true;
+ try {
+ log("Validating " + afile.getName() + "... ", Project.MSG_VERBOSE);
+ errorHandler.init(afile);
+ InputSource is = new InputSource(new FileInputStream(afile));
+ String uri = FILE_UTILS.toURI(afile.getAbsolutePath());
+ is.setSystemId(uri);
+ xmlReader.parse(is);
+ } catch (SAXException ex) {
+ log("Caught when validating: " + ex.toString(), Project.MSG_DEBUG);
+ if (failOnError) {
+ throw new BuildException(
+ "Could not validate document " + afile);
+ }
+ log("Could not validate document " + afile + ": " + ex.toString());
+ result = false;
+ } catch (IOException ex) {
+ throw new BuildException(
+ "Could not validate document " + afile,
+ ex);
+ }
+ if (errorHandler.getFailure()) {
+ if (failOnError) {
+ throw new BuildException(
+ afile + " is not a valid XML document.");
+ }
+ result = false;
+ log(afile + " is not a valid XML document", Project.MSG_ERR);
+ }
+ return result;
+ }
+
+ /**
+ * ValidatorErrorHandler role :
+ * <ul>
+ * <li> log SAX parse exceptions,
+ * <li> remember if an error occurred
+ * </ul>
+ */
+ protected class ValidatorErrorHandler implements ErrorHandler {
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected File currentFile = null;
+ protected String lastErrorMessage = null;
+ protected boolean failed = false;
+ // CheckStyle:VisibilityModifier ON
+ /**
+ * initialises the class
+ * @param file file used
+ */
+ public void init(File file) {
+ currentFile = file;
+ failed = false;
+ }
+ /**
+ * did an error happen during last parsing ?
+ * @return did an error happen during last parsing ?
+ */
+ public boolean getFailure() {
+ return failed;
+ }
+
+ /**
+ * record a fatal error
+ * @param exception the fatal error
+ */
+ public void fatalError(SAXParseException exception) {
+ failed = true;
+ doLog(exception, Project.MSG_ERR);
+ }
+ /**
+ * receive notification of a recoverable error
+ * @param exception the error
+ */
+ public void error(SAXParseException exception) {
+ failed = true;
+ doLog(exception, Project.MSG_ERR);
+ }
+ /**
+ * receive notification of a warning
+ * @param exception the warning
+ */
+ public void warning(SAXParseException exception) {
+ // depending on implementation, XMLReader can yield hips of warning,
+ // only output then if user explicitly asked for it
+ if (warn) {
+ doLog(exception, Project.MSG_WARN);
+ }
+ }
+
+ private void doLog(SAXParseException e, int logLevel) {
+
+ log(getMessage(e), logLevel);
+ }
+
+ private String getMessage(SAXParseException e) {
+ String sysID = e.getSystemId();
+ if (sysID != null) {
+ String name = sysID;
+ if (sysID.startsWith("file:")) {
+ try {
+ name = FILE_UTILS.fromURI(sysID);
+ } catch (Exception ex) {
+ // if this is not a valid file: just use the uri
+ }
+ }
+ int line = e.getLineNumber();
+ int col = e.getColumnNumber();
+ return name
+ + (line == -1
+ ? ""
+ : (":" + line + (col == -1 ? "" : (":" + col))))
+ + ": "
+ + e.getMessage();
+ }
+ return e.getMessage();
+ }
+ }
+
+ /**
+ * The class to create to set a feature of the parser.
+ * @since ant1.6
+ */
+ public static class Attribute {
+ /** The name of the attribute to set.
+ *
+ * Valid attributes <a href=
+ * "http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"
+ * >include.</a>
+ */
+ private String attributeName = null;
+
+ /**
+ * The value of the feature.
+ **/
+ private boolean attributeValue;
+
+ /**
+ * Set the feature name.
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ attributeName = name;
+ }
+ /**
+ * Set the feature value to true or false.
+ * @param value feature value
+ */
+ public void setValue(boolean value) {
+ attributeValue = value;
+ }
+
+ /**
+ * Gets the attribute name.
+ * @return the feature name
+ */
+ public String getName() {
+ return attributeName;
+ }
+
+ /**
+ * Gets the attribute value.
+ * @return the feature value
+ */
+ public boolean getValue() {
+ return attributeValue;
+ }
+ }
+
+ /**
+ * A Parser property.
+ * See <a href="http://xml.apache.org/xerces-j/properties.html">
+ * XML parser properties</a> for usable properties
+ * @since ant 1.6.2
+ */
+ public static final class Property {
+
+ private String name;
+ private String value;
+ /**
+ * accessor to the name of the property
+ * @return name of the property
+ */
+ public String getName() {
+ return name;
+ }
+ /**
+ * setter for the name of the property
+ * @param name name of the property
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * getter for the value of the property
+ * @return value of the property
+ */
+ public String getValue() {
+ return value;
+ }
+ /**
+ * sets the value of the property
+ * @param value value of the property
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ } // Property
+
+
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XSLTTraceSupport.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XSLTTraceSupport.java
new file mode 100644
index 00000000..8b684d83
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/XSLTTraceSupport.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import javax.xml.transform.Transformer;
+
+import org.apache.tools.ant.taskdefs.XSLTProcess;
+
+/**
+ * Sets up trace support for a given transformer.
+ *
+ * @since Ant 1.8.0
+ */
+public interface XSLTTraceSupport {
+ void configureTrace(Transformer t, XSLTProcess.TraceConfiguration conf);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Xalan2TraceSupport.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Xalan2TraceSupport.java
new file mode 100644
index 00000000..e5da0185
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/Xalan2TraceSupport.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.PrintWriter;
+import java.util.TooManyListenersException;
+
+import javax.xml.transform.Transformer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.XSLTProcess;
+import org.apache.xalan.trace.PrintTraceListener;
+import org.apache.xalan.transformer.TransformerImpl;
+
+/**
+ * Sets up trace support for a given transformer.
+ *
+ * @since Ant 1.8.0
+ */
+public class Xalan2TraceSupport implements XSLTTraceSupport {
+ public void configureTrace(final Transformer t,
+ final XSLTProcess.TraceConfiguration conf) {
+ if (t instanceof TransformerImpl && conf != null) {
+ final PrintWriter w = new PrintWriter(conf.getOutputStream(), false);
+ final PrintTraceListener tl = new PrintTraceListener(w);
+ tl.m_traceElements = conf.getElements();
+ tl.m_traceExtension = conf.getExtension();
+ tl.m_traceGeneration = conf.getGeneration();
+ tl.m_traceSelection = conf.getSelection();
+ tl.m_traceTemplates = conf.getTemplates();
+ try {
+ ((TransformerImpl) t).getTraceManager().addTraceListener(tl);
+ } catch (final TooManyListenersException tml) {
+ throw new BuildException(tml);
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java
new file mode 100644
index 00000000..f6a94b52
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+
+
+/**
+ * Class common to all check commands (checkout, checkin,checkin default task);
+ * @ant.task ignore="true"
+ */
+public class CCMCheck extends Continuus {
+
+ private File file = null;
+ private String comment = null;
+ private String task = null;
+
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ protected Vector filesets = new Vector();
+
+ // CheckStyle:VisibilityModifier ON
+
+ /** Constructor for CCMCheck. */
+ public CCMCheck() {
+ super();
+ }
+
+ /**
+ * Get the value of file.
+ * @return value of file.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Sets the path to the file that the command will operate on.
+ * @param v Value to assign to file.
+ */
+ public void setFile(File v) {
+ log("working file " + v, Project.MSG_VERBOSE);
+ this.file = v;
+ }
+
+ /**
+ * Get the value of comment.
+ * @return value of comment.
+ */
+ public String getComment() {
+ return comment;
+ }
+
+ /**
+ * Specifies a comment.
+ * @param v Value to assign to comment.
+ */
+ public void setComment(String v) {
+ this.comment = v;
+ }
+
+
+ /**
+ * Get the value of task.
+ * @return value of task.
+ */
+ public String getTask() {
+ return task;
+ }
+
+ /**
+ * Specifies the task number used to check
+ * in the file (may use 'default').
+ * @param v Value to assign to task.
+ */
+ public void setTask(String v) {
+ this.task = v;
+ }
+
+
+ /**
+ * Adds a set of files to copy.
+ * @param set the set of files
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute ccm and then calls Exec's run method
+ * to execute the command line.
+ * </p>
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+
+ if (file == null && filesets.size() == 0) {
+ throw new BuildException(
+ "Specify at least one source - a file or a fileset.");
+ }
+
+ if (file != null && file.exists() && file.isDirectory()) {
+ throw new BuildException("CCMCheck cannot be generated for directories");
+ }
+
+ if (file != null && filesets.size() > 0) {
+ throw new BuildException("Choose between file and fileset !");
+ }
+
+ if (getFile() != null) {
+ doit();
+ return;
+ }
+
+ int sizeofFileSet = filesets.size();
+ for (int i = 0; i < sizeofFileSet; i++) {
+ FileSet fs = (FileSet) filesets.elementAt(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ String[] srcFiles = ds.getIncludedFiles();
+ for (int j = 0; j < srcFiles.length; j++) {
+ File src = new File(fs.getDir(getProject()), srcFiles[j]);
+ setFile(src);
+ doit();
+ }
+ }
+ }
+
+ /**
+ * check the file given by getFile().
+ */
+ private void doit() {
+ Commandline commandLine = new Commandline();
+
+ // build the command line from what we got the format is
+ // ccm co /t .. files
+ // as specified in the CCM.EXE help
+
+ commandLine.setExecutable(getCcmCommand());
+ commandLine.createArgument().setValue(getCcmAction());
+
+ checkOptions(commandLine);
+
+ int result = run(commandLine);
+ if (Execute.isFailure(result)) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getComment() != null) {
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+
+ if (getTask() != null) {
+ cmd.createArgument().setValue(FLAG_TASK);
+ cmd.createArgument().setValue(getTask());
+ }
+
+ if (getFile() != null) {
+ cmd.createArgument().setValue(file.getAbsolutePath());
+ }
+ }
+
+ /**
+ * -comment flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "/comment";
+
+ /**
+ * -task flag -- associate checkout task with task
+ */
+ public static final String FLAG_TASK = "/task";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java
new file mode 100644
index 00000000..ff7472c9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+import java.util.Date;
+
+/**
+ * Performs Continuus checkin command.
+ *
+ */
+public class CCMCheckin extends CCMCheck {
+
+ /**
+ * Default constructor - setup checkin command
+ */
+ public CCMCheckin() {
+ super();
+ setCcmAction(COMMAND_CHECKIN);
+ setComment("Checkin " + new Date());
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java
new file mode 100644
index 00000000..2fe2a2a1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+/**
+ * Performs Continuus Checkin Default task command.
+ *
+ * @ant.task name="ccmcheckintask" category="scm"
+ */
+public class CCMCheckinDefault extends CCMCheck {
+
+ /** Constructor for CCMCheckinDefault. */
+ public CCMCheckinDefault() {
+ super();
+ setCcmAction(COMMAND_CHECKIN);
+ setTask(DEFAULT_TASK);
+ }
+
+ /** The default task */
+ public static final String DEFAULT_TASK = "default";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java
new file mode 100644
index 00000000..44bbc6bf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+/**
+ * Performs Continuus checkout command.
+ *
+ */
+public class CCMCheckout extends CCMCheck {
+
+ /**
+ * default constructor
+ */
+ public CCMCheckout() {
+ super();
+ setCcmAction(COMMAND_CHECKOUT);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java
new file mode 100644
index 00000000..cda13a5c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * Creates new Continuus ccm task and sets it as the default.
+ *
+ * @ant.task name="ccmcreatetask" category="scm"
+ */
+public class CCMCreateTask extends Continuus implements ExecuteStreamHandler {
+
+ private String comment = null;
+ private String platform = null;
+ private String resolver = null;
+ private String release = null;
+ private String subSystem = null;
+ private String task = null;
+
+ /**
+ * Constructor for CCMCreateTask.
+ */
+ public CCMCreateTask() {
+ super();
+ setCcmAction(COMMAND_CREATE_TASK);
+ }
+
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute ccm and then calls Exec's run method
+ * to execute the command line.
+ * </p>
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ int result = 0;
+
+ // build the command line from what we got the format
+ // as specified in the CCM.EXE help
+ commandLine.setExecutable(getCcmCommand());
+ commandLine.createArgument().setValue(getCcmAction());
+
+ checkOptions(commandLine);
+
+ result = run(commandLine, this);
+ if (Execute.isFailure(result)) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+
+ //create task ok, set this task as the default one
+ Commandline commandLine2 = new Commandline();
+ commandLine2.setExecutable(getCcmCommand());
+ commandLine2.createArgument().setValue(COMMAND_DEFAULT_TASK);
+ commandLine2.createArgument().setValue(getTask());
+
+ log(commandLine.describeCommand(), Project.MSG_DEBUG);
+
+ result = run(commandLine2);
+ if (result != 0) {
+ String msg = "Failed executing: " + commandLine2.toString();
+ throw new BuildException(msg, getLocation());
+ }
+
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getComment() != null) {
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue("\"" + getComment() + "\"");
+ }
+
+ if (getPlatform() != null) {
+ cmd.createArgument().setValue(FLAG_PLATFORM);
+ cmd.createArgument().setValue(getPlatform());
+ } // end of if ()
+
+ if (getResolver() != null) {
+ cmd.createArgument().setValue(FLAG_RESOLVER);
+ cmd.createArgument().setValue(getResolver());
+ } // end of if ()
+
+ if (getSubSystem() != null) {
+ cmd.createArgument().setValue(FLAG_SUBSYSTEM);
+ cmd.createArgument().setValue("\"" + getSubSystem() + "\"");
+ } // end of if ()
+
+ if (getRelease() != null) {
+ cmd.createArgument().setValue(FLAG_RELEASE);
+ cmd.createArgument().setValue(getRelease());
+ } // end of if ()
+ }
+
+
+ /**
+ * Get the value of comment.
+ * @return value of comment.
+ */
+ public String getComment() {
+ return comment;
+ }
+
+ /**
+ * Specifies a comment.
+ *
+ * @param v Value to assign to comment.
+ */
+ public void setComment(String v) {
+ this.comment = v;
+ }
+
+
+ /**
+ * Get the value of platform.
+ * @return value of platform.
+ */
+ public String getPlatform() {
+ return platform;
+ }
+
+ /**
+ * Specifies the target platform.
+ *
+ * @param v Value to assign to platform.
+ */
+ public void setPlatform(String v) {
+ this.platform = v;
+ }
+
+
+ /**
+ * Get the value of resolver.
+ * @return value of resolver.
+ */
+ public String getResolver() {
+ return resolver;
+ }
+
+ /**
+ * Specifies the resolver.
+ *
+ * @param v Value to assign to resolver.
+ */
+ public void setResolver(String v) {
+ this.resolver = v;
+ }
+
+
+ /**
+ * Get the value of release.
+ * @return value of release.
+ */
+ public String getRelease() {
+ return release;
+ }
+
+ /**
+ * Specify the CCM release.
+ *
+ * @param v Value to assign to release.
+ */
+ public void setRelease(String v) {
+ this.release = v;
+ }
+
+ /**
+ * Get the value of subSystem.
+ * @return value of subSystem.
+ */
+ public String getSubSystem() {
+ return subSystem;
+ }
+
+ /**
+ * Specifies the subsystem.
+ *
+ * @param v Value to assign to subSystem.
+ */
+ public void setSubSystem(String v) {
+ this.subSystem = v;
+ }
+
+
+ /**
+ * Get the value of task.
+ * @return value of task.
+ */
+ public String getTask() {
+ return task;
+ }
+
+ /**
+ * Specifies the task number used to checkin
+ * the file (may use 'default').
+ *
+ * @param v Value to assign to task.
+ */
+ public void setTask(String v) {
+ this.task = v;
+ }
+
+ /**
+ * /comment -- comments associated to the task
+ */
+ public static final String FLAG_COMMENT = "/synopsis";
+
+ /**
+ * /platform flag -- target platform
+ */
+ public static final String FLAG_PLATFORM = "/plat";
+
+ /**
+ * /resolver flag
+ */
+ public static final String FLAG_RESOLVER = "/resolver";
+
+ /**
+ * /release flag
+ */
+ public static final String FLAG_RELEASE = "/release";
+
+ /**
+ * /release flag
+ */
+ public static final String FLAG_SUBSYSTEM = "/subsystem";
+
+ /**
+ * -task flag -- associate checkout task with task
+ */
+ public static final String FLAG_TASK = "/task";
+
+
+ // implementation of org.apache.tools.ant.taskdefs.ExecuteStreamHandler interface
+
+ /**
+ *
+ * @throws IOException on error
+ */
+ public void start() throws IOException {
+ }
+
+ /**
+ *
+ */
+ public void stop() {
+ }
+
+ /**
+ *
+ * @param param1 the output stream
+ * @exception java.io.IOException on error
+ */
+ public void setProcessInputStream(OutputStream param1) throws IOException {
+ }
+
+ /**
+ *
+ * @param is the input stream
+ * @exception java.io.IOException on error
+ */
+ public void setProcessErrorStream(InputStream is) throws IOException {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String s = reader.readLine();
+ if (s != null) {
+ log("err " + s, Project.MSG_DEBUG);
+ } // end of if ()
+ }
+
+ /**
+ * read the output stream to retrieve the new task number.
+ * @param is InputStream
+ * @throws IOException on error
+ */
+ public void setProcessOutputStream(InputStream is) throws IOException {
+
+ String buffer = "";
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ buffer = reader.readLine();
+ if (buffer != null) {
+ log("buffer:" + buffer, Project.MSG_DEBUG);
+ String taskstring = buffer.substring(buffer.indexOf(' ')).trim();
+ taskstring = taskstring.substring(0, taskstring.lastIndexOf(' ')).trim();
+ setTask(taskstring);
+ log("task is " + getTask(), Project.MSG_DEBUG);
+ } // end of if ()
+ } catch (NullPointerException npe) {
+ log("error procession stream , null pointer exception", Project.MSG_ERR);
+ npe.printStackTrace();
+ throw new BuildException(npe.getClass().getName());
+ } catch (Exception e) {
+ log("error procession stream " + e.getMessage(), Project.MSG_ERR);
+ throw new BuildException(e.getMessage());
+ } // end of try-catch
+
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java
new file mode 100644
index 00000000..28f80645
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * Task allows to reconfigure a project, recursively or not
+ */
+public class CCMReconfigure extends Continuus {
+
+ private String ccmProject = null;
+ private boolean recurse = false;
+ private boolean verbose = false;
+
+ /** Constructor for CCMReconfigure. */
+ public CCMReconfigure() {
+ super();
+ setCcmAction(COMMAND_RECONFIGURE);
+ }
+
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute ccm and then calls Exec's run method
+ * to execute the command line.
+ * </p>
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ int result = 0;
+
+ // build the command line from what we got the format
+ // as specified in the CCM.EXE help
+ commandLine.setExecutable(getCcmCommand());
+ commandLine.createArgument().setValue(getCcmAction());
+
+ checkOptions(commandLine);
+
+ result = run(commandLine);
+ if (Execute.isFailure(result)) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+
+ if (isRecurse()) {
+ cmd.createArgument().setValue(FLAG_RECURSE);
+ } // end of if ()
+
+ if (isVerbose()) {
+ cmd.createArgument().setValue(FLAG_VERBOSE);
+ } // end of if ()
+
+ if (getCcmProject() != null) {
+ cmd.createArgument().setValue(FLAG_PROJECT);
+ cmd.createArgument().setValue(getCcmProject());
+ }
+
+ }
+
+ /**
+ * Get the value of project.
+ * @return value of project.
+ */
+ public String getCcmProject() {
+ return ccmProject;
+ }
+
+ /**
+ * Sets the ccm project on which the operation is applied.
+ * @param v Value to assign to project.
+ */
+ public void setCcmProject(String v) {
+ this.ccmProject = v;
+ }
+
+
+ /**
+ * Get the value of recurse.
+ * @return value of recurse.
+ */
+ public boolean isRecurse() {
+ return recurse;
+ }
+
+ /**
+ * If true, recurse on subproject (default false).
+ *
+ * @param v Value to assign to recurse.
+ */
+ public void setRecurse(boolean v) {
+ this.recurse = v;
+ }
+
+
+ /**
+ * Get the value of verbose.
+ * @return value of verbose.
+ */
+ public boolean isVerbose() {
+ return verbose;
+ }
+
+ /**
+ * If true, do a verbose reconfigure operation (default false).
+ * @param v Value to assign to verbose.
+ */
+ public void setVerbose(boolean v) {
+ this.verbose = v;
+ }
+
+
+ /**
+ * /recurse --
+ */
+ public static final String FLAG_RECURSE = "/recurse";
+
+ /**
+ * /recurse --
+ */
+ public static final String FLAG_VERBOSE = "/verbose";
+
+
+ /**
+ * /project flag -- target project
+ */
+ public static final String FLAG_PROJECT = "/project";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java
new file mode 100644
index 00000000..5618dd6a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ * A base class for creating tasks for executing commands on Continuus 5.1.
+ * <p>
+ * The class extends the task as it operates by executing the ccm.exe program
+ * supplied with Continuus/Synergy. By default the task expects the ccm executable to be
+ * in the path,
+ * you can override this be specifying the ccmdir attribute.
+ * </p>
+ *
+ */
+public abstract class Continuus extends Task {
+
+ private String ccmDir = "";
+ private String ccmAction = "";
+
+ /**
+ * Get the value of ccmAction.
+ * @return value of ccmAction.
+ */
+ public String getCcmAction() {
+ return ccmAction;
+ }
+
+ /**
+ * Set the value of ccmAction.
+ * @param v Value to assign to ccmAction.
+ * @ant.attribute ignore="true"
+ */
+ public void setCcmAction(String v) {
+ this.ccmAction = v;
+ }
+
+
+ /**
+ * Set the directory where the ccm executable is located.
+ *
+ * @param dir the directory containing the ccm executable
+ */
+ public final void setCcmDir(String dir) {
+ ccmDir = FileUtils.translatePath(dir);
+ }
+
+ /**
+ * Builds and returns the command string to execute ccm
+ * @return String containing path to the executable
+ */
+ protected final String getCcmCommand() {
+ String toReturn = ccmDir;
+ if (!toReturn.equals("") && !toReturn.endsWith("/")) {
+ toReturn += "/";
+ }
+
+ toReturn += CCM_EXE;
+
+ return toReturn;
+ }
+
+
+ /**
+ * Run the command.
+ * @param cmd the command line
+ * @param handler an execute stream handler
+ * @return the exit status of the command
+ */
+ protected int run(Commandline cmd, ExecuteStreamHandler handler) {
+ try {
+ Execute exe = new Execute(handler);
+ exe.setAntRun(getProject());
+ exe.setWorkingDirectory(getProject().getBaseDir());
+ exe.setCommandline(cmd.getCommandline());
+ return exe.execute();
+ } catch (java.io.IOException e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ /**
+ * Run the command.
+ * @param cmd the command line
+ * @return the exit status of the command
+ */
+ protected int run(Commandline cmd) {
+ return run(cmd, new LogStreamHandler(this, Project.MSG_VERBOSE, Project.MSG_WARN));
+ }
+
+ /**
+ * Constant for the thing to execute
+ */
+ private static final String CCM_EXE = "ccm";
+
+ /**
+ * The 'CreateTask' command
+ */
+ public static final String COMMAND_CREATE_TASK = "create_task";
+ /**
+ * The 'Checkout' command
+ */
+ public static final String COMMAND_CHECKOUT = "co";
+ /**
+ * The 'Checkin' command
+ */
+ public static final String COMMAND_CHECKIN = "ci";
+ /**
+ * The 'Reconfigure' command
+ */
+ public static final String COMMAND_RECONFIGURE = "reconfigure";
+
+ /**
+ * The 'Reconfigure' command
+ */
+ public static final String COMMAND_DEFAULT_TASK = "default_task";
+
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java
new file mode 100644
index 00000000..371d418b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java
@@ -0,0 +1,343 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase checkin.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>nowarn</td>
+ * <td>Suppress warning messages</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>preservetime</td>
+ * <td>Preserve the modification time</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>keepcopy</td>
+ * <td>Keeps a copy of the file with a .keep extension</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>identical</td>
+ * <td>Allows the file to be checked in even if it is identical to the original</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * </tr>
+ * </table>
+ *
+ */
+public class CCCheckin extends ClearCase {
+ private String mComment = null;
+ private String mCfile = null;
+ private boolean mNwarn = false;
+ private boolean mPtime = false;
+ private boolean mKeep = false;
+ private boolean mIdentical = true;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool checkin [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_CHECKIN);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ if (getNoWarn()) {
+ // -nwarn
+ cmd.createArgument().setValue(FLAG_NOWARN);
+ }
+
+ if (getPreserveTime()) {
+ // -ptime
+ cmd.createArgument().setValue(FLAG_PRESERVETIME);
+ }
+
+ if (getKeepCopy()) {
+ // -keep
+ cmd.createArgument().setValue(FLAG_KEEPCOPY);
+ }
+
+ if (getIdentical()) {
+ // -identical
+ cmd.createArgument().setValue(FLAG_IDENTICAL);
+ }
+
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+
+ /**
+ * Sets the comment string.
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Specifies a file containing a comment.
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * If true, suppress warning messages.
+ *
+ * @param nwarn the status to set the flag to
+ */
+ public void setNoWarn(boolean nwarn) {
+ mNwarn = nwarn;
+ }
+
+ /**
+ * Get nowarn flag status
+ *
+ * @return boolean containing status of nwarn flag
+ */
+ public boolean getNoWarn() {
+ return mNwarn;
+ }
+
+ /**
+ * If true, preserve the modification time.
+ *
+ * @param ptime the status to set the flag to
+ */
+ public void setPreserveTime(boolean ptime) {
+ mPtime = ptime;
+ }
+
+ /**
+ * Get preservetime flag status
+ *
+ * @return boolean containing status of preservetime flag
+ */
+ public boolean getPreserveTime() {
+ return mPtime;
+ }
+
+ /**
+ * If true, keeps a copy of the file with a .keep extension.
+ *
+ * @param keep the status to set the flag to
+ */
+ public void setKeepCopy(boolean keep) {
+ mKeep = keep;
+ }
+
+ /**
+ * Get keepcopy flag status
+ *
+ * @return boolean containing status of keepcopy flag
+ */
+ public boolean getKeepCopy() {
+ return mKeep;
+ }
+
+ /**
+ * If true, allows the file to be checked in even
+ * if it is identical to the original.
+ *
+ * @param identical the status to set the flag to
+ */
+ public void setIdentical(boolean identical) {
+ mIdentical = identical;
+ }
+
+ /**
+ * Get identical flag status
+ *
+ * @return boolean containing status of identical flag
+ */
+ public boolean getIdentical() {
+ return mIdentical;
+ }
+
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+ /**
+ * -nwarn flag -- suppresses warning messages
+ */
+ public static final String FLAG_NOWARN = "-nwarn";
+ /**
+ * -ptime flag -- preserves the modification time
+ */
+ public static final String FLAG_PRESERVETIME = "-ptime";
+ /**
+ * -keep flag -- keeps a copy of the file with a .keep extension
+ */
+ public static final String FLAG_KEEPCOPY = "-keep";
+ /**
+ * -identical flag -- allows the file to be checked in even if it is identical to the original
+ */
+ public static final String FLAG_IDENTICAL = "-identical";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java
new file mode 100644
index 00000000..0eaf09ac
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java
@@ -0,0 +1,516 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * Performs ClearCase checkout.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>reserved</td>
+ * <td>Specifies whether to check out the file as reserved or not</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>out</td>
+ * <td>Creates a writable file under a different filename</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>nodata</td>
+ * <td>Checks out the file but does not create an editable file containing its data</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>branch</td>
+ * <td>Specify a branch to check out the file to</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>version</td>
+ * <td>Allows checkout of a version other than main latest</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>nowarn</td>
+ * <td>Suppress warning messages</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>notco</td>
+ * <td>Fail if it's already checked out to the current view. Set to false to ignore it.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCCheckout extends ClearCase {
+ private boolean mReserved = true;
+ private String mOut = null;
+ private boolean mNdata = false;
+ private String mBranch = null;
+ private boolean mVersion = false;
+ private boolean mNwarn = false;
+ private String mComment = null;
+ private String mCfile = null;
+ private boolean mNotco = true;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got the format is
+ // cleartool checkout [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_CHECKOUT);
+
+ checkOptions(commandLine);
+ /*
+ * If configured to not care about whether the element is
+ * already checked out to the current view.
+ * Then check to see if it is checked out.
+ */
+ if (!getNotco() && lsCheckout()) {
+ getProject().log("Already checked out in this view: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ return;
+ }
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Check to see if the element is checked out in the current view.
+ */
+ private boolean lsCheckout() {
+ Commandline cmdl = new Commandline();
+ String result;
+
+ // build the command line from what we got the format is
+ // cleartool lsco [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ cmdl.setExecutable(getClearToolCommand());
+ cmdl.createArgument().setValue(COMMAND_LSCO);
+ cmdl.createArgument().setValue("-cview");
+ cmdl.createArgument().setValue("-short");
+ cmdl.createArgument().setValue("-d");
+ // viewpath
+ cmdl.createArgument().setValue(getViewPath());
+
+ result = runS(cmdl);
+
+ // System.out.println( "lsCheckout: " + result );
+
+ return (result != null && result.length() > 0) ? true : false;
+ }
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ // ClearCase items
+ if (getReserved()) {
+ // -reserved
+ cmd.createArgument().setValue(FLAG_RESERVED);
+ } else {
+ // -unreserved
+ cmd.createArgument().setValue(FLAG_UNRESERVED);
+ }
+
+ if (getOut() != null) {
+ // -out
+ getOutCommand(cmd);
+ } else {
+ if (getNoData()) {
+ // -ndata
+ cmd.createArgument().setValue(FLAG_NODATA);
+ }
+
+ }
+
+ if (getBranch() != null) {
+ // -branch
+ getBranchCommand(cmd);
+ } else {
+ if (getVersion()) {
+ // -version
+ cmd.createArgument().setValue(FLAG_VERSION);
+ }
+
+ }
+
+ if (getNoWarn()) {
+ // -nwarn
+ cmd.createArgument().setValue(FLAG_NOWARN);
+ }
+
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+
+ // Print out info about the notco option
+ // System.out.println( "Notco: " + (getNotco() ? "yes" : "no") );
+ }
+
+ /**
+ * If true, checks out the file as reserved.
+ *
+ * @param reserved the status to set the flag to
+ */
+ public void setReserved(boolean reserved) {
+ mReserved = reserved;
+ }
+
+ /**
+ * Get reserved flag status
+ *
+ * @return boolean containing status of reserved flag
+ */
+ public boolean getReserved() {
+ return mReserved;
+ }
+
+ /**
+ * If true, checkout fails if the element is already checked out to the current view.
+ *
+ * @param notco the status to set the flag to
+ * @since ant 1.6.1
+ */
+ public void setNotco(boolean notco) {
+ mNotco = notco;
+ }
+
+ /**
+ * Get notco flag status
+ *
+ * @return boolean containing status of notco flag
+ * @since ant 1.6.1
+ */
+ public boolean getNotco() {
+ return mNotco;
+ }
+
+
+ /**
+ * Creates a writable file under a different filename.
+ *
+ * @param outf the path to the out file
+ */
+ public void setOut(String outf) {
+ mOut = outf;
+ }
+
+ /**
+ * Get out file
+ *
+ * @return String containing the path to the out file
+ */
+ public String getOut() {
+ return mOut;
+ }
+
+ /**
+ * If true, checks out the file but does not create an
+ * editable file containing its data.
+ *
+ * @param ndata the status to set the flag to
+ */
+ public void setNoData(boolean ndata) {
+ mNdata = ndata;
+ }
+
+ /**
+ * Get nodata flag status
+ *
+ * @return boolean containing status of ndata flag
+ */
+ public boolean getNoData() {
+ return mNdata;
+ }
+
+ /**
+ * Specify a branch to check out the file to.
+ *
+ * @param branch the name of the branch
+ */
+ public void setBranch(String branch) {
+ mBranch = branch;
+ }
+
+ /**
+ * Get branch name
+ *
+ * @return String containing the name of the branch
+ */
+ public String getBranch() {
+ return mBranch;
+ }
+
+ /**
+ * If true, allows checkout of a version other than main latest.
+ *
+ * @param version the status to set the flag to
+ */
+ public void setVersion(boolean version) {
+ mVersion = version;
+ }
+
+ /**
+ * Get version flag status
+ *
+ * @return boolean containing status of version flag
+ */
+ public boolean getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * If true, warning messages are suppressed.
+ *
+ * @param nwarn the status to set the flag to
+ */
+ public void setNoWarn(boolean nwarn) {
+ mNwarn = nwarn;
+ }
+
+ /**
+ * Get nowarn flag status
+ *
+ * @return boolean containing status of nwarn flag
+ */
+ public boolean getNoWarn() {
+ return mNwarn;
+ }
+
+ /**
+ * Sets the comment string.
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Specifies a file containing a comment.
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * Get the 'out' command
+ *
+ * @param cmd containing the command line string with or
+ * without the out flag and path appended
+ */
+ private void getOutCommand(Commandline cmd) {
+ if (getOut() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_OUT);
+ cmd.createArgument().setValue(getOut());
+ }
+ }
+
+ /**
+ * Get the 'branch' command
+ *
+ * @param cmd containing the command line string with or
+ without the branch flag and name appended
+ */
+ private void getBranchCommand(Commandline cmd) {
+ if (getBranch() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_BRANCH);
+ cmd.createArgument().setValue(getBranch());
+ }
+ }
+
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'cfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the cfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+ /**
+ * -reserved flag -- check out the file as reserved
+ */
+ public static final String FLAG_RESERVED = "-reserved";
+ /**
+ * -reserved flag -- check out the file as unreserved
+ */
+ public static final String FLAG_UNRESERVED = "-unreserved";
+ /**
+ * -out flag -- create a writable file under a different filename
+ */
+ public static final String FLAG_OUT = "-out";
+ /**
+ * -ndata flag -- checks out the file but does not create an editable file containing its data
+ */
+ public static final String FLAG_NODATA = "-ndata";
+ /**
+ * -branch flag -- checks out the file on a specified branch
+ */
+ public static final String FLAG_BRANCH = "-branch";
+ /**
+ * -version flag -- allows checkout of a version that is not main latest
+ */
+ public static final String FLAG_VERSION = "-version";
+ /**
+ * -nwarn flag -- suppresses warning messages
+ */
+ public static final String FLAG_NOWARN = "-nwarn";
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java
new file mode 100644
index 00000000..c273554e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * TODO:
+ * comment field doesn't include all options yet
+ */
+
+
+
+/**
+ * Performs a ClearCase Lock command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>replace</td>
+ * <td>Specifies replacing an existing lock</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>nusers</td>
+ * <td>Specifies user(s) who can still modify the object/pname</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>obsolete</td>
+ * <td>Specifies that the object/pname should be marked obsolete</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specifies how to populate comments fields</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>pname</td>
+ * <td>Specifies the pathname to be locked.</td>
+ * <td>No</td>
+ * <tr>
+ * <td>objselect</td>
+ * <td>This variable is obsolete. Should use <i>objsel</i> instead.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>objsel</td>
+ * <td>Specifies the object(s) to be unlocked.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCLock extends ClearCase {
+ private boolean mReplace = false;
+ private boolean mObsolete = false;
+ private String mComment = null;
+ private String mNusers = null;
+ private String mPname = null;
+ private String mObjselect = null;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got the format is
+ // cleartool lock [options...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_LOCK);
+
+ // Check the command line options
+ checkOptions(commandLine);
+
+ // For debugging
+ // System.out.println(commandLine.toString());
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getOpType(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Check the command line options.
+ */
+private void checkOptions(Commandline cmd) {
+ // ClearCase items
+ if (getReplace()) {
+ // -replace
+ cmd.createArgument().setValue(FLAG_REPLACE);
+ }
+ if (getObsolete()) {
+ // -obsolete
+ cmd.createArgument().setValue(FLAG_OBSOLETE);
+ } else {
+ getNusersCommand(cmd);
+ }
+ getCommentCommand(cmd);
+
+ if (getObjselect() == null && getPname() == null) {
+ throw new BuildException("Should select either an element "
+ + "(pname) or an object (objselect)");
+ }
+ getPnameCommand(cmd);
+ // object selector
+ if (getObjselect() != null) {
+ cmd.createArgument().setValue(getObjselect());
+ }
+}
+
+ /**
+ * If true, replace an existing lock.
+ *
+ * @param replace the status to set the flag to
+ */
+ public void setReplace(boolean replace) {
+ mReplace = replace;
+ }
+
+ /**
+ * Get replace flag status
+ *
+ * @return boolean containing status of replace flag
+ */
+ public boolean getReplace() {
+ return mReplace;
+ }
+
+ /**
+ * If true, mark object as obsolete.
+ *
+ * @param obsolete the status to set the flag to
+ */
+ public void setObsolete(boolean obsolete) {
+ mObsolete = obsolete;
+ }
+
+ /**
+ * Get obsolete flag status
+ *
+ * @return boolean containing status of obsolete flag
+ */
+ public boolean getObsolete() {
+ return mObsolete;
+ }
+
+ /**
+ * Sets the users who may continue to
+ * edit the object while it is locked.
+ *
+ * @param nusers users excluded from lock
+ */
+ public void setNusers(String nusers) {
+ mNusers = nusers;
+ }
+
+ /**
+ * Get nusers list
+ *
+ * @return String containing the list of users excluded from lock
+ */
+ public String getNusers() {
+ return mNusers;
+ }
+
+ /**
+ * Sets how comments should be written
+ * for the event record(s)
+ *
+ * @param comment comment method to use
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment method
+ *
+ * @return String containing the desired comment method
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Sets the pathname to be locked
+ *
+ * @param pname pathname to be locked
+ */
+ public void setPname(String pname) {
+ mPname = pname;
+ }
+
+ /**
+ * Get the pathname to be locked
+ *
+ * @return String containing the pathname to be locked
+ */
+ public String getPname() {
+ return mPname;
+ }
+
+ /**
+ * Sets the object(s) to be locked
+ *
+ * @param objsel objects to be locked
+ * @since ant 1.6.1
+ */
+ public void setObjSel(String objsel) {
+ mObjselect = objsel;
+ }
+
+ /**
+ * Sets the object(s) to be locked
+ *
+ * @param objselect objects to be locked
+ */
+ public void setObjselect(String objselect) {
+ mObjselect = objselect;
+ }
+
+ /**
+ * Get list of objects to be locked
+ *
+ * @return String containing the objects to be locked
+ */
+ public String getObjselect() {
+ return mObjselect;
+ }
+
+ /**
+ * Get the 'nusers' command
+ *
+ * @param cmd containing the command line string with or
+ * without the nusers flag and value appended
+ */
+ private void getNusersCommand(Commandline cmd) {
+ if (getNusers() == null) {
+ return;
+ } else {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_NUSERS);
+ cmd.createArgument().setValue(getNusers());
+ }
+ }
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or without the
+ * comment flag and value appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() == null) {
+ return;
+ } else {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'pname' command
+ *
+ * @param cmd containing the command line string with or
+ * without the pname flag and value appended
+ */
+ private void getPnameCommand(Commandline cmd) {
+ if (getPname() == null) {
+ return;
+ } else {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_PNAME);
+ cmd.createArgument().setValue(getPname());
+ }
+ }
+
+ /**
+ * Return which object/pname is being operated on
+ *
+ * @return String containing the object/pname being worked on
+ */
+ private String getOpType() {
+
+ if (getPname() != null) {
+ return getPname();
+ } else {
+ return getObjselect();
+ }
+ }
+
+ /**
+ * -replace flag -- replace existing lock on object(s)
+ */
+ public static final String FLAG_REPLACE = "-replace";
+ /**
+ * -nusers flag -- list of users to exclude from lock
+ */
+ public static final String FLAG_NUSERS = "-nusers";
+ /**
+ * -obsolete flag -- mark locked object as obsolete
+ */
+ public static final String FLAG_OBSOLETE = "-obsolete";
+ /**
+ * -comment flag -- method to use for commenting events
+ */
+ public static final String FLAG_COMMENT = "-comment";
+ /**
+ * -pname flag -- pathname to lock
+ */
+ public static final String FLAG_PNAME = "-pname";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java
new file mode 100644
index 00000000..128ea16b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java
@@ -0,0 +1,425 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform mkattr command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>replace</td>
+ * <td>Replace the value of the attribute if it already exists</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>recurse</td>
+ * <td>Process each subdirectory under viewpath</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>version</td>
+ * <td>Identify a specific version to attach the attribute to</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>typename</td>
+ * <td>Name of the attribute type</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>typevalue</td>
+ * <td>Value to attach to the attribute type</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCMkattr extends ClearCase {
+ private boolean mReplace = false;
+ private boolean mRecurse = false;
+ private String mVersion = null;
+ private String mTypeName = null;
+ private String mTypeValue = null;
+ private String mComment = null;
+ private String mCfile = null;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Check for required attributes
+ if (getTypeName() == null) {
+ throw new BuildException("Required attribute TypeName not specified");
+ }
+ if (getTypeValue() == null) {
+ throw new BuildException("Required attribute TypeValue not specified");
+ }
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool mkattr [options...] [viewpath ...]
+ // as specified in the CLEARTOOL help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_MKATTR);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+
+ // For debugging
+ // System.out.println(commandLine.toString());
+
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getReplace()) {
+ // -replace
+ cmd.createArgument().setValue(FLAG_REPLACE);
+ }
+
+ if (getRecurse()) {
+ // -recurse
+ cmd.createArgument().setValue(FLAG_RECURSE);
+ }
+
+ if (getVersion() != null) {
+ // -version
+ getVersionCommand(cmd);
+ }
+
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ if (getTypeName() != null) {
+ // type
+ getTypeCommand(cmd);
+ }
+ if (getTypeValue() != null) {
+ // type value
+ getTypeValueCommand(cmd);
+ }
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+
+ /**
+ * Set the replace flag
+ *
+ * @param replace the status to set the flag to
+ */
+ public void setReplace(boolean replace) {
+ mReplace = replace;
+ }
+
+ /**
+ * Get replace flag status
+ *
+ * @return boolean containing status of replace flag
+ */
+ public boolean getReplace() {
+ return mReplace;
+ }
+
+ /**
+ * Set recurse flag
+ *
+ * @param recurse the status to set the flag to
+ */
+ public void setRecurse(boolean recurse) {
+ mRecurse = recurse;
+ }
+
+ /**
+ * Get recurse flag status
+ *
+ * @return boolean containing status of recurse flag
+ */
+ public boolean getRecurse() {
+ return mRecurse;
+ }
+
+ /**
+ * Set the version flag
+ *
+ * @param version the status to set the flag to
+ */
+ public void setVersion(String version) {
+ mVersion = version;
+ }
+
+ /**
+ * Get version flag status
+ *
+ * @return boolean containing status of version flag
+ */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Set comment string
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set comment file
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * Set the attribute type-name
+ *
+ * @param tn the type name
+ */
+ public void setTypeName(String tn) {
+ mTypeName = tn;
+ }
+
+ /**
+ * Get attribute type-name
+ *
+ * @return String containing type name
+ */
+ public String getTypeName() {
+ return mTypeName;
+ }
+
+ /**
+ * Set the attribute type-value
+ *
+ * @param tv the type value
+ */
+ public void setTypeValue(String tv) {
+ mTypeValue = tv;
+ }
+
+ /**
+ * Get the attribute type-value
+ *
+ * @return String containing type value
+ */
+ public String getTypeValue() {
+ return mTypeValue;
+ }
+
+
+ /**
+ * Get the 'version' command
+ *
+ * @param cmd CommandLine containing the command line string with or
+ * without the version flag and string appended
+ */
+ private void getVersionCommand(Commandline cmd) {
+ if (getVersion() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_VERSION);
+ cmd.createArgument().setValue(getVersion());
+ }
+ }
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+ /**
+ * Get the attribute type-name
+ *
+ * @param cmd containing the command line string with or
+ * without the type-name
+ */
+ private void getTypeCommand(Commandline cmd) {
+ String typenm = getTypeName();
+
+ if (typenm != null) {
+ cmd.createArgument().setValue(typenm);
+ }
+ }
+
+ /**
+ * Get the attribute type-value
+ *
+ * @param cmd containing the command line string with or
+ * without the type-value
+ */
+ private void getTypeValueCommand(Commandline cmd) {
+ String typevl = getTypeValue();
+
+ if (typevl != null) {
+ if (Os.isFamily("windows")) {
+ typevl = "\\\"" + typevl + "\\\""; // Windows quoting of the value
+ } else {
+ typevl = "\"" + typevl + "\"";
+ }
+ cmd.createArgument().setValue(typevl);
+ }
+ }
+
+ /**
+ * -replace flag -- replace the existing value of the attribute
+ */
+ public static final String FLAG_REPLACE = "-replace";
+ /**
+ * -recurse flag -- process all subdirectories
+ */
+ public static final String FLAG_RECURSE = "-recurse";
+ /**
+ * -version flag -- attach attribute to specified version
+ */
+ public static final String FLAG_VERSION = "-version";
+ /**
+ * -c flag -- comment to attach to the element
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java
new file mode 100644
index 00000000..82c96005
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to CreateBaseline command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be
+used.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or
+cfile may be used.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>baselinerootname</td>
+ * <td>Specify the name to be associated with the baseline.</td>
+ * <td>Yes</td>
+ * </tr>
+ * <tr>
+ * <td>nowarn</td>
+ * <td>Suppress warning messages</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>identical</td>
+ * <td>Allows the baseline to be created even if it is identical to the
+previous baseline.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>full</td>
+ * <td>Creates a full baseline.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>nlabel</td>
+ * <td>Allows the baseline to be created without a label.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCMkbl extends ClearCase {
+ private String mComment = null;
+ private String mCfile = null;
+ private String mBaselineRootName = null;
+ private boolean mNwarn = false;
+ private boolean mIdentical = true;
+ private boolean mFull = false;
+ private boolean mNlabel = false;
+
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool checkin [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_MKBL);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getBaselineRootName(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ if (getIdentical()) {
+ // -identical
+ cmd.createArgument().setValue(FLAG_IDENTICAL);
+ }
+
+ if (getFull()) {
+ // -full
+ cmd.createArgument().setValue(FLAG_FULL);
+ } else {
+ // -incremental
+ cmd.createArgument().setValue(FLAG_INCREMENTAL);
+ }
+
+ if (getNlabel()) {
+ // -nlabel
+ cmd.createArgument().setValue(FLAG_NLABEL);
+ }
+
+ // baseline_root_name
+ cmd.createArgument().setValue(getBaselineRootName());
+
+ }
+
+
+ /**
+ * Set comment string
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set comment file
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * Set baseline_root_name
+ *
+ * @param baselineRootName the name of the baseline
+ */
+ public void setBaselineRootName(String baselineRootName) {
+ mBaselineRootName = baselineRootName;
+ }
+
+ /**
+ * Get baseline_root_name
+ *
+ * @return String containing the name of the baseline
+ */
+ public String getBaselineRootName() {
+ return mBaselineRootName;
+ }
+
+ /**
+
+ /**
+ * Set the nowarn flag
+ *
+ * @param nwarn the status to set the flag to
+ */
+ public void setNoWarn(boolean nwarn) {
+ mNwarn = nwarn;
+ }
+
+ /**
+ * Get nowarn flag status
+ *
+ * @return boolean containing status of nwarn flag
+ */
+ public boolean getNoWarn() {
+ return mNwarn;
+ }
+
+ /**
+ * Set the identical flag
+ *
+ * @param identical the status to set the flag to
+ */
+ public void setIdentical(boolean identical) {
+ mIdentical = identical;
+ }
+
+ /**
+ * Get identical flag status
+ *
+ * @return boolean containing status of identical flag
+ */
+ public boolean getIdentical() {
+ return mIdentical;
+ }
+
+ /**
+ * Set the full flag
+ *
+ * @param full the status to set the flag to
+ */
+ public void setFull(boolean full) {
+ mFull = full;
+ }
+
+ /**
+ * Get full flag status
+ *
+ * @return boolean containing status of full flag
+ */
+ public boolean getFull() {
+ return mFull;
+ }
+
+ /**
+ * Set the nlabel flag
+ *
+ * @param nlabel the status to set the flag to
+ */
+ public void setNlabel(boolean nlabel) {
+ mNlabel = nlabel;
+ }
+
+ /**
+ * Get nlabel status
+ *
+ * @return boolean containing status of nlabel flag
+ */
+ public boolean getNlabel() {
+ return mNlabel;
+ }
+
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd CommandLine containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+ /**
+ * -identical flag -- allows the file to be checked in even if it is identical to the original
+ */
+ public static final String FLAG_IDENTICAL = "-identical";
+ /**
+ * -incremental flag -- baseline to be created is incremental
+ */
+ public static final String FLAG_INCREMENTAL = "-incremental";
+ /**
+ * -full flag -- baseline to be created is full
+ */
+ public static final String FLAG_FULL = "-full";
+ /**
+ * -nlabel -- baseline to be created without a label
+ */
+ public static final String FLAG_NLABEL = "-nlabel";
+
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java
new file mode 100644
index 00000000..4c89539f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase mkdir.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view directory that the command will operate on</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>nocheckout</td>
+ * <td>Do not checkout after element creation</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCMkdir extends ClearCase {
+ private String mComment = null;
+ private String mCfile = null;
+ private boolean mNoco = false;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool mkelem [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_MKDIR);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+ if (getNoCheckout()) {
+ // -nco
+ cmd.createArgument().setValue(FLAG_NOCHECKOUT);
+ }
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+ /**
+ * Sets the comment string.
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Specifies a file containing a comment.
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * If true, do not checkout element after creation.
+ *
+ * @param co the status to set the flag to
+ */
+ public void setNoCheckout(boolean co) {
+ mNoco = co;
+ }
+
+ /**
+ * Get no checkout flag status
+ *
+ * @return boolean containing status of noco flag
+ */
+ public boolean getNoCheckout() {
+ return mNoco;
+ }
+
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+ /**
+ * -c flag -- comment to attach to the directory
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the directory
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+ /**
+ * -nco flag -- do not checkout element after creation
+ */
+ public static final String FLAG_NOCHECKOUT = "-nco";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java
new file mode 100644
index 00000000..94faa5a6
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java
@@ -0,0 +1,424 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase mkelem.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>nowarn</td>
+ * <td>Suppress warning messages</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>nocheckout</td>
+ * <td>Do not checkout after element creation</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>checkin</td>
+ * <td>Checkin element after creation</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>preservetime</td>
+ * <td>Preserve the modification time (for checkin)</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>master</td>
+ * <td>Assign mastership of the main branch to the current site</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>eltype</td>
+ * <td>Element type to use during element creation</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCMkelem extends ClearCase {
+ private String mComment = null;
+ private String mCfile = null;
+ private boolean mNwarn = false;
+ private boolean mPtime = false;
+ private boolean mNoco = false;
+ private boolean mCheckin = false;
+ private boolean mMaster = false;
+ private String mEltype = null;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool mkelem [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_MKELEM);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ if (getNoWarn()) {
+ // -nwarn
+ cmd.createArgument().setValue(FLAG_NOWARN);
+ }
+ /*
+ * Should choose either -ci or -nco.
+ */
+ if (getNoCheckout() && getCheckin()) {
+ throw new BuildException("Should choose either [nocheckout | checkin]");
+ }
+ if (getNoCheckout()) {
+ // -nco
+ cmd.createArgument().setValue(FLAG_NOCHECKOUT);
+ }
+ if (getCheckin()) {
+ // -ci
+ cmd.createArgument().setValue(FLAG_CHECKIN);
+ if (getPreserveTime()) {
+ // -ptime
+ cmd.createArgument().setValue(FLAG_PRESERVETIME);
+ }
+ }
+ if (getMaster()) {
+ // -master
+ cmd.createArgument().setValue(FLAG_MASTER);
+ }
+ if (getEltype() != null) {
+ // -eltype
+ getEltypeCommand(cmd);
+ }
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+ /**
+ * Sets the comment string.
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Specifies a file containing a comment.
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * If true, suppress warning messages.
+ *
+ * @param nwarn the status to set the flag to
+ */
+ public void setNoWarn(boolean nwarn) {
+ mNwarn = nwarn;
+ }
+
+ /**
+ * Get nowarn flag status
+ *
+ * @return boolean containing status of nwarn flag
+ */
+ public boolean getNoWarn() {
+ return mNwarn;
+ }
+
+ /**
+ * If true, preserve the modification time.
+ *
+ * @param ptime the status to set the flag to
+ */
+ public void setPreserveTime(boolean ptime) {
+ mPtime = ptime;
+ }
+
+ /**
+ * Get preservetime flag status
+ *
+ * @return boolean containing status of preservetime flag
+ */
+ public boolean getPreserveTime() {
+ return mPtime;
+ }
+
+ /**
+ * If true, do not checkout element after creation.
+ *
+ * @param co the status to set the flag to
+ */
+ public void setNoCheckout(boolean co) {
+ mNoco = co;
+ }
+
+ /**
+ * Get no checkout flag status
+ *
+ * @return boolean containing status of noco flag
+ */
+ public boolean getNoCheckout() {
+ return mNoco;
+ }
+
+ /**
+ * If true, checkin the element after creation
+ *
+ * @param ci the status to set the flag to
+ */
+ public void setCheckin(boolean ci) {
+ mCheckin = ci;
+ }
+
+ /**
+ * Get ci flag status
+ *
+ * @return boolean containing status of ci flag
+ */
+ public boolean getCheckin() {
+ return mCheckin;
+ }
+
+ /**
+ * If true, changes mastership of the main branch
+ * to the current site
+ *
+ * @param master the status to set the flag to
+ */
+ public void setMaster(boolean master) {
+ mMaster = master;
+ }
+
+ /**
+ * Get master flag status
+ *
+ * @return boolean containing status of master flag
+ */
+ public boolean getMaster() {
+ return mMaster;
+ }
+
+ /**
+ * Specifies the element type to use.
+ *
+ * @param eltype to create element
+ */
+ public void setEltype(String eltype) {
+ mEltype = eltype;
+ }
+
+ /**
+ * Get element type
+ *
+ * @return String containing the element type
+ */
+ public String getEltype() {
+ return mEltype;
+ }
+
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+ /**
+ * Get the 'element type' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getEltypeCommand(Commandline cmd) {
+ if (getEltype() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_ELTYPE);
+ cmd.createArgument().setValue(getEltype());
+ }
+ }
+
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+ /**
+ * -nwarn flag -- suppresses warning messages
+ */
+ public static final String FLAG_NOWARN = "-nwarn";
+ /**
+ * -ptime flag -- preserves the modification time on checkin
+ */
+ public static final String FLAG_PRESERVETIME = "-ptime";
+ /**
+ * -nco flag -- do not checkout element after creation
+ */
+ public static final String FLAG_NOCHECKOUT = "-nco";
+ /**
+ * -ci flag -- checkin element after creation
+ */
+ public static final String FLAG_CHECKIN = "-ci";
+ /**
+ * -master flag -- change mastership of main branch to current site
+ */
+ public static final String FLAG_MASTER = "-master";
+ /**
+ * -eltype flag -- element type to use during creation
+ */
+ public static final String FLAG_ELTYPE = "-eltype";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java
new file mode 100644
index 00000000..e3d288df
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform mklabel command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>replace</td>
+ * <td>Replace a label of the same type on the same branch</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>recurse</td>
+ * <td>Process each subdirectory under viewpath</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>version</td>
+ * <td>Identify a specific version to attach the label to</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>typename</td>
+ * <td>Name of the label type</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>vob</td>
+ * <td>Name of the VOB</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCMklabel extends ClearCase {
+ private boolean mReplace = false;
+ private boolean mRecurse = false;
+ private String mVersion = null;
+ private String mTypeName = null;
+ private String mVOB = null;
+ private String mComment = null;
+ private String mCfile = null;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Check for required attributes
+ if (getTypeName() == null) {
+ throw new BuildException("Required attribute TypeName not specified");
+ }
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool mklabel [options...] [viewpath ...]
+ // as specified in the CLEARTOOL help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_MKLABEL);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getReplace()) {
+ // -replace
+ cmd.createArgument().setValue(FLAG_REPLACE);
+ }
+
+ if (getRecurse()) {
+ // -recurse
+ cmd.createArgument().setValue(FLAG_RECURSE);
+ }
+
+ if (getVersion() != null) {
+ // -version
+ getVersionCommand(cmd);
+ }
+
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ if (getTypeName() != null) {
+ // type
+ getTypeCommand(cmd);
+ }
+
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+
+ /**
+ * Set the replace flag
+ *
+ * @param replace the status to set the flag to
+ */
+ public void setReplace(boolean replace) {
+ mReplace = replace;
+ }
+
+ /**
+ * Get replace flag status
+ *
+ * @return boolean containing status of replace flag
+ */
+ public boolean getReplace() {
+ return mReplace;
+ }
+
+ /**
+ * Set recurse flag
+ *
+ * @param recurse the status to set the flag to
+ */
+ public void setRecurse(boolean recurse) {
+ mRecurse = recurse;
+ }
+
+ /**
+ * Get recurse flag status
+ *
+ * @return boolean containing status of recurse flag
+ */
+ public boolean getRecurse() {
+ return mRecurse;
+ }
+
+ /**
+ * Set the version flag
+ *
+ * @param version the status to set the flag to
+ */
+ public void setVersion(String version) {
+ mVersion = version;
+ }
+
+ /**
+ * Get version flag status
+ *
+ * @return boolean containing status of version flag
+ */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Set comment string
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set comment file
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * Set the type-name
+ *
+ * @param tn the type name
+ */
+ public void setTypeName(String tn) {
+ mTypeName = tn;
+ }
+
+ /**
+ * Get type-name
+ *
+ * @return String containing type name
+ */
+ public String getTypeName() {
+ return mTypeName;
+ }
+
+ /**
+ * Set the VOB name
+ *
+ * @param vob the VOB name
+ */
+ public void setVOB(String vob) {
+ mVOB = vob;
+ }
+
+ /**
+ * Get VOB name
+ *
+ * @return String containing VOB name
+ */
+ public String getVOB() {
+ return mVOB;
+ }
+
+
+ /**
+ * Get the 'version' command
+ *
+ * @param cmd CommandLine containing the command line string with or
+ * without the version flag and string appended
+ */
+ private void getVersionCommand(Commandline cmd) {
+ if (getVersion() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_VERSION);
+ cmd.createArgument().setValue(getVersion());
+ }
+ }
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+ /**
+ * Get the type-name
+ *
+ * @param cmd containing the command line string with or
+ * without the type-name
+ */
+ private void getTypeCommand(Commandline cmd) {
+ String typenm = null;
+
+ if (getTypeName() != null) {
+ typenm = getTypeName();
+ if (getVOB() != null) {
+ typenm += "@" + getVOB();
+ }
+ cmd.createArgument().setValue(typenm);
+ }
+ }
+
+
+ /**
+ * -replace flag -- replace another label of the same type
+ */
+ public static final String FLAG_REPLACE = "-replace";
+ /**
+ * -recurse flag -- process all subdirectories
+ */
+ public static final String FLAG_RECURSE = "-recurse";
+ /**
+ * -version flag -- attach label to specified version
+ */
+ public static final String FLAG_VERSION = "-version";
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java
new file mode 100644
index 00000000..7bb7192e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java
@@ -0,0 +1,440 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform mklbtype command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>typename</td>
+ * <td>Name of the label type to create</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>vob</td>
+ * <td>Name of the VOB</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>replace</td>
+ * <td>Replace an existing label definition of the same type</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>global</td>
+ * <td>Either global or ordinary can be specified, not both.
+ * Creates a label type that is global to the VOB or to
+ * VOBs that use this VOB</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>ordinary</td>
+ * <td>Either global or ordinary can be specified, not both.
+ * Creates a label type that can be used only in the current
+ * VOB. <B>Default</B></td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>pbranch</td>
+ * <td>Allows the label type to be used once per branch in a given
+ * element's version tree</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>shared</td>
+ * <td>Sets the way mastership is checked by ClearCase. See ClearCase
+ * documentation for details</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or
+ * cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCMklbtype extends ClearCase {
+ private String mTypeName = null;
+ private String mVOB = null;
+ private String mComment = null;
+ private String mCfile = null;
+ private boolean mReplace = false;
+ private boolean mGlobal = false;
+ private boolean mOrdinary = true;
+ private boolean mPbranch = false;
+ private boolean mShared = false;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ int result = 0;
+
+ // Check for required attributes
+ if (getTypeName() == null) {
+ throw new BuildException("Required attribute TypeName not specified");
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool mklbtype [options...] type-selector...
+ // as specified in the CLEARTOOL help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_MKLBTYPE);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getTypeSpecifier(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getReplace()) {
+ // -replace
+ cmd.createArgument().setValue(FLAG_REPLACE);
+ }
+
+ if (getOrdinary()) {
+ // -ordinary
+ cmd.createArgument().setValue(FLAG_ORDINARY);
+ } else {
+ if (getGlobal()) {
+ // -global
+ cmd.createArgument().setValue(FLAG_GLOBAL);
+ }
+ }
+
+ if (getPbranch()) {
+ // -pbranch
+ cmd.createArgument().setValue(FLAG_PBRANCH);
+ }
+
+ if (getShared()) {
+ // -shared
+ cmd.createArgument().setValue(FLAG_SHARED);
+ }
+
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ // type-name@vob
+ cmd.createArgument().setValue(getTypeSpecifier());
+ }
+
+
+ /**
+ * Set type-name string
+ *
+ * @param tn the type-name string
+ */
+ public void setTypeName(String tn) {
+ mTypeName = tn;
+ }
+
+ /**
+ * Get type-name string
+ *
+ * @return String containing the type-name
+ */
+ public String getTypeName() {
+ return mTypeName;
+ }
+
+ /**
+ * Set the VOB name
+ *
+ * @param vob the VOB name
+ */
+ public void setVOB(String vob) {
+ mVOB = vob;
+ }
+
+ /**
+ * Get VOB name
+ *
+ * @return String containing VOB name
+ */
+ public String getVOB() {
+ return mVOB;
+ }
+
+ /**
+ * Set the replace flag
+ *
+ * @param repl the status to set the flag to
+ */
+ public void setReplace(boolean repl) {
+ mReplace = repl;
+ }
+
+ /**
+ * Get replace flag status
+ *
+ * @return boolean containing status of replace flag
+ */
+ public boolean getReplace() {
+ return mReplace;
+ }
+
+ /**
+ * Set the global flag
+ *
+ * @param glob the status to set the flag to
+ */
+ public void setGlobal(boolean glob) {
+ mGlobal = glob;
+ }
+
+ /**
+ * Get global flag status
+ *
+ * @return boolean containing status of global flag
+ */
+ public boolean getGlobal() {
+ return mGlobal;
+ }
+
+ /**
+ * Set the ordinary flag
+ *
+ * @param ordinary the status to set the flag to
+ */
+ public void setOrdinary(boolean ordinary) {
+ mOrdinary = ordinary;
+ }
+
+ /**
+ * Get ordinary flag status
+ *
+ * @return boolean containing status of ordinary flag
+ */
+ public boolean getOrdinary() {
+ return mOrdinary;
+ }
+
+ /**
+ * Set the pbranch flag
+ *
+ * @param pbranch the status to set the flag to
+ */
+ public void setPbranch(boolean pbranch) {
+ mPbranch = pbranch;
+ }
+
+ /**
+ * Get pbranch flag status
+ *
+ * @return boolean containing status of pbranch flag
+ */
+ public boolean getPbranch() {
+ return mPbranch;
+ }
+
+ /**
+ * Set the shared flag
+ *
+ * @param shared the status to set the flag to
+ */
+ public void setShared(boolean shared) {
+ mShared = shared;
+ }
+
+ /**
+ * Get shared flag status
+ *
+ * @return boolean containing status of shared flag
+ */
+ public boolean getShared() {
+ return mShared;
+ }
+
+ /**
+ * Set comment string
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set comment file
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+ /**
+ * Get the type-name specifier
+ *
+ * @return the 'type-name-specifier' command if the attribute was
+ * specified, otherwise an empty string
+ */
+ private String getTypeSpecifier() {
+ String typenm = null;
+
+ typenm = getTypeName();
+ if (getVOB() != null) {
+ typenm += "@" + getVOB();
+ }
+
+ return typenm;
+ }
+
+
+ /**
+ * -replace flag -- replace existing label definition of the same type
+ */
+ public static final String FLAG_REPLACE = "-replace";
+ /**
+ * -global flag -- creates a label type that is global to the VOB or to VOBs that use this VOB
+ */
+ public static final String FLAG_GLOBAL = "-global";
+ /**
+ * -ordinary flag -- creates a label type that can be used only in the current VOB
+ */
+ public static final String FLAG_ORDINARY = "-ordinary";
+ /**
+ * -pbranch flag -- allows label type to be used once per branch
+ */
+ public static final String FLAG_PBRANCH = "-pbranch";
+ /**
+ * -shared flag -- sets the way mastership is checked by ClearCase
+ */
+ public static final String FLAG_SHARED = "-shared";
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java
new file mode 100644
index 00000000..cef0c3a5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java
@@ -0,0 +1,373 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform rmtype command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>typekind</td>
+ * <td>The kind of type to create. Valid types are:<br>
+ * attype attribute type<br>
+ * brtype branch type<br>
+ * eltype element type<br>
+ * hltype hyperlink type<br>
+ * lbtype label type<br>
+ * trtype trigger type<br>
+ * </td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>typename</td>
+ * <td>The name of the type to remove</td>
+ * <td>Yes</td>
+ * <tr>
+ * <tr>
+ * <td>vob</td>
+ * <td>Name of the VOB</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>ignore</td>
+ * <td>Used with trigger types only. Forces removal of trigger type
+ * even if a pre-operation trigger would prevent its removal</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>rmall</td>
+ * <td>Removes all instances of a type and the type object itself</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>commentfile</td>
+ * <td>Specify a file containing a comment. Only one of comment or cfile
+ * may be used.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCRmtype extends ClearCase {
+ private String mTypeKind = null;
+ private String mTypeName = null;
+ private String mVOB = null;
+ private String mComment = null;
+ private String mCfile = null;
+ private boolean mRmall = false;
+ private boolean mIgnore = false;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ int result = 0;
+
+ // Check for required attributes
+ if (getTypeKind() == null) {
+ throw new BuildException("Required attribute TypeKind not specified");
+ }
+ if (getTypeName() == null) {
+ throw new BuildException("Required attribute TypeName not specified");
+ }
+
+ // build the command line from what we got. the format is
+ // cleartool rmtype [options...] type-selector...
+ // as specified in the CLEARTOOL help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_RMTYPE);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getTypeSpecifier(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ if (getIgnore()) {
+ // -ignore
+ cmd.createArgument().setValue(FLAG_IGNORE);
+ }
+ if (getRmAll()) {
+ // -rmall -force
+ cmd.createArgument().setValue(FLAG_RMALL);
+ cmd.createArgument().setValue(FLAG_FORCE);
+ }
+ if (getComment() != null) {
+ // -c
+ getCommentCommand(cmd);
+ } else {
+ if (getCommentFile() != null) {
+ // -cfile
+ getCommentFileCommand(cmd);
+ } else {
+ cmd.createArgument().setValue(FLAG_NOCOMMENT);
+ }
+ }
+
+ // type-kind:type-name
+ cmd.createArgument().setValue(getTypeSpecifier());
+ }
+
+ /**
+ * Set the ignore flag
+ *
+ * @param ignore the status to set the flag to
+ */
+ public void setIgnore(boolean ignore) {
+ mIgnore = ignore;
+ }
+
+ /**
+ * Get ignore flag status
+ *
+ * @return boolean containing status of ignore flag
+ */
+ public boolean getIgnore() {
+ return mIgnore;
+ }
+
+ /**
+ * Set rmall flag
+ *
+ * @param rmall the status to set the flag to
+ */
+ public void setRmAll(boolean rmall) {
+ mRmall = rmall;
+ }
+
+ /**
+ * Get rmall flag status
+ *
+ * @return boolean containing status of rmall flag
+ */
+ public boolean getRmAll() {
+ return mRmall;
+ }
+
+ /**
+ * Set comment string
+ *
+ * @param comment the comment string
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment string
+ *
+ * @return String containing the comment
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set comment file
+ *
+ * @param cfile the path to the comment file
+ */
+ public void setCommentFile(String cfile) {
+ mCfile = cfile;
+ }
+
+ /**
+ * Get comment file
+ *
+ * @return String containing the path to the comment file
+ */
+ public String getCommentFile() {
+ return mCfile;
+ }
+
+ /**
+ * Set type-kind string
+ *
+ * @param tk the type-kind string
+ */
+ public void setTypeKind(String tk) {
+ mTypeKind = tk;
+ }
+
+ /**
+ * Get type-kind string
+ *
+ * @return String containing the type-kind
+ */
+ public String getTypeKind() {
+ return mTypeKind;
+ }
+
+ /**
+ * Set type-name string
+ *
+ * @param tn the type-name string
+ */
+ public void setTypeName(String tn) {
+ mTypeName = tn;
+ }
+
+ /**
+ * Get type-name string
+ *
+ * @return String containing the type-name
+ */
+ public String getTypeName() {
+ return mTypeName;
+ }
+
+ /**
+ * Set the VOB name
+ *
+ * @param vob the VOB name
+ */
+ public void setVOB(String vob) {
+ mVOB = vob;
+ }
+
+ /**
+ * Get VOB name
+ *
+ * @return String containing VOB name
+ */
+ public String getVOB() {
+ return mVOB;
+ }
+
+ /**
+ * Get the 'type-specifier' string
+ *
+ * @return the 'type-kind:type-name@vob' specifier
+ *
+ */
+ private String getTypeSpecifier() {
+ String tkind = getTypeKind();
+ String tname = getTypeName();
+ String typeSpec = null;
+
+ // Return the type-selector
+ typeSpec = tkind + ":" + tname;
+ if (getVOB() != null) {
+ typeSpec += "@" + getVOB();
+ }
+ return typeSpec;
+ }
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or
+ * without the comment flag and string appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'commentfile' command
+ *
+ * @param cmd containing the command line string with or
+ * without the commentfile flag and file appended
+ */
+ private void getCommentFileCommand(Commandline cmd) {
+ if (getCommentFile() != null) {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENTFILE);
+ cmd.createArgument().setValue(getCommentFile());
+ }
+ }
+
+
+ /**
+ * -ignore flag -- ignore pre-trigger operations when removing a trigger type
+ */
+ public static final String FLAG_IGNORE = "-ignore";
+ /**
+ * -rmall flag -- removes all instances of a type and the type object itself
+ */
+ public static final String FLAG_RMALL = "-rmall";
+ /**
+ * -force flag -- suppresses confirmation prompts
+ */
+ public static final String FLAG_FORCE = "-force";
+ /**
+ * -c flag -- comment to attach to the file
+ */
+ public static final String FLAG_COMMENT = "-c";
+ /**
+ * -cfile flag -- file containing a comment to attach to the file
+ */
+ public static final String FLAG_COMMENTFILE = "-cfile";
+ /**
+ * -nc flag -- no comment is specified
+ */
+ public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java
new file mode 100644
index 00000000..3c00e1af
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase UnCheckout command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>keepcopy</td>
+ * <td>Specifies whether to keep a copy of the file with a .keep extension or not</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCUnCheckout extends ClearCase {
+ private boolean mKeep = false;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got the format is
+ // cleartool uncheckout [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_UNCHECKOUT);
+
+ checkOptions(commandLine);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ // ClearCase items
+ if (getKeepCopy()) {
+ // -keep
+ cmd.createArgument().setValue(FLAG_KEEPCOPY);
+ } else {
+ // -rm
+ cmd.createArgument().setValue(FLAG_RM);
+ }
+
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+ /**
+ * If true, keep a copy of the file with a .keep extension.
+ *
+ * @param keep the status to set the flag to
+ */
+ public void setKeepCopy(boolean keep) {
+ mKeep = keep;
+ }
+
+ /**
+ * Get keepcopy flag status
+ *
+ * @return boolean containing status of keep flag
+ */
+ public boolean getKeepCopy() {
+ return mKeep;
+ }
+
+
+ /**
+ * -keep flag -- keep a copy of the file with .keep extension
+ */
+ public static final String FLAG_KEEPCOPY = "-keep";
+ /**
+ * -rm flag -- remove the copy of the file
+ */
+ public static final String FLAG_RM = "-rm";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java
new file mode 100644
index 00000000..4ca3e890
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * TODO:
+ * comment field doesn't include all options yet
+ */
+
+/**
+ * Performs a ClearCase Unlock command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>comment</td>
+ * <td>Specifies how to populate comments fields</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>pname</td>
+ * <td>Specifies the object pathname to be unlocked.</td>
+ * <td>No</td>
+ * <tr>
+ * <td>objselect</td>
+ * <td>This variable is obsolete. Should use <i>objsel</i> instead.</td>
+ * <td>no</td>
+ * <tr>
+ * <tr>
+ * <td>objsel</td>
+ * <td>Specifies the object(s) to be unlocked.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ *
+ * </table>
+ *
+ */
+public class CCUnlock extends ClearCase {
+ private String mComment = null;
+ private String mPname = null;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got the format is
+ // cleartool lock [options...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_UNLOCK);
+
+ // Check the command line options
+ checkOptions(commandLine);
+
+ // For debugging
+ // System.out.println(commandLine.toString());
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getOpType(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ // ClearCase items
+ getCommentCommand(cmd);
+
+ if (getObjSelect() == null && getPname() == null) {
+ throw new BuildException("Should select either an element "
+ + "(pname) or an object (objselect)");
+ }
+ getPnameCommand(cmd);
+ // object selector
+ if (getObjSelect() != null) {
+ cmd.createArgument().setValue(getObjSelect());
+ }
+ }
+
+ /**
+ * Sets how comments should be written
+ * for the event record(s)
+ *
+ * @param comment comment method to use
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+
+ /**
+ * Get comment method
+ *
+ * @return String containing the desired comment method
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Sets the pathname to be locked
+ *
+ * @param pname pathname to be locked
+ */
+ public void setPname(String pname) {
+ mPname = pname;
+ }
+
+ /**
+ * Get the pathname to be locked
+ *
+ * @return String containing the pathname to be locked
+ */
+ public String getPname() {
+ return mPname;
+ }
+
+ /**
+ * Sets the object(s) to be locked
+ *
+ * @param objselect objects to be locked
+ */
+ public void setObjselect(String objselect) {
+ setObjSelect(objselect);
+ }
+
+ /**
+ * Sets the object(s) to be locked
+ *
+ * @param objsel objects to be locked
+ * @since ant 1.6.1
+ */
+ public void setObjSel(String objsel) {
+ setObjSelect(objsel);
+ }
+
+ /**
+ * Get list of objects to be locked
+ *
+ * @return String containing the objects to be locked
+ */
+ public String getObjselect() {
+ return getObjSelect();
+ }
+
+ /**
+ * Get the 'comment' command
+ *
+ * @param cmd containing the command line string with or without the
+ * comment flag and value appended
+ */
+ private void getCommentCommand(Commandline cmd) {
+ if (getComment() == null) {
+ return;
+ } else {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_COMMENT);
+ cmd.createArgument().setValue(getComment());
+ }
+ }
+
+ /**
+ * Get the 'pname' command
+ *
+ * @param cmd containing the command line string with or without the
+ * pname flag and value appended
+ */
+ private void getPnameCommand(Commandline cmd) {
+ if (getPname() == null) {
+ return;
+ } else {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_PNAME);
+ cmd.createArgument().setValue(getPname());
+ }
+ }
+
+ /**
+ * Return which object/pname is being operated on
+ *
+ * @return String containing the object/pname being worked on
+ */
+ private String getOpType() {
+
+ if (getPname() != null) {
+ return getPname();
+ } else {
+ return getObjSelect();
+ }
+ }
+
+ /**
+ * -comment flag -- method to use for commenting events
+ */
+ public static final String FLAG_COMMENT = "-comment";
+ /**
+ * -pname flag -- pathname to lock
+ */
+ public static final String FLAG_PNAME = "-pname";
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java
new file mode 100644
index 00000000..712efdca
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java
@@ -0,0 +1,331 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs a ClearCase Update command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>graphical</td>
+ * <td>Displays a graphical dialog during the update</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>log</td>
+ * <td>Specifies a log file for ClearCase to write to</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>overwrite</td>
+ * <td>Specifies whether to overwrite hijacked files or not</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>rename</td>
+ * <td>Specifies that hijacked files should be renamed with a .keep extension</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>currenttime</td>
+ * <td>Specifies that modification time should be written as the current
+ * time. Either currenttime or preservetime can be specified.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>preservetime</td>
+ * <td>Specifies that modification time should preserved from the VOB
+ * time. Either currenttime or preservetime can be specified.</td>
+ * <td>No</td>
+ * <tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true</td>
+ * <td>No</td>
+ * <tr>
+ * </table>
+ *
+ */
+public class CCUpdate extends ClearCase {
+ private boolean mGraphical = false;
+ private boolean mOverwrite = false;
+ private boolean mRename = false;
+ private boolean mCtime = false;
+ private boolean mPtime = false;
+ private String mLog = null;
+
+ /**
+ * Executes the task.
+ * <p>
+ * Builds a command line to execute cleartool and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command fails and failonerr is set to true
+ */
+ public void execute() throws BuildException {
+ Commandline commandLine = new Commandline();
+ Project aProj = getProject();
+ int result = 0;
+
+ // Default the viewpath to basedir if it is not specified
+ if (getViewPath() == null) {
+ setViewPath(aProj.getBaseDir().getPath());
+ }
+
+ // build the command line from what we got the format is
+ // cleartool update [options...] [viewpath ...]
+ // as specified in the CLEARTOOL.EXE help
+ commandLine.setExecutable(getClearToolCommand());
+ commandLine.createArgument().setValue(COMMAND_UPDATE);
+
+ // Check the command line options
+ checkOptions(commandLine);
+
+ // For debugging
+ getProject().log(commandLine.toString(), Project.MSG_DEBUG);
+
+ if (!getFailOnErr()) {
+ getProject().log("Ignoring any errors that occur for: "
+ + getViewPathBasename(), Project.MSG_VERBOSE);
+ }
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnErr()) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Check the command line options.
+ */
+ private void checkOptions(Commandline cmd) {
+ // ClearCase items
+ if (getGraphical()) {
+ // -graphical
+ cmd.createArgument().setValue(FLAG_GRAPHICAL);
+ } else {
+ if (getOverwrite()) {
+ // -overwrite
+ cmd.createArgument().setValue(FLAG_OVERWRITE);
+ } else {
+ if (getRename()) {
+ // -rename
+ cmd.createArgument().setValue(FLAG_RENAME);
+ } else {
+ // -noverwrite
+ cmd.createArgument().setValue(FLAG_NOVERWRITE);
+ }
+ }
+
+ if (getCurrentTime()) {
+ // -ctime
+ cmd.createArgument().setValue(FLAG_CURRENTTIME);
+ } else {
+ if (getPreserveTime()) {
+ // -ptime
+ cmd.createArgument().setValue(FLAG_PRESERVETIME);
+ }
+ }
+
+ // -log logname
+ getLogCommand(cmd);
+ }
+
+ // viewpath
+ cmd.createArgument().setValue(getViewPath());
+ }
+
+ /**
+ * If true, displays a graphical dialog during the update.
+ *
+ * @param graphical the status to set the flag to
+ */
+ public void setGraphical(boolean graphical) {
+ mGraphical = graphical;
+ }
+
+ /**
+ * Get graphical flag status
+ *
+ * @return boolean containing status of graphical flag
+ */
+ public boolean getGraphical() {
+ return mGraphical;
+ }
+
+ /**
+ * If true, overwrite hijacked files.
+ *
+ * @param ow the status to set the flag to
+ */
+ public void setOverwrite(boolean ow) {
+ mOverwrite = ow;
+ }
+
+ /**
+ * Get overwrite hijacked files status
+ *
+ * @return boolean containing status of overwrite flag
+ */
+ public boolean getOverwrite() {
+ return mOverwrite;
+ }
+
+ /**
+ * If true, hijacked files are renamed with a .keep extension.
+ *
+ * @param ren the status to set the flag to
+ */
+ public void setRename(boolean ren) {
+ mRename = ren;
+ }
+
+ /**
+ * Get rename hijacked files status
+ *
+ * @return boolean containing status of rename flag
+ */
+ public boolean getRename() {
+ return mRename;
+ }
+
+ /**
+ * If true, modification time should be written as the current time.
+ * Either currenttime or preservetime can be specified.
+ *
+ * @param ct the status to set the flag to
+ */
+ public void setCurrentTime(boolean ct) {
+ mCtime = ct;
+ }
+
+ /**
+ * Get current time status
+ *
+ * @return boolean containing status of current time flag
+ */
+ public boolean getCurrentTime() {
+ return mCtime;
+ }
+
+ /**
+ * If true, modification time should be preserved from the VOB time.
+ * Either currenttime or preservetime can be specified.
+ *
+ * @param pt the status to set the flag to
+ */
+ public void setPreserveTime(boolean pt) {
+ mPtime = pt;
+ }
+
+ /**
+ * Get preserve time status
+ *
+ * @return boolean containing status of preserve time flag
+ */
+ public boolean getPreserveTime() {
+ return mPtime;
+ }
+
+ /**
+ * Sets the log file where cleartool records
+ * the status of the command.
+ *
+ * @param log the path to the log file
+ */
+ public void setLog(String log) {
+ mLog = log;
+ }
+
+ /**
+ * Get log file
+ *
+ * @return String containing the path to the log file
+ */
+ public String getLog() {
+ return mLog;
+ }
+
+
+ /**
+ * Get the 'log' command
+ *
+ * @param cmd containing the command line string with or without the log flag and path appended
+ */
+ private void getLogCommand(Commandline cmd) {
+ if (getLog() == null) {
+ return;
+ } else {
+ /* Had to make two separate commands here because if a space is
+ inserted between the flag and the value, it is treated as a
+ Windows filename with a space and it is enclosed in double
+ quotes ("). This breaks clearcase.
+ */
+ cmd.createArgument().setValue(FLAG_LOG);
+ cmd.createArgument().setValue(getLog());
+ }
+ }
+
+ /**
+ * -graphical flag -- display graphical dialog during update operation
+ */
+ public static final String FLAG_GRAPHICAL = "-graphical";
+ /**
+ * -log flag -- file to log status to
+ */
+ public static final String FLAG_LOG = "-log";
+ /**
+ * -overwrite flag -- overwrite hijacked files
+ */
+ public static final String FLAG_OVERWRITE = "-overwrite";
+ /**
+ * -noverwrite flag -- do not overwrite hijacked files
+ */
+ public static final String FLAG_NOVERWRITE = "-noverwrite";
+ /**
+ * -rename flag -- rename hijacked files with .keep extension
+ */
+ public static final String FLAG_RENAME = "-rename";
+ /**
+ * -ctime flag -- modified time is written as the current time
+ */
+ public static final String FLAG_CURRENTTIME = "-ctime";
+ /**
+ * -ptime flag -- modified time is written as the VOB time
+ */
+ public static final String FLAG_PRESERVETIME = "-ptime";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java
new file mode 100644
index 00000000..d81e505c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+
+
+
+/**
+ * A base class for creating tasks for executing commands on ClearCase.
+ * <p>
+ * The class extends the 'exec' task as it operates by executing the cleartool program
+ * supplied with ClearCase. By default the task expects the cleartool executable to be
+ * in the path, * you can override this be specifying the cleartooldir attribute.
+ * </p>
+ * <p>
+ * This class provides set and get methods for the 'viewpath' and 'objselect'
+ * attribute. It also contains constants for the flags that can be passed to
+ * cleartool.
+ * </p>
+ *
+ */
+public abstract class ClearCase extends Task {
+ private String mClearToolDir = "";
+ private String mviewPath = null;
+ private String mobjSelect = null;
+ private static int pcnt = 0;
+ private boolean mFailonerr = true;
+ /**
+ * Set the directory where the cleartool executable is located.
+ *
+ * @param dir the directory containing the cleartool executable
+ */
+ public final void setClearToolDir(String dir) {
+ mClearToolDir = FileUtils.translatePath(dir);
+ }
+
+ /**
+ * Builds and returns the command string to execute cleartool
+ *
+ * @return String containing path to the executable
+ */
+ protected final String getClearToolCommand() {
+ String toReturn = mClearToolDir;
+ if (!toReturn.equals("") && !toReturn.endsWith("/")) {
+ toReturn += "/";
+ }
+
+ toReturn += CLEARTOOL_EXE;
+
+ return toReturn;
+ }
+
+ /**
+ * Set the path to the item in a ClearCase view to operate on.
+ *
+ * @param viewPath Path to the view directory or file
+ */
+ public final void setViewPath(String viewPath) {
+ mviewPath = viewPath;
+ }
+
+ /**
+ * Get the path to the item in a clearcase view
+ *
+ * @return mviewPath
+ */
+ public String getViewPath() {
+ return mviewPath;
+ }
+
+ /**
+ * Get the basename path of the item in a clearcase view
+ *
+ * @return basename
+ */
+ public String getViewPathBasename() {
+ return (new File(mviewPath)).getName();
+ }
+
+ /**
+ * Set the object to operate on.
+ *
+ * @param objSelect object to operate on
+ */
+ public final void setObjSelect(String objSelect) {
+ mobjSelect = objSelect;
+ }
+
+ /**
+ * Get the object to operate on
+ *
+ * @return mobjSelect
+ */
+ public String getObjSelect() {
+ return mobjSelect;
+ }
+
+ /**
+ * Execute the given command are return success or failure
+ * @param cmd command line to execute
+ * @return the exit status of the subprocess or <code>INVALID</code>
+ */
+ protected int run(Commandline cmd) {
+ try {
+ Project aProj = getProject();
+ Execute exe
+ = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN));
+ exe.setAntRun(aProj);
+ exe.setWorkingDirectory(aProj.getBaseDir());
+ exe.setCommandline(cmd.getCommandline());
+ return exe.execute();
+ } catch (java.io.IOException e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ /**
+ * Execute the given command, and return it's output
+ * @param cmdline command line to execute
+ * @return output of the command line
+ */
+ protected String runS(Commandline cmdline) {
+ String outV = "opts.cc.runS.output" + pcnt++;
+ ExecTask exe = new ExecTask(this);
+ Commandline.Argument arg = exe.createArg();
+
+ exe.setExecutable(cmdline.getExecutable());
+ arg.setLine(Commandline.toString(cmdline.getArguments()));
+ exe.setOutputproperty(outV);
+ exe.execute();
+
+ return getProject().getProperty(outV);
+ }
+ /**
+ * If true, command will throw an exception on failure.
+ *
+ * @param failonerr the status to set the flag to
+ * @since ant 1.6.1
+ */
+ public void setFailOnErr(boolean failonerr) {
+ mFailonerr = failonerr;
+ }
+
+ /**
+ * Get failonerr flag status
+ *
+ * @return boolean containing status of failonerr flag
+ * @since ant 1.6.1
+ */
+ public boolean getFailOnErr() {
+ return mFailonerr;
+ }
+
+ /**
+ * Constant for the thing to execute
+ */
+ private static final String CLEARTOOL_EXE = "cleartool";
+ /**
+ * The 'Update' command
+ */
+ public static final String COMMAND_UPDATE = "update";
+ /**
+ * The 'Checkout' command
+ */
+ public static final String COMMAND_CHECKOUT = "checkout";
+ /**
+ * The 'Checkin' command
+ */
+ public static final String COMMAND_CHECKIN = "checkin";
+ /**
+ * The 'UndoCheckout' command
+ */
+ public static final String COMMAND_UNCHECKOUT = "uncheckout";
+ /**
+ * The 'Lock' command
+ */
+ public static final String COMMAND_LOCK = "lock";
+ /**
+ * The 'Unlock' command
+ */
+ public static final String COMMAND_UNLOCK = "unlock";
+ /**
+ * The 'Mkbl' command
+ */
+ public static final String COMMAND_MKBL = "mkbl";
+ /**
+ * The 'Mklabel' command
+ */
+ public static final String COMMAND_MKLABEL = "mklabel";
+ /**
+ * The 'Mklbtype' command
+ */
+ public static final String COMMAND_MKLBTYPE = "mklbtype";
+ /**
+ * The 'Rmtype' command
+ */
+ public static final String COMMAND_RMTYPE = "rmtype";
+ /**
+ * The 'LsCheckout' command
+ */
+ public static final String COMMAND_LSCO = "lsco";
+ /**
+ * The 'Mkelem' command
+ */
+ public static final String COMMAND_MKELEM = "mkelem";
+ /**
+ * The 'Mkattr' command
+ */
+ public static final String COMMAND_MKATTR = "mkattr";
+ /**
+ * The 'Mkdir' command
+ */
+ public static final String COMMAND_MKDIR = "mkdir";
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java
new file mode 100644
index 00000000..341f6707
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * An analyzer which uses the depend task's bytecode classes to analyze
+ * dependencies
+ *
+ */
+public class AntAnalyzer extends AbstractAnalyzer {
+ /**
+ * Default constructor
+ */
+ public AntAnalyzer() {
+ }
+
+ /**
+ * Determine the dependencies of the configured root classes.
+ *
+ * @param files a vector to be populated with the files which contain
+ * the dependency classes
+ * @param classes a vector to be populated with the names of the
+ * dependency classes.
+ */
+ protected void determineDependencies(Vector<File> files, Vector<String> classes) {
+ // we get the root classes and build up a set of
+ // classes upon which they depend
+ Hashtable<String, String> dependencies = new Hashtable<String, String>();
+ Hashtable<File, File> containers = new Hashtable<File, File>();
+ Hashtable<String, String> toAnalyze = new Hashtable<String, String>();
+ for (Enumeration<String> e = getRootClasses(); e.hasMoreElements();) {
+ String classname = e.nextElement();
+ toAnalyze.put(classname, classname);
+ }
+
+ int count = 0;
+ int maxCount = isClosureRequired() ? MAX_LOOPS : 1;
+ Hashtable<String, String> analyzedDeps = null;
+ while (toAnalyze.size() != 0 && count++ < maxCount) {
+ analyzedDeps = new Hashtable<String, String>();
+ for (Enumeration<String> e = toAnalyze.keys(); e.hasMoreElements();) {
+ String classname = e.nextElement();
+ dependencies.put(classname, classname);
+ try {
+ File container = getClassContainer(classname);
+ if (container == null) {
+ continue;
+ }
+ containers.put(container, container);
+
+ ZipFile zipFile = null;
+ InputStream inStream = null;
+ try {
+ if (container.getName().endsWith(".class")) {
+ inStream = new FileInputStream(container.getPath());
+ } else {
+ zipFile = new ZipFile(container.getPath());
+ String entryName
+ = classname.replace('.', '/') + ".class";
+ ZipEntry entry = new ZipEntry(entryName);
+ inStream
+ = zipFile.getInputStream(entry);
+ }
+ ClassFile classFile = new ClassFile();
+ classFile.read(inStream);
+ for (String dependency : classFile.getClassRefs()) {
+ analyzedDeps.put(dependency, dependency);
+ }
+ } finally {
+ FileUtils.close(inStream);
+ if (zipFile != null) {
+ zipFile.close();
+ }
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ toAnalyze.clear();
+
+ // now recover all the dependencies collected and add to the list.
+ for (String className : analyzedDeps.values()) {
+ if (!dependencies.containsKey(className)) {
+ toAnalyze.put(className, className);
+ }
+ }
+ }
+
+ // pick up the last round of dependencies that were determined
+ for (String className : analyzedDeps.values()) {
+ dependencies.put(className, className);
+ }
+
+ files.removeAllElements();
+ for (File f : containers.keySet()) {
+ files.add(f);
+ }
+
+ classes.removeAllElements();
+ for (String dependency :dependencies.keySet()) {
+ classes.add(dependency);
+ }
+ }
+
+ /**
+ * Indicate if this analyzer can determine dependent files.
+ *
+ * @return true if the analyzer provides dependency file information.
+ */
+ protected boolean supportsFileDependencies() {
+ return true;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java
new file mode 100644
index 00000000..858ce03e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ClassCPInfo;
+import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool;
+import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPoolEntry;
+
+/**
+ * A ClassFile object stores information about a Java class. The class may
+ * be read from a DataInputStream.and written to a DataOutputStream. These
+ * are usually streams from a Java class file or a class file component of a
+ * Jar file.
+ *
+ */
+public class ClassFile {
+
+ /** The Magic Value that marks the start of a Java class file */
+ private static final int CLASS_MAGIC = 0xCAFEBABE;
+
+ /** This class' constant pool. */
+ private ConstantPool constantPool;
+
+ /** The class name for this class. */
+ private String className;
+
+ /**
+ * Read the class from a data stream. This method takes an InputStream
+ * as input and parses the class from the stream. <p>
+ *
+ *
+ *
+ * @param stream an InputStream from which the class will be read
+ * @exception IOException if there is a problem reading from the given
+ * stream.
+ * @exception ClassFormatError if the class cannot be parsed correctly
+ */
+ public void read(InputStream stream) throws IOException, ClassFormatError {
+ DataInputStream classStream = new DataInputStream(stream);
+
+ if (classStream.readInt() != CLASS_MAGIC) {
+ throw new ClassFormatError("No Magic Code Found "
+ + "- probably not a Java class file.");
+ }
+
+ // right we have a good looking class file.
+ /* int minorVersion = */ classStream.readUnsignedShort();
+ /* int majorVersion = */ classStream.readUnsignedShort();
+
+ // read the constant pool in and resolve it
+ constantPool = new ConstantPool();
+
+ constantPool.read(classStream);
+ constantPool.resolve();
+
+ /* int accessFlags = */ classStream.readUnsignedShort();
+ int thisClassIndex = classStream.readUnsignedShort();
+ /* int superClassIndex = */ classStream.readUnsignedShort();
+ ClassCPInfo classInfo
+ = (ClassCPInfo) constantPool.getEntry(thisClassIndex);
+ className = classInfo.getClassName();
+ }
+
+
+ /**
+ * Get the classes which this class references.
+ *
+ * @return a vector of class names which this class references
+ */
+ public Vector<String> getClassRefs() {
+
+ Vector<String> classRefs = new Vector<String>();
+
+ final int size = constantPool.size();
+ for (int i = 0; i < size; ++i) {
+ ConstantPoolEntry entry = constantPool.getEntry(i);
+
+ if (entry != null
+ && entry.getTag() == ConstantPoolEntry.CONSTANT_CLASS) {
+ ClassCPInfo classEntry = (ClassCPInfo) entry;
+
+ if (!classEntry.getClassName().equals(className)) {
+ classRefs.add(
+ ClassFileUtils.convertSlashName(classEntry.getClassName()));
+ }
+ }
+ }
+
+ return classRefs;
+ }
+
+ /**
+ * Get the class' fully qualified name in dot format.
+ *
+ * @return the class name in dot format (eg. java.lang.Object)
+ */
+ public String getFullClassName() {
+ return ClassFileUtils.convertSlashName(className);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java
new file mode 100644
index 00000000..92fc191b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+/**
+ * Iterator interface for iterating over a set of class files
+ *
+ */
+public interface ClassFileIterator {
+
+ /**
+ * Get the next class file in the iteration
+ *
+ * @return the next class file in the iteration
+ */
+ ClassFile getNextClassFile();
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java
new file mode 100644
index 00000000..c6eec6cc
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+/**
+ * Utility class file routines. This class provides a number of static
+ * utility methods to convert between the formats used in the Java class
+ * file format and those commonly used in Java programming.
+ *
+ *
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class ClassFileUtils {
+
+ /**
+ * Convert a class name from class file slash notation to java source
+ * file dot notation.
+ *
+ * @param name the class name in slash notation org/apache/ant
+ * @return the class name in dot notation (eg. java.lang.Object).
+ */
+ public static String convertSlashName(String name) {
+ return name.replace('\\', '.').replace('/', '.');
+ }
+
+ /**
+ * Convert a class name from java source file dot notation to class file
+ * slash notation..
+ *
+ * @param dotName the class name in dot notation (eg. java.lang.Object).
+ * @return the class name in slash notation (eg. java/lang/Object).
+ */
+ public static String convertDotName(String dotName) {
+ return dotName.replace('.', '/');
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java
new file mode 100644
index 00000000..cc65129f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java
@@ -0,0 +1,917 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.rmic.DefaultRmicAdapter;
+import org.apache.tools.ant.taskdefs.rmic.WLRmic;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
+
+/**
+ * Generates a dependency file for a given set of classes.
+ *
+ */
+public class Depend extends MatchingTask {
+ private static final int ONE_SECOND = 1000;
+
+ /**
+ * A class (struct) user to manage information about a class
+ *
+ */
+ private static class ClassFileInfo {
+ /** The file where the class file is stored in the file system */
+ private File absoluteFile;
+
+ /** The Java class name of this class */
+ private String className;
+
+ /** The source File containing this class */
+ private File sourceFile;
+
+ /** if user has been warned about this file not having a source file */
+ private boolean isUserWarned = false;
+ }
+
+ /** The path where source files exist */
+ private Path srcPath;
+
+ /** The path where compiled class files exist. */
+ private Path destPath;
+
+ /** The directory which contains the dependency cache. */
+ private File cache;
+
+ /** The list of source paths derived from the srcPath field. */
+ private String[] srcPathList;
+
+ /**
+ * A map which gives for every class a list of the class which it
+ * affects.
+ */
+ private Hashtable affectedClassMap;
+
+ /** A map which gives information about a class */
+ private Hashtable classFileInfoMap;
+
+ /**
+ * A map which gives the list of jars and classes from the classpath
+ * that a class depends upon
+ */
+ private Hashtable classpathDependencies;
+
+ /** The list of classes which are out of date. */
+ private Hashtable outOfDateClasses;
+
+ /**
+ * indicates that the dependency relationships should be extended beyond
+ * direct dependencies to include all classes. So if A directly affects
+ * B and B directly affects C, then A indirectly affects C.
+ */
+ private boolean closure = false;
+
+ /**
+ * flag to enable warning if we encounter RMI stubs
+ */
+ private boolean warnOnRmiStubs = true;
+
+ /**
+ * Flag which controls whether the reversed dependencies should be
+ * dumped to the log
+ */
+ private boolean dump = false;
+
+ /** The classpath to look for additional dependencies */
+ private Path dependClasspath;
+
+ /** constants used with the cache file */
+ private static final String CACHE_FILE_NAME = "dependencies.txt";
+ /** String Used to separate classnames in the dependency file */
+ private static final String CLASSNAME_PREPEND = "||:";
+
+ /**
+ * Set the classpath to be used for this dependency check.
+ *
+ * @param classpath the classpath to be used when checking for
+ * dependencies on elements in the classpath
+ */
+ public void setClasspath(Path classpath) {
+ if (dependClasspath == null) {
+ dependClasspath = classpath;
+ } else {
+ dependClasspath.append(classpath);
+ }
+ }
+
+ /**
+ * Gets the classpath to be used for this dependency check.
+ *
+ * @return the current dependency classpath
+ */
+ public Path getClasspath() {
+ return dependClasspath;
+ }
+
+ /**
+ * Adds a classpath to be used for this dependency check.
+ *
+ * @return A path object to be configured by Ant
+ */
+ public Path createClasspath() {
+ if (dependClasspath == null) {
+ dependClasspath = new Path(getProject());
+ }
+ return dependClasspath.createPath();
+ }
+
+ /**
+ * Adds a reference to a classpath defined elsewhere.
+ *
+ * @param r a reference to a path object to be used as the depend
+ * classpath
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * Flag to set to true if you want dependency issues with RMI
+ * stubs to appear at warning level.
+ * @param warnOnRmiStubs if true set dependency issues to appear at warning level.
+ * @since Ant1.7
+ */
+ public void setWarnOnRmiStubs(boolean warnOnRmiStubs) {
+ this.warnOnRmiStubs = warnOnRmiStubs;
+ }
+
+ /**
+ * Read the dependencies from cache file
+ *
+ * @return a collection of class dependencies
+ * @exception IOException if the dependency file cannot be read
+ */
+ private Hashtable readCachedDependencies(File depFile) throws IOException {
+ Hashtable dependencyMap = new Hashtable();
+
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new FileReader(depFile));
+ String line = null;
+ Vector dependencyList = null;
+ String className = null;
+ int prependLength = CLASSNAME_PREPEND.length();
+ while ((line = in.readLine()) != null) {
+ if (line.startsWith(CLASSNAME_PREPEND)) {
+ dependencyList = new Vector();
+ className = line.substring(prependLength);
+ dependencyMap.put(className, dependencyList);
+ } else {
+ dependencyList.addElement(line);
+ }
+ }
+ } finally {
+ FileUtils.close(in);
+ }
+
+ return dependencyMap;
+ }
+
+ /**
+ * Write the dependencies to cache file
+ *
+ * @param dependencyMap the map of dependencies to be written out.
+ * @exception IOException if the dependency file cannot be written out.
+ */
+ private void writeCachedDependencies(Hashtable dependencyMap)
+ throws IOException {
+ if (cache != null) {
+ BufferedWriter pw = null;
+ try {
+ cache.mkdirs();
+ File depFile = new File(cache, CACHE_FILE_NAME);
+
+ pw = new BufferedWriter(new FileWriter(depFile));
+ Enumeration e = dependencyMap.keys();
+ while (e.hasMoreElements()) {
+ String className = (String) e.nextElement();
+
+ pw.write(CLASSNAME_PREPEND + className);
+ pw.newLine();
+
+ Vector dependencyList
+ = (Vector) dependencyMap.get(className);
+ int size = dependencyList.size();
+ for (int x = 0; x < size; x++) {
+ pw.write(String.valueOf(dependencyList.elementAt(x)));
+ pw.newLine();
+ }
+ }
+ } finally {
+ FileUtils.close(pw);
+ }
+ }
+ }
+
+ /**
+ * Get the classpath for dependency checking.
+ *
+ * This method removes the dest dirs if it is given from the dependency classpath
+ */
+ private Path getCheckClassPath() {
+ if (dependClasspath == null) {
+ return null;
+ }
+
+ String[] destPathElements = destPath.list();
+ String[] classpathElements = dependClasspath.list();
+ String checkPath = "";
+ for (int i = 0; i < classpathElements.length; ++i) {
+ String element = classpathElements[i];
+ boolean inDestPath = false;
+ for (int j = 0; j < destPathElements.length && !inDestPath; ++j) {
+ inDestPath = destPathElements[j].equals(element);
+ }
+ if (!inDestPath) {
+ if (checkPath.length() == 0) {
+ checkPath = element;
+ } else {
+ checkPath += ":" + element;
+ }
+ }
+ }
+
+ Path p = null;
+ if (checkPath.length() > 0) {
+ p = new Path(getProject(), checkPath);
+ }
+
+ log("Classpath without dest dir is " + p, Project.MSG_DEBUG);
+ return p;
+ }
+
+ /**
+ * Determine the dependencies between classes. Class dependencies are
+ * determined by examining the class references in a class file to other
+ * classes.
+ *
+ * This method sets up the following fields
+ * <ul>
+ * <li>affectedClassMap - the list of classes each class affects</li>
+ * <li>classFileInfoMap - information about each class</li>
+ * <li>classpathDependencies - the list of jars and classes from the
+ * classpath that each class depends upon.</li>
+ * </ul>
+ *
+ * If required, the dependencies are written to the cache.
+ *
+ * @exception IOException if either the dependencies cache or the class
+ * files cannot be read or written
+ */
+ private void determineDependencies() throws IOException {
+ affectedClassMap = new Hashtable();
+ classFileInfoMap = new Hashtable();
+ boolean cacheDirty = false;
+
+ Hashtable dependencyMap = new Hashtable();
+ File cacheFile = null;
+ boolean cacheFileExists = true;
+ long cacheLastModified = Long.MAX_VALUE;
+
+ // read the dependency cache from the disk
+ if (cache != null) {
+ cacheFile = new File(cache, CACHE_FILE_NAME);
+ cacheFileExists = cacheFile.exists();
+ cacheLastModified = cacheFile.lastModified();
+ if (cacheFileExists) {
+ dependencyMap = readCachedDependencies(cacheFile);
+ }
+ }
+ Enumeration classfileEnum = getClassFiles(destPath).elements();
+ while (classfileEnum.hasMoreElements()) {
+ ClassFileInfo info = (ClassFileInfo) classfileEnum.nextElement();
+ log("Adding class info for " + info.className, Project.MSG_DEBUG);
+ classFileInfoMap.put(info.className, info);
+
+ Vector dependencyList = null;
+
+ if (cache != null) {
+ // try to read the dependency info from the map if it is
+ // not out of date
+ if (cacheFileExists
+ && cacheLastModified > info.absoluteFile.lastModified()) {
+ // depFile exists and is newer than the class file
+ // need to get dependency list from the map.
+ dependencyList = (Vector) dependencyMap.get(info.className);
+ }
+ }
+
+ if (dependencyList == null) {
+ // not cached - so need to read directly from the class file
+ DependencyAnalyzer analyzer = new AntAnalyzer();
+ analyzer.addRootClass(info.className);
+ analyzer.addClassPath(destPath);
+ analyzer.setClosure(false);
+ dependencyList = new Vector();
+ Enumeration depEnum = analyzer.getClassDependencies();
+ while (depEnum.hasMoreElements()) {
+ Object o = depEnum.nextElement();
+ dependencyList.addElement(o);
+ log("Class " + info.className + " depends on " + o,
+ Project.MSG_DEBUG);
+ }
+ cacheDirty = true;
+ dependencyMap.put(info.className, dependencyList);
+ }
+
+ // This class depends on each class in the dependency list. For each
+ // one of those, add this class into their affected classes list
+ Enumeration depEnum = dependencyList.elements();
+ while (depEnum.hasMoreElements()) {
+ String dependentClass = (String) depEnum.nextElement();
+
+ Hashtable affectedClasses
+ = (Hashtable) affectedClassMap.get(dependentClass);
+ if (affectedClasses == null) {
+ affectedClasses = new Hashtable();
+ affectedClassMap.put(dependentClass, affectedClasses);
+ }
+
+ affectedClasses.put(info.className, info);
+ log(dependentClass + " affects " + info.className,
+ Project.MSG_DEBUG);
+ }
+ }
+
+ classpathDependencies = null;
+ Path checkPath = getCheckClassPath();
+ if (checkPath != null) {
+ // now determine which jars each class depends upon
+ classpathDependencies = new Hashtable();
+ AntClassLoader loader = null;
+ try {
+ loader = getProject().createClassLoader(checkPath);
+
+ Hashtable classpathFileCache = new Hashtable();
+ Object nullFileMarker = new Object();
+ for (Enumeration e = dependencyMap.keys(); e.hasMoreElements();) {
+ String className = (String) e.nextElement();
+ log("Determining classpath dependencies for " + className,
+ Project.MSG_DEBUG);
+ Vector dependencyList = (Vector) dependencyMap.get(className);
+ Hashtable dependencies = new Hashtable();
+ classpathDependencies.put(className, dependencies);
+ Enumeration e2 = dependencyList.elements();
+ while (e2.hasMoreElements()) {
+ String dependency = (String) e2.nextElement();
+ log("Looking for " + dependency, Project.MSG_DEBUG);
+ Object classpathFileObject
+ = classpathFileCache.get(dependency);
+ if (classpathFileObject == null) {
+ classpathFileObject = nullFileMarker;
+
+ if (!dependency.startsWith("java.")
+ && !dependency.startsWith("javax.")) {
+ URL classURL
+ = loader.getResource(dependency.replace('.', '/') + ".class");
+ log("URL is " + classURL, Project.MSG_DEBUG);
+ if (classURL != null) {
+ if (classURL.getProtocol().equals("jar")) {
+ String jarFilePath = classURL.getFile();
+ int classMarker = jarFilePath.indexOf('!');
+ jarFilePath = jarFilePath.substring(0, classMarker);
+ if (jarFilePath.startsWith("file:")) {
+ classpathFileObject = new File(
+ FileUtils.getFileUtils().fromURI(jarFilePath));
+ } else {
+ throw new IOException(
+ "Bizarre nested path in jar: protocol: "
+ + jarFilePath);
+ }
+ } else if (classURL.getProtocol().equals("file")) {
+ classpathFileObject = new File(
+ FileUtils.getFileUtils()
+ .fromURI(classURL.toExternalForm()));
+ }
+ log("Class " + className
+ + " depends on " + classpathFileObject
+ + " due to " + dependency, Project.MSG_DEBUG);
+ }
+ } else {
+ log("Ignoring base classlib dependency "
+ + dependency, Project.MSG_DEBUG);
+ }
+ classpathFileCache.put(dependency, classpathFileObject);
+ }
+ if (classpathFileObject != nullFileMarker) {
+ // we need to add this jar to the list for this class.
+ File jarFile = (File) classpathFileObject;
+ log("Adding a classpath dependency on " + jarFile,
+ Project.MSG_DEBUG);
+ dependencies.put(jarFile, jarFile);
+ }
+ }
+ }
+ } finally {
+ if (loader != null) {
+ loader.cleanup();
+ }
+ }
+ } else {
+ log("No classpath to check", Project.MSG_DEBUG);
+ }
+
+ // write the dependency cache to the disk
+ if (cache != null && cacheDirty) {
+ writeCachedDependencies(dependencyMap);
+ }
+ }
+
+ /**
+ * Delete all the class files which are out of date, by way of their
+ * dependency on a class which is out of date
+ *
+ * @return the number of files deleted.
+ */
+ private int deleteAllAffectedFiles() {
+ int count = 0;
+ for (Enumeration e = outOfDateClasses.elements(); e.hasMoreElements();) {
+ String className = (String) e.nextElement();
+ count += deleteAffectedFiles(className);
+ ClassFileInfo classInfo
+ = (ClassFileInfo) classFileInfoMap.get(className);
+ if (classInfo != null && classInfo.absoluteFile.exists()) {
+ if (classInfo.sourceFile == null) {
+ warnOutOfDateButNotDeleted(classInfo, className, className);
+ } else {
+ classInfo.absoluteFile.delete();
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Delete all the class files of classes which depend on the given class
+ *
+ * @param className the name of the class whose dependent classes will be
+ * deleted
+ * @return the number of class files removed
+ */
+ private int deleteAffectedFiles(String className) {
+ int count = 0;
+
+ Hashtable affectedClasses = (Hashtable) affectedClassMap.get(className);
+ if (affectedClasses == null) {
+ return count;
+ }
+ for (Enumeration e = affectedClasses.keys(); e.hasMoreElements();) {
+ String affectedClass = (String) e.nextElement();
+ ClassFileInfo affectedClassInfo
+ = (ClassFileInfo) affectedClasses.get(affectedClass);
+
+ if (!affectedClassInfo.absoluteFile.exists()) {
+ continue;
+ }
+
+ if (affectedClassInfo.sourceFile == null) {
+ warnOutOfDateButNotDeleted(affectedClassInfo, affectedClass, className);
+ continue;
+ }
+
+ log("Deleting file " + affectedClassInfo.absoluteFile.getPath()
+ + " since " + className + " out of date", Project.MSG_VERBOSE);
+
+ affectedClassInfo.absoluteFile.delete();
+ count++;
+ if (closure) {
+ count += deleteAffectedFiles(affectedClass);
+ } else {
+ // without closure we may delete an inner class but not the
+ // top level class which would not trigger a recompile.
+
+ if (affectedClass.indexOf("$") == -1) {
+ continue;
+ }
+ // need to delete the main class
+ String topLevelClassName
+ = affectedClass.substring(0, affectedClass.indexOf("$"));
+ log("Top level class = " + topLevelClassName,
+ Project.MSG_VERBOSE);
+ ClassFileInfo topLevelClassInfo
+ = (ClassFileInfo) classFileInfoMap.get(topLevelClassName);
+ if (topLevelClassInfo != null
+ && topLevelClassInfo.absoluteFile.exists()) {
+ log("Deleting file "
+ + topLevelClassInfo.absoluteFile.getPath()
+ + " since one of its inner classes was removed",
+ Project.MSG_VERBOSE);
+ topLevelClassInfo.absoluteFile.delete();
+ count++;
+ if (closure) {
+ count += deleteAffectedFiles(topLevelClassName);
+ }
+ }
+ }
+ }
+ return count;
+ }
+
+ /**
+ * warn when a class is out of date, but not deleted as its source is unknown.
+ * MSG_WARN is the normal level, but we downgrade to MSG_VERBOSE for RMI files
+ * if {@link #warnOnRmiStubs is false}
+ * @param affectedClassInfo info about the affectd class
+ * @param affectedClass the name of the affected .class file
+ * @param className the file that is triggering the out of dateness
+ */
+ private void warnOutOfDateButNotDeleted(
+ ClassFileInfo affectedClassInfo, String affectedClass,
+ String className) {
+ if (affectedClassInfo.isUserWarned) {
+ return;
+ }
+ int level = Project.MSG_WARN;
+ if (!warnOnRmiStubs) {
+ //downgrade warnings on RMI stublike classes, as they are generated
+ //by rmic, so there is no need to tell the user that their source is
+ //missing.
+ if (isRmiStub(affectedClass, className)) {
+ level = Project.MSG_VERBOSE;
+ }
+ }
+ log("The class " + affectedClass + " in file "
+ + affectedClassInfo.absoluteFile.getPath()
+ + " is out of date due to " + className
+ + " but has not been deleted because its source file"
+ + " could not be determined", level);
+ affectedClassInfo.isUserWarned = true;
+ }
+
+ /**
+ * test for being an RMI stub
+ * @param affectedClass class being tested
+ * @param className possible origin of the RMI stub
+ * @return whether the class affectedClass is a RMI stub
+ */
+ private boolean isRmiStub(String affectedClass, String className) {
+ return isStub(affectedClass, className, DefaultRmicAdapter.RMI_STUB_SUFFIX)
+ || isStub(affectedClass, className, DefaultRmicAdapter.RMI_SKEL_SUFFIX)
+ || isStub(affectedClass, className, WLRmic.RMI_STUB_SUFFIX)
+ || isStub(affectedClass, className, WLRmic.RMI_SKEL_SUFFIX);
+ }
+
+ private boolean isStub(String affectedClass, String baseClass, String suffix) {
+ return (baseClass + suffix).equals(affectedClass);
+ }
+
+ /**
+ * Dump the dependency information loaded from the classes to the Ant log
+ */
+ private void dumpDependencies() {
+ log("Reverse Dependency Dump for " + affectedClassMap.size()
+ + " classes:", Project.MSG_DEBUG);
+
+ Enumeration classEnum = affectedClassMap.keys();
+ while (classEnum.hasMoreElements()) {
+ String className = (String) classEnum.nextElement();
+ log(" Class " + className + " affects:", Project.MSG_DEBUG);
+ Hashtable affectedClasses
+ = (Hashtable) affectedClassMap.get(className);
+ Enumeration affectedClassEnum = affectedClasses.keys();
+ while (affectedClassEnum.hasMoreElements()) {
+ String affectedClass = (String) affectedClassEnum.nextElement();
+ ClassFileInfo info
+ = (ClassFileInfo) affectedClasses.get(affectedClass);
+ log(" " + affectedClass + " in "
+ + info.absoluteFile.getPath(), Project.MSG_DEBUG);
+ }
+ }
+
+ if (classpathDependencies != null) {
+ log("Classpath file dependencies (Forward):", Project.MSG_DEBUG);
+
+ Enumeration classpathEnum = classpathDependencies.keys();
+ while (classpathEnum.hasMoreElements()) {
+ String className = (String) classpathEnum.nextElement();
+ log(" Class " + className + " depends on:", Project.MSG_DEBUG);
+ Hashtable dependencies
+ = (Hashtable) classpathDependencies.get(className);
+
+ Enumeration classpathFileEnum = dependencies.elements();
+ while (classpathFileEnum.hasMoreElements()) {
+ File classpathFile = (File) classpathFileEnum.nextElement();
+ log(" " + classpathFile.getPath(), Project.MSG_DEBUG);
+ }
+ }
+ }
+ }
+
+ private void determineOutOfDateClasses() {
+ outOfDateClasses = new Hashtable();
+ for (int i = 0; i < srcPathList.length; i++) {
+ File srcDir = getProject().resolveFile(srcPathList[i]);
+ if (srcDir.exists()) {
+ DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+ String[] files = ds.getIncludedFiles();
+ scanDir(srcDir, files);
+ }
+ }
+
+ // now check classpath file dependencies
+ if (classpathDependencies == null) {
+ return;
+ }
+
+ Enumeration classpathDepsEnum = classpathDependencies.keys();
+ while (classpathDepsEnum.hasMoreElements()) {
+ String className = (String) classpathDepsEnum.nextElement();
+ if (outOfDateClasses.containsKey(className)) {
+ continue;
+ }
+ ClassFileInfo info
+ = (ClassFileInfo) classFileInfoMap.get(className);
+
+ // if we have no info about the class - it may have been deleted already and we
+ // are using cached info.
+ if (info != null) {
+ Hashtable dependencies
+ = (Hashtable) classpathDependencies.get(className);
+ for (Enumeration e2 = dependencies.elements(); e2.hasMoreElements();) {
+ File classpathFile = (File) e2.nextElement();
+ if (classpathFile.lastModified()
+ > info.absoluteFile.lastModified()) {
+ log("Class " + className
+ + " is out of date with respect to "
+ + classpathFile, Project.MSG_DEBUG);
+ outOfDateClasses.put(className, className);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Does the work.
+ *
+ * @exception BuildException Thrown in case of an unrecoverable error.
+ */
+ public void execute() throws BuildException {
+ try {
+ long start = System.currentTimeMillis();
+ if (srcPath == null) {
+ throw new BuildException("srcdir attribute must be set",
+ getLocation());
+ }
+
+ srcPathList = srcPath.list();
+ if (srcPathList.length == 0) {
+ throw new BuildException("srcdir attribute must be non-empty",
+ getLocation());
+ }
+
+ if (destPath == null) {
+ destPath = srcPath;
+ }
+
+ if (cache != null && cache.exists() && !cache.isDirectory()) {
+ throw new BuildException("The cache, if specified, must "
+ + "point to a directory");
+ }
+
+ if (cache != null && !cache.exists()) {
+ cache.mkdirs();
+ }
+
+ determineDependencies();
+ if (dump) {
+ dumpDependencies();
+ }
+ determineOutOfDateClasses();
+ int count = deleteAllAffectedFiles();
+
+ long duration = (System.currentTimeMillis() - start) / ONE_SECOND;
+
+ final int summaryLogLevel;
+ if (count > 0) {
+ summaryLogLevel = Project.MSG_INFO;
+ } else {
+ summaryLogLevel = Project.MSG_DEBUG;
+ }
+
+ log("Deleted " + count + " out of date files in "
+ + duration + " seconds", summaryLogLevel);
+ } catch (Exception e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Scans the directory looking for source files that are newer than
+ * their class files. The results are returned in the class variable
+ * compileList
+ *
+ * @param srcDir the source directory
+ * @param files the names of the files in the source dir which are to be
+ * checked.
+ */
+ protected void scanDir(File srcDir, String[] files) {
+
+ for (int i = 0; i < files.length; i++) {
+ File srcFile = new File(srcDir, files[i]);
+ if (files[i].endsWith(".java")) {
+ String filePath = srcFile.getPath();
+ String className
+ = filePath.substring(srcDir.getPath().length() + 1,
+ filePath.length() - ".java".length());
+ className = ClassFileUtils.convertSlashName(className);
+ ClassFileInfo info
+ = (ClassFileInfo) classFileInfoMap.get(className);
+ if (info == null) {
+ // there was no class file. add this class to the list
+ outOfDateClasses.put(className, className);
+ } else {
+ if (srcFile.lastModified()
+ > info.absoluteFile.lastModified()) {
+ outOfDateClasses.put(className, className);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Get the list of class files we are going to analyse.
+ *
+ * @param classLocations a path structure containing all the directories
+ * where classes can be found.
+ * @return a vector containing the classes to analyse.
+ */
+ private Vector getClassFiles(Path classLocations) {
+ // break the classLocations into its components.
+ String[] classLocationsList = classLocations.list();
+
+ Vector classFileList = new Vector();
+
+ for (int i = 0; i < classLocationsList.length; ++i) {
+ File dir = new File(classLocationsList[i]);
+ if (dir.isDirectory()) {
+ addClassFiles(classFileList, dir, dir);
+ }
+ }
+
+ return classFileList;
+ }
+
+ /**
+ * Find the source file for a given class
+ *
+ * @param classname the classname in slash format.
+ * @param sourceFileKnownToExist if not null, a file already known to exist
+ * (saves call to .exists())
+ */
+ private File findSourceFile(String classname, File sourceFileKnownToExist) {
+ String sourceFilename;
+ int innerIndex = classname.indexOf("$");
+ if (innerIndex != -1) {
+ sourceFilename = classname.substring(0, innerIndex) + ".java";
+ } else {
+ sourceFilename = classname + ".java";
+ }
+
+ // search the various source path entries
+ for (int i = 0; i < srcPathList.length; ++i) {
+ File sourceFile = new File(srcPathList[i], sourceFilename);
+ if (sourceFile.equals(sourceFileKnownToExist) || sourceFile.exists()) {
+ return sourceFile;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add the list of class files from the given directory to the class
+ * file vector, including any subdirectories.
+ *
+ * @param classFileList a list of ClassFileInfo objects for all the
+ * files in the directory tree
+ * @param dir the directory tree to be searched, recursively, for class
+ * files
+ * @param root the root of the source tree. This is used to determine
+ * the absolute class name from the relative position in the
+ * source tree
+ */
+ private void addClassFiles(Vector classFileList, File dir, File root) {
+ String[] filesInDir = dir.list();
+
+ if (filesInDir == null) {
+ return;
+ }
+ int length = filesInDir.length;
+
+ int rootLength = root.getPath().length();
+ File sourceFileKnownToExist = null; // speed optimization
+ for (int i = 0; i < length; ++i) {
+ File file = new File(dir, filesInDir[i]);
+ if (filesInDir[i].endsWith(".class")) {
+ ClassFileInfo info = new ClassFileInfo();
+ info.absoluteFile = file;
+ String relativeName = file.getPath().substring(
+ rootLength + 1,
+ file.getPath().length() - ".class".length());
+ info.className
+ = ClassFileUtils.convertSlashName(relativeName);
+ info.sourceFile = sourceFileKnownToExist = findSourceFile(
+ relativeName, sourceFileKnownToExist);
+ classFileList.addElement(info);
+ } else {
+ addClassFiles(classFileList, file, root);
+ }
+ }
+ }
+
+
+ /**
+ * Set the directories path to find the Java source files.
+ *
+ * @param srcPath the source path
+ */
+ public void setSrcdir(Path srcPath) {
+ this.srcPath = srcPath;
+ }
+
+ /**
+ * Set the destination directory where the compiled Java files exist.
+ *
+ * @param destPath the destination areas where build files are written
+ */
+ public void setDestDir(Path destPath) {
+ this.destPath = destPath;
+ }
+
+ /**
+ * Sets the dependency cache file.
+ *
+ * @param cache the dependency cache file
+ */
+ public void setCache(File cache) {
+ this.cache = cache;
+ }
+
+ /**
+ * If true, transitive dependencies are followed until the
+ * closure of the dependency set if reached.
+ * When not set, the depend task will only follow
+ * direct dependencies between classes.
+ *
+ * @param closure indicate if dependency closure is required.
+ */
+ public void setClosure(boolean closure) {
+ this.closure = closure;
+ }
+
+ /**
+ * If true, the dependency information will be written
+ * to the debug level log.
+ *
+ * @param dump set to true to dump dependency information to the log
+ */
+ public void setDump(boolean dump) {
+ this.dump = dump;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java
new file mode 100644
index 00000000..ebf244a5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * An iterator which iterates through the contents of a java directory. The
+ * iterator should be created with the directory at the root of the Java
+ * namespace.
+ *
+ */
+public class DirectoryIterator implements ClassFileIterator {
+
+ /**
+ * This is a stack of current iterators supporting the depth first
+ * traversal of the directory tree.
+ */
+ private Stack enumStack;
+
+ /**
+ * The current directory iterator. As directories encounter lower level
+ * directories, the current iterator is pushed onto the iterator stack
+ * and a new iterator over the sub directory becomes the current
+ * directory. This implements a depth first traversal of the directory
+ * namespace.
+ */
+ private Enumeration currentEnum;
+
+ /**
+ * Creates a directory iterator. The directory iterator is created to
+ * scan the root directory. If the changeInto flag is given, then the
+ * entries returned will be relative to this directory and not the
+ * current directory.
+ *
+ * @param rootDirectory the root if the directory namespace which is to
+ * be iterated over
+ * @param changeInto if true then the returned entries will be relative
+ * to the rootDirectory and not the current directory.
+ * @exception IOException if there is a problem reading the directory
+ * information.
+ */
+ public DirectoryIterator(File rootDirectory, boolean changeInto)
+ throws IOException {
+ super();
+
+ enumStack = new Stack();
+
+ Vector filesInRoot = getDirectoryEntries(rootDirectory);
+
+ currentEnum = filesInRoot.elements();
+ }
+
+ /**
+ * Get a vector covering all the entries (files and subdirectories in a
+ * directory).
+ *
+ * @param directory the directory to be scanned.
+ * @return a vector containing File objects for each entry in the
+ * directory.
+ */
+ private Vector getDirectoryEntries(File directory) {
+ Vector files = new Vector();
+
+ // File[] filesInDir = directory.listFiles();
+ String[] filesInDir = directory.list();
+
+ if (filesInDir != null) {
+ int length = filesInDir.length;
+
+ for (int i = 0; i < length; ++i) {
+ files.addElement(new File(directory, filesInDir[i]));
+ }
+ }
+
+ return files;
+ }
+
+ /**
+ * Template method to allow subclasses to supply elements for the
+ * iteration. The directory iterator maintains a stack of iterators
+ * covering each level in the directory hierarchy. The current iterator
+ * covers the current directory being scanned. If the next entry in that
+ * directory is a subdirectory, the current iterator is pushed onto the
+ * stack and a new iterator is created for the subdirectory. If the
+ * entry is a file, it is returned as the next element and the iterator
+ * remains valid. If there are no more entries in the current directory,
+ * the topmost iterator on the stack is popped off to become the
+ * current iterator.
+ *
+ * @return the next ClassFile in the iteration.
+ */
+ public ClassFile getNextClassFile() {
+ ClassFile nextElement = null;
+
+ try {
+ while (nextElement == null) {
+ if (currentEnum.hasMoreElements()) {
+ File element = (File) currentEnum.nextElement();
+
+ if (element.isDirectory()) {
+
+ // push the current iterator onto the stack and then
+ // iterate through this directory.
+ enumStack.push(currentEnum);
+
+ Vector files = getDirectoryEntries(element);
+
+ currentEnum = files.elements();
+ } else {
+
+ // we have a file. create a stream for it
+ FileInputStream inFileStream
+ = new FileInputStream(element);
+
+ if (element.getName().endsWith(".class")) {
+
+ // create a data input stream from the jar
+ // input stream
+ ClassFile javaClass = new ClassFile();
+
+ javaClass.read(inFileStream);
+
+ nextElement = javaClass;
+ }
+ }
+ } else {
+ // this iterator is exhausted. Can we pop one off the stack
+ if (enumStack.empty()) {
+ break;
+ } else {
+ currentEnum = (Enumeration) enumStack.pop();
+ }
+ }
+ }
+ } catch (IOException e) {
+ nextElement = null;
+ }
+
+ return nextElement;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java
new file mode 100644
index 00000000..bc315d2e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * A class file iterator which iterates through the contents of a Java jar
+ * file.
+ *
+ */
+public class JarFileIterator implements ClassFileIterator {
+ /** The jar stream from the jar file being iterated over*/
+ private ZipInputStream jarStream;
+
+ /**
+ * Construct an iterator over a jar stream
+ *
+ * @param stream the basic input stream from which the Jar is received
+ * @exception IOException if the jar stream cannot be created
+ */
+ public JarFileIterator(InputStream stream) throws IOException {
+ super();
+
+ jarStream = new ZipInputStream(stream);
+ }
+
+ /**
+ * Get the next ClassFile object from the jar
+ *
+ * @return a ClassFile object describing the class from the jar
+ */
+ public ClassFile getNextClassFile() {
+ ZipEntry jarEntry;
+ ClassFile nextElement = null;
+
+ try {
+ jarEntry = jarStream.getNextEntry();
+
+ while (nextElement == null && jarEntry != null) {
+ String entryName = jarEntry.getName();
+
+ if (!jarEntry.isDirectory() && entryName.endsWith(".class")) {
+
+ // create a data input stream from the jar input stream
+ ClassFile javaClass = new ClassFile();
+
+ javaClass.read(jarStream);
+
+ nextElement = javaClass;
+ } else {
+
+ jarEntry = jarStream.getNextEntry();
+ }
+ }
+ } catch (IOException e) {
+ String message = e.getMessage();
+ String text = e.getClass().getName();
+
+ if (message != null) {
+ text += ": " + message;
+ }
+
+ throw new RuntimeException("Problem reading JAR file: " + text);
+ }
+
+ return nextElement;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java
new file mode 100644
index 00000000..8abbfc82
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The constant pool entry which stores class information.
+ *
+ */
+public class ClassCPInfo extends ConstantPoolEntry {
+
+ /**
+ * The class' name. This will be only valid if the entry has been
+ * resolved against the constant pool.
+ */
+ private String className;
+
+ /**
+ * The index into the constant pool where this class' name is stored. If
+ * the class name is changed, this entry is invalid until this entry is
+ * connected to a constant pool.
+ */
+ private int index;
+
+ /**
+ * Constructor. Sets the tag value for this entry to type Class
+ */
+ public ClassCPInfo() {
+ super(CONSTANT_CLASS, 1);
+ }
+
+ /**
+ * Read the entry from a stream.
+ *
+ * @param cpStream the stream containing the constant pool entry to be
+ * read.
+ * @exception IOException thrown if there is a problem reading the entry
+ * from the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ index = cpStream.readUnsignedShort();
+ className = "unresolved";
+ }
+
+ /**
+ * Generate a string readable version of this entry
+ *
+ * @return string representation of this constant pool entry
+ */
+ public String toString() {
+ return "Class Constant Pool Entry for " + className + "[" + index + "]";
+ }
+
+ /**
+ * Resolve this class info against the given constant pool.
+ *
+ * @param constantPool the constant pool with which to resolve the
+ * class.
+ */
+ public void resolve(ConstantPool constantPool) {
+ className = ((Utf8CPInfo) constantPool.getEntry(index)).getValue();
+
+ super.resolve(constantPool);
+ }
+
+ /**
+ * Get the class name of this entry.
+ *
+ * @return the class' name.
+ */
+ public String getClassName() {
+ return className;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java
new file mode 100644
index 00000000..6103422e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+/**
+ * A Constant Pool entry which represents a constant value.
+ *
+ */
+public abstract class ConstantCPInfo extends ConstantPoolEntry {
+
+ /**
+ * The entry's untyped value. Each subclass interprets the constant
+ * value based on the subclass's type. The value here must be
+ * compatible.
+ */
+ private Object value;
+
+ /**
+ * Initialise the constant entry.
+ *
+ * @param tagValue the constant pool entry type to be used.
+ * @param entries the number of constant pool entry slots occupied by
+ * this entry.
+ */
+ protected ConstantCPInfo(int tagValue, int entries) {
+ super(tagValue, entries);
+ }
+
+ /**
+ * Get the value of the constant.
+ *
+ * @return the value of the constant (untyped).
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Set the constant value.
+ *
+ * @param newValue the new untyped value of this constant.
+ */
+ public void setValue(Object newValue) {
+ value = newValue;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java
new file mode 100644
index 00000000..67d366b8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java
@@ -0,0 +1,358 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The constant pool of a Java class. The constant pool is a collection of
+ * constants used in a Java class file. It stores strings, constant values,
+ * class names, method names, field names etc.
+ *
+ * @see <a href="http://java.sun.com/docs/books/vmspec/">The Java Virtual
+ * Machine Specification</a>
+ */
+public class ConstantPool {
+
+ /** The entries in the constant pool. */
+ private final List<ConstantPoolEntry> entries = new ArrayList<ConstantPoolEntry>();
+
+ /**
+ * A Hashtable of UTF8 entries - used to get constant pool indexes of
+ * the UTF8 values quickly
+ */
+ private final Map<String, Integer> utf8Indexes = new HashMap<String, Integer>();
+
+ /** Initialise the constant pool. */
+ public ConstantPool() {
+ // The zero index is never present in the constant pool itself so
+ // we add a null entry for it
+ entries.add(null);
+ }
+
+ /**
+ * Read the constant pool from a class input stream.
+ *
+ * @param classStream the DataInputStream of a class file.
+ * @exception IOException if there is a problem reading the constant pool
+ * from the stream
+ */
+ public void read(DataInputStream classStream) throws IOException {
+ int numEntries = classStream.readUnsignedShort();
+
+ for (int i = 1; i < numEntries;) {
+ ConstantPoolEntry nextEntry
+ = ConstantPoolEntry.readEntry(classStream);
+
+ i += nextEntry.getNumEntries();
+
+ addEntry(nextEntry);
+ }
+ }
+
+ /**
+ * Get the size of the constant pool.
+ *
+ * @return the size of the constant pool
+ */
+ public int size() {
+ return entries.size();
+ }
+
+ /**
+ * Add an entry to the constant pool.
+ *
+ * @param entry the new entry to be added to the constant pool.
+ * @return the index into the constant pool at which the entry is
+ * stored.
+ */
+ public int addEntry(ConstantPoolEntry entry) {
+ int index = entries.size();
+
+ entries.add(entry);
+
+ int numSlots = entry.getNumEntries();
+
+ // add null entries for any additional slots required.
+ for (int j = 0; j < numSlots - 1; ++j) {
+ entries.add(null);
+ }
+
+ if (entry instanceof Utf8CPInfo) {
+ Utf8CPInfo utf8Info = (Utf8CPInfo) entry;
+
+ utf8Indexes.put(utf8Info.getValue(), new Integer(index));
+ }
+
+ return index;
+ }
+
+ /**
+ * Resolve the entries in the constant pool. Resolution of the constant
+ * pool involves transforming indexes to other constant pool entries
+ * into the actual data for that entry.
+ */
+ public void resolve() {
+ for (ConstantPoolEntry poolInfo : entries) {
+ if (poolInfo != null && !poolInfo.isResolved()) {
+ poolInfo.resolve(this);
+ }
+ }
+ }
+
+
+ /**
+ * Get an constant pool entry at a particular index.
+ *
+ * @param index the index into the constant pool.
+ * @return the constant pool entry at that index.
+ */
+ public ConstantPoolEntry getEntry(int index) {
+ return entries.get(index);
+ }
+
+ /**
+ * Get the index of a given UTF8 constant pool entry.
+ *
+ * @param value the string value of the UTF8 entry.
+ * @return the index at which the given string occurs in the constant
+ * pool or -1 if the value does not occur.
+ */
+ public int getUTF8Entry(String value) {
+ int index = -1;
+ Integer indexInteger = utf8Indexes.get(value);
+
+ if (indexInteger != null) {
+ index = indexInteger.intValue();
+ }
+
+ return index;
+ }
+
+ /**
+ * Get the index of a given CONSTANT_CLASS entry in the constant pool.
+ *
+ * @param className the name of the class for which the class entry
+ * index is required.
+ * @return the index at which the given class entry occurs in the
+ * constant pool or -1 if the value does not occur.
+ */
+ public int getClassEntry(String className) {
+ int index = -1;
+
+ final int size = entries.size();
+ for (int i = 0; i < size && index == -1; ++i) {
+ Object element = entries.get(i);
+
+ if (element instanceof ClassCPInfo) {
+ ClassCPInfo classinfo = (ClassCPInfo) element;
+
+ if (classinfo.getClassName().equals(className)) {
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Get the index of a given constant value entry in the constant pool.
+ *
+ * @param constantValue the constant value for which the index is
+ * required.
+ * @return the index at which the given value entry occurs in the
+ * constant pool or -1 if the value does not occur.
+ */
+ public int getConstantEntry(Object constantValue) {
+ int index = -1;
+
+ final int size = entries.size();
+ for (int i = 0; i < size && index == -1; ++i) {
+ Object element = entries.get(i);
+
+ if (element instanceof ConstantCPInfo) {
+ ConstantCPInfo constantEntry = (ConstantCPInfo) element;
+
+ if (constantEntry.getValue().equals(constantValue)) {
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Get the index of a given CONSTANT_METHODREF entry in the constant
+ * pool.
+ *
+ * @param methodClassName the name of the class which contains the
+ * method being referenced.
+ * @param methodName the name of the method being referenced.
+ * @param methodType the type descriptor of the method being referenced.
+ * @return the index at which the given method ref entry occurs in the
+ * constant pool or -1 if the value does not occur.
+ */
+ public int getMethodRefEntry(String methodClassName, String methodName,
+ String methodType) {
+ int index = -1;
+
+ final int size = entries.size();
+ for (int i = 0; i < size && index == -1; ++i) {
+ Object element = entries.get(i);
+
+ if (element instanceof MethodRefCPInfo) {
+ MethodRefCPInfo methodRefEntry = (MethodRefCPInfo) element;
+
+ if (methodRefEntry.getMethodClassName().equals(methodClassName)
+ && methodRefEntry.getMethodName().equals(methodName)
+ && methodRefEntry.getMethodType().equals(methodType)) {
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Get the index of a given CONSTANT_INTERFACEMETHODREF entry in the
+ * constant pool.
+ *
+ * @param interfaceMethodClassName the name of the interface which
+ * contains the method being referenced.
+ * @param interfaceMethodName the name of the method being referenced.
+ * @param interfaceMethodType the type descriptor of the method being
+ * referenced.
+ * @return the index at which the given method ref entry occurs in the
+ * constant pool or -1 if the value does not occur.
+ */
+ public int getInterfaceMethodRefEntry(String interfaceMethodClassName,
+ String interfaceMethodName,
+ String interfaceMethodType) {
+ int index = -1;
+
+ final int size = entries.size();
+ for (int i = 0; i < size && index == -1; ++i) {
+ Object element = entries.get(i);
+
+ if (element instanceof InterfaceMethodRefCPInfo) {
+ InterfaceMethodRefCPInfo interfaceMethodRefEntry
+ = (InterfaceMethodRefCPInfo) element;
+
+ if (interfaceMethodRefEntry.getInterfaceMethodClassName().equals(
+ interfaceMethodClassName)
+ && interfaceMethodRefEntry.getInterfaceMethodName().equals(
+ interfaceMethodName)
+ && interfaceMethodRefEntry.getInterfaceMethodType().equals(
+ interfaceMethodType)) {
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Get the index of a given CONSTANT_FIELDREF entry in the constant
+ * pool.
+ *
+ * @param fieldClassName the name of the class which contains the field
+ * being referenced.
+ * @param fieldName the name of the field being referenced.
+ * @param fieldType the type descriptor of the field being referenced.
+ * @return the index at which the given field ref entry occurs in the
+ * constant pool or -1 if the value does not occur.
+ */
+ public int getFieldRefEntry(String fieldClassName, String fieldName,
+ String fieldType) {
+ int index = -1;
+
+ final int size = entries.size();
+ for (int i = 0; i < size && index == -1; ++i) {
+ Object element = entries.get(i);
+
+ if (element instanceof FieldRefCPInfo) {
+ FieldRefCPInfo fieldRefEntry = (FieldRefCPInfo) element;
+
+ if (fieldRefEntry.getFieldClassName().equals(fieldClassName)
+ && fieldRefEntry.getFieldName().equals(fieldName)
+ && fieldRefEntry.getFieldType().equals(fieldType)) {
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Get the index of a given CONSTANT_NAMEANDTYPE entry in the constant
+ * pool.
+ *
+ * @param name the name
+ * @param type the type
+ * @return the index at which the given NameAndType entry occurs in the
+ * constant pool or -1 if the value does not occur.
+ */
+ public int getNameAndTypeEntry(String name, String type) {
+ int index = -1;
+
+ final int size = entries.size();
+ for (int i = 0; i < size && index == -1; ++i) {
+ Object element = entries.get(i);
+
+ if (element instanceof NameAndTypeCPInfo) {
+ NameAndTypeCPInfo nameAndTypeEntry
+ = (NameAndTypeCPInfo) element;
+
+ if (nameAndTypeEntry.getName().equals(name)
+ && nameAndTypeEntry.getType().equals(type)) {
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Dump the constant pool to a string.
+ *
+ * @return the constant pool entries as strings
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder("\n");
+ final int size = entries.size();
+
+ for (int i = 0; i < size; ++i) {
+ sb.append("[" + i + "] = " + getEntry(i) + "\n");
+ }
+
+ return sb.toString();
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java
new file mode 100644
index 00000000..26a0d094
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * An entry in the constant pool. This class contains a representation of the
+ * constant pool entries. It is an abstract base class for all the different
+ * forms of constant pool entry.
+ *
+ * @see ConstantPool
+ */
+public abstract class ConstantPoolEntry {
+
+ /** Tag value for UTF8 entries. */
+ public static final int CONSTANT_UTF8 = 1;
+
+ /** Tag value for Integer entries. */
+ public static final int CONSTANT_INTEGER = 3;
+
+ /** Tag value for Float entries. */
+ public static final int CONSTANT_FLOAT = 4;
+
+ /** Tag value for Long entries. */
+ public static final int CONSTANT_LONG = 5;
+
+ /** Tag value for Double entries. */
+ public static final int CONSTANT_DOUBLE = 6;
+
+ /** Tag value for Class entries. */
+ public static final int CONSTANT_CLASS = 7;
+
+ /** Tag value for String entries. */
+ public static final int CONSTANT_STRING = 8;
+
+ /** Tag value for Field Reference entries. */
+ public static final int CONSTANT_FIELDREF = 9;
+
+ /** Tag value for Method Reference entries. */
+ public static final int CONSTANT_METHODREF = 10;
+
+ /** Tag value for Interface Method Reference entries. */
+ public static final int CONSTANT_INTERFACEMETHODREF = 11;
+
+ /** Tag value for Name and Type entries. */
+ public static final int CONSTANT_NAMEANDTYPE = 12;
+
+ /** Tag value for Method Handle entries */
+ public static final int CONSTANT_METHODHANDLE = 15;
+
+ /** Tag value for Method Type entries */
+ public static final int CONSTANT_METHODTYPE = 16;
+
+ /** Tag value for InvokeDynamic entries*/
+ public static final int CONSTANT_INVOKEDYNAMIC = 18;
+
+ /**
+ * This entry's tag which identifies the type of this constant pool
+ * entry.
+ */
+ private int tag;
+
+ /**
+ * The number of slots in the constant pool, occupied by this entry.
+ */
+ private int numEntries;
+
+ /**
+ * A flag which indicates if this entry has been resolved or not.
+ */
+ private boolean resolved;
+
+ /**
+ * Initialise the constant pool entry.
+ *
+ * @param tagValue the tag value which identifies which type of constant
+ * pool entry this is.
+ * @param entries the number of constant pool entry slots this entry
+ * occupies.
+ */
+ public ConstantPoolEntry(int tagValue, int entries) {
+ tag = tagValue;
+ numEntries = entries;
+ resolved = false;
+ }
+
+ /**
+ * Read a constant pool entry from a stream. This is a factory method
+ * which reads a constant pool entry form a stream and returns the
+ * appropriate subclass for the entry.
+ *
+ * @param cpStream the stream from which the constant pool entry is to
+ * be read.
+ * @return the appropriate ConstantPoolEntry subclass representing the
+ * constant pool entry from the stream.
+ * @exception IOException if the constant pool entry cannot be read
+ * from the stream
+ */
+ public static ConstantPoolEntry readEntry(DataInputStream cpStream)
+ throws IOException {
+ ConstantPoolEntry cpInfo = null;
+ int cpTag = cpStream.readUnsignedByte();
+
+ switch (cpTag) {
+
+ case CONSTANT_UTF8:
+ cpInfo = new Utf8CPInfo();
+
+ break;
+ case CONSTANT_INTEGER:
+ cpInfo = new IntegerCPInfo();
+
+ break;
+ case CONSTANT_FLOAT:
+ cpInfo = new FloatCPInfo();
+
+ break;
+ case CONSTANT_LONG:
+ cpInfo = new LongCPInfo();
+
+ break;
+ case CONSTANT_DOUBLE:
+ cpInfo = new DoubleCPInfo();
+
+ break;
+ case CONSTANT_CLASS:
+ cpInfo = new ClassCPInfo();
+
+ break;
+ case CONSTANT_STRING:
+ cpInfo = new StringCPInfo();
+
+ break;
+ case CONSTANT_FIELDREF:
+ cpInfo = new FieldRefCPInfo();
+
+ break;
+ case CONSTANT_METHODREF:
+ cpInfo = new MethodRefCPInfo();
+
+ break;
+ case CONSTANT_INTERFACEMETHODREF:
+ cpInfo = new InterfaceMethodRefCPInfo();
+
+ break;
+ case CONSTANT_NAMEANDTYPE:
+ cpInfo = new NameAndTypeCPInfo();
+
+ break;
+ case CONSTANT_METHODHANDLE:
+ cpInfo = new MethodHandleCPInfo();
+
+ break;
+ case CONSTANT_METHODTYPE:
+ cpInfo = new MethodTypeCPInfo();
+
+ break;
+ case CONSTANT_INVOKEDYNAMIC:
+ cpInfo = new InvokeDynamicCPInfo();
+
+ break;
+ default:
+ throw new ClassFormatError("Invalid Constant Pool entry Type "
+ + cpTag);
+ }
+
+ cpInfo.read(cpStream);
+
+ return cpInfo;
+ }
+
+ /**
+ * Indicates whether this entry has been resolved. In general a constant
+ * pool entry can reference another constant pool entry by its index
+ * value. Resolution involves replacing this index value with the
+ * constant pool entry at that index.
+ *
+ * @return true if this entry has been resolved.
+ */
+ public boolean isResolved() {
+ return resolved;
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ resolved = true;
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public abstract void read(DataInputStream cpStream) throws IOException;
+
+ /**
+ * Get the Entry's type tag.
+ *
+ * @return The Tag value of this entry
+ */
+ public int getTag() {
+ return tag;
+ }
+
+ /**
+ * Get the number of Constant Pool Entry slots within the constant pool
+ * occupied by this entry.
+ *
+ * @return the number of slots used.
+ */
+ public final int getNumEntries() {
+ return numEntries;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java
new file mode 100644
index 00000000..a21c0d66
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The constant pool entry subclass used to represent double constant
+ * values.
+ *
+ */
+public class DoubleCPInfo extends ConstantCPInfo {
+ /**
+ * Constructor
+ */
+ public DoubleCPInfo() {
+ super(CONSTANT_DOUBLE, 2);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from the
+ * stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ setValue(new Double(cpStream.readDouble()));
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ return "Double Constant Pool Entry: " + getValue();
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java
new file mode 100644
index 00000000..06c0925d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A FieldRef CP Info
+ *
+ */
+public class FieldRefCPInfo extends ConstantPoolEntry {
+ /** Name of the field's class */
+ private String fieldClassName;
+ /** name of the field in that class */
+ private String fieldName;
+ /** The type of the field */
+ private String fieldType;
+ /** Index into the constant pool for the class */
+ private int classIndex;
+ /** Index into the constant pool for the name and type entry */
+ private int nameAndTypeIndex;
+
+ /** Constructor. */
+ public FieldRefCPInfo() {
+ super(CONSTANT_FIELDREF, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ classIndex = cpStream.readUnsignedShort();
+ nameAndTypeIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ ClassCPInfo fieldClass
+ = (ClassCPInfo) constantPool.getEntry(classIndex);
+
+ fieldClass.resolve(constantPool);
+
+ fieldClassName = fieldClass.getClassName();
+
+ NameAndTypeCPInfo nt
+ = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+
+ nt.resolve(constantPool);
+
+ fieldName = nt.getName();
+ fieldType = nt.getType();
+
+ super.resolve(constantPool);
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ String value;
+
+ if (isResolved()) {
+ value = "Field : Class = " + fieldClassName + ", name = "
+ + fieldName + ", type = " + fieldType;
+ } else {
+ value = "Field : Class index = " + classIndex
+ + ", name and type index = " + nameAndTypeIndex;
+ }
+
+ return value;
+ }
+
+ /**
+ * Gets the name of the class defining the field
+ *
+ * @return the name of the class defining the field
+ */
+ public String getFieldClassName() {
+ return fieldClassName;
+ }
+
+ /**
+ * Get the name of the field
+ *
+ * @return the field's name
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ /**
+ * Get the type of the field
+ *
+ * @return the field's type in string format
+ */
+ public String getFieldType() {
+ return fieldType;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java
new file mode 100644
index 00000000..532b6725
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A Float CP Info
+ *
+ */
+public class FloatCPInfo extends ConstantCPInfo {
+
+ /** Constructor. */
+ public FloatCPInfo() {
+ super(CONSTANT_FLOAT, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ setValue(new Float(cpStream.readFloat()));
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ return "Float Constant Pool Entry: " + getValue();
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java
new file mode 100644
index 00000000..3beaa8cd
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * An Integer CP Info
+ *
+ */
+public class IntegerCPInfo extends ConstantCPInfo {
+
+ /** Constructor. */
+ public IntegerCPInfo() {
+ super(CONSTANT_INTEGER, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ setValue(new Integer(cpStream.readInt()));
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ return "Integer Constant Pool Entry: " + getValue();
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java
new file mode 100644
index 00000000..fbc23c1c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A InterfaceMethodRef CP Info
+ *
+ */
+public class InterfaceMethodRefCPInfo extends ConstantPoolEntry {
+ /** the class name of the class defining the interface method */
+ private String interfaceMethodClassName;
+ /** the name of the interface nmethod */
+ private String interfaceMethodName;
+ /** the method signature of the interface method */
+ private String interfaceMethodType;
+ /**
+ * the index into the constant pool of the class entry for the interface
+ * class
+ */
+ private int classIndex;
+ /**
+ * the index into the constant pool of the name and type entry
+ * describing the method
+ */
+ private int nameAndTypeIndex;
+
+ /** Constructor. */
+ public InterfaceMethodRefCPInfo() {
+ super(CONSTANT_INTERFACEMETHODREF, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ classIndex = cpStream.readUnsignedShort();
+ nameAndTypeIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ ClassCPInfo interfaceMethodClass
+ = (ClassCPInfo) constantPool.getEntry(classIndex);
+
+ interfaceMethodClass.resolve(constantPool);
+
+ interfaceMethodClassName = interfaceMethodClass.getClassName();
+
+ NameAndTypeCPInfo nt
+ = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+
+ nt.resolve(constantPool);
+
+ interfaceMethodName = nt.getName();
+ interfaceMethodType = nt.getType();
+
+ super.resolve(constantPool);
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ String value;
+
+ if (isResolved()) {
+ value = "InterfaceMethod : Class = " + interfaceMethodClassName
+ + ", name = " + interfaceMethodName + ", type = "
+ + interfaceMethodType;
+ } else {
+ value = "InterfaceMethod : Class index = " + classIndex
+ + ", name and type index = " + nameAndTypeIndex;
+ }
+
+ return value;
+ }
+
+ /**
+ * Gets the name of the class defining the interface method
+ *
+ * @return the name of the class defining the interface method
+ */
+ public String getInterfaceMethodClassName() {
+ return interfaceMethodClassName;
+ }
+
+ /**
+ * Get the name of the interface method
+ *
+ * @return the name of the interface method
+ */
+ public String getInterfaceMethodName() {
+ return interfaceMethodName;
+ }
+
+ /**
+ * Gets the type of the interface method
+ *
+ * @return the interface method's type signature
+ */
+ public String getInterfaceMethodType() {
+ return interfaceMethodType;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InvokeDynamicCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InvokeDynamicCPInfo.java
new file mode 100644
index 00000000..3795db75
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InvokeDynamicCPInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * An InvokeDynamic CP Info
+ *
+ */
+public class InvokeDynamicCPInfo extends ConstantCPInfo {
+
+ /** Index into the bootstrap methods for the class */
+ private int bootstrapMethodAttrIndex;
+ /** the value of the method descriptor pointed to */
+ private int nameAndTypeIndex;
+ /** the name and type CP info pointed to */
+ private NameAndTypeCPInfo nameAndTypeCPInfo;
+ /** */
+ /** Constructor. */
+ public InvokeDynamicCPInfo() {
+ super(CONSTANT_INVOKEDYNAMIC, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception java.io.IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ bootstrapMethodAttrIndex = cpStream.readUnsignedShort();
+ nameAndTypeIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ String value;
+ if (isResolved()) {
+ value = "Name = " + nameAndTypeCPInfo.getName() + ", type = " + nameAndTypeCPInfo.getType();
+ } else {
+ value = "BootstrapMethodAttrIndex inx = " + bootstrapMethodAttrIndex
+ + "NameAndType index = " + nameAndTypeIndex;
+ }
+
+ return value;
+ }
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ nameAndTypeCPInfo
+ = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+ nameAndTypeCPInfo.resolve(constantPool);
+ super.resolve(constantPool);
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java
new file mode 100644
index 00000000..e854f04f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A Long CP Info
+ *
+ */
+public class LongCPInfo extends ConstantCPInfo {
+
+ /** Constructor. */
+ public LongCPInfo() {
+ super(CONSTANT_LONG, 2);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ setValue(new Long(cpStream.readLong()));
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ return "Long Constant Pool Entry: " + getValue();
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodHandleCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodHandleCPInfo.java
new file mode 100644
index 00000000..e11e3aab
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodHandleCPInfo.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A MethodHandle CP Info
+ *
+ */
+public class MethodHandleCPInfo extends ConstantPoolEntry {
+ private ConstantPoolEntry reference;
+
+ /** reference kind **/
+ private ReferenceKind referenceKind;
+ /** Must be a valid index into the constant pool tabel. */
+ private int referenceIndex;
+ /**
+ * the index into the constant pool which defined the name and type
+ * signature of the method
+ */
+ private int nameAndTypeIndex;
+ public enum ReferenceKind {
+ REF_getField(1),
+ REF_getStatic(2),
+ REF_putField(3),
+ REF_putStatic(4),
+ REF_invokeVirtual(5),
+ REF_invokeStatic(6),
+ REF_invokeSpecial(7),
+ REF_newInvokeSpecial(8),
+ REF_invokeInterface(9);
+ private final int referenceKind;
+ ReferenceKind(int referenceKind) {
+ this.referenceKind = referenceKind;
+ }
+
+ }
+ /** Constructor. */
+ public MethodHandleCPInfo() {
+ super(CONSTANT_METHODHANDLE, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception java.io.IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ referenceKind = ReferenceKind.values()[cpStream.readUnsignedByte() - 1];
+
+ referenceIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ String value;
+
+ if (isResolved()) {
+ value = "MethodHandle : " + reference.toString();
+ } else {
+ value = "MethodHandle : Reference kind = " + referenceKind
+ + "Reference index = " + referenceIndex;
+ }
+
+ return value;
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ reference = constantPool.getEntry(referenceIndex);
+ reference.resolve(constantPool);
+ super.resolve(constantPool);
+ }
+
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java
new file mode 100644
index 00000000..6b335212
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A MethodRef CP Info
+ *
+ */
+public class MethodRefCPInfo extends ConstantPoolEntry {
+ /** the name of the class defining this method */
+ private String methodClassName;
+ /** the name of the method */
+ private String methodName;
+ /** the method's type descriptor */
+ private String methodType;
+ /** The index into the constant pool which defines the class of this method. */
+ private int classIndex;
+ /**
+ * the index into the constant pool which defined the name and type
+ * signature of the method
+ */
+ private int nameAndTypeIndex;
+
+ /** Constructor. */
+ public MethodRefCPInfo() {
+ super(CONSTANT_METHODREF, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ classIndex = cpStream.readUnsignedShort();
+ nameAndTypeIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ String value;
+
+ if (isResolved()) {
+ value = "Method : Class = " + methodClassName + ", name = "
+ + methodName + ", type = " + methodType;
+ } else {
+ value = "Method : Class index = " + classIndex
+ + ", name and type index = " + nameAndTypeIndex;
+ }
+
+ return value;
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ ClassCPInfo methodClass
+ = (ClassCPInfo) constantPool.getEntry(classIndex);
+
+ methodClass.resolve(constantPool);
+
+ methodClassName = methodClass.getClassName();
+
+ NameAndTypeCPInfo nt
+ = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+
+ nt.resolve(constantPool);
+
+ methodName = nt.getName();
+ methodType = nt.getType();
+
+ super.resolve(constantPool);
+ }
+
+ /**
+ * Get the name of the class defining the method
+ *
+ * @return the name of the class defining this method
+ */
+ public String getMethodClassName() {
+ return methodClassName;
+ }
+
+ /**
+ * Get the name of the method.
+ *
+ * @return the name of the method.
+ */
+ public String getMethodName() {
+ return methodName;
+ }
+
+ /**
+ * Get the type signature of the method.
+ *
+ * @return the type signature of the method.
+ */
+ public String getMethodType() {
+ return methodType;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodTypeCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodTypeCPInfo.java
new file mode 100644
index 00000000..d3c35cee
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodTypeCPInfo.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A Method Type CP Info
+ *
+ */
+public class MethodTypeCPInfo extends ConstantCPInfo {
+
+ /** Index into the constant pool for the class */
+ private int methodDescriptorIndex;
+ /** the value of the method descriptor pointed to */
+ private String methodDescriptor;
+ /** Constructor. */
+ public MethodTypeCPInfo() {
+ super(CONSTANT_METHODTYPE, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception java.io.IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ @Override
+ public void read(final DataInputStream cpStream) throws IOException {
+ methodDescriptorIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ @Override
+ public void resolve(final ConstantPool constantPool) {
+ final Utf8CPInfo methodClass
+ = (Utf8CPInfo) constantPool.getEntry(methodDescriptorIndex);
+ methodClass.resolve(constantPool);
+ methodDescriptor = methodClass.getValue();
+ super.resolve(constantPool);
+ }
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ @Override
+ public String toString() {
+ if (!isResolved()) {
+ return "MethodDescriptorIndex: " + methodDescriptorIndex;
+ } else {
+ return "MethodDescriptor: " + methodDescriptor;
+
+ }
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java
new file mode 100644
index 00000000..47f454d2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A NameAndType CP Info
+ *
+ */
+public class NameAndTypeCPInfo extends ConstantPoolEntry {
+
+ /** Constructor. */
+ public NameAndTypeCPInfo() {
+ super(CONSTANT_NAMEANDTYPE, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ nameIndex = cpStream.readUnsignedShort();
+ descriptorIndex = cpStream.readUnsignedShort();
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ String value;
+
+ if (isResolved()) {
+ value = "Name = " + name + ", type = " + type;
+ } else {
+ value = "Name index = " + nameIndex
+ + ", descriptor index = " + descriptorIndex;
+ }
+
+ return value;
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ name = ((Utf8CPInfo) constantPool.getEntry(nameIndex)).getValue();
+ type = ((Utf8CPInfo) constantPool.getEntry(descriptorIndex)).getValue();
+
+ super.resolve(constantPool);
+ }
+
+ /**
+ * Get the name component of this entry
+ *
+ * @return the name of this name and type entry
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the type signature of this entry
+ *
+ * @return the type signature of this entry
+ */
+ public String getType() {
+ return type;
+ }
+
+ /** the name component of this entry */
+ private String name;
+ /** the type component of this entry */
+ private String type;
+ /**
+ * the index into the constant pool at which the name component's string
+ * value is stored
+ */
+ private int nameIndex;
+ /**
+ * the index into the constant pool where the type descriptor string is
+ * stored.
+ */
+ private int descriptorIndex;
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java
new file mode 100644
index 00000000..bc9ee24b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A String Constant Pool Entry. The String info contains an index into the
+ * constant pool where a UTF8 string is stored.
+ *
+ */
+public class StringCPInfo extends ConstantCPInfo {
+
+ /** Constructor. */
+ public StringCPInfo() {
+ super(CONSTANT_STRING, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ index = cpStream.readUnsignedShort();
+
+ setValue("unresolved");
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ return "String Constant Pool Entry for "
+ + getValue() + "[" + index + "]";
+ }
+
+ /**
+ * Resolve this constant pool entry with respect to its dependents in
+ * the constant pool.
+ *
+ * @param constantPool the constant pool of which this entry is a member
+ * and against which this entry is to be resolved.
+ */
+ public void resolve(ConstantPool constantPool) {
+ setValue(((Utf8CPInfo) constantPool.getEntry(index)).getValue());
+ super.resolve(constantPool);
+ }
+
+ /** the index into the constant pool containing the string's content */
+ private int index;
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java
new file mode 100644
index 00000000..5471ccde
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A UTF8 Constant Pool Entry.
+ *
+ */
+public class Utf8CPInfo extends ConstantPoolEntry {
+ /** The String value of the UTF-8 entry */
+ private String value;
+
+ /** Constructor. */
+ public Utf8CPInfo() {
+ super(CONSTANT_UTF8, 1);
+ }
+
+ /**
+ * read a constant pool entry from a class stream.
+ *
+ * @param cpStream the DataInputStream which contains the constant pool
+ * entry to be read.
+ * @exception IOException if there is a problem reading the entry from
+ * the stream.
+ */
+ public void read(DataInputStream cpStream) throws IOException {
+ value = cpStream.readUTF();
+ }
+
+ /**
+ * Print a readable version of the constant pool entry.
+ *
+ * @return the string representation of this constant pool entry.
+ */
+ public String toString() {
+ return "UTF8 Value = " + value;
+ }
+
+ /**
+ * Get the string value of the UTF-8 entry
+ *
+ * @return the UTF-8 value as a Java string
+ */
+ public String getValue() {
+ return value;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java
new file mode 100644
index 00000000..4eefaebf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java
@@ -0,0 +1,559 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+
+/**
+ * BorlandDeploymentTool is dedicated to the Borland Application Server 4.5 and 4.5.1
+ * This task generates and compiles the stubs and skeletons for all ejb described into the
+ * Deployment Descriptor, builds the jar file including the support files and verify
+ * whether the produced jar is valid or not.
+ * The supported options are:
+ * <ul>
+ * <li>debug (boolean) : turn on the debug mode for generation of
+ * stubs and skeletons (default:false)</li>
+ * <li>verify (boolean) : turn on the verification at the end of the jar
+ * production (default:true) </li>
+ * <li>verifyargs (String) : add optional argument to verify command
+ * (see vbj com.inprise.ejb.util.Verify)</li>
+ * <li>basdtd (String) : location of the BAS DTD </li>
+ * <li>generateclient (boolean) : turn on the client jar file generation </li>
+ * <li>version (int) : tell what is the Borland appserver version 4 or 5 </li>
+ * </ul>
+ *
+ *<PRE>
+ *
+ * &lt;ejbjar srcdir=&quot;${build.classes}&quot;
+ * basejarname=&quot;vsmp&quot;
+ * descriptordir=&quot;${rsc.dir}/hrmanager&quot;&gt;
+ * &lt;borland destdir=&quot;tstlib&quot;&gt;
+ * &lt;classpath refid=&quot;classpath&quot; /&gt;
+ * &lt;/borland&gt;
+ * &lt;include name=&quot;**\ejb-jar.xml&quot;/&gt;
+ * &lt;support dir=&quot;${build.classes}&quot;&gt;
+ * &lt;include name=&quot;demo\smp\*.class&quot;/&gt;
+ * &lt;include name=&quot;demo\helper\*.class&quot;/&gt;
+ * &lt;/support&gt;
+ * &lt;/ejbjar&gt;
+ *</PRE>
+ *
+ */
+public class BorlandDeploymentTool extends GenericDeploymentTool
+ implements ExecuteStreamHandler {
+ /** Borland 1.1 ejb id */
+ public static final String PUBLICID_BORLAND_EJB
+ = "-//Inprise Corporation//DTD Enterprise JavaBeans 1.1//EN";
+
+ protected static final String DEFAULT_BAS45_EJB11_DTD_LOCATION
+ = "/com/inprise/j2ee/xml/dtds/ejb-jar.dtd";
+
+ protected static final String DEFAULT_BAS_DTD_LOCATION
+ = "/com/inprise/j2ee/xml/dtds/ejb-inprise.dtd";
+
+ protected static final String BAS_DD = "ejb-inprise.xml";
+ protected static final String BES_DD = "ejb-borland.xml";
+
+
+ /** Java2iiop executable **/
+ protected static final String JAVA2IIOP = "java2iiop";
+
+ /** Verify class */
+ protected static final String VERIFY = "com.inprise.ejb.util.Verify";
+
+ /** Instance variable that stores the suffix for the borland jarfile. */
+ private String jarSuffix = "-ejb.jar";
+
+ /** Instance variable that stores the location of the borland DTD file. */
+ private String borlandDTD;
+
+ /** Instance variable that determines whether the debug mode is on */
+ private boolean java2iiopdebug = false;
+
+ /** store additional param for java2iiop command used to build EJB Stubs */
+ private String java2iioparams = null;
+
+ /** Instance variable that determines whether the client jar file is generated */
+ private boolean generateclient = false;
+
+ /** Borland Enterprise Server = version 5 */
+ static final int BES = 5;
+ /** Borland Application Server or Inprise Application Server = version 4 */
+ static final int BAS = 4;
+
+ /** borland appserver version 4 or 5 */
+ private int version = BAS;
+
+
+ /**
+ * Instance variable that determines whether it is necessary to verify the
+ * produced jar
+ */
+ private boolean verify = true;
+ private String verifyArgs = "";
+
+ private Hashtable genfiles = new Hashtable();
+
+ /**
+ * set the debug mode for java2iiop (default false)
+ * @param debug the setting to use.
+ **/
+ public void setDebug(boolean debug) {
+ this.java2iiopdebug = debug;
+ }
+
+ /**
+ * set the verify mode for the produced jar (default true)
+ * @param verify the setting to use.
+ **/
+ public void setVerify(boolean verify) {
+ this.verify = verify;
+ }
+
+
+ /**
+ * Setter used to store the suffix for the generated borland jar file.
+ * @param inString the string to use as the suffix.
+ */
+ public void setSuffix(String inString) {
+ this.jarSuffix = inString;
+ }
+
+
+ /**
+ * sets some additional args to send to verify command
+ * @param args additional command line parameters
+ */
+ public void setVerifyArgs(String args) {
+ this.verifyArgs = args;
+ }
+
+ /**
+ * Setter used to store the location of the borland DTD. This can be a file on the system
+ * or a resource on the classpath.
+ * @param inString the string to use as the DTD location.
+ */
+ public void setBASdtd(String inString) {
+ this.borlandDTD = inString;
+ }
+
+
+ /**
+ * setter used to store whether the task will include the generate client task.
+ * (see : BorlandGenerateClient task)
+ * @param b if true generate the client task.
+ */
+ public void setGenerateclient(boolean b) {
+ this.generateclient = b;
+ }
+
+ /**
+ * setter used to store the borland appserver version [4 or 5]
+ * @param version app server version 4 or 5
+ */
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ /**
+ * If filled, the params are added to the java2iiop command.
+ * (ex: -no_warn_missing_define)
+ * @param params additional params for java2iiop
+ */
+ public void setJava2iiopParams(String params) {
+ this.java2iioparams = params;
+ }
+
+
+ /**
+ * Get the borland descriptor handler.
+ * @param srcDir the source directory.
+ * @return the descriptor.
+ */
+ protected DescriptorHandler getBorlandDescriptorHandler(final File srcDir) {
+ DescriptorHandler handler =
+ new DescriptorHandler(getTask(), srcDir) {
+ protected void processElement() {
+ if (currentElement.equals("type-storage")) {
+ // Get the filename of vendor specific descriptor
+ String fileNameWithMETA = currentText;
+ //trim the META_INF\ off of the file name
+ String fileName
+ = fileNameWithMETA.substring(META_DIR.length(),
+ fileNameWithMETA.length());
+ File descriptorFile = new File(srcDir, fileName);
+
+ ejbFiles.put(fileNameWithMETA, descriptorFile);
+ }
+ }
+ };
+ handler.registerDTD(PUBLICID_BORLAND_EJB,
+ borlandDTD == null ? DEFAULT_BAS_DTD_LOCATION : borlandDTD);
+
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+ handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+ }
+ return handler;
+ }
+
+ /**
+ * Add any vendor specific files which should be included in the
+ * EJB Jar.
+ * @param ejbFiles the map to add the files to.
+ * @param ddPrefix the prefix to use.
+ */
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+
+ //choose the right vendor DD
+ if (!(version == BES || version == BAS)) {
+ throw new BuildException("version " + version + " is not supported");
+ }
+
+ String dd = (version == BES ? BES_DD : BAS_DD);
+
+ log("vendor file : " + ddPrefix + dd, Project.MSG_DEBUG);
+
+ File borlandDD = new File(getConfig().descriptorDir, ddPrefix + dd);
+ if (borlandDD.exists()) {
+ log("Borland specific file found " + borlandDD, Project.MSG_VERBOSE);
+ ejbFiles.put(META_DIR + dd , borlandDD);
+ } else {
+ log("Unable to locate borland deployment descriptor. "
+ + "It was expected to be in "
+ + borlandDD.getPath(), Project.MSG_WARN);
+ return;
+ }
+ }
+
+ /**
+ * Get the vendor specific name of the Jar that will be output. The modification date
+ * of this jar will be checked against the dependent bean classes.
+ */
+ File getVendorOutputJarFile(String baseName) {
+ return new File(getDestDir(), baseName + jarSuffix);
+ }
+
+ /**
+ * Verify the produced jar file by invoking the Borland verify tool
+ * @param sourceJar java.io.File representing the produced jar file
+ */
+ private void verifyBorlandJar(File sourceJar) {
+ if (version == BAS) {
+ verifyBorlandJarV4(sourceJar);
+ return;
+ }
+ if (version == BES) {
+ verifyBorlandJarV5(sourceJar);
+ return;
+ }
+ log("verify jar skipped because the version is invalid ["
+ + version + "]", Project.MSG_WARN);
+ }
+
+ /**
+ * Verify the produced jar file by invoking the Borland iastool tool
+ * @param sourceJar java.io.File representing the produced jar file
+ */
+ private void verifyBorlandJarV5(File sourceJar) {
+ log("verify BES " + sourceJar, Project.MSG_INFO);
+ try {
+ ExecTask execTask = null;
+ execTask = new ExecTask(getTask());
+ execTask.setDir(new File("."));
+ execTask.setExecutable("iastool");
+ //classpath
+ if (getCombinedClasspath() != null) {
+ execTask.createArg().setValue("-VBJclasspath");
+ execTask.createArg().setValue(getCombinedClasspath().toString());
+ }
+
+ if (java2iiopdebug) {
+ execTask.createArg().setValue("-debug");
+ }
+ execTask.createArg().setValue("-verify");
+ execTask.createArg().setValue("-src");
+ // ejb jar file to verify
+ execTask.createArg().setValue(sourceJar.getPath());
+ log("Calling iastool", Project.MSG_VERBOSE);
+ execTask.execute();
+ } catch (Exception e) {
+ // Have to catch this because of the semantics of calling main()
+ String msg = "Exception while calling generateclient Details: "
+ + e.toString();
+ throw new BuildException(msg, e);
+ }
+ }
+
+ /**
+ * Verify the produced jar file by invoking the Borland verify tool
+ * @param sourceJar java.io.File representing the produced jar file
+ */
+ private void verifyBorlandJarV4(File sourceJar) {
+ org.apache.tools.ant.taskdefs.Java javaTask = null;
+ log("verify BAS " + sourceJar, Project.MSG_INFO);
+ try {
+ String args = verifyArgs;
+ args += " " + sourceJar.getPath();
+
+ javaTask = new Java(getTask());
+ javaTask.setTaskName("verify");
+ javaTask.setClassname(VERIFY);
+ Commandline.Argument arguments = javaTask.createArg();
+ arguments.setLine(args);
+ Path classpath = getCombinedClasspath();
+ if (classpath != null) {
+ javaTask.setClasspath(classpath);
+ javaTask.setFork(true);
+ }
+
+ log("Calling " + VERIFY + " for " + sourceJar.toString(),
+ Project.MSG_VERBOSE);
+ javaTask.execute();
+ } catch (Exception e) {
+ //TO DO : delete the file if it is not a valid file.
+ String msg = "Exception while calling " + VERIFY + " Details: "
+ + e.toString();
+ throw new BuildException(msg, e);
+ }
+ }
+
+
+ /**
+ * Generate the client jar corresponding to the jar file passed as parameter
+ * the method uses the BorlandGenerateClient task.
+ * @param sourceJar java.io.File representing the produced jar file
+ */
+ private void generateClient(File sourceJar) {
+ getTask().getProject().addTaskDefinition("internal_bas_generateclient",
+ org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient.class);
+
+ org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient gentask = null;
+ log("generate client for " + sourceJar, Project.MSG_INFO);
+ try {
+ Project project = getTask().getProject();
+ gentask
+ = (BorlandGenerateClient) project.createTask("internal_bas_generateclient");
+ gentask.setEjbjar(sourceJar);
+ gentask.setDebug(java2iiopdebug);
+ Path classpath = getCombinedClasspath();
+ if (classpath != null) {
+ gentask.setClasspath(classpath);
+ }
+ gentask.setVersion(version);
+ gentask.setTaskName("generate client");
+ gentask.execute();
+ } catch (Exception e) {
+ //TO DO : delete the file if it is not a valid file.
+ String msg = "Exception while calling " + VERIFY + " Details: "
+ + e.toString();
+ throw new BuildException(msg, e);
+ }
+ }
+
+ /**
+ * Generate stubs & skeleton for each home found into the DD
+ * Add all the generate class file into the ejb files
+ * @param ithomes : iterator on home class
+ */
+ private void buildBorlandStubs(Iterator ithomes) {
+ Execute execTask = null;
+
+ execTask = new Execute(this);
+ Project project = getTask().getProject();
+ execTask.setAntRun(project);
+ execTask.setWorkingDirectory(project.getBaseDir());
+
+ Commandline commandline = new Commandline();
+ commandline.setExecutable(JAVA2IIOP);
+ //debug ?
+ if (java2iiopdebug) {
+ commandline.createArgument().setValue("-VBJdebug");
+ }
+ //set the classpath
+ commandline.createArgument().setValue("-VBJclasspath");
+ commandline.createArgument().setPath(getCombinedClasspath());
+ //list file
+ commandline.createArgument().setValue("-list_files");
+ //no TIE classes
+ commandline.createArgument().setValue("-no_tie");
+
+ if (java2iioparams != null) {
+ log("additional " + java2iioparams + " to java2iiop ", 0);
+ commandline.createArgument().setLine(java2iioparams);
+ }
+
+
+ //root dir
+ commandline.createArgument().setValue("-root_dir");
+ commandline.createArgument().setValue(getConfig().srcDir.getAbsolutePath());
+ //compiling order
+ commandline.createArgument().setValue("-compile");
+ //add the home class
+ while (ithomes.hasNext()) {
+ commandline.createArgument().setValue(ithomes.next().toString());
+ }
+
+ try {
+ log("Calling java2iiop", Project.MSG_VERBOSE);
+ log(commandline.describeCommand(), Project.MSG_DEBUG);
+ execTask.setCommandline(commandline.getCommandline());
+ int result = execTask.execute();
+ if (Execute.isFailure(result)) {
+ String msg = "Failed executing java2iiop (ret code is "
+ + result + ")";
+ throw new BuildException(msg, getTask().getLocation());
+ }
+ } catch (java.io.IOException e) {
+ log("java2iiop exception :" + e.getMessage(), Project.MSG_ERR);
+ throw new BuildException(e, getTask().getLocation());
+ }
+ }
+
+ /**
+ * Method used to encapsulate the writing of the JAR file. Iterates over the
+ * filenames/java.io.Files in the Hashtable stored on the instance variable
+ * ejbFiles.
+ * @param baseName the base name.
+ * @param jarFile the jar file to write to.
+ * @param files the files to write to the jar.
+ * @param publicId the id to use.
+ * @throws BuildException if there is an error.
+ */
+ protected void writeJar(String baseName, File jarFile, Hashtable files, String publicId)
+ throws BuildException {
+ //build the home classes list.
+ Vector homes = new Vector();
+ Iterator it = files.keySet().iterator();
+ while (it.hasNext()) {
+ String clazz = (String) it.next();
+ if (clazz.endsWith("Home.class")) {
+ //remove .class extension
+ String home = toClass(clazz);
+ homes.add(home);
+ log(" Home " + home, Project.MSG_VERBOSE);
+ }
+ }
+
+ buildBorlandStubs(homes.iterator());
+
+ //add the gen files to the collection
+ files.putAll(genfiles);
+
+ super.writeJar(baseName, jarFile, files, publicId);
+
+ if (verify) {
+ verifyBorlandJar(jarFile);
+ }
+
+ if (generateclient) {
+ generateClient(jarFile);
+ }
+ genfiles.clear();
+ }
+
+ /**
+ * convert a class file name : A/B/C/toto.class
+ * into a class name: A.B.C.toto
+ */
+ private String toClass(String filename) {
+ //remove the .class
+ String classname = filename.substring(0, filename.lastIndexOf(".class"));
+ classname = classname.replace('\\', '.');
+ return classname;
+ }
+
+ /**
+ * convert a file name : A/B/C/toto.java
+ * into a class name: A/B/C/toto.class
+ */
+ private String toClassFile(String filename) {
+ //remove the .class
+ String classfile = filename.substring(0, filename.lastIndexOf(".java"));
+ classfile = classfile + ".class";
+ return classfile;
+ }
+
+ // implementation of org.apache.tools.ant.taskdefs.ExecuteStreamHandler interface
+
+ /** {@inheritDoc}. */
+ public void start() throws IOException { }
+ /** {@inheritDoc}. */
+ public void stop() { }
+ /** {@inheritDoc}. */
+ public void setProcessInputStream(OutputStream param1) throws IOException { }
+
+ /**
+ * Set the output stream of the process.
+ * @param is the input stream.
+ * @throws IOException if there is an error.
+ */
+ public void setProcessOutputStream(InputStream is) throws IOException {
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String javafile;
+ while ((javafile = reader.readLine()) != null) {
+ if (javafile.endsWith(".java")) {
+ String classfile = toClassFile(javafile);
+ String key = classfile.substring(
+ getConfig().srcDir.getAbsolutePath().length() + 1);
+ genfiles.put(key, new File(classfile));
+ }
+ }
+ reader.close();
+ } catch (Exception e) {
+ String msg = "Exception while parsing java2iiop output. Details: " + e.toString();
+ throw new BuildException(msg, e);
+ }
+ }
+
+ /**
+ * Set the error stream of the process.
+ * @param is the input stream.
+ * @throws IOException if there is an error.
+ */
+ public void setProcessErrorStream(InputStream is) throws IOException {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String s = reader.readLine();
+ if (s != null) {
+ log("[java2iiop] " + s, Project.MSG_ERR);
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java
new file mode 100644
index 00000000..dd46269d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Generates a Borland Application Server 4.5 client JAR using as
+ * input the EJB JAR file.
+ *
+ * Two mode are available: java mode (default) and fork mode. With the fork mode,
+ * it is impossible to add classpath to the command line.
+ *
+ * @ant.task name="blgenclient" category="ejb"
+ */
+public class BorlandGenerateClient extends Task {
+ static final String JAVA_MODE = "java";
+ static final String FORK_MODE = "fork";
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /** debug the generateclient task */
+ boolean debug = false;
+
+ /** hold the ejbjar file name */
+ File ejbjarfile = null;
+
+ /** hold the client jar file name */
+ File clientjarfile = null;
+
+ /** hold the classpath */
+ Path classpath;
+
+ /** hold the mode (java|fork) */
+ String mode = FORK_MODE;
+
+ /** hold the version */
+ int version = BorlandDeploymentTool.BAS;
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Set the version attribute.
+ * @param version the value to use.
+ */
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ /**
+ * Command launching mode: java or fork.
+ * @param s the mode to use.
+ */
+ public void setMode(String s) {
+ mode = s;
+ }
+
+ /**
+ * If true, turn on the debug mode for each of the Borland tools launched.
+ * @param debug a <code>boolean</code> value.
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * EJB JAR file.
+ * @param ejbfile the file to use.
+ */
+ public void setEjbjar(File ejbfile) {
+ ejbjarfile = ejbfile;
+ }
+
+ /**
+ * Client JAR file name.
+ * @param clientjar the file to use.
+ */
+ public void setClientjar(File clientjar) {
+ clientjarfile = clientjar;
+ }
+
+ /**
+ * Path to use for classpath.
+ * @param classpath the path to use.
+ */
+ public void setClasspath(Path classpath) {
+ if (this.classpath == null) {
+ this.classpath = classpath;
+ } else {
+ this.classpath.append(classpath);
+ }
+ }
+
+ /**
+ * Adds path to the classpath.
+ * @return a path to be configured as a nested element.
+ */
+ public Path createClasspath() {
+ if (this.classpath == null) {
+ this.classpath = new Path(getProject());
+ }
+ return this.classpath.createPath();
+ }
+
+ /**
+ * Reference to existing path, to use as a classpath.
+ * @param r the reference to use.
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+
+ /**
+ * Do the work.
+ *
+ * The work is actually done by creating a separate JVM to run a java task.
+ *
+ * @exception BuildException if something goes wrong with the build
+ */
+ public void execute() throws BuildException {
+ if (ejbjarfile == null || ejbjarfile.isDirectory()) {
+ throw new BuildException("invalid ejb jar file.");
+ }
+
+ if (clientjarfile == null || clientjarfile.isDirectory()) {
+ log("invalid or missing client jar file.", Project.MSG_VERBOSE);
+ String ejbjarname = ejbjarfile.getAbsolutePath();
+ //clientname = ejbjarfile+client.jar
+ String clientname = ejbjarname.substring(0, ejbjarname.lastIndexOf("."));
+ clientname = clientname + "client.jar";
+ clientjarfile = new File(clientname);
+ }
+
+ if (mode == null) {
+ log("mode is null default mode is java");
+ setMode(JAVA_MODE);
+ }
+
+ if (!(version == BorlandDeploymentTool.BES
+ || version == BorlandDeploymentTool.BAS)) {
+ throw new BuildException("version " + version
+ + " is not supported");
+ }
+
+ log("client jar file is " + clientjarfile);
+
+ if (mode.equalsIgnoreCase(FORK_MODE)) {
+ executeFork();
+ } else {
+ executeJava();
+ } // end of else
+ }
+
+ /**
+ * launch the generate client using java api.
+ * @throws BuildException if there is an error.
+ */
+ protected void executeJava() throws BuildException {
+ try {
+ if (version == BorlandDeploymentTool.BES) {
+ throw new BuildException("java mode is supported only for "
+ + "previous version <=" + BorlandDeploymentTool.BAS);
+ }
+
+ log("mode : java");
+
+ Java execTask = null;
+ execTask = new Java(this);
+
+ execTask.setDir(new File("."));
+ execTask.setClassname("com.inprise.server.commandline.EJBUtilities");
+ //classpath
+ //add at the end of the classpath
+ //the system classpath in order to find the tools.jar file
+ execTask.setClasspath(classpath.concatSystemClasspath());
+
+ execTask.setFork(true);
+ execTask.createArg().setValue("generateclient");
+ if (debug) {
+ execTask.createArg().setValue("-trace");
+ }
+
+ execTask.createArg().setValue("-short");
+ execTask.createArg().setValue("-jarfile");
+ // ejb jar file
+ execTask.createArg().setValue(ejbjarfile.getAbsolutePath());
+ //client jar file
+ execTask.createArg().setValue("-single");
+ execTask.createArg().setValue("-clientjarfile");
+ execTask.createArg().setValue(clientjarfile.getAbsolutePath());
+
+ log("Calling EJBUtilities", Project.MSG_VERBOSE);
+ execTask.execute();
+
+ } catch (Exception e) {
+ // Have to catch this because of the semantics of calling main()
+ String msg = "Exception while calling generateclient Details: " + e.toString();
+ throw new BuildException(msg, e);
+ }
+ }
+
+ /**
+ * launch the generate client using system api.
+ * @throws BuildException if there is an error.
+ */
+ protected void executeFork() throws BuildException {
+ if (version == BorlandDeploymentTool.BAS) {
+ executeForkV4();
+ }
+ if (version == BorlandDeploymentTool.BES) {
+ executeForkV5();
+ }
+ }
+
+ /**
+ * launch the generate client using system api.
+ * @throws BuildException if there is an error.
+ */
+ protected void executeForkV4() throws BuildException {
+ try {
+
+ log("mode : fork " + BorlandDeploymentTool.BAS, Project.MSG_DEBUG);
+
+ ExecTask execTask = new ExecTask(this);
+
+ execTask.setDir(new File("."));
+ execTask.setExecutable("iastool");
+ execTask.createArg().setValue("generateclient");
+ if (debug) {
+ execTask.createArg().setValue("-trace");
+ }
+
+ execTask.createArg().setValue("-short");
+ execTask.createArg().setValue("-jarfile");
+ // ejb jar file
+ execTask.createArg().setValue(ejbjarfile.getAbsolutePath());
+ //client jar file
+ execTask.createArg().setValue("-single");
+ execTask.createArg().setValue("-clientjarfile");
+ execTask.createArg().setValue(clientjarfile.getAbsolutePath());
+
+ log("Calling iastool", Project.MSG_VERBOSE);
+ execTask.execute();
+ } catch (Exception e) {
+ // Have to catch this because of the semantics of calling main()
+ String msg = "Exception while calling generateclient Details: "
+ + e.toString();
+ throw new BuildException(msg, e);
+ }
+
+ }
+
+ /**
+ * launch the generate client using system api.
+ * @throws BuildException if there is an error.
+ */
+ protected void executeForkV5() throws BuildException {
+ try {
+ log("mode : fork " + BorlandDeploymentTool.BES, Project.MSG_DEBUG);
+ ExecTask execTask = new ExecTask(this);
+
+ execTask.setDir(new File("."));
+
+ execTask.setExecutable("iastool");
+ if (debug) {
+ execTask.createArg().setValue("-debug");
+ }
+ execTask.createArg().setValue("-genclient");
+ execTask.createArg().setValue("-jars");
+ // ejb jar file
+ execTask.createArg().setValue(ejbjarfile.getAbsolutePath());
+ //client jar file
+ execTask.createArg().setValue("-target");
+ execTask.createArg().setValue(clientjarfile.getAbsolutePath());
+ //classpath
+ execTask.createArg().setValue("-cp");
+ execTask.createArg().setValue(classpath.toString());
+ log("Calling iastool", Project.MSG_VERBOSE);
+ execTask.execute();
+ } catch (Exception e) {
+ // Have to catch this because of the semantics of calling main()
+ String msg = "Exception while calling generateclient Details: "
+ + e.toString();
+ throw new BuildException(msg, e);
+ }
+
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java
new file mode 100644
index 00000000..158cba93
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java
@@ -0,0 +1,390 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.xml.sax.AttributeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Inner class used by EjbJar to facilitate the parsing of deployment
+ * descriptors and the capture of appropriate information. Extends
+ * HandlerBase so it only implements the methods needed. During parsing
+ * creates a hashtable consisting of entries mapping the name it should be
+ * inserted into an EJB jar as to a File representing the file on disk. This
+ * list can then be accessed through the getFiles() method.
+ */
+public class DescriptorHandler extends org.xml.sax.HandlerBase {
+ private static final int DEFAULT_HASH_TABLE_SIZE = 10;
+ private static final int STATE_LOOKING_EJBJAR = 1;
+ private static final int STATE_IN_EJBJAR = 2;
+ private static final int STATE_IN_BEANS = 3;
+ private static final int STATE_IN_SESSION = 4;
+ private static final int STATE_IN_ENTITY = 5;
+ private static final int STATE_IN_MESSAGE = 6;
+
+ private Task owningTask;
+
+ private String publicId = null;
+
+ /**
+ * Bunch of constants used for storing entries in a hashtable, and for
+ * constructing the filenames of various parts of the ejb jar.
+ */
+ private static final String EJB_REF = "ejb-ref";
+ private static final String EJB_LOCAL_REF = "ejb-local-ref";
+ private static final String HOME_INTERFACE = "home";
+ private static final String REMOTE_INTERFACE = "remote";
+ private static final String LOCAL_HOME_INTERFACE = "local-home";
+ private static final String LOCAL_INTERFACE = "local";
+ private static final String BEAN_CLASS = "ejb-class";
+ private static final String PK_CLASS = "prim-key-class";
+ private static final String EJB_NAME = "ejb-name";
+ private static final String EJB_JAR = "ejb-jar";
+ private static final String ENTERPRISE_BEANS = "enterprise-beans";
+ private static final String ENTITY_BEAN = "entity";
+ private static final String SESSION_BEAN = "session";
+ private static final String MESSAGE_BEAN = "message-driven";
+
+ /**
+ * The state of the parsing
+ */
+ private int parseState = STATE_LOOKING_EJBJAR;
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /**
+ * Instance variable used to store the name of the current element being
+ * processed by the SAX parser. Accessed by the SAX parser call-back methods
+ * startElement() and endElement().
+ */
+ protected String currentElement = null;
+
+ /**
+ * The text of the current element
+ */
+ protected String currentText = null;
+
+ /**
+ * Instance variable that stores the names of the files as they will be
+ * put into the jar file, mapped to File objects Accessed by the SAX
+ * parser call-back method characters().
+ */
+ protected Hashtable ejbFiles = null;
+
+ /**
+ * Instance variable that stores the value found in the &lt;ejb-name&gt; element
+ */
+ protected String ejbName = null;
+
+ private Hashtable fileDTDs = new Hashtable();
+
+ private Hashtable resourceDTDs = new Hashtable();
+
+ private boolean inEJBRef = false;
+
+ private Hashtable urlDTDs = new Hashtable();
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ /**
+ * The directory containing the bean classes and interfaces. This is
+ * used for performing dependency file lookups.
+ */
+ private File srcDir;
+
+ /**
+ * Constructor for DescriptorHandler.
+ * @param task the task that owns this descriptor
+ * @param srcDir the source directory
+ */
+ public DescriptorHandler(Task task, File srcDir) {
+ this.owningTask = task;
+ this.srcDir = srcDir;
+ }
+
+ /**
+ * Register a dtd with a location.
+ * The location is one of a filename, a resource name in the classpath, or
+ * a URL.
+ * @param publicId the public identity of the dtd
+ * @param location the location of the dtd
+ */
+ public void registerDTD(String publicId, String location) {
+ if (location == null) {
+ return;
+ }
+
+ File fileDTD = new File(location);
+ if (!fileDTD.exists()) {
+ // resolve relative to project basedir
+ fileDTD = owningTask.getProject().resolveFile(location);
+ }
+
+ if (fileDTD.exists()) {
+ if (publicId != null) {
+ fileDTDs.put(publicId, fileDTD);
+ owningTask.log("Mapped publicId " + publicId + " to file "
+ + fileDTD, Project.MSG_VERBOSE);
+ }
+ return;
+ }
+
+ if (getClass().getResource(location) != null) {
+ if (publicId != null) {
+ resourceDTDs.put(publicId, location);
+ owningTask.log("Mapped publicId " + publicId + " to resource "
+ + location, Project.MSG_VERBOSE);
+ }
+ }
+
+ try {
+ if (publicId != null) {
+ URL urldtd = new URL(location);
+ urlDTDs.put(publicId, urldtd);
+ }
+ } catch (java.net.MalformedURLException e) {
+ //ignored
+ }
+
+ }
+
+ /**
+ * Resolve the entity.
+ * @see org.xml.sax.EntityResolver#resolveEntity(String, String).
+ * @param publicId The public identifier, or <code>null</code>
+ * if none is available.
+ * @param systemId The system identifier provided in the XML
+ * document. Will not be <code>null</code>.
+ * @return an inputsource for this identifier
+ * @throws SAXException if there is a problem.
+ */
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException {
+ this.publicId = publicId;
+
+ File dtdFile = (File) fileDTDs.get(publicId);
+ if (dtdFile != null) {
+ try {
+ owningTask.log("Resolved " + publicId + " to local file "
+ + dtdFile, Project.MSG_VERBOSE);
+ return new InputSource(new FileInputStream(dtdFile));
+ } catch (FileNotFoundException ex) {
+ // ignore
+ }
+ }
+
+ String dtdResourceName = (String) resourceDTDs.get(publicId);
+ if (dtdResourceName != null) {
+ InputStream is = this.getClass().getResourceAsStream(dtdResourceName);
+ if (is != null) {
+ owningTask.log("Resolved " + publicId + " to local resource "
+ + dtdResourceName, Project.MSG_VERBOSE);
+ return new InputSource(is);
+ }
+ }
+
+ URL dtdUrl = (URL) urlDTDs.get(publicId);
+ if (dtdUrl != null) {
+ try {
+ InputStream is = dtdUrl.openStream();
+ owningTask.log("Resolved " + publicId + " to url "
+ + dtdUrl, Project.MSG_VERBOSE);
+ return new InputSource(is);
+ } catch (IOException ioe) {
+ //ignore
+ }
+ }
+
+ owningTask.log("Could not resolve ( publicId: " + publicId
+ + ", systemId: " + systemId + ") to a local entity", Project.MSG_INFO);
+
+ return null;
+ }
+
+ /**
+ * Getter method that returns the set of files to include in the EJB jar.
+ * @return the map of files
+ */
+ public Hashtable getFiles() {
+ return (ejbFiles == null) ? new Hashtable() : ejbFiles;
+ }
+
+ /**
+ * Get the publicId of the DTD
+ * @return the public id
+ */
+ public String getPublicId() {
+ return publicId;
+ }
+
+ /**
+ * Getter method that returns the value of the &lt;ejb-name&gt; element.
+ * @return the ejb name
+ */
+ public String getEjbName() {
+ return ejbName;
+ }
+
+ /**
+ * SAX parser call-back method that is used to initialize the values of some
+ * instance variables to ensure safe operation.
+ * @throws SAXException on error
+ */
+ public void startDocument() throws SAXException {
+ this.ejbFiles = new Hashtable(DEFAULT_HASH_TABLE_SIZE, 1);
+ this.currentElement = null;
+ inEJBRef = false;
+ }
+
+
+ /**
+ * SAX parser call-back method that is invoked when a new element is entered
+ * into. Used to store the context (attribute name) in the currentAttribute
+ * instance variable.
+ * @param name The name of the element being entered.
+ * @param attrs Attributes associated to the element.
+ * @throws SAXException on error
+ */
+ public void startElement(String name, AttributeList attrs)
+ throws SAXException {
+ this.currentElement = name;
+ currentText = "";
+ if (name.equals(EJB_REF) || name.equals(EJB_LOCAL_REF)) {
+ inEJBRef = true;
+ } else if (parseState == STATE_LOOKING_EJBJAR && name.equals(EJB_JAR)) {
+ parseState = STATE_IN_EJBJAR;
+ } else if (parseState == STATE_IN_EJBJAR && name.equals(ENTERPRISE_BEANS)) {
+ parseState = STATE_IN_BEANS;
+ } else if (parseState == STATE_IN_BEANS && name.equals(SESSION_BEAN)) {
+ parseState = STATE_IN_SESSION;
+ } else if (parseState == STATE_IN_BEANS && name.equals(ENTITY_BEAN)) {
+ parseState = STATE_IN_ENTITY;
+ } else if (parseState == STATE_IN_BEANS && name.equals(MESSAGE_BEAN)) {
+ parseState = STATE_IN_MESSAGE;
+ }
+ }
+
+
+ /**
+ * SAX parser call-back method that is invoked when an element is exited.
+ * Used to blank out (set to the empty string, not nullify) the name of
+ * the currentAttribute. A better method would be to use a stack as an
+ * instance variable, however since we are only interested in leaf-node
+ * data this is a simpler and workable solution.
+ * @param name The name of the attribute being exited. Ignored
+ * in this implementation.
+ * @throws SAXException on error
+ */
+ public void endElement(String name) throws SAXException {
+ processElement();
+ currentText = "";
+ this.currentElement = "";
+ if (name.equals(EJB_REF) || name.equals(EJB_LOCAL_REF)) {
+ inEJBRef = false;
+ } else if (parseState == STATE_IN_ENTITY && name.equals(ENTITY_BEAN)) {
+ parseState = STATE_IN_BEANS;
+ } else if (parseState == STATE_IN_SESSION && name.equals(SESSION_BEAN)) {
+ parseState = STATE_IN_BEANS;
+ } else if (parseState == STATE_IN_MESSAGE && name.equals(MESSAGE_BEAN)) {
+ parseState = STATE_IN_BEANS;
+ } else if (parseState == STATE_IN_BEANS && name.equals(ENTERPRISE_BEANS)) {
+ parseState = STATE_IN_EJBJAR;
+ } else if (parseState == STATE_IN_EJBJAR && name.equals(EJB_JAR)) {
+ parseState = STATE_LOOKING_EJBJAR;
+ }
+ }
+
+ /**
+ * SAX parser call-back method invoked whenever characters are located within
+ * an element. currentAttribute (modified by startElement and endElement)
+ * tells us whether we are in an interesting element (one of the up to four
+ * classes of an EJB). If so then converts the classname from the format
+ * org.apache.tools.ant.Parser to the convention for storing such a class,
+ * org/apache/tools/ant/Parser.class. This is then resolved into a file
+ * object under the srcdir which is stored in a Hashtable.
+ * @param ch A character array containing all the characters in
+ * the element, and maybe others that should be ignored.
+ * @param start An integer marking the position in the char
+ * array to start reading from.
+ * @param length An integer representing an offset into the
+ * char array where the current data terminates.
+ * @throws SAXException on error
+ */
+ public void characters(char[] ch, int start, int length)
+ throws SAXException {
+
+ currentText += new String(ch, start, length);
+ }
+
+
+ /**
+ * Called when an endelement is seen.
+ * This may be overridden in derived classes.
+ * This updates the ejbfiles if the element is an interface or a bean class.
+ * This updates the ejbname if the element is an ejb name.
+ */
+ protected void processElement() {
+ if (inEJBRef
+ || (parseState != STATE_IN_ENTITY
+ && parseState != STATE_IN_SESSION
+ && parseState != STATE_IN_MESSAGE)) {
+ return;
+ }
+
+ if (currentElement.equals(HOME_INTERFACE)
+ || currentElement.equals(REMOTE_INTERFACE)
+ || currentElement.equals(LOCAL_INTERFACE)
+ || currentElement.equals(LOCAL_HOME_INTERFACE)
+ || currentElement.equals(BEAN_CLASS)
+ || currentElement.equals(PK_CLASS)) {
+
+ // Get the filename into a String object
+ File classFile = null;
+ String className = currentText.trim();
+
+ // If it's a primitive wrapper then we shouldn't try and put
+ // it into the jar, so ignore it.
+ if (!className.startsWith("java.")
+ && !className.startsWith("javax.")) {
+ // Translate periods into path separators, add .class to the
+ // name, create the File object and add it to the Hashtable.
+ className = className.replace('.', File.separatorChar);
+ className += ".class";
+ classFile = new File(srcDir, className);
+ ejbFiles.put(className, classFile);
+ }
+ }
+
+ // Get the value of the <ejb-name> tag. Only the first occurrence.
+ if (currentElement.equals(EJB_NAME)) {
+ if (ejbName == null) {
+ ejbName = currentText.trim();
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java
new file mode 100644
index 00000000..6ed8e34a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+
+
+import javax.xml.parsers.SAXParser;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+
+/**
+ * The interface to implement for deployment tools.
+ */
+public interface EJBDeploymentTool {
+ /**
+ * Process a deployment descriptor, generating the necessary vendor specific
+ * deployment files.
+ *
+ * @param descriptorFilename the name of the deployment descriptor
+ * @param saxParser a SAX parser which can be used to parse the deployment descriptor.
+ * @throws BuildException if there is an error.
+ */
+ void processDescriptor(String descriptorFilename, SAXParser saxParser)
+ throws BuildException;
+
+ /**
+ * Called to validate that the tool parameters have been configured.
+ * @throws BuildException if there is an error.
+ */
+ void validateConfigured() throws BuildException;
+
+ /**
+ * Set the task which owns this tool
+ * @param task the task.
+ */
+ void setTask(Task task);
+
+ /**
+ * Configure this tool for use in the ejbjar task.
+ * @param config contains configuration state.
+ */
+ void configure(EjbJar.Config config);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
new file mode 100644
index 00000000..e9b7ed42
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
@@ -0,0 +1,630 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+// Standard java imports
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.xml.sax.SAXException;
+
+/**
+ * Provides automated EJB JAR file creation.
+ * <p>
+ * Extends the
+ * MatchingTask class provided in the default ant distribution to provide a
+ * directory scanning EJB jarfile generator.
+ * </p>
+ *
+ * <p>
+ * The task works by taking the deployment descriptors one at a time and
+ * parsing them to locate the names of the classes which should be placed in
+ * the jar. The classnames are translated to java.io.Files by replacing
+ * periods with File.separatorChar and resolving the generated filename as a
+ * relative path under the srcDir attribute. All necessary files are then
+ * assembled into a jarfile. One jarfile is constructed for each deployment
+ * descriptor found.
+ * </p>
+ *
+ * */
+public class EjbJar extends MatchingTask {
+
+ /**
+ * Inner class used to record information about the location of a local DTD
+ */
+ public static class DTDLocation
+ extends org.apache.tools.ant.types.DTDLocation {
+ }
+
+ /**
+ * A class which contains the configuration state of the ejbjar task.
+ * This state is passed to the deployment tools for configuration
+ */
+ static class Config {
+ // CheckStyle:VisibilityModifier OFF - bc
+ /**
+ * Stores a handle to the directory under which to search for class
+ * files
+ */
+ public File srcDir;
+
+ /**
+ * Stores a handle to the directory under which to search for
+ * deployment descriptors
+ */
+ public File descriptorDir;
+
+ /** Instance variable that marks the end of the 'basename' */
+ public String baseNameTerminator = "-";
+
+ /** Stores a handle to the destination EJB Jar file */
+ public String baseJarName;
+
+ /**
+ * Instance variable that determines whether to use a package structure
+ * of a flat directory as the destination for the jar files.
+ */
+ public boolean flatDestDir = false;
+
+ /**
+ * The classpath to use when loading classes
+ */
+ public Path classpath;
+
+ /**
+ * A Fileset of support classes
+ */
+ public List supportFileSets = new ArrayList();
+
+ /**
+ * The list of configured DTD locations
+ */
+ public ArrayList dtdLocations = new ArrayList();
+
+ /**
+ * The naming scheme used to determine the generated jar name
+ * from the descriptor information
+ */
+ public NamingScheme namingScheme;
+
+ /**
+ * The Manifest file
+ */
+ public File manifest;
+
+ /**
+ * The dependency analyzer to use to add additional classes to the jar
+ */
+ public String analyzer;
+ // CheckStyle:VisibilityModifier ON
+ }
+
+ /**
+ * An EnumeratedAttribute class for handling different EJB jar naming
+ * schemes
+ */
+ public static class NamingScheme extends EnumeratedAttribute {
+ /**
+ * Naming scheme where generated jar is determined from the ejb-name in
+ * the deployment descriptor
+ */
+ public static final String EJB_NAME = "ejb-name";
+
+ /**
+ * Naming scheme where the generated jar name is based on the
+ * name of the directory containing the deployment descriptor
+ */
+ public static final String DIRECTORY = "directory";
+
+ /**
+ * Naming scheme where the generated jar name is based on the name of
+ * the deployment descriptor file
+ */
+ public static final String DESCRIPTOR = "descriptor";
+
+ /**
+ * Naming scheme where the generated jar is named by the basejarname
+ * attribute
+ */
+ public static final String BASEJARNAME = "basejarname";
+
+ /**
+ * Gets the values of the NamingScheme
+ *
+ * @return an array of the values of this attribute class.
+ */
+ public String[] getValues() {
+ return new String[] {EJB_NAME, DIRECTORY, DESCRIPTOR, BASEJARNAME};
+ }
+ }
+
+ /**
+ * CMP versions supported
+ * valid CMP versions are 1.0 and 2.0
+ * @since ant 1.6
+ */
+ public static class CMPVersion extends EnumeratedAttribute {
+ /** 1.0 value */
+ public static final String CMP1_0 = "1.0";
+ /** 2.0 value */
+ public static final String CMP2_0 = "2.0";
+ /** {@inheritDoc}. */
+ public String[] getValues() {
+ return new String[]{
+ CMP1_0,
+ CMP2_0,
+ };
+ }
+ }
+ /**
+ * The config which is built by this task and used by the various deployment
+ * tools to access the configuration of the ejbjar task
+ */
+ private Config config = new Config();
+
+
+ /**
+ * Stores a handle to the directory to put the Jar files in. This is
+ * only used by the generic deployment descriptor tool which is created
+ * if no other deployment descriptor tools are provided. Normally each
+ * deployment tool will specify the desitination dir itself.
+ */
+ private File destDir;
+
+ /** Instance variable that stores the suffix for the generated jarfile. */
+ private String genericJarSuffix = "-generic.jar";
+
+ /** Instance variable that stores the CMP version for the jboss jarfile. */
+ private String cmpVersion = CMPVersion.CMP1_0;
+
+ /** The list of deployment tools we are going to run. */
+ private ArrayList deploymentTools = new ArrayList();
+
+ /**
+ * Add a deployment tool to the list of deployment tools that will be
+ * processed
+ *
+ * @param deploymentTool a deployment tool instance to which descriptors
+ * will be passed for processing.
+ */
+ protected void addDeploymentTool(EJBDeploymentTool deploymentTool) {
+ deploymentTool.setTask(this);
+ deploymentTools.add(deploymentTool);
+ }
+
+ /**
+ * Adds a deployment tool for Weblogic server.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public WeblogicDeploymentTool createWeblogic() {
+ WeblogicDeploymentTool tool = new WeblogicDeploymentTool();
+ addDeploymentTool(tool);
+ return tool;
+ }
+
+ /**
+ * Adds a deployment tool for Websphere 4.0 server.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public WebsphereDeploymentTool createWebsphere() {
+ WebsphereDeploymentTool tool = new WebsphereDeploymentTool();
+ addDeploymentTool(tool);
+ return tool;
+ }
+
+ /**
+ * Adds a deployment tool for Borland server.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public BorlandDeploymentTool createBorland() {
+ log("Borland deployment tools", Project.MSG_VERBOSE);
+
+ BorlandDeploymentTool tool = new BorlandDeploymentTool();
+ tool.setTask(this);
+ deploymentTools.add(tool);
+ return tool;
+ }
+
+ /**
+ * Adds a deployment tool for iPlanet Application Server.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public IPlanetDeploymentTool createIplanet() {
+ log("iPlanet Application Server deployment tools", Project.MSG_VERBOSE);
+
+ IPlanetDeploymentTool tool = new IPlanetDeploymentTool();
+ addDeploymentTool(tool);
+ return tool;
+ }
+
+ /**
+ * Adds a deployment tool for JBoss server.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public JbossDeploymentTool createJboss() {
+ JbossDeploymentTool tool = new JbossDeploymentTool();
+ addDeploymentTool(tool);
+ return tool;
+ }
+
+ /**
+ * Adds a deployment tool for JOnAS server.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public JonasDeploymentTool createJonas() {
+ log("JOnAS deployment tools", Project.MSG_VERBOSE);
+
+ JonasDeploymentTool tool = new JonasDeploymentTool();
+ addDeploymentTool(tool);
+ return tool;
+ }
+
+ /**
+ * Adds a deployment tool for Weblogic when using the Toplink
+ * Object-Relational mapping.
+ *
+ * @return the deployment tool instance to be configured.
+ */
+ public WeblogicTOPLinkDeploymentTool createWeblogictoplink() {
+ log("The <weblogictoplink> element is no longer required. Please use "
+ + "the <weblogic> element and set newCMP=\"true\"",
+ Project.MSG_INFO);
+ WeblogicTOPLinkDeploymentTool tool
+ = new WeblogicTOPLinkDeploymentTool();
+ addDeploymentTool(tool);
+ return tool;
+ }
+
+ /**
+ * Adds to the classpath used to locate the super classes and
+ * interfaces of the classes that will make up the EJB JAR.
+ *
+ * @return the path to be configured.
+ */
+ public Path createClasspath() {
+ if (config.classpath == null) {
+ config.classpath = new Path(getProject());
+ }
+ return config.classpath.createPath();
+ }
+
+ /**
+ * Create a DTD location record. This stores the location of a DTD. The
+ * DTD is identified by its public Id. The location may either be a file
+ * location or a resource location.
+ *
+ * @return the DTD location object to be configured by Ant
+ */
+ public DTDLocation createDTD() {
+ DTDLocation dtdLocation = new DTDLocation();
+ config.dtdLocations.add(dtdLocation);
+
+ return dtdLocation;
+ }
+
+ /**
+ * Adds a fileset for support elements.
+ *
+ * @return a fileset which can be populated with support files.
+ */
+ public FileSet createSupport() {
+ FileSet supportFileSet = new FileSet();
+ config.supportFileSets.add(supportFileSet);
+ return supportFileSet;
+ }
+
+
+ /**
+ * Set the Manifest file to use when jarring. As of EJB 1.1, manifest
+ * files are no longer used to configure the EJB. However, they still
+ * have a vital importance if the EJB is intended to be packaged in an
+ * EAR file. By adding "Class-Path" settings to a Manifest file, the EJB
+ * can look for classes inside the EAR file itself, allowing for easier
+ * deployment. This is outlined in the J2EE specification, and all J2EE
+ * components are meant to support it.
+ *
+ * @param manifest the manifest to be used in the EJB jar
+ */
+ public void setManifest(File manifest) {
+ config.manifest = manifest;
+ }
+
+ /**
+ * Sets the source directory, which is the directory that
+ * contains the classes that will be added to the EJB jar. Typically
+ * this will include the home and remote interfaces and the bean class.
+ *
+ * @param inDir the source directory.
+ */
+ public void setSrcdir(File inDir) {
+ config.srcDir = inDir;
+ }
+
+ /**
+ * Set the descriptor directory. The descriptor directory contains the
+ * EJB deployment descriptors. These are XML files that declare the
+ * properties of a bean in a particular deployment scenario. Such
+ * properties include, for example, the transactional nature of the bean
+ * and the security access control to the bean's methods.
+ *
+ * @param inDir the directory containing the deployment descriptors.
+ */
+ public void setDescriptordir(File inDir) {
+ config.descriptorDir = inDir;
+ }
+
+ /**
+ * Set the analyzer to use when adding in dependencies to the JAR.
+ *
+ * @param analyzer the name of the dependency analyzer or a class.
+ */
+ public void setDependency(String analyzer) {
+ config.analyzer = analyzer;
+ }
+
+ /**
+ * Set the base name of the EJB JAR that is to be created if it is not
+ * to be determined from the name of the deployment descriptor files.
+ *
+ * @param inValue the basename that will be used when writing the jar
+ * file containing the EJB
+ */
+ public void setBasejarname(String inValue) {
+ config.baseJarName = inValue;
+ if (config.namingScheme == null) {
+ config.namingScheme = new NamingScheme();
+ config.namingScheme.setValue(NamingScheme.BASEJARNAME);
+ } else if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)) {
+ throw new BuildException("The basejarname attribute is not "
+ + "compatible with the "
+ + config.namingScheme.getValue() + " naming scheme");
+ }
+ }
+
+ /**
+ * Set the naming scheme used to determine the name of the generated jars
+ * from the deployment descriptor
+ *
+ * @param namingScheme the naming scheme to be used
+ */
+ public void setNaming(NamingScheme namingScheme) {
+ config.namingScheme = namingScheme;
+ if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
+ && config.baseJarName != null) {
+ throw new BuildException("The basejarname attribute is not "
+ + "compatible with the "
+ + config.namingScheme.getValue() + " naming scheme");
+ }
+ }
+
+ /**
+ * Gets the destination directory.
+ *
+ * @return destination directory
+ * @since ant 1.6
+ */
+ public File getDestdir() {
+ return this.destDir;
+ }
+
+ /**
+ * Set the destination directory. The EJB jar files will be written into
+ * this directory. The jar files that exist in this directory are also
+ * used when determining if the contents of the jar file have changed.
+ * Note that this parameter is only used if no deployment tools are
+ * specified. Typically each deployment tool will specify its own
+ * destination directory.
+ *
+ * @param inDir the destination directory in which to generate jars
+ */
+ public void setDestdir(File inDir) {
+ this.destDir = inDir;
+ }
+
+ /**
+ * Gets the CMP version.
+ *
+ * @return CMP version
+ * @since ant 1.6
+ */
+ public String getCmpversion() {
+ return this.cmpVersion;
+ }
+
+ /**
+ * Sets the CMP version.
+ *
+ * @param version CMP version.
+ * Must be either <code>1.0</code> or <code>2.0</code>.<br/>
+ * Default is <code>1.0</code>.<br/>
+ * Initially, only the JBoss implementation does something specific for CMP 2.0.<br/>
+ * @since ant 1.6
+ */
+ public void setCmpversion(CMPVersion version) {
+ this.cmpVersion = version.getValue();
+ }
+
+ /**
+ * Set the classpath to use when resolving classes for inclusion in the jar.
+ *
+ * @param classpath the classpath to use.
+ */
+ public void setClasspath(Path classpath) {
+ config.classpath = classpath;
+ }
+
+ /**
+ * Controls whether the
+ * destination JARs are written out in the destination directory with
+ * the same hierarchical structure from which the deployment descriptors
+ * have been read. If this is set to true the generated EJB jars are
+ * written into the root of the destination directory, otherwise they
+ * are written out in the same relative position as the deployment
+ * descriptors in the descriptor directory.
+ *
+ * @param inValue the new value of the flatdestdir flag.
+ */
+ public void setFlatdestdir(boolean inValue) {
+ config.flatDestDir = inValue;
+ }
+
+ /**
+ * Set the suffix for the generated jar file. When generic jars are
+ * generated, they have a suffix which is appended to the the bean name
+ * to create the name of the jar file. Note that this suffix includes
+ * the extension fo te jar file and should therefore end with an
+ * appropriate extension such as .jar or .ear
+ *
+ * @param inString the string to use as the suffix.
+ */
+ public void setGenericjarsuffix(String inString) {
+ this.genericJarSuffix = inString;
+ }
+
+ /**
+ * The string which terminates the bean name.
+ * The convention used by this task is
+ * that bean descriptors are named as the BeanName with some suffix. The
+ * baseNameTerminator string separates the bean name and the suffix and
+ * is used to determine the bean name.
+ *
+ * @param inValue a string which marks the end of the basename.
+ */
+ public void setBasenameterminator(String inValue) {
+ config.baseNameTerminator = inValue;
+ }
+
+ /**
+ * Validate the config that has been configured from the build file
+ *
+ * @throws BuildException if the config is not valid
+ */
+ private void validateConfig() throws BuildException {
+ if (config.srcDir == null) {
+ throw new BuildException("The srcDir attribute must be specified");
+ }
+
+ if (config.descriptorDir == null) {
+ config.descriptorDir = config.srcDir;
+ }
+
+ if (config.namingScheme == null) {
+ config.namingScheme = new NamingScheme();
+ config.namingScheme.setValue(NamingScheme.DESCRIPTOR);
+ } else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
+ && config.baseJarName == null) {
+ throw new BuildException("The basejarname attribute must "
+ + "be specified with the basejarname naming scheme");
+ }
+ }
+
+ /**
+ * Invoked by Ant after the task is prepared, when it is ready to execute
+ * this task.
+ *
+ * This will configure all of the nested deployment tools to allow them to
+ * process the jar. If no deployment tools have been configured a generic
+ * tool is created to handle the jar.
+ *
+ * A parser is configured and then each descriptor found is passed to all
+ * the deployment tool elements for processing.
+ *
+ * @exception BuildException thrown whenever a problem is
+ * encountered that cannot be recovered from, to signal to ant
+ * that a major problem occurred within this task.
+ */
+ public void execute() throws BuildException {
+ validateConfig();
+
+ if (deploymentTools.size() == 0) {
+ GenericDeploymentTool genericTool = new GenericDeploymentTool();
+ genericTool.setTask(this);
+ genericTool.setDestdir(destDir);
+ genericTool.setGenericJarSuffix(genericJarSuffix);
+ deploymentTools.add(genericTool);
+ }
+
+ for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
+ EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
+ tool.configure(config);
+ tool.validateConfigured();
+ }
+
+ try {
+ // Create the parser using whatever parser the system dictates
+ SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+ saxParserFactory.setValidating(true);
+ SAXParser saxParser = saxParserFactory.newSAXParser();
+
+
+ DirectoryScanner ds = getDirectoryScanner(config.descriptorDir);
+ ds.scan();
+ String[] files = ds.getIncludedFiles();
+
+ log(files.length + " deployment descriptors located.",
+ Project.MSG_VERBOSE);
+
+ // Loop through the files. Each file represents one deployment
+ // descriptor, and hence one bean in our model.
+ for (int index = 0; index < files.length; ++index) {
+ // process the deployment descriptor in each tool
+ for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
+ EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
+ tool.processDescriptor(files[index], saxParser);
+ }
+ }
+ } catch (SAXException se) {
+ String msg = "SAXException while creating parser."
+ + " Details: "
+ + se.getMessage();
+ throw new BuildException(msg, se);
+ } catch (ParserConfigurationException pce) {
+ String msg = "ParserConfigurationException while creating parser. "
+ + "Details: " + pce.getMessage();
+ throw new BuildException(msg, pce);
+ }
+ } // end of execute()
+
+}
+
+
+
+
+
+
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
new file mode 100644
index 00000000..069bdfcf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
@@ -0,0 +1,953 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import javax.xml.parsers.SAXParser;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * A deployment tool which creates generic EJB jars. Generic jars contains
+ * only those classes and META-INF entries specified in the EJB 1.1 standard
+ *
+ * This class is also used as a framework for the creation of vendor specific
+ * deployment tools. A number of template methods are provided through which the
+ * vendor specific tool can hook into the EJB creation process.
+ *
+ */
+public class GenericDeploymentTool implements EJBDeploymentTool {
+ /** The default buffer byte size to use for IO */
+ public static final int DEFAULT_BUFFER_SIZE = 1024;
+ /** The level to use for compression */
+ public static final int JAR_COMPRESS_LEVEL = 9;
+
+ /** The standard META-INF directory in jar files */
+ protected static final String META_DIR = "META-INF/";
+
+ /** The standard MANIFEST file */
+ protected static final String MANIFEST = META_DIR + "MANIFEST.MF";
+
+ /** Name for EJB Deployment descriptor within EJB jars */
+ protected static final String EJB_DD = "ejb-jar.xml";
+
+ /** A dependency analyzer name to find ancestor classes */
+ public static final String ANALYZER_SUPER = "super";
+ /** A dependency analyzer name to find all related classes */
+ public static final String ANALYZER_FULL = "full";
+ /** A dependency analyzer name for no analyzer */
+ public static final String ANALYZER_NONE = "none";
+
+ /** The default analyzer */
+ public static final String DEFAULT_ANALYZER = ANALYZER_SUPER;
+
+ /** The analyzer class for the super analyzer */
+ public static final String ANALYZER_CLASS_SUPER
+ = "org.apache.tools.ant.util.depend.bcel.AncestorAnalyzer";
+ /** The analyzer class for the super analyzer */
+ public static final String ANALYZER_CLASS_FULL
+ = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer";
+
+ /**
+ * The configuration from the containing task. This config combined
+ * with the settings of the individual attributes here constitues the
+ * complete config for this deployment tool.
+ */
+ private EjbJar.Config config;
+
+ /** Stores a handle to the directory to put the Jar files in */
+ private File destDir;
+
+ /** The classpath to use with this deployment tool. This is appended to
+ any paths from the ejbjar task itself.*/
+ private Path classpath;
+
+ /** Instance variable that stores the suffix for the generated jarfile. */
+ private String genericJarSuffix = "-generic.jar";
+
+ /**
+ * The task to which this tool belongs. This is used to access services
+ * provided by the ant core, such as logging.
+ */
+ private Task task;
+
+ /**
+ * The classloader generated from the given classpath to load
+ * the super classes and super interfaces.
+ */
+ private ClassLoader classpathLoader = null;
+
+ /**
+ * Set of files have been loaded into the EJB jar
+ */
+ private Set addedfiles;
+
+ /**
+ * Handler used to parse the EJB XML descriptor
+ */
+ private DescriptorHandler handler;
+
+ /**
+ * Dependency analyzer used to collect class dependencies
+ */
+ private DependencyAnalyzer dependencyAnalyzer;
+
+ /** No arg constructor */
+ public GenericDeploymentTool() {
+ }
+
+
+ /**
+ * Set the destination directory; required.
+ * @param inDir the destination directory.
+ */
+ public void setDestdir(File inDir) {
+ this.destDir = inDir;
+ }
+
+ /**
+ * Get the destination directory.
+ *
+ * @return the destination directory into which EJB jars are to be written
+ */
+ protected File getDestDir() {
+ return destDir;
+ }
+
+
+ /**
+ * Set the task which owns this tool
+ *
+ * @param task the Task to which this deployment tool is associated.
+ */
+ public void setTask(Task task) {
+ this.task = task;
+ }
+
+ /**
+ * Get the task for this tool.
+ *
+ * @return the Task instance this tool is associated with.
+ */
+ protected Task getTask() {
+ return task;
+ }
+
+ /**
+ * Get the basename terminator.
+ *
+ * @return an ejbjar task configuration
+ */
+ protected EjbJar.Config getConfig() {
+ return config;
+ }
+
+ /**
+ * Indicate if this build is using the base jar name.
+ *
+ * @return true if the name of the generated jar is coming from the
+ * basejarname attribute
+ */
+ protected boolean usingBaseJarName() {
+ return config.baseJarName != null;
+ }
+
+ /**
+ * Set the suffix for the generated jar file.
+ * @param inString the string to use as the suffix.
+ */
+ public void setGenericJarSuffix(String inString) {
+ this.genericJarSuffix = inString;
+ }
+
+ /**
+ * Add the classpath for the user classes
+ *
+ * @return a Path instance to be configured by Ant.
+ */
+ public Path createClasspath() {
+ if (classpath == null) {
+ classpath = new Path(task.getProject());
+ }
+ return classpath.createPath();
+ }
+
+ /**
+ * Set the classpath to be used for this compilation.
+ *
+ * @param classpath the classpath to be used for this build.
+ */
+ public void setClasspath(Path classpath) {
+ this.classpath = classpath;
+ }
+
+ /**
+ * Get the classpath by combining the one from the surrounding task, if any
+ * and the one from this tool.
+ *
+ * @return the combined classpath
+ */
+ protected Path getCombinedClasspath() {
+ Path combinedPath = classpath;
+ if (config.classpath != null) {
+ if (combinedPath == null) {
+ combinedPath = config.classpath;
+ } else {
+ combinedPath.append(config.classpath);
+ }
+ }
+
+ return combinedPath;
+ }
+
+ /**
+ * Log a message to the Ant output.
+ *
+ * @param message the message to be logged.
+ * @param level the severity of this message.
+ */
+ protected void log(String message, int level) {
+ getTask().log(message, level);
+ }
+
+ /**
+ * Get the build file location associated with this element's task.
+ *
+ * @return the task's location instance.
+ */
+ protected Location getLocation() {
+ return getTask().getLocation();
+ }
+
+ private void createAnalyzer() {
+ String analyzer = config.analyzer;
+ if (analyzer == null) {
+ analyzer = DEFAULT_ANALYZER;
+ }
+
+ if (analyzer.equals(ANALYZER_NONE)) {
+ return;
+ }
+
+ String analyzerClassName = null;
+ if (analyzer.equals(ANALYZER_SUPER)) {
+ analyzerClassName = ANALYZER_CLASS_SUPER;
+ } else if (analyzer.equals(ANALYZER_FULL)) {
+ analyzerClassName = ANALYZER_CLASS_FULL;
+ } else {
+ analyzerClassName = analyzer;
+ }
+
+ try {
+ Class analyzerClass = Class.forName(analyzerClassName);
+ dependencyAnalyzer
+ = (DependencyAnalyzer) analyzerClass.newInstance();
+ dependencyAnalyzer.addClassPath(new Path(task.getProject(),
+ config.srcDir.getPath()));
+ dependencyAnalyzer.addClassPath(config.classpath);
+ } catch (NoClassDefFoundError e) {
+ dependencyAnalyzer = null;
+ task.log("Unable to load dependency analyzer: " + analyzerClassName
+ + " - dependent class not found: " + e.getMessage(),
+ Project.MSG_WARN);
+ } catch (Exception e) {
+ dependencyAnalyzer = null;
+ task.log("Unable to load dependency analyzer: " + analyzerClassName
+ + " - exception: " + e.getMessage(),
+ Project.MSG_WARN);
+ }
+ }
+
+
+ /**
+ * Configure this tool for use in the ejbjar task.
+ *
+ * @param config the configuration from the surrounding ejbjar task.
+ */
+ public void configure(EjbJar.Config config) {
+ this.config = config;
+
+ createAnalyzer();
+ classpathLoader = null;
+ }
+
+ /**
+ * Utility method that encapsulates the logic of adding a file entry to
+ * a .jar file. Used by execute() to add entries to the jar file as it is
+ * constructed.
+ * @param jStream A JarOutputStream into which to write the
+ * jar entry.
+ * @param inputFile A File from which to read the
+ * contents the file being added.
+ * @param logicalFilename A String representing the name, including
+ * all relevant path information, that should be stored for the entry
+ * being added.
+ * @throws BuildException if there is a problem.
+ */
+ protected void addFileToJar(JarOutputStream jStream,
+ File inputFile,
+ String logicalFilename)
+ throws BuildException {
+ FileInputStream iStream = null;
+ try {
+ if (!addedfiles.contains(logicalFilename)) {
+ iStream = new FileInputStream(inputFile);
+ // Create the zip entry and add it to the jar file
+ ZipEntry zipEntry = new ZipEntry(logicalFilename.replace('\\', '/'));
+ jStream.putNextEntry(zipEntry);
+
+ // Create the file input stream, and buffer everything over
+ // to the jar output stream
+ byte[] byteBuffer = new byte[2 * DEFAULT_BUFFER_SIZE];
+ int count = 0;
+ do {
+ jStream.write(byteBuffer, 0, count);
+ count = iStream.read(byteBuffer, 0, byteBuffer.length);
+ } while (count != -1);
+
+ //add it to list of files in jar
+ addedfiles.add(logicalFilename);
+ }
+ } catch (IOException ioe) {
+ log("WARNING: IOException while adding entry "
+ + logicalFilename + " to jarfile from "
+ + inputFile.getPath() + " " + ioe.getClass().getName()
+ + "-" + ioe.getMessage(), Project.MSG_WARN);
+ } finally {
+ // Close up the file input stream for the class file
+ if (iStream != null) {
+ try {
+ iStream.close();
+ } catch (IOException closeException) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Get a descriptionHandler.
+ * @param srcDir the source directory.
+ * @return a handler.
+ */
+ protected DescriptorHandler getDescriptorHandler(File srcDir) {
+ DescriptorHandler h = new DescriptorHandler(getTask(), srcDir);
+
+ registerKnownDTDs(h);
+
+ // register any DTDs supplied by the user
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+ h.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+ }
+ return h;
+ }
+
+ /**
+ * Register the locations of all known DTDs.
+ *
+ * vendor-specific subclasses should override this method to define
+ * the vendor-specific locations of the EJB DTDs
+ * @param handler no used in this class.
+ */
+ protected void registerKnownDTDs(DescriptorHandler handler) {
+ // none to register for generic
+ }
+
+ /** {@inheritDoc}. */
+ public void processDescriptor(String descriptorFileName, SAXParser saxParser) {
+
+ checkConfiguration(descriptorFileName, saxParser);
+
+ try {
+ handler = getDescriptorHandler(config.srcDir);
+
+ // Retrive the files to be added to JAR from EJB descriptor
+ Hashtable ejbFiles = parseEjbFiles(descriptorFileName, saxParser);
+
+ // Add any support classes specified in the build file
+ addSupportClasses(ejbFiles);
+
+ // Determine the JAR filename (without filename extension)
+ String baseName = getJarBaseName(descriptorFileName);
+
+ String ddPrefix = getVendorDDPrefix(baseName, descriptorFileName);
+
+ File manifestFile = getManifestFile(ddPrefix);
+ if (manifestFile != null) {
+ ejbFiles.put(MANIFEST, manifestFile);
+ }
+
+
+
+ // First the regular deployment descriptor
+ ejbFiles.put(META_DIR + EJB_DD,
+ new File(config.descriptorDir, descriptorFileName));
+
+ // now the vendor specific files, if any
+ addVendorFiles(ejbFiles, ddPrefix);
+
+ // add any dependent files
+ checkAndAddDependants(ejbFiles);
+
+ // Lastly create File object for the Jar files. If we are using
+ // a flat destination dir, then we need to redefine baseName!
+ if (config.flatDestDir && baseName.length() != 0) {
+ int startName = baseName.lastIndexOf(File.separator);
+ if (startName == -1) {
+ startName = 0;
+ }
+
+ int endName = baseName.length();
+ baseName = baseName.substring(startName, endName);
+ }
+
+ File jarFile = getVendorOutputJarFile(baseName);
+
+
+ // Check to see if we need a build and start doing the work!
+ if (needToRebuild(ejbFiles, jarFile)) {
+ // Log that we are going to build...
+ log("building "
+ + jarFile.getName()
+ + " with "
+ + String.valueOf(ejbFiles.size())
+ + " files",
+ Project.MSG_INFO);
+
+ // Use helper method to write the jarfile
+ String publicId = getPublicId();
+ writeJar(baseName, jarFile, ejbFiles, publicId);
+
+ } else {
+ // Log that the file is up to date...
+ log(jarFile.toString() + " is up to date.",
+ Project.MSG_VERBOSE);
+ }
+
+ } catch (SAXException se) {
+ String msg = "SAXException while parsing '"
+ + descriptorFileName
+ + "'. This probably indicates badly-formed XML."
+ + " Details: "
+ + se.getMessage();
+ throw new BuildException(msg, se);
+ } catch (IOException ioe) {
+ String msg = "IOException while parsing'"
+ + descriptorFileName
+ + "'. This probably indicates that the descriptor"
+ + " doesn't exist. Details: "
+ + ioe.getMessage();
+ throw new BuildException(msg, ioe);
+ }
+ }
+
+ /**
+ * This method is called as the first step in the processDescriptor method
+ * to allow vendor-specific subclasses to validate the task configuration
+ * prior to processing the descriptor. If the configuration is invalid,
+ * a BuildException should be thrown.
+ *
+ * @param descriptorFileName String representing the file name of an EJB
+ * descriptor to be processed
+ * @param saxParser SAXParser which may be used to parse the XML
+ * descriptor
+ * @throws BuildException if there is a problem.
+ */
+ protected void checkConfiguration(String descriptorFileName,
+ SAXParser saxParser) throws BuildException {
+
+ /*
+ * For the GenericDeploymentTool, do nothing. Vendor specific
+ * subclasses should throw a BuildException if the configuration is
+ * invalid for their server.
+ */
+ }
+
+ /**
+ * This method returns a list of EJB files found when the specified EJB
+ * descriptor is parsed and processed.
+ *
+ * @param descriptorFileName String representing the file name of an EJB
+ * descriptor to be processed
+ * @param saxParser SAXParser which may be used to parse the XML
+ * descriptor
+ * @return Hashtable of EJB class (and other) files to be
+ * added to the completed JAR file
+ * @throws SAXException Any SAX exception, possibly wrapping another
+ * exception
+ * @throws IOException An IOException from the parser, possibly from a
+ * the byte stream or character stream
+ */
+ protected Hashtable parseEjbFiles(String descriptorFileName, SAXParser saxParser)
+ throws IOException, SAXException {
+ FileInputStream descriptorStream = null;
+ Hashtable ejbFiles = null;
+
+ try {
+
+ /* Parse the ejb deployment descriptor. While it may not
+ * look like much, we use a SAXParser and an inner class to
+ * get hold of all the classfile names for the descriptor.
+ */
+ descriptorStream
+ = new FileInputStream(new File(config.descriptorDir, descriptorFileName));
+ saxParser.parse(new InputSource(descriptorStream), handler);
+
+ ejbFiles = handler.getFiles();
+
+ } finally {
+ if (descriptorStream != null) {
+ try {
+ descriptorStream.close();
+ } catch (IOException closeException) {
+ // ignore
+ }
+ }
+ }
+
+ return ejbFiles;
+ }
+
+ /**
+ * Adds any classes the user specifies using <i>support</i> nested elements
+ * to the <code>ejbFiles</code> Hashtable.
+ *
+ * @param ejbFiles Hashtable of EJB classes (and other) files that will be
+ * added to the completed JAR file
+ */
+ protected void addSupportClasses(Hashtable ejbFiles) {
+ // add in support classes if any
+ Project project = task.getProject();
+ for (Iterator i = config.supportFileSets.iterator(); i.hasNext();) {
+ FileSet supportFileSet = (FileSet) i.next();
+ File supportBaseDir = supportFileSet.getDir(project);
+ DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project);
+ supportScanner.scan();
+ String[] supportFiles = supportScanner.getIncludedFiles();
+ for (int j = 0; j < supportFiles.length; ++j) {
+ ejbFiles.put(supportFiles[j], new File(supportBaseDir, supportFiles[j]));
+ }
+ }
+ }
+
+
+ /**
+ * Using the EJB descriptor file name passed from the <code>ejbjar</code>
+ * task, this method returns the "basename" which will be used to name the
+ * completed JAR file.
+ *
+ * @param descriptorFileName String representing the file name of an EJB
+ * descriptor to be processed
+ * @return The "basename" which will be used to name the
+ * completed JAR file
+ */
+ protected String getJarBaseName(String descriptorFileName) {
+
+ String baseName = "";
+
+ // Work out what the base name is
+ if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)) {
+ String canonicalDescriptor = descriptorFileName.replace('\\', '/');
+ int index = canonicalDescriptor.lastIndexOf('/');
+ if (index != -1) {
+ baseName = descriptorFileName.substring(0, index + 1);
+ }
+ baseName += config.baseJarName;
+ } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
+ int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator);
+ int endBaseName = -1;
+ if (lastSeparatorIndex != -1) {
+ endBaseName = descriptorFileName.indexOf(config.baseNameTerminator,
+ lastSeparatorIndex);
+ } else {
+ endBaseName = descriptorFileName.indexOf(config.baseNameTerminator);
+ }
+
+ if (endBaseName != -1) {
+ baseName = descriptorFileName.substring(0, endBaseName);
+ } else {
+ throw new BuildException("Unable to determine jar name "
+ + "from descriptor \"" + descriptorFileName + "\"");
+ }
+ } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) {
+ File descriptorFile = new File(config.descriptorDir, descriptorFileName);
+ String path = descriptorFile.getAbsolutePath();
+ int lastSeparatorIndex
+ = path.lastIndexOf(File.separator);
+ if (lastSeparatorIndex == -1) {
+ throw new BuildException("Unable to determine directory name holding descriptor");
+ }
+ String dirName = path.substring(0, lastSeparatorIndex);
+ int dirSeparatorIndex = dirName.lastIndexOf(File.separator);
+ if (dirSeparatorIndex != -1) {
+ dirName = dirName.substring(dirSeparatorIndex + 1);
+ }
+
+ baseName = dirName;
+ } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)) {
+ baseName = handler.getEjbName();
+ }
+ return baseName;
+ }
+
+ /**
+ * Get the prefix for vendor deployment descriptors.
+ *
+ * This will contain the path and the start of the descriptor name,
+ * depending on the naming scheme
+ * @param baseName the base name to use.
+ * @param descriptorFileName the file name to use.
+ * @return the prefix.
+ */
+ public String getVendorDDPrefix(String baseName, String descriptorFileName) {
+ String ddPrefix = null;
+
+ if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
+ ddPrefix = baseName + config.baseNameTerminator;
+ } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)
+ || config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)
+ || config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) {
+ String canonicalDescriptor = descriptorFileName.replace('\\', '/');
+ int index = canonicalDescriptor.lastIndexOf('/');
+ if (index == -1) {
+ ddPrefix = "";
+ } else {
+ ddPrefix = descriptorFileName.substring(0, index + 1);
+ }
+ }
+ return ddPrefix;
+ }
+
+ /**
+ * Add any vendor specific files which should be included in the
+ * EJB Jar.
+ * @param ejbFiles a hashtable entryname -> file.
+ * @param ddPrefix a prefix to use.
+ */
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+ // nothing to add for generic tool.
+ }
+
+
+ /**
+ * Get the vendor specific name of the Jar that will be output. The modification date
+ * of this jar will be checked against the dependent bean classes.
+ * @param baseName the basename to use.
+ */
+ File getVendorOutputJarFile(String baseName) {
+ return new File(destDir, baseName + genericJarSuffix);
+ }
+
+ /**
+ * This method checks the timestamp on each file listed in the <code>
+ * ejbFiles</code> and compares them to the timestamp on the <code>jarFile
+ * </code>. If the <code>jarFile</code>'s timestamp is more recent than
+ * each EJB file, <code>true</code> is returned. Otherwise, <code>false
+ * </code> is returned.
+ * TODO: find a way to check the manifest-file, that is found by naming convention
+ *
+ * @param ejbFiles Hashtable of EJB classes (and other) files that will be
+ * added to the completed JAR file
+ * @param jarFile JAR file which will contain all of the EJB classes (and
+ * other) files
+ * @return boolean indicating whether or not the <code>jarFile</code>
+ * is up to date
+ */
+ protected boolean needToRebuild(Hashtable ejbFiles, File jarFile) {
+ if (jarFile.exists()) {
+ long lastBuild = jarFile.lastModified();
+
+ Iterator fileIter = ejbFiles.values().iterator();
+
+ // Loop through the files seeing if any has been touched
+ // more recently than the destination jar.
+ while (fileIter.hasNext()) {
+ File currentFile = (File) fileIter.next();
+ if (lastBuild < currentFile.lastModified()) {
+ log("Build needed because " + currentFile.getPath() + " is out of date",
+ Project.MSG_VERBOSE);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the Public ID of the DTD specified in the EJB descriptor. Not
+ * every vendor-specific <code>DeploymentTool</code> will need to reference
+ * this value or may want to determine this value in a vendor-specific way.
+ *
+ * @return Public ID of the DTD specified in the EJB descriptor.
+ */
+ protected String getPublicId() {
+ return handler.getPublicId();
+ }
+
+ /**
+ * Get the manifest file to use for building the generic jar.
+ *
+ * If the file does not exist the global manifest from the config is used
+ * otherwise the default Ant manifest will be used.
+ *
+ * @param prefix the prefix where to llook for the manifest file based on
+ * the naming convention.
+ *
+ * @return the manifest file or null if the manifest file does not exist
+ */
+ protected File getManifestFile(String prefix) {
+ File manifestFile
+ = new File(getConfig().descriptorDir, prefix + "manifest.mf");
+ if (manifestFile.exists()) {
+ return manifestFile;
+ }
+
+ if (config.manifest != null) {
+ return config.manifest;
+ }
+ return null;
+ }
+
+ /**
+ * Method used to encapsulate the writing of the JAR file. Iterates over the
+ * filenames/java.io.Files in the Hashtable stored on the instance variable
+ * ejbFiles.
+ * @param baseName the base name to use.
+ * @param jarfile the jar file to write to.
+ * @param files the files to write to the jar.
+ * @param publicId the id to use.
+ * @throws BuildException if there is a problem.
+ */
+ protected void writeJar(String baseName, File jarfile, Hashtable files,
+ String publicId) throws BuildException {
+
+ JarOutputStream jarStream = null;
+ try {
+ // clean the addedfiles set
+ if (addedfiles == null) {
+ addedfiles = new HashSet();
+ } else {
+ addedfiles.clear();
+ }
+
+ /* If the jarfile already exists then whack it and recreate it.
+ * Should probably think of a more elegant way to handle this
+ * so that in case of errors we don't leave people worse off
+ * than when we started =)
+ */
+ if (jarfile.exists()) {
+ jarfile.delete();
+ }
+ jarfile.getParentFile().mkdirs();
+ jarfile.createNewFile();
+
+ InputStream in = null;
+ Manifest manifest = null;
+ try {
+ File manifestFile = (File) files.get(MANIFEST);
+ if (manifestFile != null && manifestFile.exists()) {
+ in = new FileInputStream(manifestFile);
+ } else {
+ String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf";
+ in = this.getClass().getResourceAsStream(defaultManifest);
+ if (in == null) {
+ throw new BuildException("Could not find "
+ + "default manifest: " + defaultManifest);
+ }
+ }
+
+ manifest = new Manifest(in);
+ } catch (IOException e) {
+ throw new BuildException ("Unable to read manifest", e, getLocation());
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+
+ // Create the streams necessary to write the jarfile
+
+ jarStream = new JarOutputStream(new FileOutputStream(jarfile), manifest);
+ jarStream.setMethod(JarOutputStream.DEFLATED);
+
+ // Loop through all the class files found and add them to the jar
+ for (Iterator entryIterator = files.keySet().iterator(); entryIterator.hasNext();) {
+ String entryName = (String) entryIterator.next();
+ if (entryName.equals(MANIFEST)) {
+ continue;
+ }
+
+ File entryFile = (File) files.get(entryName);
+
+ log("adding file '" + entryName + "'",
+ Project.MSG_VERBOSE);
+
+ addFileToJar(jarStream, entryFile, entryName);
+
+ // See if there are any inner classes for this class and add them in if there are
+ InnerClassFilenameFilter flt = new InnerClassFilenameFilter(entryFile.getName());
+ File entryDir = entryFile.getParentFile();
+ String[] innerfiles = entryDir.list(flt);
+ if (innerfiles != null) {
+ for (int i = 0, n = innerfiles.length; i < n; i++) {
+
+ //get and clean up innerclass name
+ int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1;
+ if (entryIndex < 0) {
+ entryName = innerfiles[i];
+ } else {
+ entryName = entryName.substring(0, entryIndex)
+ + File.separatorChar + innerfiles[i];
+ }
+ // link the file
+ entryFile = new File(config.srcDir, entryName);
+
+ log("adding innerclass file '" + entryName + "'",
+ Project.MSG_VERBOSE);
+
+ addFileToJar(jarStream, entryFile, entryName);
+
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ String msg = "IOException while processing ejb-jar file '"
+ + jarfile.toString()
+ + "'. Details: "
+ + ioe.getMessage();
+ throw new BuildException(msg, ioe);
+ } finally {
+ if (jarStream != null) {
+ try {
+ jarStream.close();
+ } catch (IOException closeException) {
+ // ignore
+ }
+ }
+ }
+ } // end of writeJar
+
+
+ /**
+ * Add all available classes, that depend on Remote, Home, Bean, PK
+ * @param checkEntries files, that are extracted from the deployment descriptor
+ * @throws BuildException if there is a problem.
+ */
+ protected void checkAndAddDependants(Hashtable checkEntries)
+ throws BuildException {
+
+ if (dependencyAnalyzer == null) {
+ return;
+ }
+
+ dependencyAnalyzer.reset();
+
+ Iterator i = checkEntries.keySet().iterator();
+ while (i.hasNext()) {
+ String entryName = (String) i.next();
+ if (entryName.endsWith(".class")) {
+ String className = entryName.substring(0,
+ entryName.length() - ".class".length());
+ className = className.replace(File.separatorChar, '/');
+ className = className.replace('/', '.');
+
+ dependencyAnalyzer.addRootClass(className);
+ }
+ }
+
+ Enumeration e = dependencyAnalyzer.getClassDependencies();
+
+ while (e.hasMoreElements()) {
+ String classname = (String) e.nextElement();
+ String location
+ = classname.replace('.', File.separatorChar) + ".class";
+ File classFile = new File(config.srcDir, location);
+ if (classFile.exists()) {
+ checkEntries.put(location, classFile);
+ log("dependent class: " + classname + " - " + classFile,
+ Project.MSG_VERBOSE);
+ }
+ }
+ }
+
+
+ /**
+ * Returns a Classloader object which parses the passed in generic EjbJar classpath.
+ * The loader is used to dynamically load classes from javax.ejb.* and the classes
+ * being added to the jar.
+ * @return a classloader.
+ */
+ protected ClassLoader getClassLoaderForBuild() {
+ if (classpathLoader != null) {
+ return classpathLoader;
+ }
+
+ Path combinedClasspath = getCombinedClasspath();
+
+ // only generate a new ClassLoader if we have a classpath
+ if (combinedClasspath == null) {
+ classpathLoader = getClass().getClassLoader();
+ } else {
+ // Memory leak in line below
+ classpathLoader
+ = getTask().getProject().createClassLoader(combinedClasspath);
+ }
+
+ return classpathLoader;
+ }
+
+ /**
+ * Called to validate that the tool parameters have been configured.
+ *
+ * @throws BuildException If the Deployment Tool's configuration isn't
+ * valid
+ */
+ public void validateConfigured() throws BuildException {
+ if ((destDir == null) || (!destDir.isDirectory())) {
+ String msg = "A valid destination directory must be specified "
+ + "using the \"destdir\" attribute.";
+ throw new BuildException(msg, getLocation());
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java
new file mode 100644
index 00000000..cbc8526a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.xml.parsers.SAXParser;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.xml.sax.SAXException;
+
+/**
+ * This class is used to generate iPlanet Application Server (iAS) 6.0 stubs and
+ * skeletons and build an EJB Jar file. It is designed to be used with the Ant
+ * <code>ejbjar</code> task. If only stubs and skeletons need to be generated
+ * (in other words, if no JAR file needs to be created), refer to the
+ * <code>iplanet-ejbc</code> task and the <code>IPlanetEjbcTask</code> class.
+ * <p>
+ * The following attributes may be specified by the user:
+ * <ul>
+ * <li><i>destdir</i> -- The base directory into which the generated JAR
+ * files will be written. Each JAR file is written
+ * in directories which correspond to their location
+ * within the "descriptordir" namespace. This is a
+ * required attribute.
+ * <li><i>classpath</i> -- The classpath used when generating EJB stubs and
+ * skeletons. This is an optional attribute (if
+ * omitted, the classpath specified in the "ejbjar"
+ * parent task will be used). If specified, the
+ * classpath elements will be prepended to the
+ * classpath specified in the parent "ejbjar" task.
+ * Note that nested "classpath" elements may also be
+ * used.
+ * <li><i>keepgenerated</i> -- Indicates whether or not the Java source
+ * files which are generated by ejbc will be
+ * saved or automatically deleted. If "yes",
+ * the source files will be retained. This is
+ * an optional attribute (if omitted, it
+ * defaults to "no").
+ * <li><i>debug</i> -- Indicates whether or not the ejbc utility should
+ * log additional debugging statements to the standard
+ * output. If "yes", the additional debugging statements
+ * will be generated (if omitted, it defaults to "no").
+ * <li><i>iashome</i> -- May be used to specify the "home" directory for
+ * this iPlanet Application server installation. This
+ * is used to find the ejbc utility if it isn't
+ * included in the user's system path. This is an
+ * optional attribute (if specified, it should refer
+ * to the <code>[install-location]/iplanet/ias6/ias
+ * </code> directory). If omitted, the ejbc utility
+ * must be on the user's system path.
+ * <li><i>suffix</i> -- String value appended to the JAR filename when
+ * creating each JAR. This attribute is not required
+ * (if omitted, it defaults to ".jar").
+ * </ul>
+ * <p>
+ * For each EJB descriptor found in the "ejbjar" parent task, this deployment
+ * tool will locate the three classes that comprise the EJB. If these class
+ * files cannot be located in the specified <code>srcdir</code> directory, the
+ * task will fail. The task will also attempt to locate the EJB stubs and
+ * skeletons in this directory. If found, the timestamps on the stubs and
+ * skeletons will be checked to ensure they are up to date. Only if these files
+ * cannot be found or if they are out of date will ejbc be called.
+ *
+ * @see IPlanetEjbc
+ */
+public class IPlanetDeploymentTool extends GenericDeploymentTool {
+
+ /* Attributes set by the Ant build file */
+ private File iashome;
+ private String jarSuffix = ".jar";
+ private boolean keepgenerated = false;
+ private boolean debug = false;
+
+ /*
+ * Filenames of the standard EJB descriptor (which is passed to this class
+ * from the parent "ejbjar" task) and the iAS-specific EJB descriptor
+ * (whose name is determined by this class). Both filenames are relative
+ * to the directory specified by the "srcdir" attribute in the ejbjar task.
+ */
+ private String descriptorName;
+ private String iasDescriptorName;
+
+ /*
+ * The displayName variable stores the value of the "display-name" element
+ * from the standard EJB descriptor. As a future enhancement to this task,
+ * we may determine the name of the EJB JAR file using this display-name,
+ * but this has not be implemented yet.
+ */
+ private String displayName;
+
+ /*
+ * Regardless of the name of the iAS-specific EJB descriptor file, it will
+ * written in the completed JAR file as "ias-ejb-jar.xml". This is the
+ * naming convention implemented by iAS.
+ */
+ private static final String IAS_DD = "ias-ejb-jar.xml";
+
+ /**
+ * Setter method used to store the "home" directory of the user's iAS
+ * installation. The directory specified should typically be
+ * <code>[install-location]/iplanet/ias6/ias</code>.
+ *
+ * @param iashome The home directory for the user's iAS installation.
+ */
+ public void setIashome(File iashome) {
+ this.iashome = iashome;
+ }
+
+ /**
+ * Setter method used to specify whether the Java source files generated by
+ * the ejbc utility should be saved or automatically deleted.
+ *
+ * @param keepgenerated boolean which, if <code>true</code>, indicates that
+ * Java source files generated by ejbc for the stubs
+ * and skeletons should be kept.
+ */
+ public void setKeepgenerated(boolean keepgenerated) {
+ this.keepgenerated = keepgenerated;
+ }
+
+ /**
+ * Sets whether or not debugging output will be generated when ejbc is
+ * executed.
+ *
+ * @param debug A boolean indicating if debugging output should be generated
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * Setter method used to specify the filename suffix (for example, ".jar")
+ * for the JAR files to be created.
+ *
+ * @param jarSuffix The string to use as the JAR filename suffix.
+ */
+ public void setSuffix(String jarSuffix) {
+ this.jarSuffix = jarSuffix;
+ }
+
+ /**
+ * Since iAS doesn't generate a "generic" JAR as part of its processing,
+ * this attribute is ignored and a warning message is displayed to the user.
+ *
+ * @param inString the string to use as the suffix. This parameter is
+ * ignored.
+ */
+ @Override
+ public void setGenericJarSuffix(String inString) {
+ log("Since a generic JAR file is not created during processing, the "
+ + "iPlanet Deployment Tool does not support the "
+ + "\"genericjarsuffix\" attribute. It will be ignored.",
+ Project.MSG_WARN);
+ }
+
+ /** {@inheritDoc}. */
+ @Override
+ public void processDescriptor(String descriptorName, SAXParser saxParser) {
+ this.descriptorName = descriptorName;
+ this.iasDescriptorName = null;
+
+ log("iPlanet Deployment Tool processing: " + descriptorName + " (and "
+ + getIasDescriptorName() + ")", Project.MSG_VERBOSE);
+
+ super.processDescriptor(descriptorName, saxParser);
+ }
+
+ /**
+ * Verifies that the user selections are valid.
+ *
+ * @param descriptorFileName String representing the file name of an EJB
+ * descriptor to be processed
+ * @param saxParser SAXParser which may be used to parse the XML
+ * descriptor
+ * @throws BuildException If the user selections are invalid.
+ */
+ @Override
+ protected void checkConfiguration(String descriptorFileName,
+ SAXParser saxParser) throws BuildException {
+
+ int startOfName = descriptorFileName.lastIndexOf(File.separatorChar) + 1;
+ String stdXml = descriptorFileName.substring(startOfName);
+ if (stdXml.equals(EJB_DD) && (getConfig().baseJarName == null)) {
+ String msg = "No name specified for the completed JAR file. The EJB"
+ + " descriptor should be prepended with the JAR "
+ + "name or it should be specified using the "
+ + "attribute \"basejarname\" in the \"ejbjar\" task.";
+ throw new BuildException(msg, getLocation());
+ }
+
+ File iasDescriptor = new File(getConfig().descriptorDir,
+ getIasDescriptorName());
+ if ((!iasDescriptor.exists()) || (!iasDescriptor.isFile())) {
+ String msg = "The iAS-specific EJB descriptor ("
+ + iasDescriptor + ") was not found.";
+ throw new BuildException(msg, getLocation());
+ }
+
+ if ((iashome != null) && (!iashome.isDirectory())) {
+ String msg = "If \"iashome\" is specified, it must be a valid "
+ + "directory (it was set to " + iashome + ").";
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * This method returns a list of EJB files found when the specified EJB
+ * descriptor is parsed and processed.
+ *
+ * @param descriptorFileName String representing the file name of an EJB
+ * descriptor to be processed
+ * @param saxParser SAXParser which may be used to parse the XML
+ * descriptor
+ * @return Hashtable of EJB class (and other) files to be
+ * added to the completed JAR file
+ * @throws IOException An IOException from the parser, possibly from
+ * the byte stream or character stream
+ * @throws SAXException Any SAX exception, possibly wrapping another
+ * exception
+ */
+ @Override
+ protected Hashtable parseEjbFiles(String descriptorFileName,
+ SAXParser saxParser) throws IOException, SAXException {
+
+ Hashtable files;
+
+ /* Build and populate an instance of the ejbc utility */
+ IPlanetEjbc ejbc = new IPlanetEjbc(
+ new File(getConfig().descriptorDir,
+ descriptorFileName),
+ new File(getConfig().descriptorDir,
+ getIasDescriptorName()),
+ getConfig().srcDir,
+ getCombinedClasspath().toString(),
+ saxParser);
+ ejbc.setRetainSource(keepgenerated);
+ ejbc.setDebugOutput(debug);
+ if (iashome != null) {
+ ejbc.setIasHomeDir(iashome);
+ }
+ if (getConfig().dtdLocations != null) {
+ for (Iterator i = getConfig().dtdLocations.iterator();
+ i.hasNext();) {
+ EjbJar.DTDLocation dtdLocation =
+ (EjbJar.DTDLocation) i.next();
+ ejbc.registerDTD(dtdLocation.getPublicId(),
+ dtdLocation.getLocation());
+ }
+ }
+
+ /* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */
+ try {
+ ejbc.execute();
+ } catch (IPlanetEjbc.EjbcException e) {
+ throw new BuildException("An error has occurred while trying to "
+ + "execute the iAS ejbc utility", e, getLocation());
+ }
+
+ displayName = ejbc.getDisplayName();
+ files = ejbc.getEjbFiles();
+
+ /* Add CMP descriptors to the list of EJB files */
+ String[] cmpDescriptors = ejbc.getCmpDescriptors();
+ if (cmpDescriptors.length > 0) {
+ File baseDir = getConfig().descriptorDir;
+
+ int endOfPath = descriptorFileName.lastIndexOf(File.separator);
+ String relativePath = descriptorFileName.substring(0, endOfPath + 1);
+
+ for (int i = 0; i < cmpDescriptors.length; i++) {
+ int endOfCmp = cmpDescriptors[i].lastIndexOf('/');
+ String cmpDescriptor = cmpDescriptors[i].substring(endOfCmp + 1);
+
+ File cmpFile = new File(baseDir, relativePath + cmpDescriptor);
+ if (!cmpFile.exists()) {
+ throw new BuildException("The CMP descriptor file ("
+ + cmpFile + ") could not be found.", getLocation());
+ }
+ files.put(cmpDescriptors[i], cmpFile);
+ }
+ }
+
+ return files;
+ }
+
+ /**
+ * Add the iAS-specific EJB descriptor to the list of files which will be
+ * written to the JAR file.
+ *
+ * @param ejbFiles Hashtable of EJB class (and other) files to be added to
+ * the completed JAR file.
+ * @param ddPrefix not used
+ */
+ @Override
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+ ejbFiles.put(META_DIR + IAS_DD, new File(getConfig().descriptorDir,
+ getIasDescriptorName()));
+ }
+
+ /**
+ * Get the name of the Jar that will be written. The modification date
+ * of this jar will be checked against the dependent bean classes.
+ *
+ * @param baseName String name of the EJB JAR file to be written (without
+ * a filename extension).
+ *
+ * @return File representing the JAR file which will be written.
+ */
+ @Override
+ File getVendorOutputJarFile(String baseName) {
+ File jarFile = new File(getDestDir(), baseName + jarSuffix);
+ log("JAR file name: " + jarFile.toString(), Project.MSG_VERBOSE);
+ return jarFile;
+ }
+
+ /**
+ * The iAS ejbc utility doesn't require the Public ID of the descriptor's
+ * DTD for it to process correctly--this method always returns <code>null
+ * </code>.
+ *
+ * @return <code>null</code>.
+ */
+ @Override
+ protected String getPublicId() {
+ return null;
+ }
+
+ /**
+ * Determines the name of the iAS-specific EJB descriptor using the
+ * specified standard EJB descriptor name. In general, the standard
+ * descriptor will be named "[basename]-ejb-jar.xml", and this method will
+ * return "[basename]-ias-ejb-jar.xml".
+ *
+ * @return The name of the iAS-specific EJB descriptor file.
+ */
+ private String getIasDescriptorName() {
+
+ /* Only calculate the descriptor name once */
+ if (iasDescriptorName != null) {
+ return iasDescriptorName;
+ }
+
+ String path = ""; // Directory path of the EJB descriptor
+ String basename; // Filename appearing before name terminator
+ String remainder; // Filename appearing after the name terminator
+
+ /* Find the end of the standard descriptor's relative path */
+ int startOfFileName = descriptorName.lastIndexOf(File.separatorChar);
+ if (startOfFileName != -1) {
+ path = descriptorName.substring(0, startOfFileName + 1);
+ }
+
+ /* Check to see if the standard name is used (there's no basename) */
+ if (descriptorName.substring(startOfFileName + 1).equals(EJB_DD)) {
+ basename = "";
+ remainder = EJB_DD;
+
+ } else {
+ int endOfBaseName = descriptorName.indexOf(
+ getConfig().baseNameTerminator,
+ startOfFileName);
+ /*
+ * Check for the odd case where the terminator and/or filename
+ * extension aren't found. These will ensure "ias-" appears at the
+ * end of the name and before the '.' (if present).
+ */
+ if (endOfBaseName < 0) {
+ endOfBaseName = descriptorName.lastIndexOf('.') - 1;
+ if (endOfBaseName < 0) {
+ endOfBaseName = descriptorName.length() - 1;
+ }
+ }
+
+ basename = descriptorName.substring(startOfFileName + 1,
+ endOfBaseName + 1);
+ remainder = descriptorName.substring(endOfBaseName + 1);
+ }
+
+ iasDescriptorName = path + basename + "ias-" + remainder;
+ return iasDescriptorName;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java
new file mode 100644
index 00000000..ed799d33
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java
@@ -0,0 +1,1495 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.AttributeList;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Compiles EJB stubs and skeletons for the iPlanet Application
+ * Server (iAS). The class will read a standard EJB descriptor (as well as an
+ * EJB descriptor specific to iPlanet Application Server) to identify one or
+ * more EJBs to process. It will search for EJB "source" classes (the remote
+; * interface, home interface, and EJB implementation class) and the EJB stubs
+ * and skeletons in the specified destination directory. Only if the stubs and
+ * skeletons cannot be found or if they're out of date will the iPlanet
+ * Application Server ejbc utility be run.
+ * <p>
+ * Because this class (and it's assorted inner classes) may be bundled into the
+ * iPlanet Application Server distribution at some point (and removed from the
+ * Ant distribution), the class has been written to be independent of all
+ * Ant-specific classes. It is also for this reason (and to avoid cluttering
+ * the Apache Ant source files) that this utility has been packaged into a
+ * single source file.
+ * <p>
+ * For more information on Ant Tasks for iPlanet Application Server, see the
+ * <code>IPlanetDeploymentTool</code> and <code>IPlanetEjbcTask</code> classes.
+ *
+ * @see IPlanetDeploymentTool
+ * @see IPlanetEjbcTask
+ * @ant.task ignore="true"
+ */
+public class IPlanetEjbc {
+
+ private static final int MIN_NUM_ARGS = 2;
+ private static final int MAX_NUM_ARGS = 8;
+ private static final int NUM_CLASSES_WITH_IIOP = 15;
+ private static final int NUM_CLASSES_WITHOUT_IIOP = 9;
+
+ /* Constants used for the "beantype" attribute */
+ private static final String ENTITY_BEAN = "entity";
+ private static final String STATELESS_SESSION = "stateless";
+ private static final String STATEFUL_SESSION = "stateful";
+
+ /* Filenames of the standard EJB descriptor and the iAS-specific descriptor */
+ private File stdDescriptor;
+ private File iasDescriptor;
+
+ /*
+ * Directory where "source" EJB files are stored and where stubs and
+ * skeletons will also be written.
+ */
+ private File destDirectory;
+
+ /* Classpath used when the iAS ejbc is called */
+ private String classpath;
+ private String[] classpathElements;
+
+ /* Options passed to the iAS ejbc */
+ private boolean retainSource = false;
+ private boolean debugOutput = false;
+
+ /* iAS installation directory (used if ejbc isn't on user's PATH) */
+ private File iasHomeDir;
+
+ /* Parser and handler used to process both EJB descriptor files */
+ private SAXParser parser;
+ private EjbcHandler handler = new EjbcHandler();
+
+ /*
+ * This Hashtable maintains a list of EJB class files processed by the ejbc
+ * utility (both "source" class files as well as stubs and skeletons). The
+ * key for the Hashtable is a String representing the path to the class file
+ * (relative to the destination directory). The value for the Hashtable is
+ * a File object which reference the actual class file.
+ */
+ private Hashtable ejbFiles = new Hashtable();
+
+ /* Value of the display-name element read from the standard EJB descriptor */
+ private String displayName;
+
+ /**
+ * Constructs an instance which may be used to process EJB descriptors and
+ * generate EJB stubs and skeletons, if needed.
+ *
+ * @param stdDescriptor File referencing a standard EJB descriptor.
+ * @param iasDescriptor File referencing an iAS-specific EJB descriptor.
+ * @param destDirectory File referencing the base directory where both
+ * EJB "source" files are found and where stubs and
+ * skeletons will be written.
+ * @param classpath String representation of the classpath to be used
+ * by the iAS ejbc utility.
+ * @param parser SAXParser to be used to process both of the EJB
+ * descriptors.
+ * @todo classpathElements is not needed here, its never used
+ * (at least IDEA tells me so! :)
+ */
+ public IPlanetEjbc(File stdDescriptor,
+ File iasDescriptor,
+ File destDirectory,
+ String classpath,
+ SAXParser parser) {
+ this.stdDescriptor = stdDescriptor;
+ this.iasDescriptor = iasDescriptor;
+ this.destDirectory = destDirectory;
+ this.classpath = classpath;
+ this.parser = parser;
+
+ /*
+ * Parse the classpath into it's individual elements and store the
+ * results in the "classpathElements" instance variable.
+ */
+ List elements = new ArrayList();
+ if (classpath != null) {
+ StringTokenizer st = new StringTokenizer(classpath,
+ File.pathSeparator);
+ while (st.hasMoreTokens()) {
+ elements.add(st.nextToken());
+ }
+ classpathElements
+ = (String[]) elements.toArray(new String[elements.size()]);
+ }
+ }
+
+ /**
+ * If true, the Java source files which are generated by the
+ * ejbc process are retained.
+ *
+ * @param retainSource A boolean indicating if the Java source files for
+ * the stubs and skeletons should be retained.
+ * @todo This is not documented in the HTML. On purpose?
+ */
+ public void setRetainSource(boolean retainSource) {
+ this.retainSource = retainSource;
+ }
+
+ /**
+ * If true, enables debugging output when ejbc is executed.
+ *
+ * @param debugOutput A boolean indicating if debugging output should be
+ * generated
+ */
+ public void setDebugOutput(boolean debugOutput) {
+ this.debugOutput = debugOutput;
+ }
+
+ /**
+ * Registers the location of a local DTD file or resource. By registering
+ * a local DTD, EJB descriptors can be parsed even when the remote servers
+ * which contain the "public" DTDs cannot be accessed.
+ *
+ * @param publicID The public DTD identifier found in an XML document.
+ * @param location The file or resource name for the appropriate DTD stored
+ * on the local machine.
+ */
+ public void registerDTD(String publicID, String location) {
+ handler.registerDTD(publicID, location);
+ }
+
+ /**
+ * May be used to specify the "home" directory for this iAS installation.
+ * The directory specified should typically be
+ * <code>[install-location]/iplanet/ias6/ias</code>.
+ *
+ * @param iasHomeDir The home directory for the user's iAS installation.
+ */
+ public void setIasHomeDir(File iasHomeDir) {
+ this.iasHomeDir = iasHomeDir;
+ }
+
+ /**
+ * Returns a Hashtable which contains a list of EJB class files processed by
+ * the ejbc utility (both "source" class files as well as stubs and
+ * skeletons). The key for the Hashtable is a String representing the path
+ * to the class file (relative to the destination directory). The value for
+ * the Hashtable is a File object which reference the actual class file.
+ *
+ * @return The list of EJB files processed by the ejbc utility.
+ */
+ public Hashtable getEjbFiles() {
+ return ejbFiles;
+ }
+
+ /**
+ * Returns the display-name element read from the standard EJB descriptor.
+ *
+ * @return The EJB-JAR display name.
+ */
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ /**
+ * Returns the list of CMP descriptors referenced in the EJB descriptors.
+ *
+ * @return An array of CMP descriptors.
+ */
+ public String[] getCmpDescriptors() {
+ List returnList = new ArrayList();
+
+ EjbInfo[] ejbs = handler.getEjbs();
+
+ for (int i = 0; i < ejbs.length; i++) {
+ List descriptors = (List) ejbs[i].getCmpDescriptors();
+ returnList.addAll(descriptors);
+ }
+
+ return (String[]) returnList.toArray(new String[returnList.size()]);
+ }
+
+ /**
+ * Main application method for the iPlanet Application Server ejbc utility.
+ * If the application is run with no commandline arguments, a usage
+ * statement is printed for the user.
+ *
+ * @param args The commandline arguments passed to the application.
+ */
+ public static void main(String[] args) {
+ File stdDescriptor;
+ File iasDescriptor;
+ File destDirectory = null;
+ String classpath = null;
+ SAXParser parser = null;
+ boolean debug = false;
+ boolean retainSource = false;
+ IPlanetEjbc ejbc;
+
+ if ((args.length < MIN_NUM_ARGS) || (args.length > MAX_NUM_ARGS)) {
+ usage();
+ return;
+ }
+
+ stdDescriptor = new File(args[args.length - 2]);
+ iasDescriptor = new File(args[args.length - 1]);
+
+ for (int i = 0; i < args.length - 2; i++) {
+ if (args[i].equals("-classpath")) {
+ classpath = args[++i];
+ } else if (args[i].equals("-d")) {
+ destDirectory = new File(args[++i]);
+ } else if (args[i].equals("-debug")) {
+ debug = true;
+ } else if (args[i].equals("-keepsource")) {
+ retainSource = true;
+ } else {
+ usage();
+ return;
+ }
+ }
+
+ /* If the -classpath flag isn't specified, use the system classpath */
+ if (classpath == null) {
+ Properties props = System.getProperties();
+ classpath = props.getProperty("java.class.path");
+ }
+
+ /*
+ * If the -d flag isn't specified, use the working directory as the
+ * destination directory
+ */
+ if (destDirectory == null) {
+ Properties props = System.getProperties();
+ destDirectory = new File(props.getProperty("user.dir"));
+ }
+
+ /* Construct a SAXParser used to process the descriptors */
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ parserFactory.setValidating(true);
+ try {
+ parser = parserFactory.newSAXParser();
+ } catch (Exception e) {
+ // SAXException or ParserConfigurationException may be thrown
+ System.out.println("An exception was generated while trying to ");
+ System.out.println("create a new SAXParser.");
+ e.printStackTrace();
+ return;
+ }
+
+ /* Build and populate an instance of the ejbc utility */
+ ejbc = new IPlanetEjbc(stdDescriptor, iasDescriptor, destDirectory,
+ classpath, parser);
+ ejbc.setDebugOutput(debug);
+ ejbc.setRetainSource(retainSource);
+
+ /* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */
+ try {
+ ejbc.execute();
+ } catch (IOException e) {
+ System.out.println("An IOException has occurred while reading the "
+ + "XML descriptors (" + e.getMessage() + ").");
+ return;
+ } catch (SAXException e) {
+ System.out.println("A SAXException has occurred while reading the "
+ + "XML descriptors (" + e.getMessage() + ").");
+ return;
+ } catch (IPlanetEjbc.EjbcException e) {
+ System.out.println("An error has occurred while executing the ejbc "
+ + "utility (" + e.getMessage() + ").");
+ return;
+ }
+ }
+
+ /**
+ * Print a usage statement.
+ */
+ private static void usage() {
+ System.out.println("java org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbc \\");
+ System.out.println(" [OPTIONS] [EJB 1.1 descriptor] [iAS EJB descriptor]");
+ System.out.println("");
+ System.out.println("Where OPTIONS are:");
+ System.out.println(" -debug -- for additional debugging output");
+ System.out.println(" -keepsource -- to retain Java source files generated");
+ System.out.println(" -classpath [classpath] -- classpath used for compilation");
+ System.out.println(" -d [destination directory] -- directory for compiled classes");
+ System.out.println("");
+ System.out.println("If a classpath is not specified, the system classpath");
+ System.out.println("will be used. If a destination directory is not specified,");
+ System.out.println("the current working directory will be used (classes will");
+ System.out.println("still be placed in subfolders which correspond to their");
+ System.out.println("package name).");
+ System.out.println("");
+ System.out.println("The EJB home interface, remote interface, and implementation");
+ System.out.println("class must be found in the destination directory. In");
+ System.out.println("addition, the destination will look for the stubs and skeletons");
+ System.out.println("in the destination directory to ensure they are up to date.");
+ }
+
+ /**
+ * Compiles the stub and skeletons for the specified EJBs, if they need to
+ * be updated.
+ *
+ * @throws EjbcException If the ejbc utility cannot be correctly configured
+ * or if one or more of the EJB "source" classes
+ * cannot be found in the destination directory
+ * @throws IOException If the parser encounters a problem reading the XML
+ * file
+ * @throws SAXException If the parser encounters a problem processing the
+ * XML descriptor (it may wrap another exception)
+ */
+ public void execute() throws EjbcException, IOException, SAXException {
+
+ checkConfiguration(); // Throws EjbcException if unsuccessful
+
+ EjbInfo[] ejbs = getEjbs(); // Returns list of EJBs for processing
+
+ for (int i = 0; i < ejbs.length; i++) {
+ log("EJBInfo...");
+ log(ejbs[i].toString());
+ }
+
+ for (int i = 0; i < ejbs.length; i++) {
+ EjbInfo ejb = ejbs[i];
+
+ ejb.checkConfiguration(destDirectory); // Throws EjbcException
+
+ if (ejb.mustBeRecompiled(destDirectory)) {
+ log(ejb.getName() + " must be recompiled using ejbc.");
+
+ String[] arguments = buildArgumentList(ejb);
+ callEjbc(arguments);
+
+ } else {
+ log(ejb.getName() + " is up to date.");
+ }
+ }
+ }
+
+ /**
+ * Executes the iPlanet Application Server ejbc command-line utility.
+ *
+ * @param arguments Command line arguments to be passed to the ejbc utility.
+ */
+ private void callEjbc(String[] arguments) {
+
+ /* Concatenate all of the command line arguments into a single String */
+ StringBuffer args = new StringBuffer();
+ for (int i = 0; i < arguments.length; i++) {
+ args.append(arguments[i]).append(" ");
+ }
+
+ /* If an iAS home directory is specified, prepend it to the commmand */
+ String command;
+ if (iasHomeDir == null) {
+ command = "";
+ } else {
+ command = iasHomeDir.toString() + File.separator + "bin"
+ + File.separator;
+ }
+ command += "ejbc ";
+
+ log(command + args);
+
+ /*
+ * Use the Runtime object to execute an external command. Use the
+ * RedirectOutput inner class to direct the standard and error output
+ * from the command to the JRE's standard output
+ */
+ try {
+ Process p = Runtime.getRuntime().exec(command + args);
+ RedirectOutput output = new RedirectOutput(p.getInputStream());
+ RedirectOutput error = new RedirectOutput(p.getErrorStream());
+ output.start();
+ error.start();
+ p.waitFor();
+ p.destroy();
+ } catch (IOException e) {
+ log("An IOException has occurred while trying to execute ejbc.");
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ // Do nothing
+ }
+ }
+
+ /**
+ * Verifies that the user selections are valid.
+ *
+ * @throws EjbcException If the user selections are invalid.
+ */
+ protected void checkConfiguration() throws EjbcException {
+
+ String msg = "";
+
+ if (stdDescriptor == null) {
+ msg += "A standard XML descriptor file must be specified. ";
+ }
+ if (iasDescriptor == null) {
+ msg += "An iAS-specific XML descriptor file must be specified. ";
+ }
+ if (classpath == null) {
+ msg += "A classpath must be specified. ";
+ }
+ if (parser == null) {
+ msg += "An XML parser must be specified. ";
+ }
+
+ if (destDirectory == null) {
+ msg += "A destination directory must be specified. ";
+ } else if (!destDirectory.exists()) {
+ msg += "The destination directory specified does not exist. ";
+ } else if (!destDirectory.isDirectory()) {
+ msg += "The destination specified is not a directory. ";
+ }
+
+ if (msg.length() > 0) {
+ throw new EjbcException(msg);
+ }
+ }
+
+ /**
+ * Parses the EJB descriptors and returns a list of EJBs which may need to
+ * be compiled.
+ *
+ * @return An array of objects which describe the EJBs to be
+ * processed.
+ * @throws IOException If the parser encounters a problem reading the XML
+ * files
+ * @throws SAXException If the parser encounters a problem processing the
+ * XML descriptor (it may wrap another exception)
+ */
+ private EjbInfo[] getEjbs() throws IOException, SAXException {
+ EjbInfo[] ejbs = null;
+
+ /*
+ * The EJB information is gathered from the standard XML EJB descriptor
+ * and the iAS-specific XML EJB descriptor using a SAX parser.
+ */
+
+ parser.parse(stdDescriptor, handler);
+ parser.parse(iasDescriptor, handler);
+ ejbs = handler.getEjbs();
+
+ return ejbs;
+ }
+
+ /**
+ * Based on this object's instance variables as well as the EJB to be
+ * processed, the correct flags and parameters are set for the ejbc
+ * command-line utility.
+ * @param ejb The EJB for which stubs and skeletons will be compiled.
+ * @return An array of Strings which are the command-line parameters for
+ * for the ejbc utility.
+ */
+ private String[] buildArgumentList(EjbInfo ejb) {
+
+ List arguments = new ArrayList();
+
+ /* OPTIONAL COMMAND LINE PARAMETERS */
+
+ if (debugOutput) {
+ arguments.add("-debug");
+ }
+
+ /* No beantype flag is needed for an entity bean */
+ if (ejb.getBeantype().equals(STATELESS_SESSION)) {
+ arguments.add("-sl");
+ } else if (ejb.getBeantype().equals(STATEFUL_SESSION)) {
+ arguments.add("-sf");
+ }
+
+ if (ejb.getIiop()) {
+ arguments.add("-iiop");
+ }
+
+ if (ejb.getCmp()) {
+ arguments.add("-cmp");
+ }
+
+ if (retainSource) {
+ arguments.add("-gs");
+ }
+
+ if (ejb.getHasession()) {
+ arguments.add("-fo");
+ }
+
+ /* REQUIRED COMMAND LINE PARAMETERS */
+
+ arguments.add("-classpath");
+ arguments.add(classpath);
+
+ arguments.add("-d");
+ arguments.add(destDirectory.toString());
+
+ arguments.add(ejb.getHome().getQualifiedClassName());
+ arguments.add(ejb.getRemote().getQualifiedClassName());
+ arguments.add(ejb.getImplementation().getQualifiedClassName());
+
+ /* Convert the List into an Array and return it */
+ return (String[]) arguments.toArray(new String[arguments.size()]);
+ }
+
+ /**
+ * Convenience method used to print messages to the user if debugging
+ * messages are enabled.
+ *
+ * @param msg The String to print to standard output.
+ */
+ private void log(String msg) {
+ if (debugOutput) {
+ System.out.println(msg);
+ }
+ }
+
+
+ /* Inner classes follow */
+
+
+ /**
+ * This inner class is used to signal any problems during the execution of
+ * the ejbc compiler.
+ *
+ */
+ public class EjbcException extends Exception {
+
+ /**
+ * Constructs an exception with the given descriptive message.
+ *
+ * @param msg Description of the exception which has occurred.
+ */
+ public EjbcException(String msg) {
+ super(msg);
+ }
+ } // End of EjbcException inner class
+
+
+ /**
+ * This inner class is an XML document handler that can be used to parse EJB
+ * descriptors (both the standard EJB descriptor as well as the iAS-specific
+ * descriptor that stores additional values for iAS). Once the descriptors
+ * have been processed, the list of EJBs found can be obtained by calling
+ * the <code>getEjbs()</code> method.
+ *
+ * @see IPlanetEjbc.EjbInfo
+ */
+ private class EjbcHandler extends HandlerBase {
+ /** EJB 1.1 ID */
+ private static final String PUBLICID_EJB11 =
+ "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+ /** IPlanet ID */
+ private static final String PUBLICID_IPLANET_EJB_60 =
+ "-//Sun Microsystems, Inc.//DTD iAS Enterprise JavaBeans 1.0//EN";
+ /** EJB 1.1 location */
+ private static final String DEFAULT_IAS60_EJB11_DTD_LOCATION =
+ "ejb-jar_1_1.dtd";
+ /** IAS60 location */
+ private static final String DEFAULT_IAS60_DTD_LOCATION =
+ "IASEjb_jar_1_0.dtd";
+
+ /*
+ * Two Maps are used to track local DTDs that will be used in case the
+ * remote copies of these DTDs cannot be accessed. The key for the Map
+ * is the DTDs public ID and the value is the local location for the DTD
+ */
+ private Map resourceDtds = new HashMap();
+ private Map fileDtds = new HashMap();
+
+ private Map ejbs = new HashMap(); // List of EJBs found in XML
+ private EjbInfo currentEjb; // One item within the Map
+ private boolean iasDescriptor = false; // Is doc iAS or EJB descriptor
+
+ private String currentLoc = ""; // Tracks current element
+ private String currentText; // Tracks current text data
+ private String ejbType; // "session" or "entity"
+
+ /**
+ * Constructs a new instance of the handler and registers local copies
+ * of the standard EJB 1.1 descriptor DTD as well as iAS's EJB
+ * descriptor DTD.
+ */
+ public EjbcHandler() {
+ registerDTD(PUBLICID_EJB11, DEFAULT_IAS60_EJB11_DTD_LOCATION);
+ registerDTD(PUBLICID_IPLANET_EJB_60, DEFAULT_IAS60_DTD_LOCATION);
+ }
+
+ /**
+ * Returns the list of EJB objects found during the processing of the
+ * standard EJB 1.1 descriptor and iAS-specific EJB descriptor.
+ *
+ * @return An array of EJBs which were found during the descriptor
+ * parsing.
+ */
+ public EjbInfo[] getEjbs() {
+ return (EjbInfo[]) ejbs.values().toArray(new EjbInfo[ejbs.size()]);
+ }
+
+ /**
+ * Returns the value of the display-name element found in the standard
+ * EJB 1.1 descriptor.
+ *
+ * @return String display-name value.
+ */
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ /**
+ * Registers a local DTD that will be used when parsing an EJB
+ * descriptor. When the DTD's public identifier is found in an XML
+ * document, the parser will reference the local DTD rather than the
+ * remote DTD. This enables XML documents to be processed even when the
+ * public DTD isn't available.
+ *
+ * @param publicID The DTD's public identifier.
+ * @param location The location of the local DTD copy -- the location
+ * may either be a resource found on the classpath or a
+ * local file.
+ */
+ public void registerDTD(String publicID, String location) {
+ log("Registering: " + location);
+ if ((publicID == null) || (location == null)) {
+ return;
+ }
+
+ if (ClassLoader.getSystemResource(location) != null) {
+ log("Found resource: " + location);
+ resourceDtds.put(publicID, location);
+ } else {
+ File dtdFile = new File(location);
+ if (dtdFile.exists() && dtdFile.isFile()) {
+ log("Found file: " + location);
+ fileDtds.put(publicID, location);
+ }
+ }
+ }
+
+ /**
+ * Resolves an external entity found during XML processing. If a public
+ * ID is found that has been registered with the handler, an <code>
+ * InputSource</code> will be returned which refers to the local copy.
+ * If the public ID hasn't been registered or if an error occurs, the
+ * superclass implementation is used.
+ *
+ * @param publicId The DTD's public identifier.
+ * @param systemId The location of the DTD, as found in the XML document.
+ */
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException {
+ InputStream inputStream = null;
+
+
+ try {
+
+ /* Search the resource Map and (if not found) file Map */
+
+ String location = (String) resourceDtds.get(publicId);
+ if (location != null) {
+ inputStream
+ = ClassLoader.getSystemResource(location).openStream();
+ } else {
+ location = (String) fileDtds.get(publicId);
+ if (location != null) {
+ inputStream = new FileInputStream(location);
+ }
+ }
+ } catch (IOException e) {
+ return super.resolveEntity(publicId, systemId);
+ }
+
+ if (inputStream == null) {
+ return super.resolveEntity(publicId, systemId);
+ } else {
+ return new InputSource(inputStream);
+ }
+ }
+
+ /**
+ * Receive notification that the start of an XML element has been found.
+ *
+ * @param name String name of the element found.
+ * @param atts AttributeList of the attributes included with the element
+ * (if any).
+ * @throws SAXException If the parser cannot process the document.
+ */
+ public void startElement(String name, AttributeList atts)
+ throws SAXException {
+
+ /*
+ * I need to "push" the element onto the String (currentLoc) which
+ * always represents the current location in the XML document.
+ */
+ currentLoc += "\\" + name;
+
+ /* A new element has started, so reset the text being captured */
+ currentText = "";
+
+ if (currentLoc.equals("\\ejb-jar")) {
+ iasDescriptor = false;
+ } else if (currentLoc.equals("\\ias-ejb-jar")) {
+ iasDescriptor = true;
+ }
+
+ if ((name.equals("session")) || (name.equals("entity"))) {
+ ejbType = name;
+ }
+ }
+
+ /**
+ * Receive notification that character data has been found in the XML
+ * document
+ *
+ * @param ch Array of characters which have been found in the document.
+ * @param start Starting index of the data found in the document.
+ * @param len The number of characters found in the document.
+ * @throws SAXException If the parser cannot process the document.
+ */
+ public void characters(char[] ch, int start, int len)
+ throws SAXException {
+
+ currentText += new String(ch).substring(start, start + len);
+ }
+
+ /**
+ * Receive notification that the end of an XML element has been found.
+ *
+ * @param name String name of the element.
+ * @throws SAXException If the parser cannot process the document.
+ */
+ public void endElement(String name) throws SAXException {
+
+ /*
+ * If this is a standard EJB 1.1 descriptor, we are looking for one
+ * set of data, while if this is an iAS-specific descriptor, we're
+ * looking for different set of data. Hand the processing off to
+ * the appropriate method.
+ */
+ if (iasDescriptor) {
+ iasCharacters(currentText);
+ } else {
+ stdCharacters(currentText);
+ }
+
+ /*
+ * I need to "pop" the element off the String (currentLoc) which
+ * always represents my current location in the XML document.
+ */
+
+ int nameLength = name.length() + 1; // Add one for the "\"
+ int locLength = currentLoc.length();
+
+ currentLoc = currentLoc.substring(0, locLength - nameLength);
+ }
+
+ /**
+ * Receive notification that character data has been found in a standard
+ * EJB 1.1 descriptor. We're interested in retrieving the home
+ * interface, remote interface, implementation class, the type of bean,
+ * and if the bean uses CMP.
+ *
+ * @param value String data found in the XML document.
+ */
+ private void stdCharacters(String value) {
+
+ if (currentLoc.equals("\\ejb-jar\\display-name")) {
+ displayName = value;
+ return;
+ }
+
+ String base = "\\ejb-jar\\enterprise-beans\\" + ejbType;
+
+ if (currentLoc.equals(base + "\\ejb-name")) {
+ currentEjb = (EjbInfo) ejbs.get(value);
+ if (currentEjb == null) {
+ currentEjb = new EjbInfo(value);
+ ejbs.put(value, currentEjb);
+ }
+ } else if (currentLoc.equals(base + "\\home")) {
+ currentEjb.setHome(value);
+ } else if (currentLoc.equals(base + "\\remote")) {
+ currentEjb.setRemote(value);
+ } else if (currentLoc.equals(base + "\\ejb-class")) {
+ currentEjb.setImplementation(value);
+ } else if (currentLoc.equals(base + "\\prim-key-class")) {
+ currentEjb.setPrimaryKey(value);
+ } else if (currentLoc.equals(base + "\\session-type")) {
+ currentEjb.setBeantype(value);
+ } else if (currentLoc.equals(base + "\\persistence-type")) {
+ currentEjb.setCmp(value);
+ }
+ }
+
+ /**
+ * Receive notification that character data has been found in an
+ * iAS-specific descriptor. We're interested in retrieving data
+ * indicating whether the bean must support RMI/IIOP access, whether
+ * the bean must provide highly available stubs and skeletons (in the
+ * case of stateful session beans), and if this bean uses additional
+ * CMP XML descriptors (in the case of entity beans with CMP).
+ *
+ * @param value String data found in the XML document.
+ */
+ private void iasCharacters(String value) {
+ String base = "\\ias-ejb-jar\\enterprise-beans\\" + ejbType;
+
+ if (currentLoc.equals(base + "\\ejb-name")) {
+ currentEjb = (EjbInfo) ejbs.get(value);
+ if (currentEjb == null) {
+ currentEjb = new EjbInfo(value);
+ ejbs.put(value, currentEjb);
+ }
+ } else if (currentLoc.equals(base + "\\iiop")) {
+ currentEjb.setIiop(value);
+ } else if (currentLoc.equals(base + "\\failover-required")) {
+ currentEjb.setHasession(value);
+ } else if (currentLoc.equals(base + "\\persistence-manager"
+ + "\\properties-file-location")) {
+ currentEjb.addCmpDescriptor(value);
+ }
+ }
+ } // End of EjbcHandler inner class
+
+
+ /**
+ * This inner class represents an EJB that will be compiled using ejbc.
+ *
+ */
+ private class EjbInfo {
+ private String name; // EJB's display name
+ private Classname home; // EJB's home interface name
+ private Classname remote; // EJB's remote interface name
+ private Classname implementation; // EJB's implementation class
+ private Classname primaryKey; // EJB's primary key class
+ private String beantype = "entity"; // or "stateful" or "stateless"
+ private boolean cmp = false; // Does this EJB support CMP?
+ private boolean iiop = false; // Does this EJB support IIOP?
+ private boolean hasession = false; // Does this EJB require failover?
+ private List cmpDescriptors = new ArrayList(); // CMP descriptor list
+
+ /**
+ * Construct a new EJBInfo object with the given name.
+ *
+ * @param name The display name for the EJB.
+ */
+ public EjbInfo(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the display name of the EJB. If a display name has not been
+ * set, it returns the EJB implementation classname (if the
+ * implementation class is not set, it returns "[unnamed]").
+ *
+ * @return The display name for the EJB.
+ */
+ public String getName() {
+ if (name == null) {
+ if (implementation == null) {
+ return "[unnamed]";
+ } else {
+ return implementation.getClassName();
+ }
+ }
+ return name;
+ }
+
+ /*
+ * Below are getter's and setter's for each of the instance variables.
+ * Note that (in addition to supporting setters with the same type as
+ * the instance variable) a setter is provided with takes a String
+ * argument -- this are provided so the XML document handler can set
+ * the EJB values using the Strings it parses.
+ */
+
+ public void setHome(String home) {
+ setHome(new Classname(home));
+ }
+
+ public void setHome(Classname home) {
+ this.home = home;
+ }
+
+ public Classname getHome() {
+ return home;
+ }
+
+ public void setRemote(String remote) {
+ setRemote(new Classname(remote));
+ }
+
+ public void setRemote(Classname remote) {
+ this.remote = remote;
+ }
+
+ public Classname getRemote() {
+ return remote;
+ }
+
+ public void setImplementation(String implementation) {
+ setImplementation(new Classname(implementation));
+ }
+
+ public void setImplementation(Classname implementation) {
+ this.implementation = implementation;
+ }
+
+ public Classname getImplementation() {
+ return implementation;
+ }
+
+ public void setPrimaryKey(String primaryKey) {
+ setPrimaryKey(new Classname(primaryKey));
+ }
+
+ public void setPrimaryKey(Classname primaryKey) {
+ this.primaryKey = primaryKey;
+ }
+
+ public Classname getPrimaryKey() {
+ return primaryKey;
+ }
+
+ public void setBeantype(String beantype) {
+ this.beantype = beantype.toLowerCase();
+ }
+
+ public String getBeantype() {
+ return beantype;
+ }
+
+ public void setCmp(boolean cmp) {
+ this.cmp = cmp;
+ }
+
+ public void setCmp(String cmp) {
+ setCmp(cmp.equals("Container"));
+ }
+
+ public boolean getCmp() {
+ return cmp;
+ }
+
+ public void setIiop(boolean iiop) {
+ this.iiop = iiop;
+ }
+
+ public void setIiop(String iiop) {
+ setIiop(iiop.equals("true"));
+ }
+
+ public boolean getIiop() {
+ return iiop;
+ }
+
+ public void setHasession(boolean hasession) {
+ this.hasession = hasession;
+ }
+
+ public void setHasession(String hasession) {
+ setHasession(hasession.equals("true"));
+ }
+
+ public boolean getHasession() {
+ return hasession;
+ }
+
+ public void addCmpDescriptor(String descriptor) {
+ cmpDescriptors.add(descriptor);
+ }
+
+ public List getCmpDescriptors() {
+ return cmpDescriptors;
+ }
+
+ /**
+ * Verifies that the EJB is valid--if it is invalid, an exception is
+ * thrown
+ *
+ *
+ * @param buildDir The directory where the EJB remote interface, home
+ * interface, and implementation class must be found.
+ * @throws EjbcException If the EJB is invalid.
+ */
+ private void checkConfiguration(File buildDir) throws EjbcException {
+
+ /* Check that the specified instance variables are valid */
+ if (home == null) {
+ throw new EjbcException("A home interface was not found "
+ + "for the " + name + " EJB.");
+ }
+ if (remote == null) {
+ throw new EjbcException("A remote interface was not found "
+ + "for the " + name + " EJB.");
+ }
+ if (implementation == null) {
+ throw new EjbcException("An EJB implementation class was not "
+ + "found for the " + name + " EJB.");
+ }
+
+ if ((!beantype.equals(ENTITY_BEAN))
+ && (!beantype.equals(STATELESS_SESSION))
+ && (!beantype.equals(STATEFUL_SESSION))) {
+ throw new EjbcException("The beantype found (" + beantype + ") "
+ + "isn't valid in the " + name + " EJB.");
+ }
+
+ if (cmp && (!beantype.equals(ENTITY_BEAN))) {
+ System.out.println("CMP stubs and skeletons may not be generated"
+ + " for a Session Bean -- the \"cmp\" attribute will be"
+ + " ignoredfor the " + name + " EJB.");
+ }
+
+ if (hasession && (!beantype.equals(STATEFUL_SESSION))) {
+ System.out.println("Highly available stubs and skeletons may "
+ + "only be generated for a Stateful Session Bean -- the "
+ + "\"hasession\" attribute will be ignored for the "
+ + name + " EJB.");
+ }
+
+ /* Check that the EJB "source" classes all exist */
+ if (!remote.getClassFile(buildDir).exists()) {
+ throw new EjbcException("The remote interface "
+ + remote.getQualifiedClassName() + " could not be "
+ + "found.");
+ }
+ if (!home.getClassFile(buildDir).exists()) {
+ throw new EjbcException("The home interface "
+ + home.getQualifiedClassName() + " could not be "
+ + "found.");
+ }
+ if (!implementation.getClassFile(buildDir).exists()) {
+ throw new EjbcException("The EJB implementation class "
+ + implementation.getQualifiedClassName() + " could "
+ + "not be found.");
+ }
+ }
+
+ /**
+ * Determines if the ejbc utility needs to be run or not. If the stubs
+ * and skeletons can all be found in the destination directory AND all
+ * of their timestamps are more recent than the EJB source classes
+ * (home, remote, and implementation classes), the method returns
+ * <code>false</code>. Otherwise, the method returns <code>true</code>.
+ *
+ * @param destDir The directory where the EJB source classes, stubs and
+ * skeletons are located.
+ * @return A boolean indicating whether or not the ejbc utility needs to
+ * be run to bring the stubs and skeletons up to date.
+ */
+ public boolean mustBeRecompiled(File destDir) {
+
+ long sourceModified = sourceClassesModified(destDir);
+
+ long destModified = destClassesModified(destDir);
+
+ return (destModified < sourceModified);
+ }
+
+ /**
+ * Examines each of the EJB source classes (home, remote, and
+ * implementation) and returns the modification timestamp for the
+ * "oldest" class.
+ *
+ * @param classpath The classpath to be used to find the source EJB
+ * classes. If <code>null</code>, the system classpath
+ * is used.
+ * @return The modification timestamp for the "oldest" EJB source class.
+ * @throws BuildException If one of the EJB source classes cannot be
+ * found on the classpath.
+ */
+ private long sourceClassesModified(File buildDir) {
+ long latestModified; // The timestamp of the "newest" class
+ long modified; // Timestamp for a given class
+ File remoteFile; // File for the remote interface class
+ File homeFile; // File for the home interface class
+ File implFile; // File for the EJB implementation class
+ File pkFile; // File for the EJB primary key class
+
+ /* Check the timestamp on the remote interface */
+ remoteFile = remote.getClassFile(buildDir);
+ modified = remoteFile.lastModified();
+ if (modified == -1) {
+ System.out.println("The class "
+ + remote.getQualifiedClassName() + " couldn't "
+ + "be found on the classpath");
+ return -1;
+ }
+ latestModified = modified;
+
+ /* Check the timestamp on the home interface */
+ homeFile = home.getClassFile(buildDir);
+ modified = homeFile.lastModified();
+ if (modified == -1) {
+ System.out.println("The class "
+ + home.getQualifiedClassName() + " couldn't be "
+ + "found on the classpath");
+ return -1;
+ }
+ latestModified = Math.max(latestModified, modified);
+
+ /* Check the timestamp of the primary key class */
+ if (primaryKey != null) {
+ pkFile = primaryKey.getClassFile(buildDir);
+ modified = pkFile.lastModified();
+ if (modified == -1) {
+ System.out.println("The class "
+ + primaryKey.getQualifiedClassName() + "couldn't be "
+ + "found on the classpath");
+ return -1;
+ }
+ latestModified = Math.max(latestModified, modified);
+ } else {
+ pkFile = null;
+ }
+
+ /* Check the timestamp on the EJB implementation class.
+ *
+ * Note that if ONLY the implementation class has changed, it's not
+ * necessary to rebuild the EJB stubs and skeletons. For this
+ * reason, we ensure the file exists (using lastModified above), but
+ * we DON'T compare it's timestamp with the timestamps of the home
+ * and remote interfaces (because it's irrelevant in determining if
+ * ejbc must be run)
+ */
+ implFile = implementation.getClassFile(buildDir);
+ modified = implFile.lastModified();
+ if (modified == -1) {
+ System.out.println("The class "
+ + implementation.getQualifiedClassName()
+ + " couldn't be found on the classpath");
+ return -1;
+ }
+
+ String pathToFile = remote.getQualifiedClassName();
+ pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+ ejbFiles.put(pathToFile, remoteFile);
+
+ pathToFile = home.getQualifiedClassName();
+ pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+ ejbFiles.put(pathToFile, homeFile);
+
+ pathToFile = implementation.getQualifiedClassName();
+ pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+ ejbFiles.put(pathToFile, implFile);
+
+ if (pkFile != null) {
+ pathToFile = primaryKey.getQualifiedClassName();
+ pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+ ejbFiles.put(pathToFile, pkFile);
+ }
+
+ return latestModified;
+ }
+
+ /**
+ * Examines each of the EJB stubs and skeletons in the destination
+ * directory and returns the modification timestamp for the "oldest"
+ * class. If one of the stubs or skeletons cannot be found, <code>-1
+ * </code> is returned.
+ *
+ * @param dest The directory in which the EJB stubs and skeletons are
+ * stored.
+ * @return The modification timestamp for the "oldest" EJB stub or
+ * skeleton. If one of the classes cannot be found, <code>-1
+ * </code> is returned.
+ * @throws BuildException If the canonical path of the destination
+ * directory cannot be found.
+ */
+ private long destClassesModified(File destDir) {
+ String[] classnames = classesToGenerate(); // List of all stubs & skels
+ long destClassesModified = new Date().getTime(); // Earliest mod time
+ boolean allClassesFound = true; // Has each been found?
+
+ /*
+ * Loop through each stub/skeleton class that must be generated, and
+ * determine (if all exist) which file has the most recent timestamp
+ */
+ for (int i = 0; i < classnames.length; i++) {
+
+ String pathToClass =
+ classnames[i].replace('.', File.separatorChar) + ".class";
+ File classFile = new File(destDir, pathToClass);
+
+ /*
+ * Add each stub/skeleton class to the list of EJB files. Note
+ * that each class is added even if it doesn't exist now.
+ */
+ ejbFiles.put(pathToClass, classFile);
+
+ allClassesFound = allClassesFound && classFile.exists();
+
+ if (allClassesFound) {
+ long fileMod = classFile.lastModified();
+
+ /* Keep track of the oldest modification timestamp */
+ destClassesModified = Math.min(destClassesModified, fileMod);
+ }
+ }
+
+ return (allClassesFound) ? destClassesModified : -1;
+ }
+
+ /**
+ * Builds an array of class names which represent the stubs and
+ * skeletons which need to be generated for a given EJB. The class
+ * names are fully qualified. Nine classes are generated for all EJBs
+ * while an additional six classes are generated for beans requiring
+ * RMI/IIOP access.
+ *
+ * @return An array of Strings representing the fully-qualified class
+ * names for the stubs and skeletons to be generated.
+ */
+ private String[] classesToGenerate() {
+ String[] classnames = (iiop)
+ ? new String[NUM_CLASSES_WITH_IIOP]
+ : new String[NUM_CLASSES_WITHOUT_IIOP];
+
+ final String remotePkg = remote.getPackageName() + ".";
+ final String remoteClass = remote.getClassName();
+ final String homePkg = home.getPackageName() + ".";
+ final String homeClass = home.getClassName();
+ final String implPkg = implementation.getPackageName() + ".";
+ final String implFullClass = implementation.getQualifiedWithUnderscores();
+ int index = 0;
+
+ classnames[index++] = implPkg + "ejb_fac_" + implFullClass;
+ classnames[index++] = implPkg + "ejb_home_" + implFullClass;
+ classnames[index++] = implPkg + "ejb_skel_" + implFullClass;
+ classnames[index++] = remotePkg + "ejb_kcp_skel_" + remoteClass;
+ classnames[index++] = homePkg + "ejb_kcp_skel_" + homeClass;
+ classnames[index++] = remotePkg + "ejb_kcp_stub_" + remoteClass;
+ classnames[index++] = homePkg + "ejb_kcp_stub_" + homeClass;
+ classnames[index++] = remotePkg + "ejb_stub_" + remoteClass;
+ classnames[index++] = homePkg + "ejb_stub_" + homeClass;
+
+ if (!iiop) {
+ return classnames;
+ }
+
+ classnames[index++] = "org.omg.stub." + remotePkg + "_"
+ + remoteClass + "_Stub";
+ classnames[index++] = "org.omg.stub." + homePkg + "_"
+ + homeClass + "_Stub";
+ classnames[index++] = "org.omg.stub." + remotePkg
+ + "_ejb_RmiCorbaBridge_"
+ + remoteClass + "_Tie";
+ classnames[index++] = "org.omg.stub." + homePkg
+ + "_ejb_RmiCorbaBridge_"
+ + homeClass + "_Tie";
+
+ classnames[index++] = remotePkg + "ejb_RmiCorbaBridge_"
+ + remoteClass;
+ classnames[index++] = homePkg + "ejb_RmiCorbaBridge_" + homeClass;
+
+ return classnames;
+ }
+
+ /**
+ * Convenience method which creates a String representation of all the
+ * instance variables of an EjbInfo object.
+ *
+ * @return A String representing the EjbInfo instance.
+ */
+ public String toString() {
+ String s = "EJB name: " + name
+ + "\n\r home: " + home
+ + "\n\r remote: " + remote
+ + "\n\r impl: " + implementation
+ + "\n\r primaryKey: " + primaryKey
+ + "\n\r beantype: " + beantype
+ + "\n\r cmp: " + cmp
+ + "\n\r iiop: " + iiop
+ + "\n\r hasession: " + hasession;
+
+ Iterator i = cmpDescriptors.iterator();
+ while (i.hasNext()) {
+ s += "\n\r CMP Descriptor: " + i.next();
+ }
+
+ return s;
+ }
+
+ } // End of EjbInfo inner class
+
+ /**
+ * Convenience class used to represent the fully qualified name of a Java
+ * class. It provides an easy way to retrieve components of the class name
+ * in a format that is convenient for building iAS stubs and skeletons.
+ *
+ */
+ private static class Classname {
+ private String qualifiedName; // Fully qualified name of the Java class
+ private String packageName; // Name of the package for this class
+ private String className; // Name of the class without the package
+
+ /**
+ * This constructor builds an object which represents the name of a Java
+ * class.
+ *
+ * @param qualifiedName String representing the fully qualified class
+ * name of the Java class.
+ */
+ public Classname(String qualifiedName) {
+ if (qualifiedName == null) {
+ return;
+ }
+
+ this.qualifiedName = qualifiedName;
+
+ int index = qualifiedName.lastIndexOf('.');
+ if (index == -1) {
+ className = qualifiedName;
+ packageName = "";
+ } else {
+ packageName = qualifiedName.substring(0, index);
+ className = qualifiedName.substring(index + 1);
+ }
+ }
+
+ /**
+ * Gets the fully qualified name of the Java class.
+ *
+ * @return String representing the fully qualified class name.
+ */
+ public String getQualifiedClassName() {
+ return qualifiedName;
+ }
+
+ /**
+ * Gets the package name for the Java class.
+ *
+ * @return String representing the package name for the class.
+ */
+ public String getPackageName() {
+ return packageName;
+ }
+
+ /**
+ * Gets the Java class name without the package structure.
+ *
+ * @return String representing the name for the class.
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ /**
+ * Gets the fully qualified name of the Java class with underscores
+ * separating the components of the class name rather than periods.
+ * This format is used in naming some of the stub and skeleton classes
+ * for the iPlanet Application Server.
+ *
+ * @return String representing the fully qualified class name using
+ * underscores instead of periods.
+ */
+ public String getQualifiedWithUnderscores() {
+ return qualifiedName.replace('.', '_');
+ }
+
+ /**
+ * Returns a File which references the class relative to the specified
+ * directory. Note that the class file may or may not exist.
+ *
+ * @param directory A File referencing the base directory containing
+ * class files.
+ * @return File referencing this class.
+ */
+ public File getClassFile(File directory) {
+ String pathToFile = qualifiedName.replace('.', File.separatorChar)
+ + ".class";
+ return new File(directory, pathToFile);
+ }
+
+ /**
+ * String representation of this class name. It returns the fully
+ * qualified class name.
+ *
+ * @return String representing the fully qualified class name.
+ */
+ public String toString() {
+ return getQualifiedClassName();
+ }
+ } // End of Classname inner class
+
+
+ /**
+ * Thread class used to redirect output from an <code>InputStream</code> to
+ * the JRE standard output. This class may be used to redirect output from
+ * an external process to the standard output.
+ *
+ */
+ private static class RedirectOutput extends Thread {
+
+ private InputStream stream; // Stream to read and redirect to standard output
+
+ /**
+ * Constructs a new instance that will redirect output from the
+ * specified stream to the standard output.
+ *
+ * @param stream InputStream which will be read and redirected to the
+ * standard output.
+ */
+ public RedirectOutput(InputStream stream) {
+ this.stream = stream;
+ }
+
+ /**
+ * Reads text from the input stream and redirects it to standard output
+ * using a separate thread.
+ */
+ public void run() {
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(stream));
+ String text;
+ try {
+ while ((text = reader.readLine()) != null) {
+ System.out.println(text);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+ } // End of RedirectOutput inner class
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java
new file mode 100644
index 00000000..ee5dc854
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.xml.sax.SAXException;
+
+/**
+ * Compiles EJB stubs and skeletons for the iPlanet Application Server.
+ * The EJBs to be processed are specified by the EJB 1.1 standard XML
+ * descriptor, and additional attributes are obtained from the iPlanet Application
+ * Server-specific XML descriptor. Since the XML descriptors can include
+ * multiple EJBs, this is a convenient way of specifying many EJBs in a single
+ * Ant task. The following attributes are allowed:
+ * <ul>
+ * <li><i>ejbdescriptor</i> -- Standard EJB 1.1 XML descriptor (typically
+ * titled "ejb-jar.xml"). This attribute is
+ * required.
+ * <li><i>iasdescriptor</i> -- EJB XML descriptor for iPlanet Application
+ * Server (typically titled "ias-ejb-jar.xml).
+ * This attribute is required.
+ * <li><i>dest</i> -- The is the base directory where the RMI stubs and
+ * skeletons are written. In addition, the class files
+ * for each bean (home interface, remote interface, and
+ * EJB implementation) must be found in this directory.
+ * This attribute is required.
+ * <li><i>classpath</i> -- The classpath used when generating EJB stubs and
+ * skeletons. This is an optional attribute (if
+ * omitted, the classpath specified when Ant was
+ * started will be used). Nested "classpath"
+ * elements may also be used.
+ * <li><i>keepgenerated</i> -- Indicates whether or not the Java source
+ * files which are generated by ejbc will be
+ * saved or automatically deleted. If "yes",
+ * the source files will be retained. This is
+ * an optional attribute (if omitted, it
+ * defaults to "no").
+ * <li><i>debug</i> -- Indicates whether or not the ejbc utility should
+ * log additional debugging statements to the standard
+ * output. If "yes", the additional debugging statements
+ * will be generated (if omitted, it defaults to "no").
+ * <li><i>iashome</i> -- May be used to specify the "home" directory for
+ * this iPlanet Application Server installation. This
+ * is used to find the ejbc utility if it isn't
+ * included in the user's system path. This is an
+ * optional attribute (if specified, it should refer
+ * to the <code>[install-location]/iplanet/ias6/ias
+ * </code> directory). If omitted, the ejbc utility
+ * must be on the user's system path.
+ * </ul>
+ * <p>
+ * For each EJB specified, this task will locate the three classes that comprise
+ * the EJB. If these class files cannot be located in the <code>dest</code>
+ * directory, the task will fail. The task will also attempt to locate the EJB
+ * stubs and skeletons in this directory. If found, the timestamps on the
+ * stubs and skeletons will be checked to ensure they are up to date. Only if
+ * these files cannot be found or if they are out of date will ejbc be called
+ * to generate new stubs and skeletons.
+ *
+ * @see IPlanetEjbc
+ *
+ * @ant.task name="iplanet-ejbc" category="ejb"
+ */
+public class IPlanetEjbcTask extends Task {
+
+ /* Attributes set by the Ant build file */
+ private File ejbdescriptor;
+ private File iasdescriptor;
+ private File dest;
+ private Path classpath;
+ private boolean keepgenerated = false;
+ private boolean debug = false;
+ private File iashome;
+
+ /**
+ * Sets the location of the standard XML EJB descriptor. Typically, this
+ * file is named "ejb-jar.xml".
+ *
+ * @param ejbdescriptor The name and location of the EJB descriptor.
+ */
+ public void setEjbdescriptor(File ejbdescriptor) {
+ this.ejbdescriptor = ejbdescriptor;
+ }
+
+ /**
+ * Sets the location of the iAS-specific XML EJB descriptor. Typically,
+ * this file is named "ias-ejb-jar.xml".
+ *
+ * @param iasdescriptor The name and location of the iAS-specific EJB
+ * descriptor.
+ */
+ public void setIasdescriptor (File iasdescriptor) {
+ this.iasdescriptor = iasdescriptor;
+ }
+
+ /**
+ * Sets the destination directory where the EJB source classes must exist
+ * and where the stubs and skeletons will be written. The destination
+ * directory must exist before this task is executed.
+ *
+ * @param dest The directory where the compiled classes will be written.
+ */
+ public void setDest(File dest) {
+ this.dest = dest;
+ }
+
+ /**
+ * Sets the classpath to be used when compiling the EJB stubs and skeletons.
+ *
+ * @param classpath The classpath to be used.
+ */
+ public void setClasspath(Path classpath) {
+ if (this.classpath == null) {
+ this.classpath = classpath;
+ } else {
+ this.classpath.append(classpath);
+ }
+ }
+
+ /**
+ * Adds to the classpath used when compiling the EJB stubs and skeletons.
+ * @return the class path.
+ */
+ public Path createClasspath() {
+ if (classpath == null) {
+ classpath = new Path(getProject());
+ }
+ return classpath.createPath();
+ }
+
+ /**
+ * If true, the Java source files which are generated by ejbc will be saved .
+ *
+ * @param keepgenerated A boolean indicating if the Java source files for
+ * the stubs and skeletons should be retained.
+ */
+ public void setKeepgenerated(boolean keepgenerated) {
+ this.keepgenerated = keepgenerated;
+ }
+
+ /**
+ * If true, debugging output will be generated when ejbc is
+ * executed.
+ *
+ * @param debug A boolean indicating if debugging output should be generated
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * May be used to specify the "home" directory for this iAS installation.
+ * The directory specified should typically be
+ * <code>[install-location]/iplanet/ias6/ias</code>.
+ *
+ * @param iashome The home directory for the user's iAS installation.
+ */
+ public void setIashome(File iashome) {
+ this.iashome = iashome;
+ }
+
+ /**
+ * Does the work.
+ * @throws BuildException if there is a problem.
+ */
+ public void execute() throws BuildException {
+ checkConfiguration();
+
+ executeEjbc(getParser());
+ }
+
+ /**
+ * Verifies that the user selections are valid.
+ *
+ * @throws BuildException If the user selections are invalid.
+ */
+ private void checkConfiguration() throws BuildException {
+
+ if (ejbdescriptor == null) {
+ String msg = "The standard EJB descriptor must be specified using "
+ + "the \"ejbdescriptor\" attribute.";
+ throw new BuildException(msg, getLocation());
+ }
+ if ((!ejbdescriptor.exists()) || (!ejbdescriptor.isFile())) {
+ String msg = "The standard EJB descriptor (" + ejbdescriptor
+ + ") was not found or isn't a file.";
+ throw new BuildException(msg, getLocation());
+ }
+
+ if (iasdescriptor == null) {
+ String msg = "The iAS-speific XML descriptor must be specified using"
+ + " the \"iasdescriptor\" attribute.";
+ throw new BuildException(msg, getLocation());
+ }
+ if ((!iasdescriptor.exists()) || (!iasdescriptor.isFile())) {
+ String msg = "The iAS-specific XML descriptor (" + iasdescriptor
+ + ") was not found or isn't a file.";
+ throw new BuildException(msg, getLocation());
+ }
+
+ if (dest == null) {
+ String msg = "The destination directory must be specified using "
+ + "the \"dest\" attribute.";
+ throw new BuildException(msg, getLocation());
+ }
+ if ((!dest.exists()) || (!dest.isDirectory())) {
+ String msg = "The destination directory (" + dest + ") was not "
+ + "found or isn't a directory.";
+ throw new BuildException(msg, getLocation());
+ }
+
+ if ((iashome != null) && (!iashome.isDirectory())) {
+ String msg = "If \"iashome\" is specified, it must be a valid "
+ + "directory (it was set to " + iashome + ").";
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Returns a SAXParser that may be used to process the XML descriptors.
+ *
+ * @return Parser which may be used to process the EJB descriptors.
+ * @throws BuildException If the parser cannot be created or configured.
+ */
+ private SAXParser getParser() throws BuildException {
+
+ SAXParser saxParser = null;
+ try {
+ SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+ saxParserFactory.setValidating(true);
+ saxParser = saxParserFactory.newSAXParser();
+ } catch (SAXException e) {
+ String msg = "Unable to create a SAXParser: " + e.getMessage();
+ throw new BuildException(msg, e, getLocation());
+ } catch (ParserConfigurationException e) {
+ String msg = "Unable to create a SAXParser: " + e.getMessage();
+ throw new BuildException(msg, e, getLocation());
+ }
+
+ return saxParser;
+ }
+
+ /**
+ * Executes the EJBc utility using the SAXParser provided.
+ *
+ * @param saxParser SAXParser that may be used to process the EJB
+ * descriptors
+ * @throws BuildException If there is an error reading or parsing the XML
+ * descriptors
+ */
+ private void executeEjbc(SAXParser saxParser) throws BuildException {
+ IPlanetEjbc ejbc = new IPlanetEjbc(ejbdescriptor,
+ iasdescriptor,
+ dest,
+ getClasspath().toString(),
+ saxParser);
+ ejbc.setRetainSource(keepgenerated);
+ ejbc.setDebugOutput(debug);
+ if (iashome != null) {
+ ejbc.setIasHomeDir(iashome);
+ }
+
+ try {
+ ejbc.execute();
+ } catch (IOException e) {
+ String msg = "An IOException occurred while trying to read the XML "
+ + "descriptor file: " + e.getMessage();
+ throw new BuildException(msg, e, getLocation());
+ } catch (SAXException e) {
+ String msg = "A SAXException occurred while trying to read the XML "
+ + "descriptor file: " + e.getMessage();
+ throw new BuildException(msg, e, getLocation());
+ } catch (IPlanetEjbc.EjbcException e) {
+ String msg = "An exception occurred while trying to run the ejbc "
+ + "utility: " + e.getMessage();
+ throw new BuildException(msg, e, getLocation());
+ }
+ }
+
+ /**
+ * Returns the CLASSPATH to be used when calling EJBc. If no user CLASSPATH
+ * is specified, the System classpath is returned instead.
+ *
+ * @return Path The classpath to be used for EJBc.
+ */
+ private Path getClasspath() {
+ Path cp = null;
+ if (classpath == null) {
+ cp = (new Path(getProject())).concatSystemClasspath("last");
+ } else {
+ cp = classpath.concatSystemClasspath("ignore");
+ }
+
+ return cp;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java
new file mode 100644
index 00000000..e92d9879
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FilenameFilter;
+
+/**
+ * A filename filter for inner class files of a particular class.
+ */
+public class InnerClassFilenameFilter implements FilenameFilter {
+ private String baseClassName;
+
+ /**
+ * Constructor of filter.
+ * @param baseclass the class to filter inner classes on.
+ */
+ InnerClassFilenameFilter(String baseclass) {
+ int extidx = baseclass.lastIndexOf(".class");
+ if (extidx == -1) {
+ extidx = baseclass.length() - 1;
+ }
+ baseClassName = baseclass.substring(0, extidx);
+ }
+
+ /**
+ * Check if the file name passes the filter.
+ * @param dir not used.
+ * @param filename the filename to filter on.
+ * @return true if the filename is an inner class of the base class.
+ */
+ public boolean accept(File dir, String filename) {
+ if ((filename.lastIndexOf(".") != filename.lastIndexOf(".class"))
+ || (filename.indexOf(baseClassName + "$") != 0)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java
new file mode 100644
index 00000000..79f4574e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * The deployment tool to add the jboss specific deployment descriptor to the ejb jar file.
+ * Jboss only requires one additional file jboss.xml and does not require any additional
+ * compilation.
+ *
+ * @version 1.0
+ * @see EjbJar#createJboss
+ */
+public class JbossDeploymentTool extends GenericDeploymentTool {
+ protected static final String JBOSS_DD = "jboss.xml";
+ protected static final String JBOSS_CMP10D = "jaws.xml";
+ protected static final String JBOSS_CMP20D = "jbosscmp-jdbc.xml";
+
+ /** Instance variable that stores the suffix for the jboss jarfile. */
+ private String jarSuffix = ".jar";
+
+ /**
+ * Setter used to store the suffix for the generated JBoss jar file.
+ * @param inString the string to use as the suffix.
+ */
+ public void setSuffix(String inString) {
+ jarSuffix = inString;
+ }
+
+ /**
+ * Add any vendor specific files which should be included in the
+ * EJB Jar.
+ * @param ejbFiles the hashtable of files to populate.
+ * @param ddPrefix the prefix to use.
+ */
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+ File jbossDD = new File(getConfig().descriptorDir, ddPrefix + JBOSS_DD);
+ if (jbossDD.exists()) {
+ ejbFiles.put(META_DIR + JBOSS_DD, jbossDD);
+ } else {
+ log("Unable to locate jboss deployment descriptor. "
+ + "It was expected to be in " + jbossDD.getPath(),
+ Project.MSG_WARN);
+ return;
+ }
+ String descriptorFileName = JBOSS_CMP10D;
+ if (EjbJar.CMPVersion.CMP2_0.equals(getParent().getCmpversion())) {
+ descriptorFileName = JBOSS_CMP20D;
+ }
+ File jbossCMPD
+ = new File(getConfig().descriptorDir, ddPrefix + descriptorFileName);
+
+ if (jbossCMPD.exists()) {
+ ejbFiles.put(META_DIR + descriptorFileName, jbossCMPD);
+ } else {
+ log("Unable to locate jboss cmp descriptor. "
+ + "It was expected to be in "
+ + jbossCMPD.getPath(), Project.MSG_VERBOSE);
+ return;
+ }
+ }
+
+ /**
+ * Get the vendor specific name of the Jar that will be output. The modification date
+ * of this jar will be checked against the dependent bean classes.
+ */
+ File getVendorOutputJarFile(String baseName) {
+ if (getDestDir() == null && getParent().getDestdir() == null) {
+ throw new BuildException("DestDir not specified");
+ }
+ if (getDestDir() == null) {
+ return new File(getParent().getDestdir(), baseName + jarSuffix);
+ } else {
+ return new File(getDestDir(), baseName + jarSuffix);
+ }
+ }
+
+ /**
+ * Called to validate that the tool parameters have been configured.
+ *
+ * @throws BuildException If the Deployment Tool's configuration isn't
+ * valid
+ * @since ant 1.6
+ */
+ public void validateConfigured() throws BuildException {
+ }
+
+ private EjbJar getParent() {
+ return (EjbJar) this.getTask();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java
new file mode 100644
index 00000000..81fe8059
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java
@@ -0,0 +1,835 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.xml.parsers.SAXParser;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The deployment tool to add the jonas specific deployment descriptors to the
+ * ejb JAR file. JONAS only requires one additional file jonas-ejb-jar.xml.
+ *
+ * @version 1.0
+ * @see EjbJar#createJonas
+ */
+public class JonasDeploymentTool extends GenericDeploymentTool {
+
+ /** Public Id of the standard deployment descriptor DTD. */
+ protected static final String EJB_JAR_1_1_PUBLIC_ID
+ = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+ protected static final String EJB_JAR_2_0_PUBLIC_ID
+ = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
+
+ /** Public Id of the JOnAS-specific deployment descriptor DTD. */
+ protected static final String JONAS_EJB_JAR_2_4_PUBLIC_ID
+ = "-//ObjectWeb//DTD JOnAS 2.4//EN";
+ protected static final String JONAS_EJB_JAR_2_5_PUBLIC_ID
+ = "-//ObjectWeb//DTD JOnAS 2.5//EN";
+
+ /** RMI ORB. */
+ protected static final String RMI_ORB = "RMI";
+
+ /** JEREMIE ORB. */
+ protected static final String JEREMIE_ORB = "JEREMIE";
+
+ /** DAVID ORB. */
+ protected static final String DAVID_ORB = "DAVID";
+
+ /**
+ * Name of the standard deployment descriptor DTD (these files are stored in
+ * the ${JONAS_ROOT}/xml directory).
+ */
+ protected static final String EJB_JAR_1_1_DTD = "ejb-jar_1_1.dtd";
+ protected static final String EJB_JAR_2_0_DTD = "ejb-jar_2_0.dtd";
+
+ /**
+ * Name of the JOnAS-specific deployment descriptor DTD (these files are
+ * stored in the ${JONAS_ROOT}/xml directory).
+ */
+ protected static final String JONAS_EJB_JAR_2_4_DTD
+ = "jonas-ejb-jar_2_4.dtd";
+ protected static final String JONAS_EJB_JAR_2_5_DTD
+ = "jonas-ejb-jar_2_5.dtd";
+
+ /** Default JOnAS deployment descriptor name. */
+ protected static final String JONAS_DD = "jonas-ejb-jar.xml";
+
+ /** GenIC class name (JOnAS 2.5) */
+ protected static final String GENIC_CLASS =
+ "org.objectweb.jonas_ejb.genic.GenIC";
+
+ /** Old GenIC class name (JOnAS 2.4.x). */
+ protected static final String OLD_GENIC_CLASS_1 =
+ "org.objectweb.jonas_ejb.tools.GenWholeIC";
+
+ /** Old GenIC class name. */
+ protected static final String OLD_GENIC_CLASS_2 =
+ "org.objectweb.jonas_ejb.tools.GenIC";
+
+ /**
+ * Filename of the standard EJB descriptor (which is passed to this class
+ * from the parent "ejbjar" task). This file is relative to the directory
+ * specified by the "srcdir" attribute in the ejbjar task.
+ */
+ private String descriptorName;
+
+ /**
+ * Filename of the JOnAS-specific EJB descriptor (which is passed to this
+ * class from the parent "ejbjar" task). This file is relative to the
+ * directory specified by the "srcdir" attribute in the ejbjar task.
+ */
+ private String jonasDescriptorName;
+
+ /* ------------- */
+ /* GenIC options */
+ /* ------------- */
+
+ /**
+ * Temporary output directory used by GenIC.
+ */
+ private File outputdir;
+
+ /**
+ * <code>true</code> if the intermediate Java source files generated by
+ * GenIC must be deleted or not. The default is <code>false</code>
+ */
+ private boolean keepgenerated = false;
+
+ /**
+ * <code>true</code> if the generated source files must not be compiled via
+ * the java and rmi compilers. The default is <code>false</code>.
+ */
+ private boolean nocompil = false;
+
+ /**
+ * <code>true</code> if the XML deployment descriptors must be parsed
+ * without validation. The default is <code>false</code>.
+ */
+ private boolean novalidation = false;
+
+ /**
+ * Java compiler to use. The default is the value of
+ * <code>build.compiler</code> property.
+ */
+ private String javac;
+
+ /** Options to pass to the java compiler. */
+ private String javacopts;
+
+ /** Options to pass to the rmi compiler. */
+ private String rmicopts;
+
+ /**
+ * Whether or not the RMI skeleton and stub must be modified to
+ * implement the implicit propagation of the security context (the
+ * transactional context is always provided). The default is
+ * <code>false</code>.
+ */
+ private boolean secpropag = false;
+
+ /**
+ * <code>true</code> if the GenIC call must be verbose. The default
+ * is <code>false</code>.
+ */
+ private boolean verbose = false;
+
+ /** Additional args to send to GenIC. */
+ private String additionalargs;
+
+ /* ------------- */
+ /* other options */
+ /* ------------- */
+
+ /** JOnAS root directory. */
+ private File jonasroot;
+
+ /**
+ * <code>true</code> if the generic JAR file used as input to GenIC must be
+ * retained. The default is <code>false</code>.
+ */
+ private boolean keepgeneric = false;
+
+ /** Stores the suffix for the JOnAS JAR file. The default is '.jar'. */
+ private String suffix = ".jar";
+
+ /**
+ * ORB to use (RMI, JEREMIE or DAVID). If omitted, it defaults to the one
+ * present in classpath. If specified, the corresponding JOnAS JAR is
+ * automatically added to the classpath.
+ */
+ private String orb;
+
+ /**
+ * <code>true</code> if GenIC must not be run on the EJB JAR.
+ * The default is <code>false</code>.
+ */
+ private boolean nogenic = false;
+
+ /* -------------------- */
+ /* GenIC options setter */
+ /* -------------------- */
+
+ /**
+ * Sets the <code>keepgenerated</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setKeepgenerated(boolean aBoolean) {
+ keepgenerated = aBoolean;
+ }
+
+ /**
+ * Sets the additional arguments.
+ *
+ * @param aString additional args.
+ */
+ public void setAdditionalargs(String aString) {
+ additionalargs = aString;
+ }
+
+ /**
+ * Sets the <code>nocompil</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setNocompil(boolean aBoolean) {
+ nocompil = aBoolean;
+ }
+
+ /**
+ * Sets the <code>novalidation</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setNovalidation(boolean aBoolean) {
+ novalidation = aBoolean;
+ }
+
+ /**
+ * Sets the java compiler to use.
+ *
+ * @param aString the java compiler.
+ */
+ public void setJavac(String aString) {
+ javac = aString;
+ }
+
+ /**
+ * Set the options to pass to the java compiler.
+ *
+ * @param aString the options.
+ */
+ public void setJavacopts(String aString) {
+ javacopts = aString;
+ }
+
+ /**
+ * Set the options to pass to the rmi compiler.
+ *
+ * @param aString the options.
+ */
+ public void setRmicopts(String aString) {
+ rmicopts = aString;
+ }
+
+ /**
+ * Sets the <code>secpropag</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setSecpropag(boolean aBoolean) {
+ secpropag = aBoolean;
+ }
+
+ /**
+ * Sets the <code>verbose</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setVerbose(boolean aBoolean) {
+ verbose = aBoolean;
+ }
+
+ /* -------------------- */
+ /* other options setter */
+ /* -------------------- */
+
+ /**
+ * Set the JOnAS root directory.
+ *
+ * @param aFile the JOnAS root directory.
+ */
+ public void setJonasroot(File aFile) {
+ jonasroot = aFile;
+ }
+
+ /**
+ * Sets the <code>keepgeneric</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setKeepgeneric(boolean aBoolean) {
+ keepgeneric = aBoolean;
+ }
+
+ /**
+ * Sets the jar suffix.
+ *
+ * @param aString the string to use as the suffix.
+ */
+ public void setJarsuffix(String aString) {
+ suffix = aString;
+ }
+
+ /**
+ * Sets the <code>orb</code> to construct classpath.
+ *
+ * @param aString 'RMI', 'JEREMIE', or 'DAVID'.
+ */
+ public void setOrb(String aString) {
+ orb = aString;
+ }
+
+ /**
+ * Sets the <code>nogenic</code> flag.
+ *
+ * @param aBoolean <code>true</code> if the flag must be set.
+ */
+ public void setNogenic(boolean aBoolean) {
+ nogenic = aBoolean;
+ }
+
+ /* ------------- */
+ /* other methods */
+ /* ------------- */
+
+ /** {@inheritDoc}. */
+ public void processDescriptor(String aDescriptorName, SAXParser saxParser) {
+
+ descriptorName = aDescriptorName;
+
+ log("JOnAS Deployment Tool processing: " + descriptorName,
+ Project.MSG_VERBOSE);
+
+ super.processDescriptor(descriptorName, saxParser);
+
+ if (outputdir != null) {
+ // the method deleteOnExit() do not work because the directory is not empty
+ log("Deleting temp output directory '" + outputdir + "'.", Project.MSG_VERBOSE);
+ deleteAllFiles(outputdir);
+ }
+ }
+
+ /** {@inheritDoc}. */
+ protected void writeJar(String baseName, File jarfile, Hashtable ejbFiles, String publicId)
+ throws BuildException {
+
+ // create the generic jar first
+ File genericJarFile = super.getVendorOutputJarFile(baseName);
+ super.writeJar(baseName, genericJarFile, ejbFiles, publicId);
+
+ // GenIC call on generic jar
+ addGenICGeneratedFiles(genericJarFile, ejbFiles);
+
+ // create the real jar
+ super.writeJar(baseName, getVendorOutputJarFile(baseName), ejbFiles, publicId);
+
+ if (!keepgeneric) {
+ log("Deleting generic JAR " + genericJarFile.toString(), Project.MSG_VERBOSE);
+ genericJarFile.delete();
+ }
+ }
+
+ /** {@inheritDoc}. */
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+
+ // JOnAS-specific descriptor deployment
+ jonasDescriptorName = getJonasDescriptorName();
+ File jonasDD = new File(getConfig().descriptorDir, jonasDescriptorName);
+
+ if (jonasDD.exists()) {
+ ejbFiles.put(META_DIR + JONAS_DD, jonasDD);
+ } else {
+ log("Unable to locate the JOnAS deployment descriptor. It was expected to be in: "
+ + jonasDD.getPath() + ".", Project.MSG_WARN);
+ }
+ }
+
+ /** {@inheritDoc}. */
+ protected File getVendorOutputJarFile(String baseName) {
+ return new File(getDestDir(), baseName + suffix);
+ }
+
+ /**
+ * Determines the name of the JOnAS-specific EJB descriptor using the
+ * specified standard EJB descriptor name. In general, the standard
+ * descriptor will be named "[basename]-ejb-jar.xml", and this method will
+ * return "[basename]-jonas-ejb-jar.xml" or "jonas-[basename].xml"
+ *
+ * @return The name of the JOnAS-specific EJB descriptor file.
+ */
+ private String getJonasDescriptorName() {
+
+ // descriptorName = <path><basename><basenameterminator><remainder>
+ // examples = /org/objectweb/fooAppli/foo/Foo-ejb-jar.xml
+ // examples = /org/objectweb/fooAppli/foo/Foo.xml (JOnAS convention)
+
+ String jonasDN; // JOnAS-specific DD
+ boolean jonasConvention = false; // true if the JOnAS convention is used for the DD
+ String path; // Directory path of the EJB descriptor
+ String fileName; // EJB descriptor file name
+ String baseName; // Filename appearing before name terminator
+ String remainder; // Filename appearing after the name terminator
+
+ int startOfFileName = descriptorName.lastIndexOf(File.separatorChar);
+ if (startOfFileName != -1) {
+ // extract path info
+ path = descriptorName.substring(0, startOfFileName + 1);
+ fileName = descriptorName.substring(startOfFileName + 1);
+ } else {
+ // descriptorName is just a file without path
+ path = "";
+ fileName = descriptorName;
+ }
+
+ if (fileName.startsWith(EJB_DD)) {
+ return path + JONAS_DD;
+ }
+
+ int endOfBaseName = descriptorName.indexOf(getConfig().baseNameTerminator, startOfFileName);
+
+ /*
+ * Check for the odd case where the terminator and/or filename
+ * extension aren't found. These will ensure "jonas-" appears at the
+ * end of the name and before the '.' (if present).
+ */
+ if (endOfBaseName < 0) {
+ // baseNameTerminator not found: the descriptor use the
+ // JOnAS naming convention, ie [Foo.xml,jonas-Foo.xml] and
+ // not [Foo<baseNameTerminator>-ejb-jar.xml,
+ // Foo<baseNameTerminator>-jonas-ejb-jar.xml].
+ endOfBaseName = descriptorName.lastIndexOf('.') - 1;
+ if (endOfBaseName < 0) {
+ // no . found
+ endOfBaseName = descriptorName.length() - 1;
+ }
+
+ jonasConvention = true;
+ }
+
+ baseName = descriptorName.substring(startOfFileName + 1, endOfBaseName + 1);
+ remainder = descriptorName.substring(endOfBaseName + 1);
+
+ if (jonasConvention) {
+ jonasDN = path + "jonas-" + baseName + ".xml";
+ } else {
+ jonasDN = path + baseName + "jonas-" + remainder;
+ }
+
+ log("Standard EJB descriptor name: " + descriptorName, Project.MSG_VERBOSE);
+ log("JOnAS-specific descriptor name: " + jonasDN, Project.MSG_VERBOSE);
+
+ return jonasDN;
+ }
+
+ /** {@inheritDoc}. */
+ protected String getJarBaseName(String descriptorFileName) {
+
+ String baseName = null;
+
+ if (getConfig().namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
+
+ // try to find JOnAS specific convention name
+ if (descriptorFileName.indexOf(getConfig().baseNameTerminator) == -1) {
+
+ // baseNameTerminator not found: the descriptor use the
+ // JOnAS naming convention, ie [Foo.xml,jonas-Foo.xml] and
+ // not [Foo<baseNameTerminator>-ejb-jar.xml,
+ // Foo<baseNameTerminator>-jonas-ejb-jar.xml].
+
+ String aCanonicalDescriptor = descriptorFileName.replace('\\', '/');
+ int lastSeparatorIndex = aCanonicalDescriptor.lastIndexOf('/');
+ int endOfBaseName;
+
+ if (lastSeparatorIndex != -1) {
+ endOfBaseName = descriptorFileName.indexOf(".xml", lastSeparatorIndex);
+ } else {
+ endOfBaseName = descriptorFileName.indexOf(".xml");
+ }
+
+ if (endOfBaseName != -1) {
+ baseName = descriptorFileName.substring(0, endOfBaseName);
+ }
+ }
+ }
+
+ if (baseName == null) {
+ // else get standard baseName
+ baseName = super.getJarBaseName(descriptorFileName);
+ }
+
+ log("JAR base name: " + baseName, Project.MSG_VERBOSE);
+
+ return baseName;
+ }
+
+ /** {@inheritDoc}. */
+ protected void registerKnownDTDs(DescriptorHandler handler) {
+ handler.registerDTD(EJB_JAR_1_1_PUBLIC_ID,
+ jonasroot + File.separator + "xml" + File.separator + EJB_JAR_1_1_DTD);
+ handler.registerDTD(EJB_JAR_2_0_PUBLIC_ID,
+ jonasroot + File.separator + "xml" + File.separator + EJB_JAR_2_0_DTD);
+
+ handler.registerDTD(JONAS_EJB_JAR_2_4_PUBLIC_ID,
+ jonasroot + File.separator + "xml" + File.separator + JONAS_EJB_JAR_2_4_DTD);
+ handler.registerDTD(JONAS_EJB_JAR_2_5_PUBLIC_ID,
+ jonasroot + File.separator + "xml" + File.separator + JONAS_EJB_JAR_2_5_DTD);
+ }
+
+ /**
+ * Add to the given hashtable all the file generated by GenIC.
+ *
+ * @param genericJarFile jar file.
+ * @param ejbFiles the hashtable.
+ */
+ private void addGenICGeneratedFiles(
+ File genericJarFile, Hashtable ejbFiles) {
+ Java genicTask = null; // GenIC task
+ String genicClass = null; // GenIC class (3 are supported for various
+ // versions
+ if (nogenic) {
+ return;
+ }
+
+ genicTask = new Java(getTask());
+ genicTask.setTaskName("genic");
+ genicTask.setFork(true);
+
+ // jonasroot
+ genicTask.createJvmarg().setValue("-Dinstall.root=" + jonasroot);
+
+ // java policy file
+ String jonasConfigDir = jonasroot + File.separator + "config";
+ File javaPolicyFile = new File(jonasConfigDir, "java.policy");
+ if (javaPolicyFile.exists()) {
+ genicTask.createJvmarg().setValue("-Djava.security.policy="
+ + javaPolicyFile.toString());
+ }
+
+ // outputdir
+ try {
+ outputdir = createTempDir();
+ } catch (IOException aIOException) {
+ String msg = "Cannot create temp dir: " + aIOException.getMessage();
+ throw new BuildException(msg, aIOException);
+ }
+ log("Using temporary output directory: " + outputdir, Project.MSG_VERBOSE);
+
+ genicTask.createArg().setValue("-d");
+ genicTask.createArg().setFile(outputdir);
+
+ // work around a bug of GenIC 2.5
+ String key;
+ File f;
+ Enumeration keys = ejbFiles.keys();
+ while (keys.hasMoreElements()) {
+ key = (String) keys.nextElement();
+ f = new File(outputdir + File.separator + key);
+ f.getParentFile().mkdirs();
+ }
+ log("Worked around a bug of GenIC 2.5.", Project.MSG_VERBOSE);
+
+ // classpath
+ Path classpath = getCombinedClasspath();
+ if (classpath == null) {
+ classpath = new Path(getTask().getProject());
+ }
+ classpath.append(new Path(classpath.getProject(), jonasConfigDir));
+ classpath.append(new Path(classpath.getProject(), outputdir.toString()));
+
+ // try to create the classpath for the correct ORB
+ if (orb != null) {
+ String orbJar = jonasroot + File.separator + "lib"
+ + File.separator + orb + "_jonas.jar";
+ classpath.append(new Path(classpath.getProject(), orbJar));
+ }
+ log("Using classpath: " + classpath.toString(), Project.MSG_VERBOSE);
+ genicTask.setClasspath(classpath);
+
+ // class name (search in the classpath provided for the ejbjar element)
+ genicClass = getGenicClassName(classpath);
+ if (genicClass == null) {
+ log("Cannot find GenIC class in classpath.", Project.MSG_ERR);
+ throw new BuildException("GenIC class not found, please check the classpath.");
+ } else {
+ log("Using '" + genicClass + "' GenIC class." , Project.MSG_VERBOSE);
+ genicTask.setClassname(genicClass);
+ }
+
+ // keepgenerated
+ if (keepgenerated) {
+ genicTask.createArg().setValue("-keepgenerated");
+ }
+
+ // nocompil
+ if (nocompil) {
+ genicTask.createArg().setValue("-nocompil");
+ }
+
+ // novalidation
+ if (novalidation) {
+ genicTask.createArg().setValue("-novalidation");
+ }
+
+ // javac
+ if (javac != null) {
+ genicTask.createArg().setValue("-javac");
+ genicTask.createArg().setLine(javac);
+ }
+
+ // javacopts
+ if (javacopts != null && !javacopts.equals("")) {
+ genicTask.createArg().setValue("-javacopts");
+ genicTask.createArg().setLine(javacopts);
+ }
+
+ // rmicopts
+ if (rmicopts != null && !rmicopts.equals("")) {
+ genicTask.createArg().setValue("-rmicopts");
+ genicTask.createArg().setLine(rmicopts);
+ }
+
+ // secpropag
+ if (secpropag) {
+ genicTask.createArg().setValue("-secpropag");
+ }
+
+ // verbose
+ if (verbose) {
+ genicTask.createArg().setValue("-verbose");
+ }
+
+ // additionalargs
+ if (additionalargs != null) {
+ genicTask.createArg().setValue(additionalargs);
+ }
+
+ // the generated classes must not be added in the generic JAR!
+ // is that buggy on old JOnAS (2.4) ??
+ genicTask.createArg().setValue("-noaddinjar");
+
+ // input file to process by GenIC
+ genicTask.createArg().setValue(genericJarFile.getPath());
+
+ // calling GenIC task
+ log("Calling " + genicClass + " for " + getConfig().descriptorDir
+ + File.separator + descriptorName + ".", Project.MSG_VERBOSE);
+
+ if (genicTask.executeJava() != 0) {
+
+ // the method deleteOnExit() do not work because the directory is not empty
+ log("Deleting temp output directory '" + outputdir + "'.", Project.MSG_VERBOSE);
+ deleteAllFiles(outputdir);
+
+ if (!keepgeneric) {
+ log("Deleting generic JAR " + genericJarFile.toString(),
+ Project.MSG_VERBOSE);
+ genericJarFile.delete();
+ }
+
+ throw new BuildException("GenIC reported an error.");
+ }
+
+ // add the generated files to the ejbFiles
+ addAllFiles(outputdir, "", ejbFiles);
+ }
+
+ /**
+ * Get the GenIC class name to use in the given classpath.
+ *
+ * @param classpath classpath where the GenIC class must be searched.
+ * @return the GenIC class name. Return <code>null</code> if the class name
+ * cannot be found.
+ */
+ String getGenicClassName(Path classpath) {
+
+ log("Looking for GenIC class in classpath: "
+ + classpath.toString(), Project.MSG_VERBOSE);
+
+ AntClassLoader cl = null;
+
+ try {
+ cl = classpath.getProject().createClassLoader(classpath);
+
+ try {
+ cl.loadClass(JonasDeploymentTool.GENIC_CLASS);
+ log("Found GenIC class '" + JonasDeploymentTool.GENIC_CLASS
+ + "' in classpath.", Project.MSG_VERBOSE);
+ return JonasDeploymentTool.GENIC_CLASS;
+
+ } catch (ClassNotFoundException cnf1) {
+ log("GenIC class '" + JonasDeploymentTool.GENIC_CLASS
+ + "' not found in classpath.",
+ Project.MSG_VERBOSE);
+ }
+
+ try {
+ cl.loadClass(JonasDeploymentTool.OLD_GENIC_CLASS_1);
+ log("Found GenIC class '"
+ + JonasDeploymentTool.OLD_GENIC_CLASS_1
+ + "' in classpath.", Project.MSG_VERBOSE);
+ return JonasDeploymentTool.OLD_GENIC_CLASS_1;
+
+ } catch (ClassNotFoundException cnf2) {
+ log("GenIC class '" + JonasDeploymentTool.OLD_GENIC_CLASS_1
+ + "' not found in classpath.",
+ Project.MSG_VERBOSE);
+ }
+
+ try {
+ cl.loadClass(JonasDeploymentTool.OLD_GENIC_CLASS_2);
+ log("Found GenIC class '"
+ + JonasDeploymentTool.OLD_GENIC_CLASS_2
+ + "' in classpath.", Project.MSG_VERBOSE);
+ return JonasDeploymentTool.OLD_GENIC_CLASS_2;
+
+ } catch (ClassNotFoundException cnf3) {
+ log("GenIC class '" + JonasDeploymentTool.OLD_GENIC_CLASS_2
+ + "' not found in classpath.",
+ Project.MSG_VERBOSE);
+ }
+ } finally {
+ if (cl != null) {
+ cl.cleanup();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Verify the configuration.
+ * @param descriptorFileName the name of the descriptor file.
+ * @param saxParser not used.
+ * @throws BuildException if there is an error.
+ */
+ protected void checkConfiguration(String descriptorFileName,
+ SAXParser saxParser) throws BuildException {
+
+ // jonasroot
+ if (jonasroot == null) {
+ throw new BuildException("The jonasroot attribut is not set.");
+ } else if (!jonasroot.isDirectory()) {
+ throw new BuildException("The jonasroot attribut '" + jonasroot
+ + "' is not a valid directory.");
+ }
+
+ // orb
+ if (orb != null && !orb.equals(RMI_ORB) && !orb.equals(JEREMIE_ORB)
+ && !orb.equals(DAVID_ORB)) {
+ throw new BuildException("The orb attribut '" + orb
+ + "' is not valid (must be either "
+ + RMI_ORB + ", " + JEREMIE_ORB + " or " + DAVID_ORB + ").");
+ }
+
+ // additionalargs
+ if (additionalargs != null && additionalargs.equals("")) {
+ throw new BuildException("Empty additionalargs attribut.");
+ }
+
+ // javac
+ if (javac != null && javac.equals("")) {
+ throw new BuildException("Empty javac attribut.");
+ }
+ }
+
+ /* ----------------------------------------------------------------------------------- */
+ /* utilitary methods */
+ /* ----------------------------------------------------------------------------------- */
+
+ /**
+ * Create a temporary directory for GenIC output.
+ *
+ * @return the temp directory.
+ * @throws BuildException if a temp directory cannot be created.
+ */
+ private File createTempDir() throws IOException {
+ File tmpDir = File.createTempFile("genic", null, null);
+ tmpDir.delete();
+ if (!tmpDir.mkdir()) {
+ throw new IOException("Cannot create the temporary directory '" + tmpDir + "'.");
+ }
+ return tmpDir;
+ }
+
+ /**
+ * Delete a file. If the file is a directory, delete recursivly all the
+ * files inside.
+ *
+ * @param aFile file to delete.
+ */
+ private void deleteAllFiles(File aFile) {
+ if (aFile.isDirectory()) {
+ File[] someFiles = aFile.listFiles();
+
+ for (int i = 0; i < someFiles.length; i++) {
+ deleteAllFiles(someFiles[i]);
+ }
+ }
+ aFile.delete();
+ }
+
+ /**
+ * Add a file to the a given hashtable. If the file is a directory, add
+ * recursivly all the files inside to the hashtable.
+ *
+ * @param file the file to add.
+ * @param rootDir the current sub-directory to scan.
+ * @param hashtable the hashtable where to add the files.
+ */
+ private void addAllFiles(File file, String rootDir, Hashtable hashtable) {
+
+ if (!file.exists()) {
+ throw new IllegalArgumentException();
+ }
+
+ String newRootDir;
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (rootDir.length() > 0) {
+ newRootDir = rootDir + File.separator + files[i].getName();
+ } else {
+ newRootDir = files[i].getName();
+ }
+ addAllFiles(files[i], newRootDir, hashtable);
+ }
+ } else {
+ hashtable.put(rootDir, file);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java
new file mode 100644
index 00000000..550f59ce
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java
@@ -0,0 +1,932 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+import org.xml.sax.InputSource;
+
+/**
+ The weblogic element is used to control the weblogic.ejbc compiler for
+ generating weblogic EJB jars. Prior to Ant 1.3, the method of locating CMP
+ descriptors was to use the ejbjar naming convention. So if your ejb-jar was
+ called, Customer-ejb-jar.xml, your weblogic descriptor was called Customer-
+ weblogic-ejb-jar.xml and your CMP descriptor had to be Customer-weblogic-cmp-
+ rdbms-jar.xml. In addition, the &lt;type-storage&gt; element in the weblogic
+ descriptor had to be set to the standard name META-INF/weblogic-cmp-rdbms-
+ jar.xml, as that is where the CMP descriptor was mapped to in the generated
+ jar.
+*/
+public class WeblogicDeploymentTool extends GenericDeploymentTool {
+ /** EJB11 id */
+ public static final String PUBLICID_EJB11
+ = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+ /** EJB20 id */
+ public static final String PUBLICID_EJB20
+ = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
+ /** Weblogic 5.1.0 id */
+ public static final String PUBLICID_WEBLOGIC_EJB510
+ = "-//BEA Systems, Inc.//DTD WebLogic 5.1.0 EJB//EN";
+ /** Weblogic 6.0.0 id */
+ public static final String PUBLICID_WEBLOGIC_EJB600
+ = "-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN";
+ /** Weblogic 7.0.0 id */
+ public static final String PUBLICID_WEBLOGIC_EJB700
+ = "-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN";
+
+ /** Weblogic 5.1 dtd location */
+ protected static final String DEFAULT_WL51_EJB11_DTD_LOCATION
+ = "/weblogic/ejb/deployment/xml/ejb-jar.dtd";
+ /** Weblogic 6.0 ejb 1.1 dtd location */
+ protected static final String DEFAULT_WL60_EJB11_DTD_LOCATION
+ = "/weblogic/ejb20/dd/xml/ejb11-jar.dtd";
+ /** Weblogic 6.0 ejb 2.0 dtd location */
+ protected static final String DEFAULT_WL60_EJB20_DTD_LOCATION
+ = "/weblogic/ejb20/dd/xml/ejb20-jar.dtd";
+
+ protected static final String DEFAULT_WL51_DTD_LOCATION
+ = "/weblogic/ejb/deployment/xml/weblogic-ejb-jar.dtd";
+ protected static final String DEFAULT_WL60_51_DTD_LOCATION
+ = "/weblogic/ejb20/dd/xml/weblogic510-ejb-jar.dtd";
+ protected static final String DEFAULT_WL60_DTD_LOCATION
+ = "/weblogic/ejb20/dd/xml/weblogic600-ejb-jar.dtd";
+ protected static final String DEFAULT_WL70_DTD_LOCATION
+ = "/weblogic/ejb20/dd/xml/weblogic700-ejb-jar.dtd";
+
+ protected static final String DEFAULT_COMPILER = "default";
+
+ protected static final String WL_DD = "weblogic-ejb-jar.xml";
+ protected static final String WL_CMP_DD = "weblogic-cmp-rdbms-jar.xml";
+
+ protected static final String COMPILER_EJB11 = "weblogic.ejbc";
+ protected static final String COMPILER_EJB20 = "weblogic.ejbc20";
+
+ /** File utilities instance for copying jars */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /** Instance variable that stores the suffix for the weblogic jarfile. */
+ private String jarSuffix = ".jar";
+
+ /** Instance variable that stores the location of the weblogic DTD file. */
+ private String weblogicDTD;
+
+ /** Instance variable that stores the location of the ejb 1.1 DTD file. */
+ private String ejb11DTD;
+
+ /** Instance variable that determines whether generic ejb jars are kept. */
+ private boolean keepgenerated = false;
+
+ /**
+ * Instance variable that stores the fully qualified classname of the
+ * weblogic EJBC compiler
+ */
+ private String ejbcClass = null;
+
+ private String additionalArgs = "";
+
+ /**
+ * additional args to pass to the spawned jvm
+ */
+ private String additionalJvmArgs = "";
+
+ private boolean keepGeneric = false;
+
+ private String compiler = null;
+
+ private boolean alwaysRebuild = true;
+
+ /** controls whether ejbc is run on the generated jar */
+ private boolean noEJBC = false;
+
+ /** Indicates if the old CMP location convention is to be used. */
+ private boolean newCMP = false;
+
+ /** The classpath to the weblogic classes. */
+ private Path wlClasspath = null;
+
+ /** System properties for the JVM. */
+ private Vector sysprops = new Vector();
+
+ /**
+ * The weblogic.StdoutSeverityLevel to use when running the JVM that
+ * executes ejbc. Set to 16 to avoid the warnings about EJB Home and
+ * Remotes being in the classpath
+ */
+ private Integer jvmDebugLevel = null;
+
+ private File outputDir;
+
+ /**
+ * Add a nested sysproperty element.
+ * @param sysp the element to add.
+ */
+ public void addSysproperty(Environment.Variable sysp) {
+ sysprops.add(sysp);
+ }
+
+
+ /**
+ * Get the classpath to the weblogic classpaths.
+ * @return the classpath to configure.
+ */
+ public Path createWLClasspath() {
+ if (wlClasspath == null) {
+ wlClasspath = new Path(getTask().getProject());
+ }
+ return wlClasspath.createPath();
+ }
+
+ /**
+ * If set ejbc will use this directory as the output
+ * destination rather than a jar file. This allows for the
+ * generation of &quot;exploded&quot; jars.
+ * @param outputDir the directory to be used.
+ */
+ public void setOutputDir(File outputDir) {
+ this.outputDir = outputDir;
+ }
+
+
+ /**
+ * Optional classpath to WL6.0.
+ * Weblogic 6.0 will give a warning if the home and remote interfaces
+ * of a bean are on the system classpath used to run weblogic.ejbc.
+ * In that case, the standard weblogic classes should be set with
+ * this attribute (or equivalent nested element) and the
+ * home and remote interfaces located with the standard classpath
+ * attribute.
+ * @param wlClasspath the path to be used.
+ */
+ public void setWLClasspath(Path wlClasspath) {
+ this.wlClasspath = wlClasspath;
+ }
+
+
+ /**
+ * The compiler (switch <code>-compiler</code>) to use; optional.
+ * This allows for the selection of a different compiler
+ * to be used for the compilation of the generated Java
+ * files. This could be set, for example, to Jikes to
+ * compile with the Jikes compiler. If this is not set
+ * and the <code>build.compiler</code> property is set
+ * to jikes, the Jikes compiler will be used. If this
+ * is not desired, the value &quot;<code>default</code>&quot;
+ * may be given to use the default compiler.
+ * @param compiler the compiler to be used.
+ */
+ public void setCompiler(String compiler) {
+ this.compiler = compiler;
+ }
+
+
+ /**
+ * Set the rebuild flag to false to only update changes in the jar rather
+ * than rerunning ejbc; optional, default true.
+ * This flag controls whether weblogic.ejbc is always
+ * invoked to build the jar file. In certain circumstances,
+ * such as when only a bean class has been changed, the jar
+ * can be generated by merely replacing the changed classes
+ * and not rerunning ejbc. Setting this to false will reduce
+ * the time to run ejbjar.
+ * @param rebuild a <code>boolean</code> value.
+ */
+ public void setRebuild(boolean rebuild) {
+ this.alwaysRebuild = rebuild;
+ }
+
+
+ /**
+ * Sets the weblogic.StdoutSeverityLevel to use when running the JVM that
+ * executes ejbc; optional. Set to 16 to avoid the warnings about EJB Home and
+ * Remotes being in the classpath
+ * @param jvmDebugLevel the value to use.
+ */
+ public void setJvmDebugLevel(Integer jvmDebugLevel) {
+ this.jvmDebugLevel = jvmDebugLevel;
+ }
+
+
+ /**
+ * Get the debug level.
+ * @return the jvm debug level (may be null).
+ */
+ public Integer getJvmDebugLevel() {
+ return jvmDebugLevel;
+ }
+
+
+
+ /**
+ * Setter used to store the suffix for the generated weblogic jar file.
+ *
+ * @param inString the string to use as the suffix.
+ */
+ public void setSuffix(String inString) {
+ this.jarSuffix = inString;
+ }
+
+
+ /**
+ * controls whether the generic file used as input to
+ * ejbc is retained; defaults to false
+ *
+ * @param inValue true for keep generic
+ */
+ public void setKeepgeneric(boolean inValue) {
+ this.keepGeneric = inValue;
+ }
+
+
+ /**
+ * Controls whether weblogic will keep the generated Java
+ * files used to build the class files added to the
+ * jar. This can be useful when debugging; default is false.
+ *
+ * @param inValue either 'true' or 'false'
+ */
+ public void setKeepgenerated(String inValue) {
+ this.keepgenerated = Boolean.valueOf(inValue).booleanValue();
+ }
+
+
+ /**
+ * Any optional extra arguments pass to the weblogic.ejbc
+ * tool.
+ * @param args extra arguments to pass to the ejbc tool.
+ */
+ public void setArgs(String args) {
+ this.additionalArgs = args;
+ }
+
+
+ /**
+ * Set any additional arguments to pass to the weblogic JVM; optional.
+ * @param args the arguments to be passed to the JVM
+ */
+ public void setJvmargs(String args) {
+ this.additionalJvmArgs = args;
+ }
+
+ /**
+ * Set the classname of the ejbc compiler; optional
+ * Normally ejbjar determines
+ * the appropriate class based on the DTD used for the EJB. The EJB 2.0 compiler
+ * featured in weblogic 6 has, however, been deprecated in version 7. When
+ * using with version 7 this attribute should be set to
+ * &quot;weblogic.ejbc&quot; to avoid the deprecation warning.
+ * @param ejbcClass the name of the class to use.
+ */
+ public void setEjbcClass(String ejbcClass) {
+ this.ejbcClass = ejbcClass;
+ }
+
+
+ /**
+ * Get the ejbc compiler class.
+ * @return the name of the ejbc compiler class.
+ */
+ public String getEjbcClass() {
+ return ejbcClass;
+ }
+
+
+ /**
+ * <b>Deprecated</b>. Defines the location of the ejb-jar DTD in
+ * the weblogic class hierarchy. Should not be needed, and the
+ * nested &lt;dtd&gt; element is recommended when it is.
+ *
+ * @param inString the string to use as the DTD location.
+ */
+ public void setWeblogicdtd(String inString) {
+ setEJBdtd(inString);
+ }
+
+
+ /**
+ * <b>Deprecated</b>. Defines the location of weblogic DTD in
+ * the weblogic class hierarchy. Should not be needed, and the
+ * nested &lt;dtd&gt; element is recommended when it is.
+ *
+ * @param inString the string to use as the DTD location.
+ */
+ public void setWLdtd(String inString) {
+ this.weblogicDTD = inString;
+ }
+
+
+ /**
+ * <b>Deprecated</b>. Defines the location of Sun's EJB DTD in
+ * the weblogic class hierarchy. Should not be needed, and the
+ * nested &lt;dtd&gt; element is recommended when it is.
+ *
+ * @param inString the string to use as the DTD location.
+ */
+ public void setEJBdtd(String inString) {
+ this.ejb11DTD = inString;
+ }
+
+
+ /**
+ * Set the value of the oldCMP scheme. This is an antonym for newCMP
+ * @ant.attribute ignore="true'
+ * @param oldCMP a <code>boolean</code> value.
+ */
+ public void setOldCMP(boolean oldCMP) {
+ this.newCMP = !oldCMP;
+ }
+
+
+ /**
+ * If this is set to true, the new method for locating
+ * CMP descriptors will be used; optional, default false.
+ * <P>
+ * The old CMP scheme locates the
+ * weblogic CMP descriptor based on the naming convention where the
+ * weblogic CMP file is expected to be named with the bean name as the
+ * prefix. Under this scheme the name of the CMP descriptor does not match
+ * the name actually used in the main weblogic EJB descriptor. Also,
+ * descriptors which contain multiple CMP references could not be used.
+ * @param newCMP a <code>boolean</code> value.
+ */
+ public void setNewCMP(boolean newCMP) {
+ this.newCMP = newCMP;
+ }
+
+
+ /**
+ * Do not EJBC the jar after it has been put together;
+ * optional, default false
+ * @param noEJBC a <code>boolean</code> value.
+ */
+ public void setNoEJBC(boolean noEJBC) {
+ this.noEJBC = noEJBC;
+ }
+
+
+ /**
+ * Register the DTDs.
+ * @param handler the handler to use.
+ */
+ protected void registerKnownDTDs(DescriptorHandler handler) {
+ // register all the known DTDs
+ handler.registerDTD(PUBLICID_EJB11, DEFAULT_WL51_EJB11_DTD_LOCATION);
+ handler.registerDTD(PUBLICID_EJB11, DEFAULT_WL60_EJB11_DTD_LOCATION);
+ handler.registerDTD(PUBLICID_EJB11, ejb11DTD);
+ handler.registerDTD(PUBLICID_EJB20, DEFAULT_WL60_EJB20_DTD_LOCATION);
+ }
+
+
+ /**
+ * Get the weblogic descriptor handler.
+ * @param srcDir the source directory.
+ * @return the descriptor.
+ */
+ protected DescriptorHandler getWeblogicDescriptorHandler(final File srcDir) {
+ DescriptorHandler handler =
+ new DescriptorHandler(getTask(), srcDir) {
+ protected void processElement() {
+ if (currentElement.equals("type-storage")) {
+ // Get the filename of vendor specific descriptor
+ String fileNameWithMETA = currentText;
+ //trim the META_INF\ off of the file name
+ String fileName
+ = fileNameWithMETA.substring(META_DIR.length(),
+ fileNameWithMETA.length());
+ File descriptorFile = new File(srcDir, fileName);
+
+ ejbFiles.put(fileNameWithMETA, descriptorFile);
+ }
+ }
+ };
+
+ handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, DEFAULT_WL51_DTD_LOCATION);
+ handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, DEFAULT_WL60_51_DTD_LOCATION);
+ handler.registerDTD(PUBLICID_WEBLOGIC_EJB600, DEFAULT_WL60_DTD_LOCATION);
+ handler.registerDTD(PUBLICID_WEBLOGIC_EJB700, DEFAULT_WL70_DTD_LOCATION);
+ handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, weblogicDTD);
+ handler.registerDTD(PUBLICID_WEBLOGIC_EJB600, weblogicDTD);
+
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+
+ handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+ }
+ return handler;
+ }
+
+
+ /**
+ * Add any vendor specific files which should be included in the EJB Jar.
+ * @param ejbFiles the hash table to be populated.
+ * @param ddPrefix the prefix to use.
+ */
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+ File weblogicDD = new File(getConfig().descriptorDir, ddPrefix + WL_DD);
+
+ if (weblogicDD.exists()) {
+ ejbFiles.put(META_DIR + WL_DD,
+ weblogicDD);
+ } else {
+ log("Unable to locate weblogic deployment descriptor. "
+ + "It was expected to be in "
+ + weblogicDD.getPath(), Project.MSG_WARN);
+ return;
+ }
+
+ if (!newCMP) {
+ log("The old method for locating CMP files has been DEPRECATED.", Project.MSG_VERBOSE);
+ log("Please adjust your weblogic descriptor and set "
+ + "newCMP=\"true\" to use the new CMP descriptor "
+ + "inclusion mechanism. ", Project.MSG_VERBOSE);
+ // The the weblogic cmp deployment descriptor
+ File weblogicCMPDD = new File(getConfig().descriptorDir, ddPrefix + WL_CMP_DD);
+
+ if (weblogicCMPDD.exists()) {
+ ejbFiles.put(META_DIR + WL_CMP_DD,
+ weblogicCMPDD);
+ }
+ } else {
+ // now that we have the weblogic descriptor, we parse the file
+ // to find other descriptors needed to deploy the bean.
+ // this could be the weblogic-cmp-rdbms.xml or any other O/R
+ // mapping tool descriptors.
+ try {
+ File ejbDescriptor = (File) ejbFiles.get(META_DIR + EJB_DD);
+ SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+
+ saxParserFactory.setValidating(true);
+
+ SAXParser saxParser = saxParserFactory.newSAXParser();
+ DescriptorHandler handler
+ = getWeblogicDescriptorHandler(ejbDescriptor.getParentFile());
+
+ saxParser.parse(new InputSource
+ (new FileInputStream(weblogicDD)),
+ handler);
+
+ Hashtable ht = handler.getFiles();
+ Enumeration e = ht.keys();
+
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+
+ ejbFiles.put(key, ht.get(key));
+ }
+ } catch (Exception e) {
+ String msg = "Exception while adding Vendor specific files: " + e.toString();
+
+ throw new BuildException(msg, e);
+ }
+ }
+ }
+
+
+ /**
+ * Get the vendor specific name of the Jar that will be output. The
+ * modification date of this jar will be checked against the dependent
+ * bean classes.
+ */
+ File getVendorOutputJarFile(String baseName) {
+ return new File(getDestDir(), baseName + jarSuffix);
+ }
+
+
+ /**
+ * Helper method invoked by execute() for each WebLogic jar to be built.
+ * Encapsulates the logic of constructing a java task for calling
+ * weblogic.ejbc and executing it.
+ *
+ * @param sourceJar java.io.File representing the source (EJB1.1) jarfile.
+ * @param destJar java.io.File representing the destination, WebLogic
+ * jarfile.
+ */
+ private void buildWeblogicJar(File sourceJar, File destJar, String publicId) {
+ Java javaTask = null;
+
+ if (noEJBC) {
+ try {
+ FILE_UTILS.copyFile(sourceJar, destJar);
+ if (!keepgenerated) {
+ sourceJar.delete();
+ }
+ return;
+ } catch (IOException e) {
+ throw new BuildException("Unable to write EJB jar", e);
+ }
+ }
+
+ String ejbcClassName = ejbcClass;
+
+ try {
+ javaTask = new Java(getTask());
+ javaTask.setTaskName("ejbc");
+
+ javaTask.createJvmarg().setLine(additionalJvmArgs);
+ if (!(sysprops.isEmpty())) {
+ for (Enumeration en = sysprops.elements(); en.hasMoreElements();) {
+ Environment.Variable entry
+ = (Environment.Variable) en.nextElement();
+ javaTask.addSysproperty(entry);
+ }
+ }
+
+ if (getJvmDebugLevel() != null) {
+ javaTask.createJvmarg().setLine(" -Dweblogic.StdoutSeverityLevel=" + jvmDebugLevel);
+ }
+
+ if (ejbcClassName == null) {
+ // try to determine it from publicId
+ if (PUBLICID_EJB11.equals(publicId)) {
+ ejbcClassName = COMPILER_EJB11;
+ } else if (PUBLICID_EJB20.equals(publicId)) {
+ ejbcClassName = COMPILER_EJB20;
+ } else {
+ log("Unrecognized publicId " + publicId
+ + " - using EJB 1.1 compiler", Project.MSG_WARN);
+ ejbcClassName = COMPILER_EJB11;
+ }
+ }
+
+ javaTask.setClassname(ejbcClassName);
+ javaTask.createArg().setLine(additionalArgs);
+ if (keepgenerated) {
+ javaTask.createArg().setValue("-keepgenerated");
+ }
+ if (compiler == null) {
+ // try to use the compiler specified by build.compiler.
+ // Right now we are just going to allow Jikes
+ String buildCompiler
+ = getTask().getProject().getProperty("build.compiler");
+
+ if (buildCompiler != null && buildCompiler.equals("jikes")) {
+ javaTask.createArg().setValue("-compiler");
+ javaTask.createArg().setValue("jikes");
+ }
+ } else {
+ if (!compiler.equals(DEFAULT_COMPILER)) {
+ javaTask.createArg().setValue("-compiler");
+ javaTask.createArg().setLine(compiler);
+ }
+ }
+
+ Path combinedClasspath = getCombinedClasspath();
+ if (wlClasspath != null && combinedClasspath != null
+ && combinedClasspath.toString().trim().length() > 0) {
+ javaTask.createArg().setValue("-classpath");
+ javaTask.createArg().setPath(combinedClasspath);
+ }
+
+ javaTask.createArg().setValue(sourceJar.getPath());
+ if (outputDir == null) {
+ javaTask.createArg().setValue(destJar.getPath());
+ } else {
+ javaTask.createArg().setValue(outputDir.getPath());
+ }
+
+ Path classpath = wlClasspath;
+
+ if (classpath == null) {
+ classpath = getCombinedClasspath();
+ }
+
+ javaTask.setFork(true);
+ if (classpath != null) {
+ javaTask.setClasspath(classpath);
+ }
+
+ log("Calling " + ejbcClassName + " for " + sourceJar.toString(),
+ Project.MSG_VERBOSE);
+
+ if (javaTask.executeJava() != 0) {
+ throw new BuildException("Ejbc reported an error");
+ }
+ } catch (Exception e) {
+ // Have to catch this because of the semantics of calling main()
+ String msg = "Exception while calling " + ejbcClassName
+ + ". Details: " + e.toString();
+
+ throw new BuildException(msg, e);
+ }
+ }
+
+
+ /**
+ * Method used to encapsulate the writing of the JAR file. Iterates over
+ * the filenames/java.io.Files in the Hashtable stored on the instance
+ * variable ejbFiles.
+ * @param baseName the base name.
+ * @param jarFile the jar file to populate.
+ * @param files the hash table of files to write.
+ * @param publicId the id to use.
+ * @throws BuildException if there is a problem.
+ */
+ protected void writeJar(String baseName, File jarFile, Hashtable files,
+ String publicId) throws BuildException {
+ // need to create a generic jar first.
+ File genericJarFile = super.getVendorOutputJarFile(baseName);
+
+ super.writeJar(baseName, genericJarFile, files, publicId);
+
+ if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
+ buildWeblogicJar(genericJarFile, jarFile, publicId);
+ }
+ if (!keepGeneric) {
+ log("deleting generic jar " + genericJarFile.toString(),
+ Project.MSG_VERBOSE);
+ genericJarFile.delete();
+ }
+ }
+
+
+ /**
+ * Called to validate that the tool parameters have been configured.
+ * @throws BuildException if there is an error.
+ */
+ public void validateConfigured() throws BuildException {
+ super.validateConfigured();
+ }
+
+
+ /**
+ * Helper method to check to see if a weblogic EBJ1.1 jar needs to be
+ * rebuilt using ejbc. Called from writeJar it sees if the "Bean" classes
+ * are the only thing that needs to be updated and either updates the Jar
+ * with the Bean classfile or returns true, saying that the whole weblogic
+ * jar needs to be regened with ejbc. This allows faster build times for
+ * working developers. <p>
+ *
+ * The way weblogic ejbc works is it creates wrappers for the publicly
+ * defined methods as they are exposed in the remote interface. If the
+ * actual bean changes without changing the the method signatures then
+ * only the bean classfile needs to be updated and the rest of the
+ * weblogic jar file can remain the same. If the Interfaces, ie. the
+ * method signatures change or if the xml deployment descriptors changed,
+ * the whole jar needs to be rebuilt with ejbc. This is not strictly true
+ * for the xml files. If the JNDI name changes then the jar doesn't have to
+ * be rebuild, but if the resources references change then it does. At
+ * this point the weblogic jar gets rebuilt if the xml files change at
+ * all.
+ *
+ * @param genericJarFile java.io.File The generic jar file.
+ * @param weblogicJarFile java.io.File The weblogic jar file to check to
+ * see if it needs to be rebuilt.
+ * @return true if the jar needs to be rebuilt.
+ */
+ // CheckStyle:MethodLength OFF - this will no be fixed
+ protected boolean isRebuildRequired(File genericJarFile, File weblogicJarFile) {
+ boolean rebuild = false;
+
+ JarFile genericJar = null;
+ JarFile wlJar = null;
+ File newWLJarFile = null;
+ JarOutputStream newJarStream = null;
+ ClassLoader genericLoader = null;
+
+ try {
+ log("Checking if weblogic Jar needs to be rebuilt for jar " + weblogicJarFile.getName(),
+ Project.MSG_VERBOSE);
+ // Only go forward if the generic and the weblogic file both exist
+ if (genericJarFile.exists() && genericJarFile.isFile()
+ && weblogicJarFile.exists() && weblogicJarFile.isFile()) {
+ //open jar files
+ genericJar = new JarFile(genericJarFile);
+ wlJar = new JarFile(weblogicJarFile);
+
+ Hashtable genericEntries = new Hashtable();
+ Hashtable wlEntries = new Hashtable();
+ Hashtable replaceEntries = new Hashtable();
+
+ //get the list of generic jar entries
+ for (Enumeration e = genericJar.entries(); e.hasMoreElements();) {
+ JarEntry je = (JarEntry) e.nextElement();
+
+ genericEntries.put(je.getName().replace('\\', '/'), je);
+ }
+ //get the list of weblogic jar entries
+ for (Enumeration e = wlJar.entries(); e.hasMoreElements();) {
+ JarEntry je = (JarEntry) e.nextElement();
+
+ wlEntries.put(je.getName(), je);
+ }
+
+ //Cycle Through generic and make sure its in weblogic
+ genericLoader = getClassLoaderFromJar(genericJarFile);
+
+ for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) {
+ String filepath = (String) e.nextElement();
+
+ if (wlEntries.containsKey(filepath)) {
+ // File name/path match
+
+ // Check files see if same
+ JarEntry genericEntry = (JarEntry) genericEntries.get(filepath);
+ JarEntry wlEntry = (JarEntry) wlEntries.get(filepath);
+
+ if ((genericEntry.getCrc() != wlEntry.getCrc())
+ || (genericEntry.getSize() != wlEntry.getSize())) {
+
+ if (genericEntry.getName().endsWith(".class")) {
+ //File are different see if its an object or an interface
+ String classname
+ = genericEntry.getName()
+ .replace(File.separatorChar, '.')
+ .replace('/', '.');
+
+ classname = classname.substring(0, classname.lastIndexOf(".class"));
+
+ Class genclass = genericLoader.loadClass(classname);
+
+ if (genclass.isInterface()) {
+ //Interface changed rebuild jar.
+ log("Interface " + genclass.getName()
+ + " has changed", Project.MSG_VERBOSE);
+ rebuild = true;
+ break;
+ } else {
+ //Object class Changed update it.
+ replaceEntries.put(filepath, genericEntry);
+ }
+ } else {
+ // is it the manifest. If so ignore it
+ if (!genericEntry.getName().equals("META-INF/MANIFEST.MF")) {
+ //File other then class changed rebuild
+ log("Non class file " + genericEntry.getName()
+ + " has changed", Project.MSG_VERBOSE);
+ rebuild = true;
+ break;
+ }
+ }
+ }
+ } else {
+ // a file doesn't exist rebuild
+
+ log("File " + filepath + " not present in weblogic jar",
+ Project.MSG_VERBOSE);
+ rebuild = true;
+ break;
+ }
+ }
+
+ if (!rebuild) {
+ log("No rebuild needed - updating jar", Project.MSG_VERBOSE);
+ newWLJarFile = new File(weblogicJarFile.getAbsolutePath() + ".temp");
+ if (newWLJarFile.exists()) {
+ newWLJarFile.delete();
+ }
+
+ newJarStream = new JarOutputStream(new FileOutputStream(newWLJarFile));
+ newJarStream.setLevel(0);
+
+ //Copy files from old weblogic jar
+ for (Enumeration e = wlEntries.elements(); e.hasMoreElements();) {
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int bytesRead;
+ InputStream is;
+ JarEntry je = (JarEntry) e.nextElement();
+
+ if (je.getCompressedSize() == -1
+ || je.getCompressedSize() == je.getSize()) {
+ newJarStream.setLevel(0);
+ } else {
+ newJarStream.setLevel(JAR_COMPRESS_LEVEL);
+ }
+
+ // Update with changed Bean class
+ if (replaceEntries.containsKey(je.getName())) {
+ log("Updating Bean class from generic Jar "
+ + je.getName(), Project.MSG_VERBOSE);
+ // Use the entry from the generic jar
+ je = (JarEntry) replaceEntries.get(je.getName());
+ is = genericJar.getInputStream(je);
+ } else {
+ //use fle from original weblogic jar
+
+ is = wlJar.getInputStream(je);
+ }
+ newJarStream.putNextEntry(new JarEntry(je.getName()));
+
+ while ((bytesRead = is.read(buffer)) != -1) {
+ newJarStream.write(buffer, 0, bytesRead);
+ }
+ is.close();
+ }
+ } else {
+ log("Weblogic Jar rebuild needed due to changed "
+ + "interface or XML", Project.MSG_VERBOSE);
+ }
+ } else {
+ rebuild = true;
+ }
+ } catch (ClassNotFoundException cnfe) {
+ String cnfmsg = "ClassNotFoundException while processing ejb-jar file"
+ + ". Details: "
+ + cnfe.getMessage();
+
+ throw new BuildException(cnfmsg, cnfe);
+ } catch (IOException ioe) {
+ String msg = "IOException while processing ejb-jar file "
+ + ". Details: "
+ + ioe.getMessage();
+
+ throw new BuildException(msg, ioe);
+ } finally {
+ // need to close files and perhaps rename output
+ if (genericJar != null) {
+ try {
+ genericJar.close();
+ } catch (IOException closeException) {
+ // empty
+ }
+ }
+
+ if (wlJar != null) {
+ try {
+ wlJar.close();
+ } catch (IOException closeException) {
+ // empty
+ }
+ }
+
+ if (newJarStream != null) {
+ try {
+ newJarStream.close();
+ } catch (IOException closeException) {
+ // empty
+ }
+
+ try {
+ FILE_UTILS.rename(newWLJarFile, weblogicJarFile);
+ } catch (IOException renameException) {
+ log(renameException.getMessage(), Project.MSG_WARN);
+ rebuild = true;
+ }
+ }
+ if (genericLoader != null
+ && genericLoader instanceof AntClassLoader) {
+ AntClassLoader loader = (AntClassLoader) genericLoader;
+ loader.cleanup();
+ }
+ }
+
+ return rebuild;
+ }
+
+
+ /**
+ * Helper method invoked by isRebuildRequired to get a ClassLoader for a
+ * Jar File passed to it.
+ *
+ * @param classjar java.io.File representing jar file to get classes from.
+ * @return the classloader for the jarfile.
+ * @throws IOException if there is a problem.
+ */
+ protected ClassLoader getClassLoaderFromJar(File classjar) throws IOException {
+ Path lookupPath = new Path(getTask().getProject());
+
+ lookupPath.setLocation(classjar);
+
+ Path classpath = getCombinedClasspath();
+
+ if (classpath != null) {
+ lookupPath.append(classpath);
+ }
+
+ return getTask().getProject().createClassLoader(lookupPath);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java
new file mode 100644
index 00000000..0752bbec
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Deployment tool for Weblogic TOPLink.
+ */
+public class WeblogicTOPLinkDeploymentTool extends WeblogicDeploymentTool {
+
+ private static final String TL_DTD_LOC
+ = "http://www.objectpeople.com/tlwl/dtd/toplink-cmp_2_5_1.dtd";
+
+ private String toplinkDescriptor;
+ private String toplinkDTD;
+
+ /**
+ * Setter used to store the name of the toplink descriptor.
+ * @param inString the string to use as the descriptor name.
+ */
+ public void setToplinkdescriptor(String inString) {
+ this.toplinkDescriptor = inString;
+ }
+
+ /**
+ * Setter used to store the location of the toplink DTD file.
+ * This is expected to be an URL (file or otherwise). If running
+ * this on NT using a file URL, the safest thing would be to not use a
+ * drive spec in the URL and make sure the file resides on the drive that
+ * ANT is running from. This will keep the setting in the build XML
+ * platform independent.
+ *
+ * @param inString the string to use as the DTD location.
+ */
+ public void setToplinkdtd(String inString) {
+ this.toplinkDTD = inString;
+ }
+
+ /**
+ * Get the descriptor handler.
+ * @param srcDir the source file.
+ * @return the descriptor handler.
+ */
+ protected DescriptorHandler getDescriptorHandler(File srcDir) {
+ DescriptorHandler handler = super.getDescriptorHandler(srcDir);
+ if (toplinkDTD != null) {
+ handler.registerDTD("-//The Object People, Inc.//"
+ + "DTD TOPLink for WebLogic CMP 2.5.1//EN", toplinkDTD);
+ } else {
+ handler.registerDTD("-//The Object People, Inc.//"
+ + "DTD TOPLink for WebLogic CMP 2.5.1//EN", TL_DTD_LOC);
+ }
+ return handler;
+ }
+
+ /**
+ * Add any vendor specific files which should be included in the
+ * EJB Jar.
+ * @param ejbFiles the hashtable to add files to.
+ * @param ddPrefix the prefix to use.
+ */
+ protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+ super.addVendorFiles(ejbFiles, ddPrefix);
+ // Then the toplink deployment descriptor
+
+ // Setup a naming standard here?.
+
+
+ File toplinkDD = new File(getConfig().descriptorDir, ddPrefix + toplinkDescriptor);
+
+ if (toplinkDD.exists()) {
+ ejbFiles.put(META_DIR + toplinkDescriptor,
+ toplinkDD);
+ } else {
+ log("Unable to locate toplink deployment descriptor. "
+ + "It was expected to be in "
+ + toplinkDD.getPath(), Project.MSG_WARN);
+ }
+ }
+
+ /**
+ * Called to validate that the tool parameters have been configured.
+ * @throws BuildException if there is an error.
+ */
+ public void validateConfigured() throws BuildException {
+ super.validateConfigured();
+ if (toplinkDescriptor == null) {
+ throw new BuildException("The toplinkdescriptor attribute must "
+ + "be specified");
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java
new file mode 100644
index 00000000..d15f9f52
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java
@@ -0,0 +1,897 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Websphere deployment tool that augments the ejbjar task.
+ * Searches for the websphere specific deployment descriptors and
+ * adds them to the final ejb jar file. Websphere has two specific descriptors for session
+ * beans:
+ * <ul>
+ * <li>ibm-ejb-jar-bnd.xmi</li>
+ * <li>ibm-ejb-jar-ext.xmi</li>
+ * </ul>
+ * and another two for container managed entity beans:
+ * <ul>
+ * <li>Map.mapxmi</li>
+ * <li>Schema.dbxmi</li>
+ * </ul>
+ * In terms of WebSphere, the generation of container code and stubs is
+ * called <code>deployment</code>. This step can be performed by the websphere
+ * element as part of the jar generation process. If the switch
+ * <code>ejbdeploy</code> is on, the ejbdeploy tool from the websphere toolset
+ * is called for every ejb-jar. Unfortunately, this step only works, if you
+ * use the ibm jdk. Otherwise, the rmic (called by ejbdeploy) throws a
+ * ClassFormatError. Be sure to switch ejbdeploy off, if run ant with
+ * sun jdk.
+ *
+ */
+public class WebsphereDeploymentTool extends GenericDeploymentTool {
+
+ /** ID for ejb 1.1 */
+ public static final String PUBLICID_EJB11
+ = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+ /** ID for ejb 2.0 */
+ public static final String PUBLICID_EJB20
+ = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
+ /** Schema directory */
+ protected static final String SCHEMA_DIR = "Schema/";
+
+ protected static final String WAS_EXT = "ibm-ejb-jar-ext.xmi";
+ protected static final String WAS_BND = "ibm-ejb-jar-bnd.xmi";
+ protected static final String WAS_CMP_MAP = "Map.mapxmi";
+ protected static final String WAS_CMP_SCHEMA = "Schema.dbxmi";
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /** Instance variable that stores the suffix for the websphere jarfile. */
+ private String jarSuffix = ".jar";
+
+ /** Instance variable that stores the location of the ejb 1.1 DTD file. */
+ private String ejb11DTD;
+
+ /** Instance variable that determines whether generic ejb jars are kept. */
+
+ private boolean keepGeneric = false;
+
+ private boolean alwaysRebuild = true;
+
+ private boolean ejbdeploy = true;
+
+ /** Indicates if the old CMP location convention is to be used. */
+ private boolean newCMP = false;
+
+ /** The classpath to the websphere classes. */
+ private Path wasClasspath = null;
+
+ /** The DB Vendor name, the EJB is persisted against */
+ private String dbVendor;
+
+ /** The name of the database to create. (For top-down mapping only) */
+ private String dbName;
+
+ /** The name of the schema to create. (For top-down mappings only) */
+ private String dbSchema;
+
+ /** true - Only generate the deployment code, do not run RMIC or Javac */
+ private boolean codegen;
+
+ /** true - Only output error messages, suppress informational messages */
+ private boolean quiet = true;
+
+ /** true - Disable the validation steps */
+ private boolean novalidate;
+
+ /** true - Disable warning and informational messages */
+ private boolean nowarn;
+
+ /** true - Disable informational messages */
+ private boolean noinform;
+
+ /** true - Enable internal tracing */
+ private boolean trace;
+
+ /** Additional options for RMIC */
+ private String rmicOptions;
+
+ /** true- Use the WebSphere 3.5 compatible mapping rules */
+ private boolean use35MappingRules;
+
+ /** the scratchdir for the ejbdeploy operation */
+ private String tempdir = "_ejbdeploy_temp";
+
+ /** the home directory for websphere */
+ private File websphereHome;
+
+ /**
+ * Get the classpath to the websphere classpaths.
+ * @return the websphere classpath.
+ */
+ public Path createWASClasspath() {
+ if (wasClasspath == null) {
+ wasClasspath = new Path(getTask().getProject());
+ }
+ return wasClasspath.createPath();
+ }
+
+
+ /**
+ * Set the websphere classpath.
+ * @param wasClasspath the websphere classpath.
+ */
+ public void setWASClasspath(Path wasClasspath) {
+ this.wasClasspath = wasClasspath;
+ }
+
+
+ /** Sets the DB Vendor for the Entity Bean mapping ; optional.
+ * <p>
+ * Valid options can be obtained by running the following command:
+ * <code>
+ * &lt;WAS_HOME&gt;/bin/EJBDeploy.[sh/bat] -help
+ * </code>
+ * </p>
+ * <p>
+ * This is also used to determine the name of the Map.mapxmi and
+ * Schema.dbxmi files, for example Account-DB2UDB_V81-Map.mapxmi
+ * and Account-DB2UDB_V81-Schema.dbxmi.
+ * </p>
+ *
+ * @param dbvendor database vendor type
+ */
+ public void setDbvendor(String dbvendor) {
+ this.dbVendor = dbvendor;
+ }
+
+
+ /**
+ * Sets the name of the Database to create; optional.
+ *
+ * @param dbName name of the database
+ */
+ public void setDbname(String dbName) {
+ this.dbName = dbName;
+ }
+
+
+ /**
+ * Sets the name of the schema to create; optional.
+ *
+ * @param dbSchema name of the schema
+ */
+ public void setDbschema(String dbSchema) {
+ this.dbSchema = dbSchema;
+ }
+
+
+ /**
+ * Flag, default false, to only generate the deployment
+ * code, do not run RMIC or Javac
+ *
+ * @param codegen option
+ */
+ public void setCodegen(boolean codegen) {
+ this.codegen = codegen;
+ }
+
+
+ /**
+ * Flag, default true, to only output error messages.
+ *
+ * @param quiet option
+ */
+ public void setQuiet(boolean quiet) {
+ this.quiet = quiet;
+ }
+
+
+ /**
+ * Flag to disable the validation steps; optional, default false.
+ *
+ * @param novalidate option
+ */
+ public void setNovalidate(boolean novalidate) {
+ this.novalidate = novalidate;
+ }
+
+
+ /**
+ * Flag to disable warning and informational messages; optional, default false.
+ *
+ * @param nowarn option
+ */
+ public void setNowarn(boolean nowarn) {
+ this.nowarn = nowarn;
+ }
+
+
+ /**
+ * Flag to disable informational messages; optional, default false.
+ *
+ * @param noinform if true disables informational messages
+ */
+ public void setNoinform(boolean noinform) {
+ this.noinform = noinform;
+ }
+
+
+ /**
+ * Flag to enable internal tracing when set, optional, default false.
+ *
+ * @param trace a <code>boolean</code> value.
+ */
+ public void setTrace(boolean trace) {
+ this.trace = trace;
+ }
+
+ /**
+ * Set the rmic options.
+ *
+ * @param options the options to use.
+ */
+ public void setRmicoptions(String options) {
+ this.rmicOptions = options;
+ }
+
+ /**
+ * Flag to use the WebSphere 3.5 compatible mapping rules ; optional, default false.
+ *
+ * @param attr a <code>boolean</code> value.
+ */
+ public void setUse35(boolean attr) {
+ use35MappingRules = attr;
+ }
+
+
+ /**
+ * Set the rebuild flag to false to only update changes in the jar rather
+ * than rerunning ejbdeploy; optional, default true.
+ * @param rebuild a <code>boolean</code> value.
+ */
+ public void setRebuild(boolean rebuild) {
+ this.alwaysRebuild = rebuild;
+ }
+
+
+ /**
+ * String value appended to the basename of the deployment
+ * descriptor to create the filename of the WebLogic EJB
+ * jar file. Optional, default '.jar'.
+ * @param inString the string to use as the suffix.
+ */
+ public void setSuffix(String inString) {
+ this.jarSuffix = inString;
+ }
+
+
+ /**
+ * This controls whether the generic file used as input to
+ * ejbdeploy is retained; optional, default false.
+ * @param inValue either 'true' or 'false'.
+ */
+ public void setKeepgeneric(boolean inValue) {
+ this.keepGeneric = inValue;
+ }
+
+
+ /**
+ * Decide, whether ejbdeploy should be called or not;
+ * optional, default true.
+ *
+ * @param ejbdeploy a <code>boolean</code> value.
+ */
+ public void setEjbdeploy(boolean ejbdeploy) {
+ this.ejbdeploy = ejbdeploy;
+ }
+
+
+ /**
+ * Setter used to store the location of the Sun's Generic EJB DTD. This
+ * can be a file on the system or a resource on the classpath.
+ *
+ * @param inString the string to use as the DTD location.
+ */
+ public void setEJBdtd(String inString) {
+ this.ejb11DTD = inString;
+ }
+
+
+ /**
+ * Set the value of the oldCMP scheme. This is an antonym for newCMP
+ * @ant.attribute ignore="true"
+ * @param oldCMP a <code>boolean</code> value.
+ */
+ public void setOldCMP(boolean oldCMP) {
+ this.newCMP = !oldCMP;
+ }
+
+
+ /**
+ * Set the value of the newCMP scheme. The old CMP scheme locates the
+ * websphere CMP descriptor based on the naming convention where the
+ * websphere CMP file is expected to be named with the bean name as the
+ * prefix. Under this scheme the name of the CMP descriptor does not match
+ * the name actually used in the main websphere EJB descriptor. Also,
+ * descriptors which contain multiple CMP references could not be used.
+ * @param newCMP a <code>boolean</code> value.
+ */
+ public void setNewCMP(boolean newCMP) {
+ this.newCMP = newCMP;
+ }
+
+
+ /**
+ * The directory, where ejbdeploy will write temporary files;
+ * optional, defaults to '_ejbdeploy_temp'.
+ * @param tempdir the directory name to use.
+ */
+ public void setTempdir(String tempdir) {
+ this.tempdir = tempdir;
+ }
+
+
+ /** {@inheritDoc}. */
+ protected DescriptorHandler getDescriptorHandler(File srcDir) {
+ DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir);
+ // register all the DTDs, both the ones that are known and
+ // any supplied by the user
+ handler.registerDTD(PUBLICID_EJB11, ejb11DTD);
+
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+
+ handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+ }
+
+ return handler;
+ }
+
+
+ /**
+ * Get a description handler.
+ * @param srcDir the source directory.
+ * @return the handler.
+ */
+ protected DescriptorHandler getWebsphereDescriptorHandler(final File srcDir) {
+ DescriptorHandler handler =
+ new DescriptorHandler(getTask(), srcDir) {
+ protected void processElement() {
+ }
+ };
+
+ for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+ EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+
+ handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+ }
+ return handler;
+ }
+
+
+ /**
+ * Add any vendor specific files which should be included in the EJB Jar.
+ * @param ejbFiles a hashtable entryname -> file.
+ * @param baseName a prefix to use.
+ */
+ protected void addVendorFiles(Hashtable ejbFiles, String baseName) {
+
+ String ddPrefix = (usingBaseJarName() ? "" : baseName);
+ String dbPrefix = (dbVendor == null) ? "" : dbVendor + "-";
+
+ // Get the Extensions document
+ File websphereEXT = new File(getConfig().descriptorDir, ddPrefix + WAS_EXT);
+
+ if (websphereEXT.exists()) {
+ ejbFiles.put(META_DIR + WAS_EXT,
+ websphereEXT);
+ } else {
+ log("Unable to locate websphere extensions. "
+ + "It was expected to be in "
+ + websphereEXT.getPath(), Project.MSG_VERBOSE);
+ }
+
+ File websphereBND = new File(getConfig().descriptorDir, ddPrefix + WAS_BND);
+
+ if (websphereBND.exists()) {
+ ejbFiles.put(META_DIR + WAS_BND,
+ websphereBND);
+ } else {
+ log("Unable to locate websphere bindings. "
+ + "It was expected to be in "
+ + websphereBND.getPath(), Project.MSG_VERBOSE);
+ }
+
+ if (!newCMP) {
+ log("The old method for locating CMP files has been DEPRECATED.",
+ Project.MSG_VERBOSE);
+ log("Please adjust your websphere descriptor and set "
+ + "newCMP=\"true\" to use the new CMP descriptor "
+ + "inclusion mechanism. ", Project.MSG_VERBOSE);
+ } else {
+ // We attempt to put in the MAP and Schema files of CMP beans
+ try {
+ // Add the Map file
+ File websphereMAP = new File(getConfig().descriptorDir,
+ ddPrefix + dbPrefix + WAS_CMP_MAP);
+
+ if (websphereMAP.exists()) {
+ ejbFiles.put(META_DIR + WAS_CMP_MAP,
+ websphereMAP);
+ } else {
+ log("Unable to locate the websphere Map: "
+ + websphereMAP.getPath(), Project.MSG_VERBOSE);
+ }
+
+ File websphereSchema = new File(getConfig().descriptorDir,
+ ddPrefix + dbPrefix + WAS_CMP_SCHEMA);
+
+ if (websphereSchema.exists()) {
+ ejbFiles.put(META_DIR + SCHEMA_DIR + WAS_CMP_SCHEMA,
+ websphereSchema);
+ } else {
+ log("Unable to locate the websphere Schema: "
+ + websphereSchema.getPath(), Project.MSG_VERBOSE);
+ }
+ // Theres nothing else to see here...keep moving sonny
+ } catch (Exception e) {
+ String msg = "Exception while adding Vendor specific files: "
+ + e.toString();
+
+ throw new BuildException(msg, e);
+ }
+ }
+ }
+
+
+ /**
+ * Get the vendor specific name of the Jar that will be output. The
+ * modification date of this jar will be checked against the dependent
+ * bean classes.
+ */
+ File getVendorOutputJarFile(String baseName) {
+ return new File(getDestDir(), baseName + jarSuffix);
+ }
+
+
+ /**
+ * Gets the options for the EJB Deploy operation
+ *
+ * @return String
+ */
+ protected String getOptions() {
+ // Set the options
+ StringBuffer options = new StringBuffer();
+
+ if (dbVendor != null) {
+ options.append(" -dbvendor ").append(dbVendor);
+ }
+ if (dbName != null) {
+ options.append(" -dbname \"").append(dbName).append("\"");
+ }
+
+ if (dbSchema != null) {
+ options.append(" -dbschema \"").append(dbSchema).append("\"");
+ }
+
+ if (codegen) {
+ options.append(" -codegen");
+ }
+
+ if (quiet) {
+ options.append(" -quiet");
+ }
+
+ if (novalidate) {
+ options.append(" -novalidate");
+ }
+
+ if (nowarn) {
+ options.append(" -nowarn");
+ }
+
+ if (noinform) {
+ options.append(" -noinform");
+ }
+
+ if (trace) {
+ options.append(" -trace");
+ }
+
+ if (use35MappingRules) {
+ options.append(" -35");
+ }
+
+ if (rmicOptions != null) {
+ options.append(" -rmic \"").append(rmicOptions).append("\"");
+ }
+
+ return options.toString();
+ }
+
+
+ /**
+ * Helper method invoked by execute() for each websphere jar to be built.
+ * Encapsulates the logic of constructing a java task for calling
+ * websphere.ejbdeploy and executing it.
+ *
+ * @param sourceJar java.io.File representing the source (EJB1.1) jarfile.
+ * @param destJar java.io.File representing the destination, websphere
+ * jarfile.
+ */
+ private void buildWebsphereJar(File sourceJar, File destJar) {
+ try {
+ if (ejbdeploy) {
+ Java javaTask = new Java(getTask());
+ // Set the JvmArgs
+ javaTask.createJvmarg().setValue("-Xms64m");
+ javaTask.createJvmarg().setValue("-Xmx128m");
+
+ // Set the Environment variable
+ Environment.Variable var = new Environment.Variable();
+
+ var.setKey("websphere.lib.dir");
+ File libdir = new File(websphereHome, "lib");
+ var.setValue(libdir.getAbsolutePath());
+ javaTask.addSysproperty(var);
+
+ // Set the working directory
+ javaTask.setDir(websphereHome);
+
+ // Set the Java class name
+ javaTask.setTaskName("ejbdeploy");
+ javaTask.setClassname("com.ibm.etools.ejbdeploy.EJBDeploy");
+
+ javaTask.createArg().setValue(sourceJar.getPath());
+ javaTask.createArg().setValue(tempdir);
+ javaTask.createArg().setValue(destJar.getPath());
+ javaTask.createArg().setLine(getOptions());
+ if (getCombinedClasspath() != null
+ && getCombinedClasspath().toString().length() > 0) {
+ javaTask.createArg().setValue("-cp");
+ javaTask.createArg().setValue(getCombinedClasspath().toString());
+ }
+
+ Path classpath = wasClasspath;
+
+ if (classpath == null) {
+ classpath = getCombinedClasspath();
+ }
+
+ javaTask.setFork(true);
+ if (classpath != null) {
+ javaTask.setClasspath(classpath);
+ }
+
+ log("Calling websphere.ejbdeploy for " + sourceJar.toString(),
+ Project.MSG_VERBOSE);
+
+ javaTask.execute();
+ }
+ } catch (Exception e) {
+ // Have to catch this because of the semantics of calling main()
+ String msg = "Exception while calling ejbdeploy. Details: " + e.toString();
+
+ throw new BuildException(msg, e);
+ }
+ }
+
+ /** {@inheritDoc}. */
+ protected void writeJar(String baseName, File jarFile, Hashtable files, String publicId)
+ throws BuildException {
+ if (ejbdeploy) {
+ // create the -generic.jar, if required
+ File genericJarFile = super.getVendorOutputJarFile(baseName);
+
+ super.writeJar(baseName, genericJarFile, files, publicId);
+
+ // create the output .jar, if required
+ if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
+ buildWebsphereJar(genericJarFile, jarFile);
+ }
+ if (!keepGeneric) {
+ log("deleting generic jar " + genericJarFile.toString(),
+ Project.MSG_VERBOSE);
+ genericJarFile.delete();
+ }
+ } else {
+ // create the "undeployed" output .jar, if required
+ super.writeJar(baseName, jarFile, files, publicId);
+ }
+ }
+
+
+ /**
+ * Called to validate that the tool parameters have been configured.
+ * @throws BuildException if there is an error.
+ */
+ public void validateConfigured() throws BuildException {
+ super.validateConfigured();
+ if (ejbdeploy) {
+ String home = getTask().getProject().getProperty("websphere.home");
+ if (home == null) {
+ throw new BuildException("The 'websphere.home' property must "
+ + "be set when 'ejbdeploy=true'");
+ }
+ websphereHome = getTask().getProject().resolveFile(home);
+ }
+ }
+
+
+ /**
+ * Helper method to check to see if a websphere EBJ1.1 jar needs to be
+ * rebuilt using ejbdeploy. Called from writeJar it sees if the "Bean"
+ * classes are the only thing that needs to be updated and either updates
+ * the Jar with the Bean classfile or returns true, saying that the whole
+ * websphere jar needs to be regened with ejbdeploy. This allows faster
+ * build times for working developers. <p>
+ *
+ * The way websphere ejbdeploy works is it creates wrappers for the
+ * publicly defined methods as they are exposed in the remote interface.
+ * If the actual bean changes without changing the the method signatures
+ * then only the bean classfile needs to be updated and the rest of the
+ * websphere jar file can remain the same. If the Interfaces, ie. the
+ * method signatures change or if the xml deployment descriptors changed,
+ * the whole jar needs to be rebuilt with ejbdeploy. This is not strictly
+ * true for the xml files. If the JNDI name changes then the jar doesn't
+ * have to be rebuild, but if the resources references change then it
+ * does. At this point the websphere jar gets rebuilt if the xml files
+ * change at all.
+ *
+ * @param genericJarFile java.io.File The generic jar file.
+ * @param websphereJarFile java.io.File The websphere jar file to check to
+ * see if it needs to be rebuilt.
+ * @return true if a rebuild is required.
+ */
+ // CheckStyle:MethodLength OFF - this will no be fixed
+ protected boolean isRebuildRequired(File genericJarFile, File websphereJarFile) {
+ boolean rebuild = false;
+
+ JarFile genericJar = null;
+ JarFile wasJar = null;
+ File newwasJarFile = null;
+ JarOutputStream newJarStream = null;
+ ClassLoader genericLoader = null;
+
+ try {
+ log("Checking if websphere Jar needs to be rebuilt for jar "
+ + websphereJarFile.getName(), Project.MSG_VERBOSE);
+ // Only go forward if the generic and the websphere file both exist
+ if (genericJarFile.exists() && genericJarFile.isFile()
+ && websphereJarFile.exists() && websphereJarFile.isFile()) {
+ //open jar files
+ genericJar = new JarFile(genericJarFile);
+ wasJar = new JarFile(websphereJarFile);
+
+ Hashtable genericEntries = new Hashtable();
+ Hashtable wasEntries = new Hashtable();
+ Hashtable replaceEntries = new Hashtable();
+
+ //get the list of generic jar entries
+ for (Enumeration e = genericJar.entries(); e.hasMoreElements();) {
+ JarEntry je = (JarEntry) e.nextElement();
+
+ genericEntries.put(je.getName().replace('\\', '/'), je);
+ }
+ //get the list of websphere jar entries
+ for (Enumeration e = wasJar.entries(); e.hasMoreElements();) {
+ JarEntry je = (JarEntry) e.nextElement();
+
+ wasEntries.put(je.getName(), je);
+ }
+
+ //Cycle Through generic and make sure its in websphere
+ genericLoader = getClassLoaderFromJar(genericJarFile);
+
+ for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) {
+ String filepath = (String) e.nextElement();
+
+ if (wasEntries.containsKey(filepath)) {
+ // File name/path match
+ // Check files see if same
+ JarEntry genericEntry = (JarEntry) genericEntries.get(filepath);
+ JarEntry wasEntry = (JarEntry) wasEntries.get(filepath);
+
+ if ((genericEntry.getCrc() != wasEntry.getCrc())
+ || (genericEntry.getSize() != wasEntry.getSize())) {
+
+ if (genericEntry.getName().endsWith(".class")) {
+ //File are different see if its an object or an interface
+ String classname
+ = genericEntry.getName().replace(File.separatorChar, '.');
+
+ classname = classname.substring(0, classname.lastIndexOf(".class"));
+
+ Class genclass = genericLoader.loadClass(classname);
+
+ if (genclass.isInterface()) {
+ //Interface changed rebuild jar.
+ log("Interface " + genclass.getName()
+ + " has changed", Project.MSG_VERBOSE);
+ rebuild = true;
+ break;
+ } else {
+ //Object class Changed update it.
+ replaceEntries.put(filepath, genericEntry);
+ }
+ } else {
+ // is it the manifest. If so ignore it
+ if (!genericEntry.getName().equals("META-INF/MANIFEST.MF")) {
+ //File other then class changed rebuild
+ log("Non class file " + genericEntry.getName()
+ + " has changed", Project.MSG_VERBOSE);
+ rebuild = true;
+ }
+ break;
+ }
+ }
+ } else {
+ // a file doesn't exist rebuild
+
+ log("File " + filepath + " not present in websphere jar",
+ Project.MSG_VERBOSE);
+ rebuild = true;
+ break;
+ }
+ }
+
+ if (!rebuild) {
+ log("No rebuild needed - updating jar", Project.MSG_VERBOSE);
+ newwasJarFile = new File(websphereJarFile.getAbsolutePath() + ".temp");
+ if (newwasJarFile.exists()) {
+ newwasJarFile.delete();
+ }
+
+ newJarStream = new JarOutputStream(new FileOutputStream(newwasJarFile));
+ newJarStream.setLevel(0);
+
+ //Copy files from old websphere jar
+ for (Enumeration e = wasEntries.elements(); e.hasMoreElements();) {
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int bytesRead;
+ InputStream is;
+ JarEntry je = (JarEntry) e.nextElement();
+
+ if (je.getCompressedSize() == -1
+ || je.getCompressedSize() == je.getSize()) {
+ newJarStream.setLevel(0);
+ } else {
+ newJarStream.setLevel(JAR_COMPRESS_LEVEL);
+ }
+
+ // Update with changed Bean class
+ if (replaceEntries.containsKey(je.getName())) {
+ log("Updating Bean class from generic Jar " + je.getName(),
+ Project.MSG_VERBOSE);
+ // Use the entry from the generic jar
+ je = (JarEntry) replaceEntries.get(je.getName());
+ is = genericJar.getInputStream(je);
+ } else {
+ //use fle from original websphere jar
+
+ is = wasJar.getInputStream(je);
+ }
+ newJarStream.putNextEntry(new JarEntry(je.getName()));
+
+ while ((bytesRead = is.read(buffer)) != -1) {
+ newJarStream.write(buffer, 0, bytesRead);
+ }
+ is.close();
+ }
+ } else {
+ log("websphere Jar rebuild needed due to changed "
+ + "interface or XML", Project.MSG_VERBOSE);
+ }
+ } else {
+ rebuild = true;
+ }
+ } catch (ClassNotFoundException cnfe) {
+ String cnfmsg = "ClassNotFoundException while processing ejb-jar file"
+ + ". Details: "
+ + cnfe.getMessage();
+
+ throw new BuildException(cnfmsg, cnfe);
+ } catch (IOException ioe) {
+ String msg = "IOException while processing ejb-jar file "
+ + ". Details: "
+ + ioe.getMessage();
+
+ throw new BuildException(msg, ioe);
+ } finally {
+ // need to close files and perhaps rename output
+ if (genericJar != null) {
+ try {
+ genericJar.close();
+ } catch (IOException closeException) {
+ // Ignore
+ }
+ }
+
+ if (wasJar != null) {
+ try {
+ wasJar.close();
+ } catch (IOException closeException) {
+ // Ignore
+ }
+ }
+
+ if (newJarStream != null) {
+ try {
+ newJarStream.close();
+ } catch (IOException closeException) {
+ // Ignore
+ }
+
+ try {
+ FILE_UTILS.rename(newwasJarFile, websphereJarFile);
+ } catch (IOException renameException) {
+ log(renameException.getMessage(), Project.MSG_WARN);
+ rebuild = true;
+ }
+ }
+ if (genericLoader != null
+ && genericLoader instanceof AntClassLoader) {
+ AntClassLoader loader = (AntClassLoader) genericLoader;
+ loader.cleanup();
+ }
+ }
+
+ return rebuild;
+ }
+
+
+ /**
+ * Helper method invoked by isRebuildRequired to get a ClassLoader for a
+ * Jar File passed to it.
+ *
+ * @param classjar java.io.File representing jar file to get classes from.
+ * @return a classloader for the jar file.
+ * @throws IOException if there is an error.
+ */
+ protected ClassLoader getClassLoaderFromJar(File classjar) throws IOException {
+ Path lookupPath = new Path(getTask().getProject());
+
+ lookupPath.setLocation(classjar);
+
+ Path classpath = getCombinedClasspath();
+
+ if (classpath != null) {
+ lookupPath.append(classpath);
+ }
+
+ return getTask().getProject().createClassLoader(lookupPath);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java
new file mode 100644
index 00000000..2c06daf1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+/**
+ * Enum used in (@link Extension) to indicate the compatibility
+ * of one extension to another. See (@link Extension) for instances
+ * of object.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ * This file is from excalibur.extension package. Dont edit this file
+ * directly as there is no unit tests to make sure it is operational
+ * in ant. Edit file in excalibur and run tests there before changing
+ * ants file.
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * @see Extension
+ */
+public final class Compatability {
+ /**
+ * A string representation of compatibility level.
+ */
+ private final String name;
+
+ /**
+ * Create a compatibility enum with specified name.
+ *
+ * @param name the name of compatibility level
+ */
+ Compatability(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return name of compatibility level.
+ *
+ * @return the name of compatibility level
+ */
+ public String toString() {
+ return name;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java
new file mode 100644
index 00000000..bb28cd6b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+/**
+ * Enum used in (@link Extension) to indicate the compatibility
+ * of one extension to another. See (@link Extension) for instances
+ * of object.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ * This file is from excalibur.extension package. Dont edit this file
+ * directly as there is no unit tests to make sure it is operational
+ * in ant. Edit file in excalibur and run tests there before changing
+ * ants file.
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * @see Extension
+ */
+public final class Compatibility {
+ /**
+ * A string representation of compatibility level.
+ */
+ private final String name;
+
+ /**
+ * Create a compatibility enum with specified name.
+ *
+ * @param name the name of compatibility level
+ */
+ Compatibility(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return name of compatibility level.
+ *
+ * @return the name of compatibility level
+ */
+ public String toString() {
+ return name;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java
new file mode 100644
index 00000000..2edc2a78
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+
+/**
+ * Utility class to contain version numbers in "Dewey Decimal"
+ * syntax. Numbers in the "Dewey Decimal" syntax consist of positive
+ * decimal integers separated by periods ".". For example, "2.0" or
+ * "1.2.3.4.5.6.7". This allows an extensible number to be used to
+ * represent major, minor, micro, etc versions. The version number
+ * must begin with a number.
+ *
+ * Original Implementation moved to org.apache.tools.ant.util.DeweyDecimal
+ * @deprecated use org.apache.tools.ant.util.DeweyDecimal instead.
+ * Deprecated since ant 1.8
+ */
+public final class DeweyDecimal extends org.apache.tools.ant.util.DeweyDecimal {
+
+ /**
+ * Construct a DeweyDecimal from an array of integer components.
+ *
+ * @param components an array of integer components.
+ */
+ public DeweyDecimal(final int[] components) {
+ super(components);
+ }
+
+ /**
+ * Construct a DeweyDecimal from string in DeweyDecimal format.
+ *
+ * @param string the string in dewey decimal format
+ * @exception NumberFormatException if string is malformed
+ */
+ public DeweyDecimal(final String string)
+ throws NumberFormatException {
+ super(string);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java
new file mode 100644
index 00000000..d13d2f4e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java
@@ -0,0 +1,690 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.util.DeweyDecimal;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * <p>Utility class that represents either an available "Optional Package"
+ * (formerly known as "Standard Extension") as described in the manifest
+ * of a JAR file, or the requirement for such an optional package.</p>
+ *
+ * <p>For more information about optional packages, see the document
+ * <em>Optional Package Versioning</em> in the documentation bundle for your
+ * Java2 Standard Edition package, in file
+ * <code>guide/extensions/versioning.html</code>.</p>
+ *
+ */
+public final class Extension {
+ /**
+ * Manifest Attribute Name object for EXTENSION_LIST.
+ */
+ public static final Attributes.Name EXTENSION_LIST
+ = new Attributes.Name("Extension-List");
+
+ /**
+ * <code>Name</code> object for <code>Optional-Extension-List</code>
+ * manifest attribute used for declaring optional dependencies on
+ * installed extensions. Note that the dependencies declared by this method
+ * are not required for the library to operate but if present will be used.
+ * It is NOT part of the official "Optional Package" specification.
+ *
+ * @see <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/spec.html#dependency">
+ * Installed extension dependency</a>
+ */
+ public static final Attributes.Name OPTIONAL_EXTENSION_LIST
+ = new Attributes.Name("Optional-Extension-List");
+
+ /**
+ * Manifest Attribute Name object for EXTENSION_NAME.
+ */
+ public static final Attributes.Name EXTENSION_NAME =
+ new Attributes.Name("Extension-Name");
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_VERSION.
+ */
+ public static final Attributes.Name SPECIFICATION_VERSION
+ = Attributes.Name.SPECIFICATION_VERSION;
+
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_VENDOR.
+ */
+ public static final Attributes.Name SPECIFICATION_VENDOR
+ = Attributes.Name.SPECIFICATION_VENDOR;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
+ */
+ public static final Attributes.Name IMPLEMENTATION_VERSION
+ = Attributes.Name.IMPLEMENTATION_VERSION;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
+ */
+ public static final Attributes.Name IMPLEMENTATION_VENDOR
+ = Attributes.Name.IMPLEMENTATION_VENDOR;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_URL.
+ */
+ public static final Attributes.Name IMPLEMENTATION_URL
+ = new Attributes.Name("Implementation-URL");
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VENDOR_ID.
+ */
+ public static final Attributes.Name IMPLEMENTATION_VENDOR_ID
+ = new Attributes.Name("Implementation-Vendor-Id");
+
+ /**
+ * Enum indicating that extension is compatible with other extension.
+ */
+ public static final Compatibility COMPATIBLE
+ = new Compatibility("COMPATIBLE");
+
+ /**
+ * Enum indicating that extension requires an upgrade
+ * of specification to be compatible with other extension.
+ */
+ public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE
+ = new Compatibility("REQUIRE_SPECIFICATION_UPGRADE");
+
+ /**
+ * Enum indicating that extension requires a vendor
+ * switch to be compatible with other extension.
+ */
+ public static final Compatibility REQUIRE_VENDOR_SWITCH
+ = new Compatibility("REQUIRE_VENDOR_SWITCH");
+
+ /**
+ * Enum indicating that extension requires an upgrade
+ * of implementation to be compatible with other extension.
+ */
+ public static final Compatibility REQUIRE_IMPLEMENTATION_UPGRADE
+ = new Compatibility("REQUIRE_IMPLEMENTATION_UPGRADE");
+
+ /**
+ * Enum indicating that extension is incompatible with
+ * other extension in ways other than other enums
+ * indicate). For example the other extension may have
+ * a different ID.
+ */
+ public static final Compatibility INCOMPATIBLE
+ = new Compatibility("INCOMPATIBLE");
+
+ /**
+ * The name of the optional package being made available, or required.
+ */
+ private String extensionName;
+
+ /**
+ * The version number (dotted decimal notation) of the specification
+ * to which this optional package conforms.
+ */
+ private DeweyDecimal specificationVersion;
+
+ /**
+ * The name of the company or organization that originated the
+ * specification to which this optional package conforms.
+ */
+ private String specificationVendor;
+
+ /**
+ * The unique identifier of the company that produced the optional
+ * package contained in this JAR file.
+ */
+ private String implementationVendorID;
+
+ /**
+ * The name of the company or organization that produced this
+ * implementation of this optional package.
+ */
+ private String implementationVendor;
+
+ /**
+ * The version number (dotted decimal notation) for this implementation
+ * of the optional package.
+ */
+ private DeweyDecimal implementationVersion;
+
+ /**
+ * The URL from which the most recent version of this optional package
+ * can be obtained if it is not already installed.
+ */
+ private String implementationURL;
+
+ /**
+ * Return an array of <code>Extension</code> objects representing optional
+ * packages that are available in the JAR file associated with the
+ * specified <code>Manifest</code>. If there are no such optional
+ * packages, a zero-length array is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the "available" extensions in specified manifest
+ */
+ public static Extension[] getAvailable(final Manifest manifest) {
+ if (null == manifest) {
+ return new Extension[ 0 ];
+ }
+
+ final ArrayList results = new ArrayList();
+
+ final Attributes mainAttributes = manifest.getMainAttributes();
+ if (null != mainAttributes) {
+ final Extension extension = getExtension("", mainAttributes);
+ if (null != extension) {
+ results.add(extension);
+ }
+ }
+
+ final Map entries = manifest.getEntries();
+ final Iterator keys = entries.keySet().iterator();
+ while (keys.hasNext()) {
+ final String key = (String) keys.next();
+ final Attributes attributes = (Attributes) entries.get(key);
+ final Extension extension = getExtension("", attributes);
+ if (null != extension) {
+ results.add(extension);
+ }
+ }
+
+ return (Extension[]) results.toArray(new Extension[results.size()]);
+ }
+
+ /**
+ * Return the set of <code>Extension</code> objects representing optional
+ * packages that are required by the application contained in the JAR
+ * file associated with the specified <code>Manifest</code>. If there
+ * are no such optional packages, a zero-length list is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the dependencies that are specified in manifest
+ */
+ public static Extension[] getRequired(final Manifest manifest) {
+ return getListed(manifest, Attributes.Name.EXTENSION_LIST);
+ }
+
+ /**
+ * Return the set of <code>Extension</code> objects representing "Optional
+ * Packages" that the application declares they will use if present. If
+ * there are no such optional packages, a zero-length list is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the optional dependencies that are specified in manifest
+ */
+ public static Extension[] getOptions(final Manifest manifest) {
+ return getListed(manifest, OPTIONAL_EXTENSION_LIST);
+ }
+
+ /**
+ * Add Extension to the specified manifest Attributes.
+ *
+ * @param attributes the attributes of manifest to add to
+ * @param extension the extension
+ */
+ public static void addExtension(final Extension extension,
+ final Attributes attributes) {
+ addExtension(extension, "", attributes);
+ }
+
+ /**
+ * Add Extension to the specified manifest Attributes.
+ * Use the specified prefix so that dependencies can added
+ * with a prefix such as "java3d-" etc.
+ *
+ * @param attributes the attributes of manifest to add to
+ * @param extension the extension
+ * @param prefix the name to prefix to extension
+ */
+ public static void addExtension(final Extension extension,
+ final String prefix,
+ final Attributes attributes) {
+ attributes.putValue(prefix + EXTENSION_NAME,
+ extension.getExtensionName());
+
+ final String specificationVendor = extension.getSpecificationVendor();
+ if (null != specificationVendor) {
+ attributes.putValue(prefix + SPECIFICATION_VENDOR,
+ specificationVendor);
+ }
+
+ final DeweyDecimal specificationVersion
+ = extension.getSpecificationVersion();
+ if (null != specificationVersion) {
+ attributes.putValue(prefix + SPECIFICATION_VERSION,
+ specificationVersion.toString());
+ }
+
+ final String implementationVendorID
+ = extension.getImplementationVendorID();
+ if (null != implementationVendorID) {
+ attributes.putValue(prefix + IMPLEMENTATION_VENDOR_ID,
+ implementationVendorID);
+ }
+
+ final String implementationVendor = extension.getImplementationVendor();
+ if (null != implementationVendor) {
+ attributes.putValue(prefix + IMPLEMENTATION_VENDOR,
+ implementationVendor);
+ }
+
+ final DeweyDecimal implementationVersion
+ = extension.getImplementationVersion();
+ if (null != implementationVersion) {
+ attributes.putValue(prefix + IMPLEMENTATION_VERSION,
+ implementationVersion.toString());
+ }
+
+ final String implementationURL = extension.getImplementationURL();
+ if (null != implementationURL) {
+ attributes.putValue(prefix + IMPLEMENTATION_URL,
+ implementationURL);
+ }
+ }
+
+ /**
+ * The constructor to create Extension object.
+ * Note that every component is allowed to be specified
+ * but only the extensionName is mandatory.
+ *
+ * @param extensionName the name of extension.
+ * @param specificationVersion the specification Version of extension.
+ * @param specificationVendor the specification Vendor of extension.
+ * @param implementationVersion the implementation Version of extension.
+ * @param implementationVendor the implementation Vendor of extension.
+ * @param implementationVendorId the implementation VendorId of extension.
+ * @param implementationURL the implementation URL of extension.
+ */
+ public Extension(final String extensionName,
+ final String specificationVersion,
+ final String specificationVendor,
+ final String implementationVersion,
+ final String implementationVendor,
+ final String implementationVendorId,
+ final String implementationURL) {
+ this.extensionName = extensionName;
+ this.specificationVendor = specificationVendor;
+
+ if (null != specificationVersion) {
+ try {
+ this.specificationVersion
+ = new DeweyDecimal(specificationVersion);
+ } catch (final NumberFormatException nfe) {
+ final String error = "Bad specification version format '"
+ + specificationVersion + "' in '" + extensionName
+ + "'. (Reason: " + nfe + ")";
+ throw new IllegalArgumentException(error);
+ }
+ }
+
+ this.implementationURL = implementationURL;
+ this.implementationVendor = implementationVendor;
+ this.implementationVendorID = implementationVendorId;
+
+ if (null != implementationVersion) {
+ try {
+ this.implementationVersion
+ = new DeweyDecimal(implementationVersion);
+ } catch (final NumberFormatException nfe) {
+ final String error = "Bad implementation version format '"
+ + implementationVersion + "' in '" + extensionName
+ + "'. (Reason: " + nfe + ")";
+ throw new IllegalArgumentException(error);
+ }
+ }
+
+ if (null == this.extensionName) {
+ throw new NullPointerException("extensionName property is null");
+ }
+ }
+
+ /**
+ * Get the name of the extension.
+ *
+ * @return the name of the extension
+ */
+ public String getExtensionName() {
+ return extensionName;
+ }
+
+ /**
+ * Get the vendor of the extensions specification.
+ *
+ * @return the vendor of the extensions specification.
+ */
+ public String getSpecificationVendor() {
+ return specificationVendor;
+ }
+
+ /**
+ * Get the version of the extensions specification.
+ *
+ * @return the version of the extensions specification.
+ */
+ public DeweyDecimal getSpecificationVersion() {
+ return specificationVersion;
+ }
+
+ /**
+ * Get the url of the extensions implementation.
+ *
+ * @return the url of the extensions implementation.
+ */
+ public String getImplementationURL() {
+ return implementationURL;
+ }
+
+ /**
+ * Get the vendor of the extensions implementation.
+ *
+ * @return the vendor of the extensions implementation.
+ */
+ public String getImplementationVendor() {
+ return implementationVendor;
+ }
+
+ /**
+ * Get the vendorID of the extensions implementation.
+ *
+ * @return the vendorID of the extensions implementation.
+ */
+ public String getImplementationVendorID() {
+ return implementationVendorID;
+ }
+
+ /**
+ * Get the version of the extensions implementation.
+ *
+ * @return the version of the extensions implementation.
+ */
+ public DeweyDecimal getImplementationVersion() {
+ return implementationVersion;
+ }
+
+ /**
+ * Return a Compatibility enum indicating the relationship of this
+ * <code>Extension</code> with the specified <code>Extension</code>.
+ *
+ * @param required Description of the required optional package
+ * @return the enum indicating the compatibility (or lack thereof)
+ * of specified extension
+ */
+ public Compatibility getCompatibilityWith(final Extension required) {
+ // Extension Name must match
+ if (!extensionName.equals(required.getExtensionName())) {
+ return INCOMPATIBLE;
+ }
+
+ // Available specification version must be >= required
+ final DeweyDecimal requiredSpecificationVersion
+ = required.getSpecificationVersion();
+ if (null != requiredSpecificationVersion) {
+ if (null == specificationVersion
+ || !isCompatible(specificationVersion, requiredSpecificationVersion)) {
+ return REQUIRE_SPECIFICATION_UPGRADE;
+ }
+ }
+
+ // Implementation Vendor ID must match
+ final String requiredImplementationVendorID
+ = required.getImplementationVendorID();
+ if (null != requiredImplementationVendorID) {
+ if (null == implementationVendorID
+ || !implementationVendorID.equals(requiredImplementationVendorID)) {
+ return REQUIRE_VENDOR_SWITCH;
+ }
+ }
+
+ // Implementation version must be >= required
+ final DeweyDecimal requiredImplementationVersion
+ = required.getImplementationVersion();
+ if (null != requiredImplementationVersion) {
+ if (null == implementationVersion
+ || !isCompatible(implementationVersion, requiredImplementationVersion)) {
+ return REQUIRE_IMPLEMENTATION_UPGRADE;
+ }
+ }
+
+ // This available optional package satisfies the requirements
+ return COMPATIBLE;
+ }
+
+ /**
+ * Return <code>true</code> if the specified <code>Extension</code>
+ * (which represents an optional package required by an application)
+ * is satisfied by this <code>Extension</code> (which represents an
+ * optional package that is already installed. Otherwise, return
+ * <code>false</code>.
+ *
+ * @param required Description of the required optional package
+ * @return true if the specified extension is compatible with this extension
+ */
+ public boolean isCompatibleWith(final Extension required) {
+ return (COMPATIBLE == getCompatibilityWith(required));
+ }
+
+ /**
+ * Return a String representation of this object.
+ *
+ * @return string representation of object.
+ */
+ public String toString() {
+ final String brace = ": ";
+
+ final StringBuffer sb = new StringBuffer(EXTENSION_NAME.toString());
+ sb.append(brace);
+ sb.append(extensionName);
+ sb.append(StringUtils.LINE_SEP);
+
+ if (null != specificationVersion) {
+ sb.append(SPECIFICATION_VERSION);
+ sb.append(brace);
+ sb.append(specificationVersion);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != specificationVendor) {
+ sb.append(SPECIFICATION_VENDOR);
+ sb.append(brace);
+ sb.append(specificationVendor);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationVersion) {
+ sb.append(IMPLEMENTATION_VERSION);
+ sb.append(brace);
+ sb.append(implementationVersion);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationVendorID) {
+ sb.append(IMPLEMENTATION_VENDOR_ID);
+ sb.append(brace);
+ sb.append(implementationVendorID);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationVendor) {
+ sb.append(IMPLEMENTATION_VENDOR);
+ sb.append(brace);
+ sb.append(implementationVendor);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationURL) {
+ sb.append(IMPLEMENTATION_URL);
+ sb.append(brace);
+ sb.append(implementationURL);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return <code>true</code> if the first version number is greater than
+ * or equal to the second; otherwise return <code>false</code>.
+ *
+ * @param first First version number (dotted decimal)
+ * @param second Second version number (dotted decimal)
+ */
+ private boolean isCompatible(final DeweyDecimal first,
+ final DeweyDecimal second) {
+ return first.isGreaterThanOrEqual(second);
+ }
+
+ /**
+ * Retrieve all the extensions listed under a particular key
+ * (Usually EXTENSION_LIST or OPTIONAL_EXTENSION_LIST).
+ *
+ * @param manifest the manifest to extract extensions from
+ * @param listKey the key used to get list (Usually
+ * EXTENSION_LIST or OPTIONAL_EXTENSION_LIST)
+ * @return the list of listed extensions
+ */
+ private static Extension[] getListed(final Manifest manifest,
+ final Attributes.Name listKey) {
+ final ArrayList results = new ArrayList();
+ final Attributes mainAttributes = manifest.getMainAttributes();
+
+ if (null != mainAttributes) {
+ getExtension(mainAttributes, results, listKey);
+ }
+
+ final Map entries = manifest.getEntries();
+ final Iterator keys = entries.keySet().iterator();
+ while (keys.hasNext()) {
+ final String key = (String) keys.next();
+ final Attributes attributes = (Attributes) entries.get(key);
+ getExtension(attributes, results, listKey);
+ }
+
+ return (Extension[]) results.toArray(new Extension[results.size()]);
+ }
+
+ /**
+ * Add required optional packages defined in the specified
+ * attributes entry, if any.
+ *
+ * @param attributes Attributes to be parsed
+ * @param required list to add required optional packages to
+ * @param listKey the key to use to lookup list, usually EXTENSION_LIST
+ * or OPTIONAL_EXTENSION_LIST
+ */
+ private static void getExtension(final Attributes attributes,
+ final ArrayList required,
+ final Attributes.Name listKey) {
+ final String names = attributes.getValue(listKey);
+ if (null == names) {
+ return;
+ }
+
+ final String[] extensions = split(names, " ");
+ for (int i = 0; i < extensions.length; i++) {
+ final String prefix = extensions[ i ] + "-";
+ final Extension extension = getExtension(prefix, attributes);
+
+ if (null != extension) {
+ required.add(extension);
+ }
+ }
+ }
+
+ /**
+ * Splits the string on every token into an array of strings.
+ *
+ * @param string the string
+ * @param onToken the token
+ * @return the resultant array
+ */
+ private static String[] split(final String string,
+ final String onToken) {
+ final StringTokenizer tokenizer = new StringTokenizer(string, onToken);
+ final String[] result = new String[ tokenizer.countTokens() ];
+
+ for (int i = 0; i < result.length; i++) {
+ result[ i ] = tokenizer.nextToken();
+ }
+
+ return result;
+ }
+
+ /**
+ * Extract an Extension from Attributes.
+ * Prefix indicates the prefix checked for each string.
+ * Usually the prefix is <em>"&lt;extension&gt;-"</em> if looking for a
+ * <b>Required</b> extension. If you are looking for an
+ * <b>Available</b> extension
+ * then the prefix is <em>""</em>.
+ *
+ * @param prefix the prefix for each attribute name
+ * @param attributes Attributes to searched
+ * @return the new Extension object, or null
+ */
+ private static Extension getExtension(final String prefix,
+ final Attributes attributes) {
+ //WARNING: We trim the values of all the attributes because
+ //Some extension declarations are badly defined (ie have spaces
+ //after version or vendorID)
+ final String nameKey = prefix + EXTENSION_NAME;
+ final String name = getTrimmedString(attributes.getValue(nameKey));
+ if (null == name) {
+ return null;
+ }
+
+ final String specVendorKey = prefix + SPECIFICATION_VENDOR;
+ final String specVendor
+ = getTrimmedString(attributes.getValue(specVendorKey));
+ final String specVersionKey = prefix + SPECIFICATION_VERSION;
+ final String specVersion
+ = getTrimmedString(attributes.getValue(specVersionKey));
+
+ final String impVersionKey = prefix + IMPLEMENTATION_VERSION;
+ final String impVersion
+ = getTrimmedString(attributes.getValue(impVersionKey));
+ final String impVendorKey = prefix + IMPLEMENTATION_VENDOR;
+ final String impVendor
+ = getTrimmedString(attributes.getValue(impVendorKey));
+ final String impVendorIDKey = prefix + IMPLEMENTATION_VENDOR_ID;
+ final String impVendorId
+ = getTrimmedString(attributes.getValue(impVendorIDKey));
+ final String impURLKey = prefix + IMPLEMENTATION_URL;
+ final String impURL = getTrimmedString(attributes.getValue(impURLKey));
+
+ return new Extension(name, specVersion, specVendor, impVersion,
+ impVendor, impVendorId, impURL);
+ }
+
+ /**
+ * Trim the supplied string if the string is non-null
+ *
+ * @param value the string to trim or null
+ * @return the trimmed string or null
+ */
+ private static String getTrimmedString(final String value) {
+ return null == value ? null : value.trim();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java
new file mode 100644
index 00000000..b3cfddc2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.DeweyDecimal;
+
+/**
+ * Simple class that represents an Extension and conforms to Ants
+ * patterns.
+ *
+ * @ant.datatype name="extension"
+ */
+public class ExtensionAdapter extends DataType {
+ /**
+ * The name of the optional package being made available, or required.
+ */
+ private String extensionName;
+
+ /**
+ * The version number (dotted decimal notation) of the specification
+ * to which this optional package conforms.
+ */
+ private DeweyDecimal specificationVersion;
+
+ /**
+ * The name of the company or organization that originated the
+ * specification to which this optional package conforms.
+ */
+ private String specificationVendor;
+
+ /**
+ * The unique identifier of the company that produced the optional
+ * package contained in this JAR file.
+ */
+ private String implementationVendorID;
+
+ /**
+ * The name of the company or organization that produced this
+ * implementation of this optional package.
+ */
+ private String implementationVendor;
+
+ /**
+ * The version number (dotted decimal notation) for this implementation
+ * of the optional package.
+ */
+ private DeweyDecimal implementationVersion;
+
+ /**
+ * The URL from which the most recent version of this optional package
+ * can be obtained if it is not already installed.
+ */
+ private String implementationURL;
+
+ /**
+ * Set the name of extension.
+ *
+ * @param extensionName the name of extension
+ */
+ public void setExtensionName(final String extensionName) {
+ verifyNotAReference();
+ this.extensionName = extensionName;
+ }
+
+ /**
+ * Set the specificationVersion of extension.
+ *
+ * @param specificationVersion the specificationVersion of extension
+ */
+ public void setSpecificationVersion(final String specificationVersion) {
+ verifyNotAReference();
+ this.specificationVersion = new DeweyDecimal(specificationVersion);
+ }
+
+ /**
+ * Set the specificationVendor of extension.
+ *
+ * @param specificationVendor the specificationVendor of extension
+ */
+ public void setSpecificationVendor(final String specificationVendor) {
+ verifyNotAReference();
+ this.specificationVendor = specificationVendor;
+ }
+
+ /**
+ * Set the implementationVendorID of extension.
+ *
+ * @param implementationVendorID the implementationVendorID of extension
+ */
+ public void setImplementationVendorId(final String implementationVendorID) {
+ verifyNotAReference();
+ this.implementationVendorID = implementationVendorID;
+ }
+
+ /**
+ * Set the implementationVendor of extension.
+ *
+ * @param implementationVendor the implementationVendor of extension
+ */
+ public void setImplementationVendor(final String implementationVendor) {
+ verifyNotAReference();
+ this.implementationVendor = implementationVendor;
+ }
+
+ /**
+ * Set the implementationVersion of extension.
+ *
+ * @param implementationVersion the implementationVersion of extension
+ */
+ public void setImplementationVersion(final String implementationVersion) {
+ verifyNotAReference();
+ this.implementationVersion = new DeweyDecimal(implementationVersion);
+ }
+
+ /**
+ * Set the implementationURL of extension.
+ *
+ * @param implementationURL the implementationURL of extension
+ */
+ public void setImplementationUrl(final String implementationURL) {
+ verifyNotAReference();
+ this.implementationURL = implementationURL;
+ }
+
+ /**
+ * Makes this instance in effect a reference to another ExtensionAdapter
+ * instance.
+ *
+ * <p>You must not set another attribute or nest elements inside
+ * this element if you make it a reference.</p>
+ *
+ * @param reference the reference to which this instance is associated
+ * @exception BuildException if this instance already has been configured.
+ */
+ public void setRefid(final Reference reference)
+ throws BuildException {
+ if (null != extensionName
+ || null != specificationVersion
+ || null != specificationVendor
+ || null != implementationVersion
+ || null != implementationVendorID
+ || null != implementationVendor
+ || null != implementationURL) {
+ throw tooManyAttributes();
+ }
+ super.setRefid(reference);
+ }
+
+ private void verifyNotAReference()
+ throws BuildException {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ }
+
+ /**
+ * Convert this adpater object into an extension object.
+ *
+ * @return the extension object
+ */
+ Extension toExtension()
+ throws BuildException {
+ if (isReference()) {
+ return ((ExtensionAdapter) getCheckedRef()).toExtension();
+ }
+ dieOnCircularReference();
+ if (null == extensionName) {
+ final String message = "Extension is missing name.";
+ throw new BuildException(message);
+ }
+
+ String specificationVersionString = null;
+ if (null != specificationVersion) {
+ specificationVersionString = specificationVersion.toString();
+ }
+ String implementationVersionString = null;
+ if (null != implementationVersion) {
+ implementationVersionString = implementationVersion.toString();
+ }
+ return new Extension(extensionName,
+ specificationVersionString,
+ specificationVendor,
+ implementationVersionString,
+ implementationVendor,
+ implementationVendorID,
+ implementationURL);
+ }
+
+ /**
+ * a debug toString method.
+ * @return the extension in a string.
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return "{" + toExtension().toString() + "}";
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java
new file mode 100644
index 00000000..a73282ec
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Interface to locate a File that satisfies extension.
+ *
+ */
+public interface ExtensionResolver {
+ /**
+ * Attempt to locate File that satisfies
+ * extension via resolver.
+ *
+ * @param extension the extension
+ * @param project the Ant project instance
+ * @return the File satisfying extension, null
+ * if can not resolve extension
+ * @throws BuildException if error occurs attempting to
+ * resolve extension
+ */
+ File resolve(Extension extension, Project project)
+ throws BuildException;
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java
new file mode 100644
index 00000000..5aba37c9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Stack;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * The Extension set lists a set of "Optional Packages" /
+ * "Extensions".
+ *
+ * @ant.datatype name="extension-set"
+ */
+public class ExtensionSet
+ extends DataType {
+ /**
+ * ExtensionAdapter objects representing extensions.
+ */
+ private final ArrayList extensions = new ArrayList();
+
+ /**
+ * Filesets specifying all the extensions wanted.
+ */
+ private final ArrayList extensionsFilesets = new ArrayList();
+
+ /**
+ * Adds an extension that this library requires.
+ *
+ * @param extensionAdapter an extension that this library requires.
+ */
+ public void addExtension(final ExtensionAdapter extensionAdapter) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ setChecked(false);
+ extensions.add(extensionAdapter);
+ }
+
+ /**
+ * Adds a set of files about which extensions data will be extracted.
+ *
+ * @param fileSet a set of files about which extensions data will be extracted.
+ */
+ public void addLibfileset(final LibFileSet fileSet) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ setChecked(false);
+ extensionsFilesets.add(fileSet);
+ }
+
+ /**
+ * Adds a set of files about which extensions data will be extracted.
+ *
+ * @param fileSet a set of files about which extensions data will be extracted.
+ */
+ public void addFileset(final FileSet fileSet) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ setChecked(false);
+ extensionsFilesets.add(fileSet);
+ }
+
+ /**
+ * Extract a set of Extension objects from the ExtensionSet.
+ *
+ * @param proj the project instance.
+ * @return an array containing the Extensions from this set
+ * @throws BuildException if an error occurs
+ */
+ public Extension[] toExtensions(final Project proj)
+ throws BuildException {
+ if (isReference()) {
+ return ((ExtensionSet) getCheckedRef()).toExtensions(proj);
+ }
+ dieOnCircularReference();
+ final ArrayList extensionsList = ExtensionUtil.toExtensions(extensions);
+ ExtensionUtil.extractExtensions(proj, extensionsList, extensionsFilesets);
+ return (Extension[]) extensionsList.toArray(new Extension[extensionsList.size()]);
+ }
+
+ /**
+ * Makes this instance in effect a reference to another ExtensionSet
+ * instance.
+ *
+ * <p>You must not set another attribute or nest elements inside
+ * this element if you make it a reference.</p>
+ *
+ * @param reference the reference to which this instance is associated
+ * @exception BuildException if this instance already has been configured.
+ */
+ @Override
+ public void setRefid(final Reference reference)
+ throws BuildException {
+ if (!extensions.isEmpty() || !extensionsFilesets.isEmpty()) {
+ throw tooManyAttributes();
+ }
+ super.setRefid(reference);
+ }
+
+ @Override
+ protected synchronized void dieOnCircularReference(Stack stk, Project p)
+ throws BuildException {
+ if (isChecked()) {
+ return;
+ }
+ if (isReference()) {
+ super.dieOnCircularReference(stk, p);
+ } else {
+ for (Iterator i = extensions.iterator(); i.hasNext();) {
+ pushAndInvokeCircularReferenceCheck((ExtensionAdapter) i.next(),
+ stk, p);
+ }
+ for (Iterator i = extensionsFilesets.iterator(); i.hasNext();) {
+ pushAndInvokeCircularReferenceCheck((FileSet) i.next(), stk, p);
+ }
+ setChecked(true);
+ }
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ * @return the extensions in a string.
+ */
+ @Override
+ public String toString() {
+ return "ExtensionSet" + Arrays.asList(toExtensions(getProject()));
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java
new file mode 100644
index 00000000..089c7894
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * A set of useful methods relating to extensions.
+ *
+ */
+public final class ExtensionUtil {
+ /**
+ * Class is not meant to be instantiated.
+ */
+ private ExtensionUtil() {
+ //all methods static
+ }
+
+ /**
+ * Convert a list of extensionAdapter objects to extensions.
+ *
+ * @param adapters the list of ExtensionAdapterss to add to convert
+ * @throws BuildException if an error occurs
+ */
+ static ArrayList toExtensions(final List adapters)
+ throws BuildException {
+ final ArrayList results = new ArrayList();
+
+ final int size = adapters.size();
+ for (int i = 0; i < size; i++) {
+ final ExtensionAdapter adapter =
+ (ExtensionAdapter) adapters.get(i);
+ final Extension extension = adapter.toExtension();
+ results.add(extension);
+ }
+
+ return results;
+ }
+
+ /**
+ * Generate a list of extensions from a specified fileset.
+ *
+ * @param libraries the list to add extensions to
+ * @param fileset the filesets containing librarys
+ * @throws BuildException if an error occurs
+ */
+ static void extractExtensions(final Project project,
+ final List libraries,
+ final List fileset)
+ throws BuildException {
+ if (!fileset.isEmpty()) {
+ final Extension[] extensions = getExtensions(project,
+ fileset);
+ for (int i = 0; i < extensions.length; i++) {
+ libraries.add(extensions[ i ]);
+ }
+ }
+ }
+
+ /**
+ * Retrieve extensions from the specified libraries.
+ *
+ * @param libraries the filesets for libraries
+ * @return the extensions contained in libraries
+ * @throws BuildException if failing to scan libraries
+ */
+ private static Extension[] getExtensions(final Project project,
+ final List libraries)
+ throws BuildException {
+ final ArrayList extensions = new ArrayList();
+ final Iterator iterator = libraries.iterator();
+ while (iterator.hasNext()) {
+ final FileSet fileSet = (FileSet) iterator.next();
+
+ boolean includeImpl = true;
+ boolean includeURL = true;
+
+ if (fileSet instanceof LibFileSet) {
+ LibFileSet libFileSet = (LibFileSet) fileSet;
+ includeImpl = libFileSet.isIncludeImpl();
+ includeURL = libFileSet.isIncludeURL();
+ }
+
+ final DirectoryScanner scanner = fileSet.getDirectoryScanner(project);
+ final File basedir = scanner.getBasedir();
+ final String[] files = scanner.getIncludedFiles();
+ for (int i = 0; i < files.length; i++) {
+ final File file = new File(basedir, files[ i ]);
+ loadExtensions(file, extensions, includeImpl, includeURL);
+ }
+ }
+ return (Extension[]) extensions.toArray(new Extension[extensions.size()]);
+ }
+
+ /**
+ * Load list of available extensions from specified file.
+ *
+ * @param file the file
+ * @param extensionList the list to add available extensions to
+ * @throws BuildException if there is an error
+ */
+ private static void loadExtensions(final File file,
+ final List extensionList,
+ final boolean includeImpl,
+ final boolean includeURL)
+ throws BuildException {
+ try {
+ final JarFile jarFile = new JarFile(file);
+ final Extension[] extensions =
+ Extension.getAvailable(jarFile.getManifest());
+ for (int i = 0; i < extensions.length; i++) {
+ final Extension extension = extensions[ i ];
+ addExtension(extensionList, extension, includeImpl, includeURL);
+ }
+ } catch (final Exception e) {
+ throw new BuildException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Add extension to list.
+ * If extension should not have implementation details but
+ * does strip them. If extension should not have url but does
+ * then strip it.
+ *
+ * @param extensionList the list of extensions to add to
+ * @param originalExtension the extension
+ * @param includeImpl false to exclude implementation details
+ * @param includeURL false to exclude implementation URL
+ */
+ private static void addExtension(final List extensionList,
+ final Extension originalExtension,
+ final boolean includeImpl,
+ final boolean includeURL) {
+ Extension extension = originalExtension;
+ if (!includeURL
+ && null != extension.getImplementationURL()) {
+ extension =
+ new Extension(extension.getExtensionName(),
+ extension.getSpecificationVersion().toString(),
+ extension.getSpecificationVendor(),
+ extension.getImplementationVersion().toString(),
+ extension.getImplementationVendor(),
+ extension.getImplementationVendorID(),
+ null);
+ }
+
+ final boolean hasImplAttributes =
+ null != extension.getImplementationURL()
+ || null != extension.getImplementationVersion()
+ || null != extension.getImplementationVendorID()
+ || null != extension.getImplementationVendor();
+
+ if (!includeImpl && hasImplAttributes) {
+ extension =
+ new Extension(extension.getExtensionName(),
+ extension.getSpecificationVersion().toString(),
+ extension.getSpecificationVendor(),
+ null,
+ null,
+ null,
+ extension.getImplementationURL());
+ }
+
+ extensionList.add(extension);
+ }
+
+ /**
+ * Retrieve manifest for specified file.
+ *
+ * @param file the file
+ * @return the manifest
+ * @throws BuildException if errror occurs (file doesn't exist,
+ * file not a jar, manifest doesn't exist in file)
+ */
+ static Manifest getManifest(final File file)
+ throws BuildException {
+ try {
+ final JarFile jarFile = new JarFile(file);
+ Manifest m = jarFile.getManifest();
+ if (m == null) {
+ throw new BuildException(file + " doesn't have a MANIFEST");
+ }
+ return m;
+ } catch (final IOException ioe) {
+ throw new BuildException(ioe.getMessage(), ioe);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java
new file mode 100644
index 00000000..d52bec41
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Simple holder for extra attributes in main section of manifest.
+ *
+ * @todo Refactor this and all the other parameter, sysproperty,
+ * property etc into a single class in framework
+ */
+public class ExtraAttribute {
+ private String name;
+ private String value;
+
+ /**
+ * Set the name of the parameter.
+ *
+ * @param name the name of parameter
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Set the value of the parameter.
+ *
+ * @param value the parameter value
+ */
+ public void setValue(final String value) {
+ this.value = value;
+ }
+
+ /**
+ * Retrieve name of parameter.
+ *
+ * @return the name of parameter.
+ */
+ String getName() {
+ return name;
+ }
+
+ /**
+ * Retrieve the value of parameter.
+ *
+ * @return the value of parameter.
+ */
+ String getValue() {
+ return value;
+ }
+
+ /**
+ * Make sure that neither the name or the value
+ * is null.
+ *
+ * @throws BuildException if the attribute is invalid.
+ */
+ public void validate() throws BuildException {
+ if (null == name) {
+ final String message = "Missing name from parameter.";
+ throw new BuildException(message);
+ } else if (null == value) {
+ final String message = "Missing value from parameter " + name + ".";
+ throw new BuildException(message);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java
new file mode 100644
index 00000000..cebcf0d5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Checks whether an extension is present in a fileset or an extensionSet.
+ *
+ * @ant.task name="jarlib-available"
+ */
+public class JarLibAvailableTask extends Task {
+ /**
+ * The library to display information about.
+ */
+ private File libraryFile;
+
+ /**
+ * Filesets specifying all the librarys
+ * to display information about.
+ */
+ private final Vector extensionFileSets = new Vector();
+
+ /**
+ * The name of the property to set if extension is available.
+ */
+ private String propertyName;
+
+ /**
+ * The extension that is required.
+ */
+ private ExtensionAdapter requiredExtension;
+
+ /**
+ * The name of property to set if extensions are available.
+ *
+ * @param property The name of property to set if extensions is available.
+ */
+ public void setProperty(final String property) {
+ this.propertyName = property;
+ }
+
+ /**
+ * The JAR library to check.
+ *
+ * @param file The jar library to check.
+ */
+ public void setFile(final File file) {
+ this.libraryFile = file;
+ }
+
+ /**
+ * Set the Extension looking for.
+ *
+ * @param extension Set the Extension looking for.
+ */
+ public void addConfiguredExtension(final ExtensionAdapter extension) {
+ if (null != requiredExtension) {
+ final String message = "Can not specify extension to "
+ + "search for multiple times.";
+ throw new BuildException(message);
+ }
+ requiredExtension = extension;
+ }
+
+ /**
+ * Adds a set of extensions to search in.
+ *
+ * @param extensionSet a set of extensions to search in.
+ */
+ public void addConfiguredExtensionSet(final ExtensionSet extensionSet) {
+ extensionFileSets.addElement(extensionSet);
+ }
+
+ /**
+ * Execute the task.
+ *
+ * @throws BuildException if something goes wrong.
+ */
+ public void execute() throws BuildException {
+ validate();
+
+ final Extension test = requiredExtension.toExtension();
+
+ // Check if list of files to check has been specified
+ if (!extensionFileSets.isEmpty()) {
+ final Iterator iterator = extensionFileSets.iterator();
+ while (iterator.hasNext()) {
+ final ExtensionSet extensionSet
+ = (ExtensionSet) iterator.next();
+ final Extension[] extensions =
+ extensionSet.toExtensions(getProject());
+ for (int i = 0; i < extensions.length; i++) {
+ final Extension extension = extensions[ i ];
+ if (extension.isCompatibleWith(test)) {
+ getProject().setNewProperty(propertyName, "true");
+ }
+ }
+ }
+ } else {
+ final Manifest manifest = ExtensionUtil.getManifest(libraryFile);
+ final Extension[] extensions = Extension.getAvailable(manifest);
+ for (int i = 0; i < extensions.length; i++) {
+ final Extension extension = extensions[ i ];
+ if (extension.isCompatibleWith(test)) {
+ getProject().setNewProperty(propertyName, "true");
+ }
+ }
+ }
+ }
+
+ /**
+ * Validate the tasks parameters.
+ *
+ * @throws BuildException if invalid parameters found
+ */
+ private void validate() throws BuildException {
+ if (null == requiredExtension) {
+ final String message = "Extension element must be specified.";
+ throw new BuildException(message);
+ }
+
+ if (null == libraryFile && extensionFileSets.isEmpty()) {
+ final String message = "File attribute not specified.";
+ throw new BuildException(message);
+ }
+ if (null != libraryFile && !libraryFile.exists()) {
+ final String message = "File '" + libraryFile + "' does not exist.";
+ throw new BuildException(message);
+ }
+ if (null != libraryFile && !libraryFile.isFile()) {
+ final String message = "\'" + libraryFile + "\' is not a file.";
+ throw new BuildException(message);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java
new file mode 100644
index 00000000..da12cd02
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Displays the "Optional Package" and "Package Specification" information
+ * contained within the specified JARs.
+ *
+ * <p>Prior to JDK1.3, an "Optional Package" was known as an Extension.
+ * The specification for this mechanism is available in the JDK1.3
+ * documentation in the directory
+ * $JDK_HOME/docs/guide/extensions/versioning.html. Alternatively it is
+ * available online at <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+ * http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+ *
+ * @ant.task name="jarlib-display"
+ */
+public class JarLibDisplayTask extends Task {
+ /**
+ * The library to display information about.
+ */
+ private File libraryFile;
+
+ /**
+ * Filesets specifying all the librarys
+ * to display information about.
+ */
+ private final Vector libraryFileSets = new Vector();
+
+ /**
+ * The JAR library to display information for.
+ *
+ * @param file The jar library to display information for.
+ */
+ public void setFile(final File file) {
+ this.libraryFile = file;
+ }
+
+ /**
+ * Adds a set of files about which library data will be displayed.
+ *
+ * @param fileSet a set of files about which library data will be displayed.
+ */
+ public void addFileset(final FileSet fileSet) {
+ libraryFileSets.addElement(fileSet);
+ }
+
+ /**
+ * Execute the task.
+ *
+ * @throws BuildException if the task fails.
+ */
+ public void execute() throws BuildException {
+ validate();
+
+ final LibraryDisplayer displayer = new LibraryDisplayer();
+ // Check if list of files to check has been specified
+ if (!libraryFileSets.isEmpty()) {
+ final Iterator iterator = libraryFileSets.iterator();
+ while (iterator.hasNext()) {
+ final FileSet fileSet = (FileSet) iterator.next();
+ final DirectoryScanner scanner
+ = fileSet.getDirectoryScanner(getProject());
+ final File basedir = scanner.getBasedir();
+ final String[] files = scanner.getIncludedFiles();
+ for (int i = 0; i < files.length; i++) {
+ final File file = new File(basedir, files[ i ]);
+ displayer.displayLibrary(file);
+ }
+ }
+ } else {
+ displayer.displayLibrary(libraryFile);
+ }
+ }
+
+ /**
+ * Validate the tasks parameters.
+ *
+ * @throws BuildException if invalid parameters found
+ */
+ private void validate() throws BuildException {
+ if (null == libraryFile && libraryFileSets.isEmpty()) {
+ final String message = "File attribute not specified.";
+ throw new BuildException(message);
+ }
+ if (null != libraryFile && !libraryFile.exists()) {
+ final String message = "File '" + libraryFile + "' does not exist.";
+ throw new BuildException(message);
+ }
+ if (null != libraryFile && !libraryFile.isFile()) {
+ final String message = "\'" + libraryFile + "\' is not a file.";
+ throw new BuildException(message);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java
new file mode 100644
index 00000000..5afc57f1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Generates a manifest that declares all the dependencies.
+ * The dependencies are determined by looking in the
+ * specified path and searching for Extension / "Optional Package"
+ * specifications in the manifests of the jars.
+ *
+ * <p>Prior to JDK1.3, an "Optional Package" was known as an Extension.
+ * The specification for this mechanism is available in the JDK1.3
+ * documentation in the directory
+ * $JDK_HOME/docs/guide/extensions/versioning.html. Alternatively it is
+ * available online at <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+ * http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+ *
+ * @ant.task name="jarlib-manifest"
+ */
+public final class JarLibManifestTask extends Task {
+ /**
+ * Version of manifest spec that task generates.
+ */
+ private static final String MANIFEST_VERSION = "1.0";
+
+ /**
+ * "Created-By" string used when creating manifest.
+ */
+ private static final String CREATED_BY = "Created-By";
+
+ /**
+ * The library to display information about.
+ */
+ private File destFile;
+
+ /**
+ * The extension supported by this library (if any).
+ */
+ private Extension extension;
+
+ /**
+ * ExtensionAdapter objects representing
+ * dependencies required by library.
+ */
+ private final ArrayList dependencies = new ArrayList();
+
+ /**
+ * ExtensionAdapter objects representing optional
+ * dependencies required by library.
+ */
+ private final ArrayList optionals = new ArrayList();
+
+ /**
+ * Extra attributes the user specifies for main section
+ * in manifest.
+ */
+ private final ArrayList extraAttributes = new ArrayList();
+
+ /**
+ * The location where generated manifest is placed.
+ *
+ * @param destFile The location where generated manifest is placed.
+ */
+ public void setDestfile(final File destFile) {
+ this.destFile = destFile;
+ }
+
+ /**
+ * Adds an extension that this library implements.
+ *
+ * @param extensionAdapter an extension that this library implements.
+ *
+ * @throws BuildException if there is multiple extensions detected
+ * in the library.
+ */
+ public void addConfiguredExtension(final ExtensionAdapter extensionAdapter)
+ throws BuildException {
+ if (null != extension) {
+ throw new BuildException("Can not have multiple extensions defined in one library.");
+ }
+ extension = extensionAdapter.toExtension();
+ }
+
+ /**
+ * Adds a set of extensions that this library requires.
+ *
+ * @param extensionSet a set of extensions that this library requires.
+ */
+ public void addConfiguredDepends(final ExtensionSet extensionSet) {
+ dependencies.add(extensionSet);
+ }
+
+ /**
+ * Adds a set of extensions that this library optionally requires.
+ *
+ * @param extensionSet a set of extensions that this library optionally requires.
+ */
+ public void addConfiguredOptions(final ExtensionSet extensionSet) {
+ optionals.add(extensionSet);
+ }
+
+ /**
+ * Adds an attribute that is to be put in main section of manifest.
+ *
+ * @param attribute an attribute that is to be put in main section of manifest.
+ */
+ public void addConfiguredAttribute(final ExtraAttribute attribute) {
+ extraAttributes.add(attribute);
+ }
+
+ /**
+ * Execute the task.
+ *
+ * @throws BuildException if the task fails.
+ */
+ public void execute() throws BuildException {
+ validate();
+
+ final Manifest manifest = new Manifest();
+ final Attributes attributes = manifest.getMainAttributes();
+
+ attributes.put(Attributes.Name.MANIFEST_VERSION, MANIFEST_VERSION);
+ attributes.putValue(CREATED_BY, "Apache Ant "
+ + getProject().getProperty(MagicNames.ANT_VERSION));
+
+ appendExtraAttributes(attributes);
+
+ if (null != extension) {
+ Extension.addExtension(extension, attributes);
+ }
+
+ //Add all the dependency data to manifest for dependencies
+ final ArrayList depends = toExtensions(dependencies);
+ appendExtensionList(attributes, Extension.EXTENSION_LIST, "lib", depends.size());
+ appendLibraryList(attributes, "lib", depends);
+
+ // Add all the dependency data to manifest for "optional"
+ //dependencies
+ final ArrayList option = toExtensions(optionals);
+ appendExtensionList(attributes, Extension.OPTIONAL_EXTENSION_LIST, "opt", option.size());
+ appendLibraryList(attributes, "opt", option);
+
+ try {
+ log("Generating manifest " + destFile.getAbsoluteFile(), Project.MSG_INFO);
+ writeManifest(manifest);
+ } catch (final IOException ioe) {
+ throw new BuildException(ioe.getMessage(), ioe);
+ }
+ }
+
+ /**
+ * Validate the tasks parameters.
+ *
+ * @throws BuildException if invalid parameters found
+ */
+ private void validate() throws BuildException {
+ if (null == destFile) {
+ throw new BuildException("Destfile attribute not specified.");
+ }
+ if (destFile.exists() && !destFile.isFile()) {
+ throw new BuildException(destFile + " is not a file.");
+ }
+ }
+
+ /**
+ * Add any extra attributes to the manifest.
+ *
+ * @param attributes the manifest section to write
+ * attributes to
+ */
+ private void appendExtraAttributes(final Attributes attributes) {
+ final Iterator iterator = extraAttributes.iterator();
+ while (iterator.hasNext()) {
+ final ExtraAttribute attribute =
+ (ExtraAttribute) iterator.next();
+ attributes.putValue(attribute.getName(),
+ attribute.getValue());
+ }
+ }
+
+ /**
+ * Write out manifest to destfile.
+ *
+ * @param manifest the manifest
+ * @throws IOException if error writing file
+ */
+ private void writeManifest(final Manifest manifest) throws IOException {
+ FileOutputStream output = null;
+ try {
+ output = new FileOutputStream(destFile);
+ manifest.write(output);
+ output.flush();
+ } finally {
+ if (null != output) {
+ try {
+ output.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Append specified extensions to specified attributes.
+ * Use the extensionKey to list the extensions, usually "Extension-List:"
+ * for required dependencies and "Optional-Extension-List:" for optional
+ * dependencies. NOTE: "Optional" dependencies are not part of the
+ * specification.
+ *
+ * @param attributes the attributes to add extensions to
+ * @param extensions the list of extensions
+ * @throws BuildException if an error occurs
+ */
+ private void appendLibraryList(final Attributes attributes, final String listPrefix,
+ final ArrayList extensions) throws BuildException {
+ final int size = extensions.size();
+ for (int i = 0; i < size; i++) {
+ final Extension ext = (Extension) extensions.get(i);
+ final String prefix = listPrefix + i + "-";
+ Extension.addExtension(ext, prefix, attributes);
+ }
+ }
+
+ /**
+ * Append an attribute such as "Extension-List: lib0 lib1 lib2"
+ * using specified prefix and counting up to specified size.
+ * Also use specified extensionKey so that can generate list of
+ * optional dependencies as well.
+ *
+ * @param size the number of librarys to list
+ * @param listPrefix the prefix for all librarys
+ * @param attributes the attributes to add key-value to
+ * @param extensionKey the key to use
+ */
+ private void appendExtensionList(final Attributes attributes,
+ final Attributes.Name extensionKey, final String listPrefix, final int size) {
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < size; i++) {
+ sb.append(listPrefix);
+ sb.append(i);
+ sb.append(' ');
+ }
+ //add in something like
+ //"Extension-List: javahelp java3d"
+ attributes.put(extensionKey, sb.toString());
+ }
+
+ /**
+ * Convert a list of ExtensionSet objects to extensions.
+ *
+ * @param extensionSets the list of ExtensionSets to add to list
+ * @throws BuildException if an error occurs
+ */
+ private ArrayList toExtensions(final ArrayList extensionSets) throws BuildException {
+ final ArrayList results = new ArrayList();
+
+ final int size = extensionSets.size();
+ for (int i = 0; i < size; i++) {
+ final ExtensionSet set = (ExtensionSet) extensionSets.get(i);
+ final Extension[] extensions = set.toExtensions(getProject());
+ for (int j = 0; j < extensions.length; j++) {
+ results.add(extensions[ j ]);
+ }
+ }
+ return results;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java
new file mode 100644
index 00000000..c13194fa
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.extension.resolvers.AntResolver;
+import org.apache.tools.ant.taskdefs.optional.extension.resolvers.LocationResolver;
+import org.apache.tools.ant.taskdefs.optional.extension.resolvers.URLResolver;
+
+/**
+ * Tries to locate a JAR to satisfy an extension and place
+ * location of JAR into property.
+ *
+ * @ant.task name="jarlib-resolve"
+ */
+public class JarLibResolveTask extends Task {
+ /**
+ * The name of the property in which the location of
+ * library is stored.
+ */
+ private String propertyName;
+
+ /**
+ * The extension that is required.
+ */
+ private Extension requiredExtension;
+
+ /**
+ * The set of resolvers to use to attempt to locate library.
+ */
+ private final ArrayList resolvers = new ArrayList();
+
+ /**
+ * Flag to indicate that you should check that
+ * the librarys resolved actually contain
+ * extension and if they don't then raise
+ * an exception.
+ */
+ private boolean checkExtension = true;
+
+ /**
+ * Flag indicating whether or not you should
+ * throw a BuildException if you cannot resolve
+ * library.
+ */
+ private boolean failOnError = true;
+
+ /**
+ * The name of the property in which the location of
+ * library is stored.
+ *
+ * @param property The name of the property in which the location of
+ * library is stored.
+ */
+ public void setProperty(final String property) {
+ this.propertyName = property;
+ }
+
+ /**
+ * Check nested libraries for extensions
+ *
+ * @param checkExtension if true, libraries returned by nested
+ * resolvers should be checked to see if they supply extension.
+ */
+ public void setCheckExtension(final boolean checkExtension) {
+ this.checkExtension = checkExtension;
+ }
+
+ /**
+ * Set whether to fail if error.
+ *
+ * @param failOnError if true, failure to locate library should fail build.
+ */
+ public void setFailOnError(final boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ /**
+ * Adds location resolver to look for a library in a location
+ * relative to project directory.
+ *
+ * @param loc the resolver location to search.
+ */
+ public void addConfiguredLocation(final LocationResolver loc) {
+ resolvers.add(loc);
+ }
+
+ /**
+ * Adds a URL resolver to download a library from a URL
+ * to a local file.
+ *
+ * @param url the URL resolver from which to download the library
+ */
+ public void addConfiguredUrl(final URLResolver url) {
+ resolvers.add(url);
+ }
+
+ /**
+ * Adds Ant resolver to run an Ant build file to generate a library.
+ *
+ * @param ant the AntResolver to generate the library.
+ */
+ public void addConfiguredAnt(final AntResolver ant) {
+ resolvers.add(ant);
+ }
+
+ /**
+ * Set the Extension looking for.
+ *
+ * @param extension Set the Extension looking for.
+ */
+ public void addConfiguredExtension(final ExtensionAdapter extension) {
+ if (null != requiredExtension) {
+ final String message = "Can not specify extension to "
+ + "resolve multiple times.";
+ throw new BuildException(message);
+ }
+ requiredExtension = extension.toExtension();
+ }
+
+ /**
+ * Execute the task.
+ *
+ * @throws BuildException if the task fails.
+ */
+ public void execute() throws BuildException {
+ validate();
+
+ getProject().log("Resolving extension: " + requiredExtension, Project.MSG_VERBOSE);
+
+ String candidate = getProject().getProperty(propertyName);
+
+ if (null != candidate) {
+ final String message = "Property Already set to: " + candidate;
+ if (failOnError) {
+ throw new BuildException(message);
+ }
+ getProject().log(message, Project.MSG_ERR);
+ return;
+ }
+
+ final int size = resolvers.size();
+ for (int i = 0; i < size; i++) {
+ final ExtensionResolver resolver =
+ (ExtensionResolver) resolvers.get(i);
+
+ getProject().log("Searching for extension using Resolver:" + resolver,
+ Project.MSG_VERBOSE);
+
+ try {
+ final File file = resolver.resolve(requiredExtension, getProject());
+ try {
+ checkExtension(file);
+ return;
+ } catch (final BuildException be) {
+ final String message = "File " + file + " returned by "
+ + "resolver failed to satisfy extension due to: " + be.getMessage();
+ getProject().log(message, Project.MSG_WARN);
+ }
+ } catch (final BuildException be) {
+ final String message = "Failed to resolve extension to file " + "using resolver "
+ + resolver + " due to: " + be;
+ getProject().log(message, Project.MSG_WARN);
+ }
+ }
+ missingExtension();
+ }
+
+ /**
+ * Utility method that will throw a {@link BuildException}
+ * if {@link #failOnError} is true else it just displays
+ * a warning.
+ */
+ private void missingExtension() {
+ final String message = "Unable to resolve extension to a file";
+ if (failOnError) {
+ throw new BuildException(message);
+ }
+ getProject().log(message, Project.MSG_ERR);
+ }
+
+ /**
+ * Check if specified file satisfies extension.
+ * If it does then set the relevant property
+ * else throw a BuildException.
+ *
+ * @param file the candidate library
+ * @throws BuildException if library does not satisfy extension
+ */
+ private void checkExtension(final File file) {
+ if (!file.exists()) {
+ throw new BuildException("File " + file + " does not exist");
+ }
+ if (!file.isFile()) {
+ throw new BuildException("File " + file + " is not a file");
+ }
+ if (!checkExtension) {
+ getProject().log("Setting property to " + file
+ + " without verifying library satisfies extension", Project.MSG_VERBOSE);
+ setLibraryProperty(file);
+ } else {
+ getProject().log("Checking file " + file + " to see if it satisfies extension",
+ Project.MSG_VERBOSE);
+ final Manifest manifest = ExtensionUtil.getManifest(file);
+ final Extension[] extensions = Extension.getAvailable(manifest);
+ for (int i = 0; i < extensions.length; i++) {
+ final Extension extension = extensions[ i ];
+ if (extension.isCompatibleWith(requiredExtension)) {
+ setLibraryProperty(file);
+ return;
+ }
+ }
+ final String message = "File " + file + " skipped as it "
+ + "does not satisfy extension";
+ getProject().log(message, Project.MSG_VERBOSE);
+ throw new BuildException(message);
+ }
+ }
+
+ /**
+ * Utility method to set the appropriate property
+ * to indicate that specified file satisfies library
+ * requirements.
+ *
+ * @param file the library
+ */
+ private void setLibraryProperty(final File file) {
+ getProject().setNewProperty(propertyName, file.getAbsolutePath());
+ }
+
+ /**
+ * Validate the tasks parameters.
+ *
+ * @throws BuildException if invalid parameters found
+ */
+ private void validate() throws BuildException {
+ if (null == propertyName) {
+ final String message = "Property attribute must be specified.";
+ throw new BuildException(message);
+ }
+
+ if (null == requiredExtension) {
+ final String message = "Extension element must be specified.";
+ throw new BuildException(message);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java
new file mode 100644
index 00000000..b21719e5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * LibFileSet represents a fileset containing libraries.
+ * Associated with the libraries is data pertaining to
+ * how they are to be handled when building manifests.
+ *
+ */
+public class LibFileSet
+ extends FileSet {
+ /**
+ * Flag indicating whether should include the
+ * "Implementation-URL" attribute in manifest.
+ * Defaults to false.
+ */
+ private boolean includeURL;
+
+ /**
+ * Flag indicating whether should include the
+ * "Implementation-*" attributes in manifest.
+ * Defaults to false.
+ */
+ private boolean includeImpl;
+
+ /**
+ * String that is the base URL for the librarys
+ * when constructing the "Implementation-URL"
+ * attribute. For instance setting the base to
+ * "http://jakarta.apache.org/avalon/libs/" and then
+ * including the library "excalibur-cli-1.0.jar" in the
+ * fileset will result in the "Implementation-URL" attribute
+ * being set to "http://jakarta.apache.org/avalon/libs/excalibur-cli-1.0.jar"
+ *
+ * Note this is only used if the library does not define
+ * "Implementation-URL" itself.
+ *
+ * Note that this also implies includeURL=true
+ */
+ private String urlBase;
+
+ /**
+ * Flag indicating whether should include the
+ * "Implementation-URL" attribute in manifest.
+ * Defaults to false.
+ *
+ * @param includeURL the flag
+ */
+ public void setIncludeUrl(boolean includeURL) {
+ this.includeURL = includeURL;
+ }
+
+ /**
+ * Flag indicating whether should include the
+ * "Implementation-*" attributes in manifest.
+ * Defaults to false.
+ *
+ * @param includeImpl the flag
+ */
+ public void setIncludeImpl(boolean includeImpl) {
+ this.includeImpl = includeImpl;
+ }
+
+ /**
+ * Set the url base for fileset.
+ *
+ * @param urlBase the base url
+ */
+ public void setUrlBase(String urlBase) {
+ this.urlBase = urlBase;
+ }
+
+ /**
+ * Get the includeURL flag.
+ *
+ * @return the includeURL flag.
+ */
+ boolean isIncludeURL() {
+ return includeURL;
+ }
+
+ /**
+ * Get the includeImpl flag.
+ *
+ * @return the includeImpl flag.
+ */
+ boolean isIncludeImpl() {
+ return includeImpl;
+ }
+
+ /**
+ * Get the urlbase.
+ *
+ * @return the urlbase.
+ */
+ String getUrlBase() {
+ return urlBase;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java
new file mode 100644
index 00000000..b0ee4f81
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.text.ParseException;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Utility class to output the information in a jar relating
+ * to "Optional Packages" (formely known as "Extensions")
+ * and Package Specifications.
+ *
+ */
+class LibraryDisplayer {
+ /**
+ * Display the extensions and specifications contained
+ * within specified file.
+ *
+ * @param file the file
+ * @throws BuildException if fail to read file
+ */
+ void displayLibrary(final File file)
+ throws BuildException {
+ final Manifest manifest = ExtensionUtil.getManifest(file);
+ displayLibrary(file, manifest);
+ }
+
+ /**
+ * Display the extensions and specifications contained
+ * within specified file.
+ *
+ * @param file the file to use while reporting
+ * @param manifest the manifest of file
+ * @throws BuildException if fail to read file
+ */
+ void displayLibrary(final File file,
+ final Manifest manifest)
+ throws BuildException {
+ final Extension[] available = Extension.getAvailable(manifest);
+ final Extension[] required = Extension.getRequired(manifest);
+ final Extension[] options = Extension.getOptions(manifest);
+ final Specification[] specifications = getSpecifications(manifest);
+
+ if (0 == available.length && 0 == required.length && 0 == options.length
+ && 0 == specifications.length) {
+ return;
+ }
+
+ final String message = "File: " + file;
+ final int size = message.length();
+ printLine(size);
+ System.out.println(message);
+ printLine(size);
+ if (0 != available.length) {
+ System.out.println("Extensions Supported By Library:");
+ for (int i = 0; i < available.length; i++) {
+ final Extension extension = available[ i ];
+ System.out.println(extension.toString());
+ }
+ }
+
+ if (0 != required.length) {
+ System.out.println("Extensions Required By Library:");
+ for (int i = 0; i < required.length; i++) {
+ final Extension extension = required[ i ];
+ System.out.println(extension.toString());
+ }
+ }
+
+ if (0 != options.length) {
+ System.out.println("Extensions that will be used by Library if present:");
+ for (int i = 0; i < options.length; i++) {
+ final Extension extension = options[ i ];
+ System.out.println(extension.toString());
+ }
+ }
+
+ if (0 != specifications.length) {
+ System.out.println("Specifications Supported By Library:");
+ for (int i = 0; i < specifications.length; i++) {
+ final Specification specification = specifications[ i ];
+ displaySpecification(specification);
+ }
+ }
+ }
+
+ /**
+ * Print out a line of '-'s equal to specified size.
+ *
+ * @param size the number of dashes to printout
+ */
+ private void printLine(final int size) {
+ for (int i = 0; i < size; i++) {
+ System.out.print("-");
+ }
+ System.out.println();
+ }
+
+ /**
+ * Get specifications from manifest.
+ *
+ * @param manifest the manifest
+ * @return the specifications or null if none
+ * @throws BuildException if malformed specification sections
+ */
+ private Specification[] getSpecifications(final Manifest manifest)
+ throws BuildException {
+ try {
+ return Specification.getSpecifications(manifest);
+ } catch (final ParseException pe) {
+ throw new BuildException(pe.getMessage(), pe);
+ }
+ }
+
+ /**
+ * Print out specification details.
+ *
+ * @param specification the specification
+ */
+ private void displaySpecification(final Specification specification) {
+ final String[] sections = specification.getSections();
+ if (null != sections) {
+ final StringBuffer sb = new StringBuffer("Sections: ");
+ for (int i = 0; i < sections.length; i++) {
+ sb.append(" ");
+ sb.append(sections[ i ]);
+ }
+ System.out.println(sb);
+ }
+ System.out.println(specification.toString());
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java
new file mode 100644
index 00000000..1e4bb7b3
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java
@@ -0,0 +1,605 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.util.DeweyDecimal;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * <p>Utility class that represents either an available "Optional Package"
+ * (formerly known as "Standard Extension") as described in the manifest
+ * of a JAR file, or the requirement for such an optional package.</p>
+ *
+ * <p>For more information about optional packages, see the document
+ * <em>Optional Package Versioning</em> in the documentation bundle for your
+ * Java2 Standard Edition package, in file
+ * <code>guide/extensions/versioning.html</code>.</p>
+ *
+ */
+public final class Specification {
+
+ private static final String MISSING = "Missing ";
+
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_TITLE.
+ */
+ public static final Attributes.Name SPECIFICATION_TITLE
+ = Attributes.Name.SPECIFICATION_TITLE;
+
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_VERSION.
+ */
+ public static final Attributes.Name SPECIFICATION_VERSION
+ = Attributes.Name.SPECIFICATION_VERSION;
+
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_VENDOR.
+ */
+ public static final Attributes.Name SPECIFICATION_VENDOR
+ = Attributes.Name.SPECIFICATION_VENDOR;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_TITLE.
+ */
+ public static final Attributes.Name IMPLEMENTATION_TITLE
+ = Attributes.Name.IMPLEMENTATION_TITLE;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
+ */
+ public static final Attributes.Name IMPLEMENTATION_VERSION
+ = Attributes.Name.IMPLEMENTATION_VERSION;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
+ */
+ public static final Attributes.Name IMPLEMENTATION_VENDOR
+ = Attributes.Name.IMPLEMENTATION_VENDOR;
+
+ /**
+ * Enum indicating that extension is compatible with other Package
+ * Specification.
+ */
+ public static final Compatibility COMPATIBLE =
+ new Compatibility("COMPATIBLE");
+
+ /**
+ * Enum indicating that extension requires an upgrade
+ * of specification to be compatible with other Package Specification.
+ */
+ public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE =
+ new Compatibility("REQUIRE_SPECIFICATION_UPGRADE");
+
+ /**
+ * Enum indicating that extension requires a vendor
+ * switch to be compatible with other Package Specification.
+ */
+ public static final Compatibility REQUIRE_VENDOR_SWITCH =
+ new Compatibility("REQUIRE_VENDOR_SWITCH");
+
+ /**
+ * Enum indicating that extension requires an upgrade
+ * of implementation to be compatible with other Package Specification.
+ */
+ public static final Compatibility REQUIRE_IMPLEMENTATION_CHANGE =
+ new Compatibility("REQUIRE_IMPLEMENTATION_CHANGE");
+
+ /**
+ * This enum indicates that an extension is incompatible with
+ * other Package Specification in ways other than other enums
+ * indicate. For example, the other Package Specification
+ * may have a different ID.
+ */
+ public static final Compatibility INCOMPATIBLE =
+ new Compatibility("INCOMPATIBLE");
+
+ /**
+ * The name of the Package Specification.
+ */
+ private String specificationTitle;
+
+ /**
+ * The version number (dotted decimal notation) of the specification
+ * to which this optional package conforms.
+ */
+ private DeweyDecimal specificationVersion;
+
+ /**
+ * The name of the company or organization that originated the
+ * specification to which this specification conforms.
+ */
+ private String specificationVendor;
+
+ /**
+ * The title of implementation.
+ */
+ private String implementationTitle;
+
+ /**
+ * The name of the company or organization that produced this
+ * implementation of this specification.
+ */
+ private String implementationVendor;
+
+ /**
+ * The version string for implementation. The version string is
+ * opaque.
+ */
+ private String implementationVersion;
+
+ /**
+ * The sections of jar that the specification applies to.
+ */
+ private String[] sections;
+
+ /**
+ * Return an array of <code>Package Specification</code> objects.
+ * If there are no such optional packages, a zero-length array is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the Package Specifications extensions in specified manifest
+ * @throws ParseException if the attributes of the specifications cannot
+ * be parsed according to their expected formats.
+ */
+ public static Specification[] getSpecifications(final Manifest manifest)
+ throws ParseException {
+ if (null == manifest) {
+ return new Specification[ 0 ];
+ }
+
+ final ArrayList results = new ArrayList();
+
+ final Map entries = manifest.getEntries();
+ final Iterator keys = entries.keySet().iterator();
+ while (keys.hasNext()) {
+ final String key = (String) keys.next();
+ final Attributes attributes = (Attributes) entries.get(key);
+ final Specification specification
+ = getSpecification(key, attributes);
+ if (null != specification) {
+ results.add(specification);
+ }
+ }
+
+ final ArrayList trimmedResults = removeDuplicates(results);
+ return (Specification[]) trimmedResults.toArray(new Specification[trimmedResults.size()]);
+ }
+
+ /**
+ * The constructor to create Package Specification object.
+ * Note that every component is allowed to be specified
+ * but only the specificationTitle is mandatory.
+ *
+ * @param specificationTitle the name of specification.
+ * @param specificationVersion the specification Version.
+ * @param specificationVendor the specification Vendor.
+ * @param implementationTitle the title of implementation.
+ * @param implementationVersion the implementation Version.
+ * @param implementationVendor the implementation Vendor.
+ */
+ public Specification(final String specificationTitle,
+ final String specificationVersion,
+ final String specificationVendor,
+ final String implementationTitle,
+ final String implementationVersion,
+ final String implementationVendor) {
+ this(specificationTitle, specificationVersion, specificationVendor,
+ implementationTitle, implementationVersion, implementationVendor,
+ null);
+ }
+
+ /**
+ * The constructor to create Package Specification object.
+ * Note that every component is allowed to be specified
+ * but only the specificationTitle is mandatory.
+ *
+ * @param specificationTitle the name of specification.
+ * @param specificationVersion the specification Version.
+ * @param specificationVendor the specification Vendor.
+ * @param implementationTitle the title of implementation.
+ * @param implementationVersion the implementation Version.
+ * @param implementationVendor the implementation Vendor.
+ * @param sections the sections/packages that Specification applies to.
+ */
+ public Specification(final String specificationTitle,
+ final String specificationVersion,
+ final String specificationVendor,
+ final String implementationTitle,
+ final String implementationVersion,
+ final String implementationVendor,
+ final String[] sections) {
+ this.specificationTitle = specificationTitle;
+ this.specificationVendor = specificationVendor;
+
+ if (null != specificationVersion) {
+ try {
+ this.specificationVersion
+ = new DeweyDecimal(specificationVersion);
+ } catch (final NumberFormatException nfe) {
+ final String error = "Bad specification version format '"
+ + specificationVersion + "' in '" + specificationTitle
+ + "'. (Reason: " + nfe + ")";
+ throw new IllegalArgumentException(error);
+ }
+ }
+
+ this.implementationTitle = implementationTitle;
+ this.implementationVendor = implementationVendor;
+ this.implementationVersion = implementationVersion;
+
+ if (null == this.specificationTitle) {
+ throw new NullPointerException("specificationTitle");
+ }
+
+ String[] copy = null;
+ if (null != sections) {
+ copy = new String[ sections.length ];
+ System.arraycopy(sections, 0, copy, 0, sections.length);
+ }
+ this.sections = copy;
+ }
+
+ /**
+ * Get the title of the specification.
+ *
+ * @return the title of specification
+ */
+ public String getSpecificationTitle() {
+ return specificationTitle;
+ }
+
+ /**
+ * Get the vendor of the specification.
+ *
+ * @return the vendor of the specification.
+ */
+ public String getSpecificationVendor() {
+ return specificationVendor;
+ }
+
+ /**
+ * Get the title of the specification.
+ *
+ * @return the title of the specification.
+ */
+ public String getImplementationTitle() {
+ return implementationTitle;
+ }
+
+ /**
+ * Get the version of the specification.
+ *
+ * @return the version of the specification.
+ */
+ public DeweyDecimal getSpecificationVersion() {
+ return specificationVersion;
+ }
+
+ /**
+ * Get the vendor of the extensions implementation.
+ *
+ * @return the vendor of the extensions implementation.
+ */
+ public String getImplementationVendor() {
+ return implementationVendor;
+ }
+
+ /**
+ * Get the version of the implementation.
+ *
+ * @return the version of the implementation.
+ */
+ public String getImplementationVersion() {
+ return implementationVersion;
+ }
+
+ /**
+ * Return an array containing sections to which specification applies
+ * or null if relevant to no sections.
+ *
+ * @return an array containing sections to which specification applies
+ * or null if relevant to no sections.
+ */
+ public String[] getSections() {
+ if (null == sections) {
+ return null;
+ }
+ final String[] newSections = new String[ sections.length ];
+ System.arraycopy(sections, 0, newSections, 0, sections.length);
+ return newSections;
+ }
+
+ /**
+ * Return a Compatibility enum indicating the relationship of this
+ * <code>Package Specification</code> with the specified
+ * <code>Extension</code>.
+ *
+ * @param other the other specification
+ * @return the enum indicating the compatibility (or lack thereof)
+ * of specified Package Specification
+ */
+ public Compatibility getCompatibilityWith(final Specification other) {
+ // Specification Name must match
+ if (!specificationTitle.equals(other.getSpecificationTitle())) {
+ return INCOMPATIBLE;
+ }
+
+ // Available specification version must be >= required
+ final DeweyDecimal otherSpecificationVersion
+ = other.getSpecificationVersion();
+ if (null != specificationVersion) {
+ if (null == otherSpecificationVersion
+ || !isCompatible(specificationVersion, otherSpecificationVersion)) {
+ return REQUIRE_SPECIFICATION_UPGRADE;
+ }
+ }
+
+ // Implementation Vendor ID must match
+ final String otherImplementationVendor
+ = other.getImplementationVendor();
+ if (null != implementationVendor) {
+ if (null == otherImplementationVendor
+ || !implementationVendor.equals(otherImplementationVendor)) {
+ return REQUIRE_VENDOR_SWITCH;
+ }
+ }
+
+ // Implementation version must be >= required
+ final String otherImplementationVersion
+ = other.getImplementationVersion();
+ if (null != implementationVersion) {
+ if (null == otherImplementationVersion
+ || !implementationVersion.equals(otherImplementationVersion)) {
+ return REQUIRE_IMPLEMENTATION_CHANGE;
+ }
+ }
+
+ // This available optional package satisfies the requirements
+ return COMPATIBLE;
+ }
+
+ /**
+ * Return <code>true</code> if the specified <code>package</code>
+ * is satisfied by this <code>Specification</code>. Otherwise, return
+ * <code>false</code>.
+ *
+ * @param other the specification
+ * @return true if the specification is compatible with this specification
+ */
+ public boolean isCompatibleWith(final Specification other) {
+ return (COMPATIBLE == getCompatibilityWith(other));
+ }
+
+ /**
+ * Return a String representation of this object.
+ *
+ * @return string representation of object.
+ */
+ public String toString() {
+ final String brace = ": ";
+
+ final StringBuffer sb
+ = new StringBuffer(SPECIFICATION_TITLE.toString());
+ sb.append(brace);
+ sb.append(specificationTitle);
+ sb.append(StringUtils.LINE_SEP);
+
+ if (null != specificationVersion) {
+ sb.append(SPECIFICATION_VERSION);
+ sb.append(brace);
+ sb.append(specificationVersion);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != specificationVendor) {
+ sb.append(SPECIFICATION_VENDOR);
+ sb.append(brace);
+ sb.append(specificationVendor);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationTitle) {
+ sb.append(IMPLEMENTATION_TITLE);
+ sb.append(brace);
+ sb.append(implementationTitle);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationVersion) {
+ sb.append(IMPLEMENTATION_VERSION);
+ sb.append(brace);
+ sb.append(implementationVersion);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ if (null != implementationVendor) {
+ sb.append(IMPLEMENTATION_VENDOR);
+ sb.append(brace);
+ sb.append(implementationVendor);
+ sb.append(StringUtils.LINE_SEP);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return <code>true</code> if the first version number is greater than
+ * or equal to the second; otherwise return <code>false</code>.
+ *
+ * @param first First version number (dotted decimal)
+ * @param second Second version number (dotted decimal)
+ */
+ private boolean isCompatible(final DeweyDecimal first,
+ final DeweyDecimal second) {
+ return first.isGreaterThanOrEqual(second);
+ }
+
+ /**
+ * Combine all specifications objects that are identical except
+ * for the sections.
+ *
+ * <p>Note this is very inefficent and should probably be fixed
+ * in the future.</p>
+ *
+ * @param list the array of results to trim
+ * @return an array list with all duplicates removed
+ */
+ private static ArrayList removeDuplicates(final ArrayList list) {
+ final ArrayList results = new ArrayList();
+ final ArrayList sections = new ArrayList();
+ while (list.size() > 0) {
+ final Specification specification = (Specification) list.remove(0);
+ final Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ final Specification other = (Specification) iterator.next();
+ if (isEqual(specification, other)) {
+ final String[] otherSections = other.getSections();
+ if (null != otherSections) {
+ sections.addAll(Arrays.asList(otherSections));
+ }
+ iterator.remove();
+ }
+ }
+
+ final Specification merged =
+ mergeInSections(specification, sections);
+ results.add(merged);
+ //Reset list of sections
+ sections.clear();
+ }
+
+ return results;
+ }
+
+ /**
+ * Test if two specifications are equal except for their sections.
+ *
+ * @param specification one specificaiton
+ * @param other the ohter specification
+ * @return true if two specifications are equal except for their
+ * sections, else false
+ */
+ private static boolean isEqual(final Specification specification,
+ final Specification other) {
+ return
+ specification.getSpecificationTitle().equals(other.getSpecificationTitle())
+ && specification.getSpecificationVersion().isEqual(other.getSpecificationVersion())
+ && specification.getSpecificationVendor().equals(other.getSpecificationVendor())
+ && specification.getImplementationTitle().equals(other.getImplementationTitle())
+ && specification.getImplementationVersion().equals(other.getImplementationVersion())
+ && specification.getImplementationVendor().equals(other.getImplementationVendor());
+ }
+
+ /**
+ * Merge the specified sections into specified section and return result.
+ * If no sections to be added then just return original specification.
+ *
+ * @param specification the specification
+ * @param sectionsToAdd the list of sections to merge
+ * @return the merged specification
+ */
+ private static Specification mergeInSections(final Specification specification,
+ final ArrayList sectionsToAdd) {
+ if (0 == sectionsToAdd.size()) {
+ return specification;
+ }
+ sectionsToAdd.addAll(Arrays.asList(specification.getSections()));
+
+ final String[] sections =
+ (String[]) sectionsToAdd.toArray(new String[sectionsToAdd.size()]);
+
+ return new Specification(specification.getSpecificationTitle(),
+ specification.getSpecificationVersion().toString(),
+ specification.getSpecificationVendor(),
+ specification.getImplementationTitle(),
+ specification.getImplementationVersion(),
+ specification.getImplementationVendor(),
+ sections);
+ }
+
+ /**
+ * Trim the supplied string if the string is non-null
+ *
+ * @param value the string to trim or null
+ * @return the trimmed string or null
+ */
+ private static String getTrimmedString(final String value) {
+ return value == null ? null : value.trim();
+ }
+
+ /**
+ * Extract an Package Specification from Attributes.
+ *
+ * @param attributes Attributes to searched
+ * @return the new Specification object, or null
+ */
+ private static Specification getSpecification(final String section,
+ final Attributes attributes)
+ throws ParseException {
+ //WARNING: We trim the values of all the attributes because
+ //Some extension declarations are badly defined (ie have spaces
+ //after version or vendor)
+ final String name
+ = getTrimmedString(attributes.getValue(SPECIFICATION_TITLE));
+ if (null == name) {
+ return null;
+ }
+
+ final String specVendor
+ = getTrimmedString(attributes.getValue(SPECIFICATION_VENDOR));
+ if (null == specVendor) {
+ throw new ParseException(MISSING + SPECIFICATION_VENDOR, 0);
+ }
+
+ final String specVersion
+ = getTrimmedString(attributes.getValue(SPECIFICATION_VERSION));
+ if (null == specVersion) {
+ throw new ParseException(MISSING + SPECIFICATION_VERSION, 0);
+ }
+
+ final String impTitle
+ = getTrimmedString(attributes.getValue(IMPLEMENTATION_TITLE));
+ if (null == impTitle) {
+ throw new ParseException(MISSING + IMPLEMENTATION_TITLE, 0);
+ }
+
+ final String impVersion
+ = getTrimmedString(attributes.getValue(IMPLEMENTATION_VERSION));
+ if (null == impVersion) {
+ throw new ParseException(MISSING + IMPLEMENTATION_VERSION, 0);
+ }
+
+ final String impVendor
+ = getTrimmedString(attributes.getValue(IMPLEMENTATION_VENDOR));
+ if (null == impVendor) {
+ throw new ParseException(MISSING + IMPLEMENTATION_VENDOR, 0);
+ }
+
+ return new Specification(name, specVersion, specVendor,
+ impTitle, impVersion, impVendor,
+ new String[]{section});
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java
new file mode 100644
index 00000000..6284679f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension.resolvers;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Ant;
+import org.apache.tools.ant.taskdefs.optional.extension.Extension;
+import org.apache.tools.ant.taskdefs.optional.extension.ExtensionResolver;
+
+/**
+ * Resolver that just returns s specified location.
+ *
+ */
+public class AntResolver implements ExtensionResolver {
+ private File antfile;
+ private File destfile;
+ private String target;
+
+ /**
+ * Sets the ant file
+ * @param antfile the ant file to set
+ */
+ public void setAntfile(final File antfile) {
+ this.antfile = antfile;
+ }
+
+ /**
+ * Sets the destination file
+ * @param destfile the destination file
+ */
+ public void setDestfile(final File destfile) {
+ this.destfile = destfile;
+ }
+
+ /**
+ * Sets the target
+ * @param target the target
+ */
+ public void setTarget(final String target) {
+ this.target = target;
+ }
+
+ /**
+ * Returns the resolved file
+ * @param extension the extension
+ * @param project the project
+ * @return the file resolved
+ * @throws BuildException if the file cannot be resolved
+ */
+ public File resolve(final Extension extension,
+ final Project project) throws BuildException {
+ validate();
+
+ final Ant ant = new Ant();
+ ant.setProject(project);
+ ant.setInheritAll(false);
+ ant.setAntfile(antfile.getName());
+
+ try {
+ final File dir =
+ antfile.getParentFile().getCanonicalFile();
+ ant.setDir(dir);
+ } catch (final IOException ioe) {
+ throw new BuildException(ioe.getMessage(), ioe);
+ }
+
+ if (null != target) {
+ ant.setTarget(target);
+ }
+
+ ant.execute();
+
+ return destfile;
+ }
+
+ /*
+ * Validates URL
+ */
+ private void validate() {
+ if (null == antfile) {
+ final String message = "Must specify Buildfile";
+ throw new BuildException(message);
+ }
+
+ if (null == destfile) {
+ final String message = "Must specify destination file";
+ throw new BuildException(message);
+ }
+ }
+
+ /**
+ * Returns a string representation
+ * @return the string representation
+ */
+ public String toString() {
+ return "Ant[" + antfile + "==>" + destfile + "]";
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java
new file mode 100644
index 00000000..e2fec022
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension.resolvers;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.optional.extension.Extension;
+import org.apache.tools.ant.taskdefs.optional.extension.ExtensionResolver;
+
+/**
+ * Resolver that just returns s specified location.
+ *
+ */
+public class LocationResolver implements ExtensionResolver {
+ private String location;
+
+ /**
+ * Sets the location for this resolver
+ * @param location the location
+ */
+ public void setLocation(final String location) {
+ this.location = location;
+ }
+
+ /**
+ * Returns the resolved file
+ * @param extension the extension
+ * @param project the project
+ * @return the file resolved
+ * @throws BuildException if no location is set
+ */
+ public File resolve(final Extension extension,
+ final Project project) throws BuildException {
+ if (null == location) {
+ final String message = "No location specified for resolver";
+ throw new BuildException(message);
+ }
+
+ return project.resolveFile(location);
+ }
+ /**
+ * Returns a string representation of the Location
+ * @return the string representation
+ */
+ public String toString() {
+ return "Location[" + location + "]";
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java
new file mode 100644
index 00000000..d693b899
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension.resolvers;
+
+import java.io.File;
+import java.net.URL;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Get;
+import org.apache.tools.ant.taskdefs.optional.extension.Extension;
+import org.apache.tools.ant.taskdefs.optional.extension.ExtensionResolver;
+
+/**
+ * Resolver that just returns s specified location.
+ *
+ */
+public class URLResolver implements ExtensionResolver {
+ private File destfile;
+ private File destdir;
+ private URL url;
+
+ /**
+ * Sets the URL
+ * @param url the url
+ */
+ public void setUrl(final URL url) {
+ this.url = url;
+ }
+
+ /**
+ * Sets the destination file
+ * @param destfile the destination file
+ */
+ public void setDestfile(final File destfile) {
+ this.destfile = destfile;
+ }
+
+ /**
+ * Sets the destination directory
+ * @param destdir the destination directory
+ */
+ public void setDestdir(final File destdir) {
+ this.destdir = destdir;
+ }
+
+ /**
+ * Returns the file resolved from URL and directory
+ * @param extension the extension
+ * @param project the project
+ * @return file the file resolved
+ * @throws BuildException if the URL is invalid
+ */
+ public File resolve(final Extension extension,
+ final Project project) throws BuildException {
+ validate();
+
+ final File file = getDest();
+
+ final Get get = new Get();
+ get.setProject(project);
+ get.setDest(file);
+ get.setSrc(url);
+ get.execute();
+
+ return file;
+ }
+
+ /*
+ * Gets the destination file
+ */
+ private File getDest() {
+ File result;
+ if (null != destfile) {
+ result = destfile;
+ } else {
+ final String file = url.getFile();
+ String filename;
+ if (null == file || file.length() <= 1) {
+ filename = "default.file";
+ } else {
+ int index = file.lastIndexOf('/');
+ if (-1 == index) {
+ index = 0;
+ }
+ filename = file.substring(index);
+ }
+ result = new File(destdir, filename);
+ }
+ return result;
+ }
+
+ /*
+ * Validates URL
+ */
+ private void validate() {
+ if (null == url) {
+ final String message = "Must specify URL";
+ throw new BuildException(message);
+ }
+
+ if (null == destdir && null == destfile) {
+ final String message = "Must specify destination file or directory";
+ throw new BuildException(message);
+ } else if (null != destdir && null != destfile) {
+ final String message = "Must not specify both destination file or directory";
+ throw new BuildException(message);
+ }
+ }
+
+ /**
+ * Returns a string representation of the URL
+ * @return the string representation
+ */
+ public String toString() {
+ return "URL[" + url + "]";
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java
new file mode 100644
index 00000000..82731fe9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java
@@ -0,0 +1,632 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.i18n;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LineTokenizer;
+
+/**
+ * Translates text embedded in files using Resource Bundle files.
+ * Since ant 1.6 preserves line endings
+ *
+ */
+public class Translate extends MatchingTask {
+ /**
+ * search a bundle matching the specified language, the country and the variant
+ */
+ private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT = 0;
+ /**
+ * search a bundle matching the specified language, and the country
+ */
+ private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY = 1;
+ /**
+ * search a bundle matching the specified language only
+ */
+ private static final int BUNDLE_SPECIFIED_LANGUAGE = 2;
+ /**
+ * search a bundle matching nothing special
+ */
+ private static final int BUNDLE_NOMATCH = 3;
+ /**
+ * search a bundle matching the language, the country and the variant
+ * of the current locale of the computer
+ */
+ private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT = 4;
+ /**
+ * search a bundle matching the language, and the country
+ * of the current locale of the computer
+ */
+ private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY = 5;
+ /**
+ * search a bundle matching the language only
+ * of the current locale of the computer
+ */
+ private static final int BUNDLE_DEFAULT_LANGUAGE = 6;
+ /**
+ * number of possibilities for the search
+ */
+ private static final int BUNDLE_MAX_ALTERNATIVES = BUNDLE_DEFAULT_LANGUAGE + 1;
+ /**
+ * Family name of resource bundle
+ */
+ private String bundle;
+
+ /**
+ * Locale specific language of the resource bundle
+ */
+ private String bundleLanguage;
+
+ /**
+ * Locale specific country of the resource bundle
+ */
+ private String bundleCountry;
+
+ /**
+ * Locale specific variant of the resource bundle
+ */
+ private String bundleVariant;
+
+ /**
+ * Destination directory
+ */
+ private File toDir;
+
+ /**
+ * Source file encoding scheme
+ */
+ private String srcEncoding;
+
+ /**
+ * Destination file encoding scheme
+ */
+ private String destEncoding;
+
+ /**
+ * Resource Bundle file encoding scheme, defaults to srcEncoding
+ */
+ private String bundleEncoding;
+
+ /**
+ * Starting token to identify keys
+ */
+ private String startToken;
+
+ /**
+ * Ending token to identify keys
+ */
+ private String endToken;
+
+ /**
+ * Whether or not to create a new destination file.
+ * Defaults to <code>false</code>.
+ */
+ private boolean forceOverwrite;
+
+ /**
+ * Vector to hold source file sets.
+ */
+ private Vector filesets = new Vector();
+
+ /**
+ * Holds key value pairs loaded from resource bundle file
+ */
+ private Hashtable resourceMap = new Hashtable();
+ /**
+
+ * Used to resolve file names.
+ */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * Last Modified Timestamp of resource bundle file being used.
+ */
+ private long[] bundleLastModified = new long[BUNDLE_MAX_ALTERNATIVES];
+
+ /**
+ * Last Modified Timestamp of source file being used.
+ */
+ private long srcLastModified;
+
+ /**
+ * Last Modified Timestamp of destination file being used.
+ */
+ private long destLastModified;
+
+ /**
+ * Has at least one file from the bundle been loaded?
+ */
+ private boolean loaded = false;
+
+ /**
+ * Sets Family name of resource bundle; required.
+ * @param bundle family name of resource bundle
+ */
+ public void setBundle(String bundle) {
+ this.bundle = bundle;
+ }
+
+ /**
+ * Sets locale specific language of resource bundle; optional.
+ * @param bundleLanguage language of the bundle
+ */
+ public void setBundleLanguage(String bundleLanguage) {
+ this.bundleLanguage = bundleLanguage;
+ }
+
+ /**
+ * Sets locale specific country of resource bundle; optional.
+ * @param bundleCountry country of the bundle
+ */
+ public void setBundleCountry(String bundleCountry) {
+ this.bundleCountry = bundleCountry;
+ }
+
+ /**
+ * Sets locale specific variant of resource bundle; optional.
+ * @param bundleVariant locale variant of resource bundle
+ */
+ public void setBundleVariant(String bundleVariant) {
+ this.bundleVariant = bundleVariant;
+ }
+
+ /**
+ * Sets Destination directory; required.
+ * @param toDir destination directory
+ */
+ public void setToDir(File toDir) {
+ this.toDir = toDir;
+ }
+
+ /**
+ * Sets starting token to identify keys; required.
+ * @param startToken starting token to identify keys
+ */
+ public void setStartToken(String startToken) {
+ this.startToken = startToken;
+ }
+
+ /**
+ * Sets ending token to identify keys; required.
+ * @param endToken ending token to identify keys
+ */
+ public void setEndToken(String endToken) {
+ this.endToken = endToken;
+ }
+
+ /**
+ * Sets source file encoding scheme; optional,
+ * defaults to encoding of local system.
+ * @param srcEncoding source file encoding
+ */
+ public void setSrcEncoding(String srcEncoding) {
+ this.srcEncoding = srcEncoding;
+ }
+
+ /**
+ * Sets destination file encoding scheme; optional. Defaults to source file
+ * encoding
+ * @param destEncoding destination file encoding scheme
+ */
+ public void setDestEncoding(String destEncoding) {
+ this.destEncoding = destEncoding;
+ }
+
+ /**
+ * Sets Resource Bundle file encoding scheme; optional. Defaults to source file
+ * encoding
+ * @param bundleEncoding bundle file encoding scheme
+ */
+ public void setBundleEncoding(String bundleEncoding) {
+ this.bundleEncoding = bundleEncoding;
+ }
+
+ /**
+ * Whether or not to overwrite existing file irrespective of
+ * whether it is newer than the source file as well as the
+ * resource bundle file.
+ * Defaults to false.
+ * @param forceOverwrite whether or not to overwrite existing files
+ */
+ public void setForceOverwrite(boolean forceOverwrite) {
+ this.forceOverwrite = forceOverwrite;
+ }
+
+ /**
+ * Adds a set of files to translate as a nested fileset element.
+ * @param set the fileset to be added
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ /**
+ * Check attributes values, load resource map and translate
+ * @throws BuildException if the required attributes are not set
+ * Required : <ul>
+ * <li>bundle</li>
+ * <li>starttoken</li>
+ * <li>endtoken</li>
+ * </ul>
+ */
+ public void execute() throws BuildException {
+ if (bundle == null) {
+ throw new BuildException("The bundle attribute must be set.",
+ getLocation());
+ }
+
+ if (startToken == null) {
+ throw new BuildException("The starttoken attribute must be set.",
+ getLocation());
+ }
+
+ if (endToken == null) {
+ throw new BuildException("The endtoken attribute must be set.",
+ getLocation());
+ }
+
+ if (bundleLanguage == null) {
+ Locale l = Locale.getDefault();
+ bundleLanguage = l.getLanguage();
+ }
+
+ if (bundleCountry == null) {
+ bundleCountry = Locale.getDefault().getCountry();
+ }
+
+ if (bundleVariant == null) {
+ Locale l = new Locale(bundleLanguage, bundleCountry);
+ bundleVariant = l.getVariant();
+ }
+
+ if (toDir == null) {
+ throw new BuildException("The todir attribute must be set.",
+ getLocation());
+ }
+
+ if (!toDir.exists()) {
+ toDir.mkdirs();
+ } else if (toDir.isFile()) {
+ throw new BuildException(toDir + " is not a directory");
+ }
+
+ if (srcEncoding == null) {
+ srcEncoding = System.getProperty("file.encoding");
+ }
+
+ if (destEncoding == null) {
+ destEncoding = srcEncoding;
+ }
+
+ if (bundleEncoding == null) {
+ bundleEncoding = srcEncoding;
+ }
+
+ loadResourceMaps();
+
+ translate();
+ }
+
+ /**
+ * Load resource maps based on resource bundle encoding scheme.
+ * The resource bundle lookup searches for resource files with various
+ * suffixes on the basis of (1) the desired locale and (2) the default
+ * locale (basebundlename), in the following order from lower-level
+ * (more specific) to parent-level (less specific):
+ *
+ * basebundlename + "_" + language1 + "_" + country1 + "_" + variant1
+ * basebundlename + "_" + language1 + "_" + country1
+ * basebundlename + "_" + language1
+ * basebundlename
+ * basebundlename + "_" + language2 + "_" + country2 + "_" + variant2
+ * basebundlename + "_" + language2 + "_" + country2
+ * basebundlename + "_" + language2
+ *
+ * To the generated name, a ".properties" string is appeneded and
+ * once this file is located, it is treated just like a properties file
+ * but with bundle encoding also considered while loading.
+ */
+ private void loadResourceMaps() throws BuildException {
+ Locale locale = new Locale(bundleLanguage,
+ bundleCountry,
+ bundleVariant);
+ String language = locale.getLanguage().length() > 0
+ ? "_" + locale.getLanguage() : "";
+ String country = locale.getCountry().length() > 0
+ ? "_" + locale.getCountry() : "";
+ String variant = locale.getVariant().length() > 0
+ ? "_" + locale.getVariant() : "";
+ String bundleFile = bundle + language + country + variant;
+ processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT, false);
+
+ bundleFile = bundle + language + country;
+ processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY, false);
+
+ bundleFile = bundle + language;
+ processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE, false);
+
+ bundleFile = bundle;
+ processBundle(bundleFile, BUNDLE_NOMATCH, false);
+
+ //Load default locale bundle files
+ //using default file encoding scheme.
+ locale = Locale.getDefault();
+
+ language = locale.getLanguage().length() > 0
+ ? "_" + locale.getLanguage() : "";
+ country = locale.getCountry().length() > 0
+ ? "_" + locale.getCountry() : "";
+ variant = locale.getVariant().length() > 0
+ ? "_" + locale.getVariant() : "";
+ bundleEncoding = System.getProperty("file.encoding");
+
+ bundleFile = bundle + language + country + variant;
+ processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT, false);
+
+ bundleFile = bundle + language + country;
+ processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY, false);
+
+ bundleFile = bundle + language;
+ processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE, true);
+ }
+
+ /**
+ * Process each file that makes up this bundle.
+ */
+ private void processBundle(final String bundleFile, final int i,
+ final boolean checkLoaded) throws BuildException {
+ final File propsFile = getProject().resolveFile(bundleFile + ".properties");
+ FileInputStream ins = null;
+ try {
+ ins = new FileInputStream(propsFile);
+ loaded = true;
+ bundleLastModified[i] = propsFile.lastModified();
+ log("Using " + propsFile, Project.MSG_DEBUG);
+ loadResourceMap(ins);
+ } catch (IOException ioe) {
+ log(propsFile + " not found.", Project.MSG_DEBUG);
+ //if all resource files associated with this bundle
+ //have been scanned for and still not able to
+ //find a single resrouce file, throw exception
+ if (!loaded && checkLoaded) {
+ throw new BuildException(ioe.getMessage(), getLocation());
+ }
+ }
+ }
+
+ /**
+ * Load resourceMap with key value pairs. Values of existing keys
+ * are not overwritten. Bundle's encoding scheme is used.
+ */
+ private void loadResourceMap(FileInputStream ins) throws BuildException {
+ try {
+ BufferedReader in = null;
+ InputStreamReader isr = new InputStreamReader(ins, bundleEncoding);
+ in = new BufferedReader(isr);
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ //So long as the line isn't empty and isn't a comment...
+ if (line.trim().length() > 1 && '#' != line.charAt(0) && '!' != line.charAt(0)) {
+ //Legal Key-Value separators are :, = and white space.
+ int sepIndex = line.indexOf('=');
+ if (-1 == sepIndex) {
+ sepIndex = line.indexOf(':');
+ }
+ if (-1 == sepIndex) {
+ for (int k = 0; k < line.length(); k++) {
+ if (Character.isSpaceChar(line.charAt(k))) {
+ sepIndex = k;
+ break;
+ }
+ }
+ }
+ //Only if we do have a key is there going to be a value
+ if (-1 != sepIndex) {
+ String key = line.substring(0, sepIndex).trim();
+ String value = line.substring(sepIndex + 1).trim();
+ //Handle line continuations, if any
+ while (value.endsWith("\\")) {
+ value = value.substring(0, value.length() - 1);
+ line = in.readLine();
+ if (line != null) {
+ value = value + line.trim();
+ } else {
+ break;
+ }
+ }
+ if (key.length() > 0) {
+ //Has key already been loaded into resourceMap?
+ if (resourceMap.get(key) == null) {
+ resourceMap.put(key, value);
+ }
+ }
+ }
+ }
+ }
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException ioe) {
+ throw new BuildException(ioe.getMessage(), getLocation());
+ }
+ }
+
+ /**
+ * Reads source file line by line using the source encoding and
+ * searches for keys that are sandwiched between the startToken
+ * and endToken. The values for these keys are looked up from
+ * the hashtable and substituted. If the hashtable doesn't
+ * contain the key, they key itself is used as the value.
+ * Detination files and directories are created as needed.
+ * The destination file is overwritten only if
+ * the forceoverwritten attribute is set to true if
+ * the source file or any associated bundle resource file is
+ * newer than the destination file.
+ */
+ private void translate() throws BuildException {
+ int filesProcessed = 0;
+ final int size = filesets.size();
+ for (int i = 0; i < size; i++) {
+ FileSet fs = (FileSet) filesets.elementAt(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ String[] srcFiles = ds.getIncludedFiles();
+ for (int j = 0; j < srcFiles.length; j++) {
+ try {
+ File dest = FILE_UTILS.resolveFile(toDir, srcFiles[j]);
+ //Make sure parent dirs exist, else, create them.
+ try {
+ File destDir = new File(dest.getParent());
+ if (!destDir.exists()) {
+ destDir.mkdirs();
+ }
+ } catch (Exception e) {
+ log("Exception occurred while trying to check/create "
+ + " parent directory. " + e.getMessage(),
+ Project.MSG_DEBUG);
+ }
+ destLastModified = dest.lastModified();
+ File src = FILE_UTILS.resolveFile(ds.getBasedir(), srcFiles[j]);
+ srcLastModified = src.lastModified();
+ //Check to see if dest file has to be recreated
+ boolean needsWork = forceOverwrite
+ || destLastModified < srcLastModified;
+ if (!needsWork) {
+ for (int icounter = 0; icounter < BUNDLE_MAX_ALTERNATIVES; icounter++) {
+ needsWork = (destLastModified < bundleLastModified[icounter]);
+ if (needsWork) {
+ break;
+ }
+ }
+ }
+ if (needsWork) {
+ log("Processing " + srcFiles[j],
+ Project.MSG_DEBUG);
+ translateOneFile(src, dest);
+ ++filesProcessed;
+ } else {
+ log("Skipping " + srcFiles[j]
+ + " as destination file is up to date",
+ Project.MSG_VERBOSE);
+ }
+ } catch (IOException ioe) {
+ throw new BuildException(ioe.getMessage(), getLocation());
+ }
+ }
+ }
+ log("Translation performed on " + filesProcessed + " file(s).", Project.MSG_DEBUG);
+ }
+
+ private void translateOneFile(File src, File dest) throws IOException {
+ BufferedWriter out = null;
+ BufferedReader in = null;
+ try {
+ FileOutputStream fos = new FileOutputStream(dest);
+ out = new BufferedWriter(new OutputStreamWriter(fos, destEncoding));
+ FileInputStream fis = new FileInputStream(src);
+ in = new BufferedReader(new InputStreamReader(fis, srcEncoding));
+ String line;
+ LineTokenizer lineTokenizer = new LineTokenizer();
+ lineTokenizer.setIncludeDelims(true);
+ line = lineTokenizer.getToken(in);
+ while ((line) != null) {
+ // 2003-02-21 new replace algorithm by tbee (tbee@tbee.org)
+ // because it wasn't able to replace something like "@aaa;@bbb;"
+
+ // is there a startToken
+ // and there is still stuff following the startToken
+ int startIndex = line.indexOf(startToken);
+ while (startIndex >= 0
+ && (startIndex + startToken.length()) <= line.length()) {
+ // the new value, this needs to be here
+ // because it is required to calculate the next position to
+ // search from at the end of the loop
+ String replace = null;
+
+ // we found a starttoken, is there an endtoken following?
+ // start at token+tokenlength because start and end
+ // token may be identical
+ int endIndex = line.indexOf(endToken, startIndex
+ + startToken.length());
+ if (endIndex < 0) {
+ startIndex += 1;
+ } else {
+ // grab the token
+ String token = line.substring(startIndex
+ + startToken.length(),
+ endIndex);
+
+ // If there is a white space or = or :, then
+ // it isn't to be treated as a valid key.
+ boolean validToken = true;
+ for (int k = 0; k < token.length() && validToken; k++) {
+ char c = token.charAt(k);
+ if (c == ':' || c == '='
+ || Character.isSpaceChar(c)) {
+ validToken = false;
+ }
+ }
+ if (!validToken) {
+ startIndex += 1;
+ } else {
+ // find the replace string
+ if (resourceMap.containsKey(token)) {
+ replace = (String) resourceMap.get(token);
+ } else {
+ log("Replacement string missing for: " + token,
+ Project.MSG_VERBOSE);
+ replace = startToken + token + endToken;
+ }
+
+
+ // generate the new line
+ line = line.substring(0, startIndex) + replace
+ + line.substring(endIndex + endToken.length());
+
+ // set start position for next search
+ startIndex += replace.length();
+ }
+ }
+
+ // find next starttoken
+ startIndex = line.indexOf(startToken, startIndex);
+ }
+ out.write(line);
+ line = lineTokenizer.getToken(in);
+ }
+ } finally {
+ FileUtils.close(in);
+ FileUtils.close(out);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java
new file mode 100644
index 00000000..162e3756
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java
@@ -0,0 +1,421 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.image;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Vector;
+
+import javax.media.jai.JAI;
+import javax.media.jai.PlanarImage;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.optional.image.Draw;
+import org.apache.tools.ant.types.optional.image.ImageOperation;
+import org.apache.tools.ant.types.optional.image.Rotate;
+import org.apache.tools.ant.types.optional.image.Scale;
+import org.apache.tools.ant.types.optional.image.TransformOperation;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.IdentityMapper;
+
+import com.sun.media.jai.codec.FileSeekableStream;
+
+/**
+ * A MatchingTask which relies on <a
+ * href="http://java.sun.com/products/java-media/jai">JAI (Java
+ * Advanced Imaging)</a> to perform image manipulation operations on
+ * existing images. The operations are represented as ImageOperation
+ * DataType objects. The operations are arranged to conform to the
+ * Chaining Model of JAI. Check out the <a
+ * href="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/">
+ * JAI Programming Guide</a>.
+ *
+ * @see org.apache.tools.ant.types.optional.image.ImageOperation
+ * @see org.apache.tools.ant.types.DataType
+ */
+public class Image extends MatchingTask {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected Vector instructions = new Vector();
+ protected boolean overwrite = false;
+ protected Vector filesets = new Vector();
+ protected File srcDir = null;
+ protected File destDir = null;
+
+ // CheckStyle:MemberNameCheck OFF - bc
+
+ //cannot remove underscores due to protected visibility >:(
+ protected String str_encoding = "JPEG";
+ protected boolean garbage_collect = false;
+
+ private boolean failonerror = true;
+
+ // CheckStyle:MemberNameCheck ON
+
+ // CheckStyle:VisibilityModifier ON
+
+ private Mapper mapperElement = null;
+
+ /**
+ * Add a set of files to be deleted.
+ * @param set the FileSet to add.
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ /**
+ * Set whether to fail on error.
+ * If false, note errors to the output but keep going.
+ * @param failonerror true or false.
+ */
+ public void setFailOnError(boolean failonerror) {
+ this.failonerror = failonerror;
+ }
+
+ /**
+ * Set the source dir to find the image files.
+ * @param srcDir the directory in which the image files reside.
+ */
+ public void setSrcdir(File srcDir) {
+ this.srcDir = srcDir;
+ }
+
+ /**
+ * Set the image encoding type. <a
+ * href="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/Encode.doc.html#56610">
+ * See this table in the JAI Programming Guide</a>.
+ * @param encoding the String image encoding.
+ */
+ public void setEncoding(String encoding) {
+ str_encoding = encoding;
+ }
+
+ /**
+ * Set whether to overwrite a file if there is a naming conflict.
+ * @param overwrite whether to overwrite.
+ */
+ public void setOverwrite(boolean overwrite) {
+ this.overwrite = overwrite;
+ }
+
+ /**
+ * Set whether to invoke Garbage Collection after each image processed.
+ * Defaults to false.
+ * @param gc whether to invoke the garbage collector.
+ */
+ public void setGc(boolean gc) {
+ garbage_collect = gc;
+ }
+
+ /**
+ * Set the destination directory for manipulated images.
+ * @param destDir The destination directory.
+ */
+ public void setDestDir(File destDir) {
+ this.destDir = destDir;
+ }
+
+ /**
+ * Add an ImageOperation to chain.
+ * @param instr The ImageOperation to append to the chain.
+ */
+ public void addImageOperation(ImageOperation instr) {
+ instructions.add(instr);
+ }
+
+ /**
+ * Add a Rotate ImageOperation to the chain.
+ * @param instr The Rotate operation to add to the chain.
+ * @see org.apache.tools.ant.types.optional.image.Rotate
+ */
+ public void addRotate(Rotate instr) {
+ instructions.add(instr);
+ }
+
+ /**
+ * Add a Scale ImageOperation to the chain.
+ * @param instr The Scale operation to add to the chain.
+ * @see org.apache.tools.ant.types.optional.image.Scale
+ */
+ public void addScale(Scale instr) {
+ instructions.add(instr);
+ }
+
+ /**
+ * Add a Draw ImageOperation to the chain. DrawOperation
+ * DataType objects can be nested inside the Draw object.
+ * @param instr The Draw operation to add to the chain.
+ * @see org.apache.tools.ant.types.optional.image.Draw
+ * @see org.apache.tools.ant.types.optional.image.DrawOperation
+ */
+ public void addDraw(Draw instr) {
+ instructions.add(instr);
+ }
+
+ /**
+ * Add an ImageOperation to chain.
+ * @param instr The ImageOperation to append to the chain.
+ * @since Ant 1.7
+ */
+ public void add(ImageOperation instr) {
+ addImageOperation(instr);
+ }
+
+ /**
+ * Defines the mapper to map source to destination files.
+ * @return a mapper to be configured
+ * @exception BuildException if more than one mapper is defined
+ * @since Ant 1.8.0
+ */
+ public Mapper createMapper() throws BuildException {
+ if (mapperElement != null) {
+ throw new BuildException("Cannot define more than one mapper",
+ getLocation());
+ }
+ mapperElement = new Mapper(getProject());
+ return mapperElement;
+ }
+
+ /**
+ * Add a nested filenamemapper.
+ * @param fileNameMapper the mapper to add.
+ * @since Ant 1.8.0
+ */
+ public void add(FileNameMapper fileNameMapper) {
+ createMapper().add(fileNameMapper);
+ }
+
+ /**
+ * Executes all the chained ImageOperations on the files inside
+ * the directory.
+ * @since Ant 1.8.0
+ */
+ public int processDir(final File srcDir, final String[] srcNames,
+ final File dstDir, final FileNameMapper mapper) {
+ int writeCount = 0;
+
+ for (int i = 0; i < srcNames.length; ++i) {
+ final String srcName = srcNames[i];
+ final File srcFile = new File(srcDir, srcName).getAbsoluteFile();
+
+ final String[] dstNames = mapper.mapFileName(srcName);
+ if (dstNames == null) {
+ log(srcFile + " skipped, don't know how to handle it",
+ Project.MSG_VERBOSE);
+ continue;
+ }
+
+ for (int j = 0; j < dstNames.length; ++j){
+
+ final String dstName = dstNames[j];
+ final File dstFile = new File(dstDir, dstName).getAbsoluteFile();
+
+ if (dstFile.exists()){
+ // avoid overwriting unless necessary
+ if(!overwrite
+ && srcFile.lastModified() <= dstFile.lastModified()) {
+
+ log(srcFile + " omitted as " + dstFile
+ + " is up to date.", Project.MSG_VERBOSE);
+
+ // don't overwrite the file
+ continue;
+ }
+
+ // avoid extra work while overwriting
+ if (!srcFile.equals(dstFile)){
+ dstFile.delete();
+ }
+ }
+ processFile(srcFile, dstFile);
+ ++writeCount;
+ }
+ }
+
+ // run the garbage collector if wanted
+ if (garbage_collect) {
+ System.gc();
+ }
+
+ return writeCount;
+ }
+
+ /**
+ * Executes all the chained ImageOperations on the file
+ * specified.
+ * @param file The file to be processed.
+ * @deprecated this method isn't used anymore
+ */
+ public void processFile(File file) {
+ processFile(file, new File(destDir == null
+ ? srcDir : destDir, file.getName()));
+ }
+
+ /**
+ * Executes all the chained ImageOperations on the file
+ * specified.
+ * @param file The file to be processed.
+ * @param newFile The file to write to.
+ * @since Ant 1.8.0
+ */
+ public void processFile(File file, File newFile) {
+ try {
+ log("Processing File: " + file.getAbsolutePath());
+
+ FileSeekableStream input = null;
+ PlanarImage image = null;
+ try {
+ input = new FileSeekableStream(file);
+ image = JAI.create("stream", input);
+ final int size = instructions.size();
+ for (int i = 0; i < size; i++) {
+ Object instr = instructions.elementAt(i);
+ if (instr instanceof TransformOperation) {
+ image = ((TransformOperation) instr)
+ .executeTransformOperation(image);
+ } else {
+ log("Not a TransformOperation: " + instr);
+ }
+ }
+ } finally {
+ FileUtils.close(input);
+ }
+
+ File dstParent = newFile.getParentFile();
+ if (!dstParent.isDirectory()
+ && !(dstParent.mkdirs() || dstParent.isDirectory())) {
+ throw new BuildException("Failed to create parent directory "
+ + dstParent);
+ }
+
+ if ((overwrite && newFile.exists()) && (!newFile.equals(file))) {
+ newFile.delete();
+ }
+
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(newFile);
+
+ JAI.create("encode", image, stream,
+ str_encoding.toUpperCase(Locale.ENGLISH),
+ null);
+ stream.flush();
+ } finally {
+ FileUtils.close(stream);
+ }
+ } catch (IOException err) {
+ if (!file.equals(newFile)){
+ newFile.delete();
+ }
+ if (!failonerror) {
+ log("Error processing file: " + err);
+ } else {
+ throw new BuildException(err);
+ }
+ } catch (java.lang.RuntimeException rerr) {
+ if (!file.equals(newFile)){
+ newFile.delete();
+ }
+ if (!failonerror) {
+ log("Error processing file: " + rerr);
+ } else {
+ throw new BuildException(rerr);
+ }
+ }
+ }
+
+ /**
+ * Executes the Task.
+ * @throws BuildException on error.
+ */
+ public void execute() throws BuildException {
+
+ validateAttributes();
+
+ try {
+ File dest = destDir != null ? destDir : srcDir;
+
+ int writeCount = 0;
+
+ // build mapper
+ final FileNameMapper mapper;
+ if (mapperElement==null){
+ mapper = new IdentityMapper();
+ } else {
+ mapper = mapperElement.getImplementation();
+ }
+
+ // deal with specified srcDir
+ if (srcDir != null) {
+ final DirectoryScanner ds = super.getDirectoryScanner(srcDir);
+
+ final String[] files = ds.getIncludedFiles();
+ writeCount += processDir(srcDir, files, dest, mapper);
+ }
+ // deal with the filesets
+ final int size = filesets.size();
+ for (int i = 0; i < size; i++) {
+ final FileSet fs = (FileSet) filesets.elementAt(i);
+ final DirectoryScanner ds =
+ fs.getDirectoryScanner(getProject());
+ final String[] files = ds.getIncludedFiles();
+ final File fromDir = fs.getDir(getProject());
+ writeCount += processDir(fromDir, files, dest, mapper);
+ }
+
+ if (writeCount>0){
+ log("Processed " + writeCount +
+ (writeCount == 1 ? " image." : " images."));
+ }
+
+ } catch (Exception err) {
+ err.printStackTrace();
+ throw new BuildException(err.getMessage());
+ }
+ }
+
+ /**
+ * Ensure we have a consistent and legal set of attributes, and set
+ * any internal flags necessary based on different combinations
+ * of attributes.
+ * @throws BuildException on error.
+ */
+ protected void validateAttributes() throws BuildException {
+ if (srcDir == null && filesets.size() == 0) {
+ throw new BuildException("Specify at least one source"
+ + "--a srcDir or a fileset.");
+ }
+ if (srcDir == null && destDir == null) {
+ throw new BuildException("Specify the destDir, or the srcDir.");
+ }
+ if (str_encoding.equalsIgnoreCase("jpg")) {
+ str_encoding = "JPEG";
+ } else if (str_encoding.equalsIgnoreCase("tif")) {
+ str_encoding = "TIFF";
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java
new file mode 100644
index 00000000..fdbde749
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Abstract class to support vendor-specific hot deployment tools.
+ * This class will validate boilerplate attributes.
+ *
+ * Subclassing this class for a vendor specific tool involves the
+ * following.
+ * <ol><li>Implement the <code>isActionValid()<code> method to insure the
+ * action supplied as the "action" attribute of ServerDeploy is valid.
+ * <li>Implement the <code>validateAttributes()</code> method to insure
+ * all required attributes are supplied, and are in the correct format.
+ * <li>Add a <code>add&lt;TOOL&gt;</code> method to the ServerDeploy
+ * class. This method will be called when Ant encounters a
+ * <code>add&lt;TOOL&gt;</code> task nested in the
+ * <code>serverdeploy</code> task.
+ * <li>Define the <code>deploy</code> method. This method should perform
+ * whatever task it takes to hot-deploy the component. IE: spawn a JVM and
+ * run class, exec a native executable, run Java code...
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public abstract class AbstractHotDeploymentTool implements HotDeploymentTool {
+ /** The parent task **/
+ private ServerDeploy task;
+
+ /** The classpath passed to the JVM on execution. **/
+ private Path classpath;
+
+ /** The username for the deployment server. **/
+ private String userName;
+
+ /** The password for the deployment server. **/
+ private String password;
+
+ /** The address of the deployment server **/
+ private String server;
+
+ /**
+ * Add a classpath as a nested element.
+ * @return A Path object representing the classpath to be used.
+ */
+ public Path createClasspath() {
+ if (classpath == null) {
+ classpath = new Path(task.getProject());
+ }
+ return classpath.createPath();
+ }
+
+ /**
+ * Determines if the "action" attribute defines a valid action.
+ * <p>Subclasses should determine if the action passed in is
+ * supported by the vendor's deployment tool.
+ * <p>Actions may by "deploy", "delete", etc... It all depends
+ * on the tool.
+ * @return true if the "action" attribute is valid, false if not.
+ */
+ protected abstract boolean isActionValid();
+
+ /**
+ * Validates the passed in attributes.
+ * Subclasses should chain to this super-method to insure
+ * validation of boilerplate attributes.
+ * <p>Only the "action" attribute is required in the
+ * base class. Subclasses should check attributes accordingly.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ public void validateAttributes() throws BuildException {
+ if (task.getAction() == null) {
+ throw new BuildException("The \"action\" attribute must be set");
+ }
+
+ if (!isActionValid()) {
+ throw new BuildException("Invalid action \"" + task.getAction() + "\" passed");
+ }
+
+ if (classpath == null) {
+ throw new BuildException("The classpath attribute must be set");
+ }
+ }
+
+ /**
+ * Perform the actual deployment.
+ * It's up to the subclasses to implement the actual behavior.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ public abstract void deploy() throws BuildException;
+
+ /**
+ * Sets the parent task.
+ * @param task a ServerDeploy object representing the parent task.
+ * @ant.attribute ignore="true"
+ */
+ public void setTask(ServerDeploy task) {
+ this.task = task;
+ }
+
+ /**
+ * Returns the task field, a ServerDeploy object.
+ * @return An ServerDeploy representing the parent task.
+ */
+ protected ServerDeploy getTask() {
+ return task;
+ }
+
+ /**
+ * gets the classpath field.
+ * @return A Path representing the "classpath" attribute.
+ */
+ public Path getClasspath() {
+ return classpath;
+ }
+
+ /**
+ * The classpath to be passed to the JVM running the tool;
+ * optional depending upon the tool.
+ * The classpath may also be supplied as a nested element.
+ * @param classpath A Path object representing the "classpath" attribute.
+ */
+ public void setClasspath(Path classpath) {
+ this.classpath = classpath;
+ }
+
+ /**
+ * Returns the userName field.
+ * @return A String representing the "userName" attribute.
+ */
+ public String getUserName() {
+ return userName;
+ }
+
+ /**
+ * The user with privileges to deploy applications to the server; optional.
+ * @param userName A String representing the "userName" attribute.
+ */
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ /**
+ * Returns the password field.
+ * @return A String representing the "password" attribute.
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * The password of the user; optional.
+ * @param password A String representing the "password" attribute.
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Returns the server field.
+ * @return A String representing the "server" attribute.
+ */
+ public String getServer() {
+ return server;
+ }
+
+ /**
+ * The address or URL for the server where the component will be deployed.
+ * @param server A String representing the "server" attribute.
+ */
+ public void setServer(String server) {
+ this.server = server;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java
new file mode 100644
index 00000000..5a5abbab
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * A generic tool for J2EE server hot deployment.
+ * <p>The simple implementation spawns a JVM with the supplied
+ * class name, jvm args, and arguments.
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public class GenericHotDeploymentTool extends AbstractHotDeploymentTool {
+ /** A Java task used to run the deployment tool **/
+ private Java java;
+
+ /** The fully qualified class name of the deployment tool **/
+ private String className;
+
+ /** List of valid actions **/
+ private static final String[] VALID_ACTIONS = {ACTION_DEPLOY};
+
+ /**
+ * Add a nested argument element to hand to the deployment tool; optional.
+ * @return A Commandline.Argument object representing the
+ * command line argument being passed when the deployment
+ * tool is run. IE: "-user=mark", "-password=venture"...
+ */
+ public Commandline.Argument createArg() {
+ return java.createArg();
+ }
+
+ /**
+ * Add a nested argument element to hand to the JVM running the
+ * deployment tool.
+ * Creates a nested arg element.
+ * @return A Commandline.Argument object representing the
+ * JVM command line argument being passed when the deployment
+ * tool is run. IE: "-ms64m", "-mx128m"...
+ */
+ public Commandline.Argument createJvmarg() {
+ return java.createJvmarg();
+ }
+
+ /**
+ * Determines if the "action" attribute defines a valid action.
+ * <p>Subclasses should determine if the action passed in is
+ * supported by the vendor's deployment tool.
+ * For this generic implementation, the only valid action is "deploy"
+ * @return true if the "action" attribute is valid, false if not.
+ */
+ protected boolean isActionValid() {
+ return (getTask().getAction().equals(VALID_ACTIONS[0]));
+ }
+
+ /**
+ * Sets the parent task.
+ * @param task An ServerDeploy object representing the parent task.
+ * @ant.attribute ignored="true"
+ */
+ public void setTask(ServerDeploy task) {
+ super.setTask(task);
+ java = new Java(task);
+ }
+
+ /**
+ * Perform the actual deployment.
+ * For this generic implementation, a JVM is spawned using the
+ * supplied classpath, classname, JVM args, and command line arguments.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ public void deploy() throws BuildException {
+ java.setClassname(className);
+ java.setClasspath(getClasspath());
+ java.setFork(true);
+ java.setFailonerror(true);
+ java.execute();
+ }
+
+ /**
+ * Validates the passed in attributes.
+ * Ensures the className and arguments attribute have been set.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ public void validateAttributes() throws BuildException {
+ super.validateAttributes();
+
+ if (className == null) {
+ throw new BuildException("The classname attribute must be set");
+ }
+ }
+
+ /**
+ * The name of the class to execute to perform
+ * deployment; required.
+ * Example: "com.foobar.tools.deploy.DeployTool"
+ * @param className The fully qualified class name of the class
+ * to perform deployment.
+ */
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ /**
+ * get the java attribute.
+ * @return the java attribute.
+ */
+ public Java getJava() {
+ return java;
+ }
+
+ /**
+ * Get the classname attribute.
+ * @return the classname value.
+ */
+ public String getClassName() {
+ return className;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java
new file mode 100644
index 00000000..16c55d8e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * An interface for vendor-specific "hot" deployment tools.
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public interface HotDeploymentTool {
+ /** The delete action String **/
+ String ACTION_DELETE = "delete";
+
+ /** The deploy action String **/
+ String ACTION_DEPLOY = "deploy";
+
+ /** The list action String **/
+ String ACTION_LIST = "list";
+
+ /** The undeploy action String **/
+ String ACTION_UNDEPLOY = "undeploy";
+
+ /** The update action String **/
+ String ACTION_UPDATE = "update";
+
+ /**
+ * Validates the passed in attributes.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ void validateAttributes() throws BuildException;
+
+ /**
+ * Perform the actual deployment.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ void deploy() throws BuildException;
+
+ /**
+ * Sets the parent task.
+ * @param task A ServerDeploy object representing the parent task.
+ */
+ void setTask(ServerDeploy task);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java
new file mode 100644
index 00000000..c7a33a19
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * An Ant wrapper task for the weblogic.deploy tool. This is used
+ * to hot-deploy J2EE applications to a running WebLogic server.
+ * This is <b>not</b> the same as creating the application
+ * archive. This task assumes the archive (EAR, JAR, or WAR) file
+ * has been assembled and is supplied as the "source" attribute.
+ * <p>
+ *
+ * In the end, this task assembles the commandline parameters and
+ * runs the weblogic.deploy tool in a separate JVM.
+ *
+ *@see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ *@see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ *@see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public class JonasHotDeploymentTool extends GenericHotDeploymentTool implements HotDeploymentTool {
+
+ /**
+ * Description of the Field
+ */
+ protected static final String DEFAULT_ORB = "RMI";
+
+ /**
+ * The classname of the tool to run *
+ */
+ private static final String JONAS_DEPLOY_CLASS_NAME = "org.objectweb.jonas.adm.JonasAdmin";
+
+ /**
+ * All the valid actions that weblogic.deploy permits *
+ */
+ private static final String[] VALID_ACTIONS
+ = {ACTION_DELETE, ACTION_DEPLOY, ACTION_LIST, ACTION_UNDEPLOY, ACTION_UPDATE};
+
+ /**
+ * Description of the Field
+ */
+ private File jonasroot;
+
+ /**
+ * Description of the Field
+ */
+ private String orb = null;
+
+ /**
+ * Description of the Field
+ */
+ private String davidHost;
+
+ /**
+ * Description of the Field
+ */
+ private int davidPort;
+
+
+ /**
+ * Set the host for the David ORB; required if
+ * ORB==david.
+ *
+ *@param inValue The new davidhost value
+ */
+ public void setDavidhost(final String inValue) {
+ davidHost = inValue;
+ }
+
+
+ /**
+ * Set the port for the David ORB; required if
+ * ORB==david.
+ *
+ *@param inValue The new davidport value
+ */
+ public void setDavidport(final int inValue) {
+ davidPort = inValue;
+ }
+
+
+ /**
+ * set the jonas root directory (-Dinstall.root=). This
+ * element is required.
+ *
+ *@param inValue The new jonasroot value
+ */
+ public void setJonasroot(final File inValue) {
+ jonasroot = inValue;
+ }
+
+
+ /**
+ *
+ * Choose your ORB : RMI, JEREMIE, DAVID, ...; optional.
+ * If omitted, it defaults
+ * to the one present in classpath. The corresponding JOnAS JAR is
+ * automatically added to the classpath. If your orb is DAVID (RMI/IIOP) you must
+ * specify davidhost and davidport properties.
+ *
+ *@param inValue RMI, JEREMIE, DAVID,...
+ */
+ public void setOrb(final String inValue) {
+ orb = inValue;
+ }
+
+
+ /**
+ * gets the classpath field.
+ *
+ *@return A Path representing the "classpath" attribute.
+ */
+ public Path getClasspath() {
+
+ Path aClassPath = super.getClasspath();
+
+ if (aClassPath == null) {
+ aClassPath = new Path(getTask().getProject());
+ }
+ if (orb != null) {
+ String aOrbJar = new File(jonasroot, "lib/" + orb + "_jonas.jar").toString();
+ String aConfigDir = new File(jonasroot, "config/").toString();
+ Path aJOnASOrbPath = new Path(aClassPath.getProject(),
+ aOrbJar + File.pathSeparator + aConfigDir);
+ aClassPath.append(aJOnASOrbPath);
+ }
+ return aClassPath;
+ }
+
+
+ /**
+ * Validates the passed in attributes. <p>
+ *
+ * The rules are:
+ * <ol>
+ * <li> If action is "deploy" or "update" the "application"
+ * and "source" attributes must be supplied.
+ * <li> If action is "delete" or "undeploy" the
+ * "application" attribute must be supplied.
+ *
+ *@exception BuildException Description
+ * of Exception
+ */
+ public void validateAttributes() throws BuildException {
+ // super.validateAttributes(); // don't want to call this method
+
+ Java java = getJava();
+
+ String action = getTask().getAction();
+ if (action == null) {
+ throw new BuildException("The \"action\" attribute must be set");
+ }
+
+ if (!isActionValid()) {
+ throw new BuildException("Invalid action \"" + action + "\" passed");
+ }
+
+ if (getClassName() == null) {
+ setClassName(JONAS_DEPLOY_CLASS_NAME);
+ }
+
+ if (jonasroot == null || jonasroot.isDirectory()) {
+ java.createJvmarg().setValue("-Dinstall.root=" + jonasroot);
+ java.createJvmarg().setValue("-Djava.security.policy=" + jonasroot
+ + "/config/java.policy");
+
+ if ("DAVID".equals(orb)) {
+ java.createJvmarg().setValue("-Dorg.omg.CORBA.ORBClass"
+ + "=org.objectweb.david.libs.binding.orbs.iiop.IIOPORB");
+ java.createJvmarg().setValue("-Dorg.omg.CORBA.ORBSingletonClass="
+ + "org.objectweb.david.libs.binding.orbs.ORBSingletonClass");
+ java.createJvmarg().setValue("-Djavax.rmi.CORBA.StubClass="
+ + "org.objectweb.david.libs.stub_factories.rmi.StubDelegate");
+ java.createJvmarg().setValue("-Djavax.rmi.CORBA.PortableRemoteObjectClass="
+ + "org.objectweb.david.libs.binding.rmi.ORBPortableRemoteObjectDelegate");
+ java.createJvmarg().setValue("-Djavax.rmi.CORBA.UtilClass="
+ + "org.objectweb.david.libs.helpers.RMIUtilDelegate");
+ java.createJvmarg().setValue("-Ddavid.CosNaming.default_method=0");
+ java.createJvmarg().setValue("-Ddavid.rmi.ValueHandlerClass="
+ + "com.sun.corba.se.internal.io.ValueHandlerImpl");
+ if (davidHost != null) {
+ java.createJvmarg().setValue("-Ddavid.CosNaming.default_host="
+ + davidHost);
+ }
+ if (davidPort != 0) {
+ java.createJvmarg().setValue("-Ddavid.CosNaming.default_port="
+ + davidPort);
+ }
+ }
+ }
+
+ if (getServer() != null) {
+ java.createArg().setLine("-n " + getServer());
+ }
+
+ if (action.equals(ACTION_DEPLOY)
+ || action.equals(ACTION_UPDATE)
+ || action.equals("redeploy")) {
+ java.createArg().setLine("-a " + getTask().getSource());
+ } else if (action.equals(ACTION_DELETE) || action.equals(ACTION_UNDEPLOY)) {
+ java.createArg().setLine("-r " + getTask().getSource());
+ } else if (action.equals(ACTION_LIST)) {
+ java.createArg().setValue("-l");
+ }
+ }
+
+
+ /**
+ * Determines if the action supplied is valid. <p>
+ *
+ * Valid actions are contained in the static array
+ * VALID_ACTIONS
+ *
+ *@return true if the action attribute is valid, false if
+ * not.
+ */
+ protected boolean isActionValid() {
+ boolean valid = false;
+
+ String action = getTask().getAction();
+
+ for (int i = 0; i < VALID_ACTIONS.length; i++) {
+ if (action.equals(VALID_ACTIONS[i])) {
+ valid = true;
+ break;
+ }
+ }
+
+ return valid;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java
new file mode 100644
index 00000000..8965b8e8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Controls hot deployment tools for J2EE servers.
+ *
+ * This class is used as a framework for the creation of vendor specific
+ * hot deployment tools.
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.GenericHotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.WebLogicHotDeploymentTool
+ */
+public class ServerDeploy extends Task {
+ /** The action to be performed. IE: "deploy", "delete", etc... **/
+ private String action;
+
+ /** The source (fully-qualified path) to the component being deployed **/
+ private File source;
+
+ /** The vendor specific tool for deploying the component **/
+ private Vector vendorTools = new Vector();
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Place vendor specific tool creations here.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a generic deployment tool.
+ * <p>Ant calls this method on creation to handle embedded "generic" elements
+ * in the ServerDeploy task.
+ * @param tool An instance of GenericHotDeployment tool, passed in by Ant.
+ */
+ public void addGeneric(GenericHotDeploymentTool tool) {
+ tool.setTask(this);
+ vendorTools.addElement(tool);
+ }
+
+ /**
+ * Creates a WebLogic deployment tool, for deployment to WebLogic servers.
+ * <p>Ant calls this method on creation to handle embedded "weblogic" elements
+ * in the ServerDeploy task.
+ * @param tool An instance of WebLogicHotDeployment tool, passed in by Ant.
+ */
+ public void addWeblogic(WebLogicHotDeploymentTool tool) {
+ tool.setTask(this);
+ vendorTools.addElement(tool);
+ }
+
+ /**
+ * Creates a JOnAS deployment tool, for deployment to JOnAS servers.
+ * <p>Ant calls this method on creation to handle embedded "jonas" elements
+ * in the ServerDeploy task.
+ * @param tool An instance of JonasHotDeployment tool, passed in by Ant.
+ */
+ public void addJonas(JonasHotDeploymentTool tool) {
+ tool.setTask(this);
+ vendorTools.addElement(tool);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Execute method
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Execute the task.
+ * <p>This method calls the deploy() method on each of the vendor-specific tools
+ * in the <code>vendorTools</code> collection. This performs the actual
+ * process of deployment on each tool.
+ * @exception org.apache.tools.ant.BuildException if the attributes
+ * are invalid or incomplete, or a failure occurs in the deployment process.
+ */
+ public void execute() throws BuildException {
+ for (Enumeration e = vendorTools.elements();
+ e.hasMoreElements();) {
+ HotDeploymentTool tool = (HotDeploymentTool) e.nextElement();
+ tool.validateAttributes();
+ tool.deploy();
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Set/get methods
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the action field.
+ * @return A string representing the "action" attribute.
+ */
+ public String getAction() {
+ return action;
+ }
+
+ /**
+ * The action to be performed, usually "deploy"; required.
+ * Some tools support additional actions, such as "delete", "list", "undeploy", "update"...
+ * @param action A String representing the "action" attribute.
+ */
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ /**
+ * Returns the source field (the path/filename of the component to be
+ * deployed.
+ * @return A File object representing the "source" attribute.
+ */
+ public File getSource() {
+ return source;
+ }
+
+ /**
+ * The filename of the component to be deployed; optional
+ * depending upon the tool and the action.
+ * @param source String representing the "source" attribute.
+ */
+ public void setSource(File source) {
+ this.source = source;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java
new file mode 100644
index 00000000..da875092
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+
+/**
+ * An Ant wrapper task for the weblogic.deploy tool. This is used to
+ * hot-deploy J2EE applications to a running WebLogic server.
+ * This is <b>not</b> the same as creating the application archive.
+ * This task assumes the archive (EAR, JAR, or WAR) file has been
+ * assembled and is supplied as the "source" attribute.
+ * <p>In the end, this task assembles the commandline parameters
+ * and runs the weblogic.deploy tool in a separate JVM.
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ * @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public class WebLogicHotDeploymentTool extends AbstractHotDeploymentTool
+ implements HotDeploymentTool {
+ private static final int STRING_BUFFER_SIZE = 1024;
+ /** The classname of the tool to run **/
+ private static final String WEBLOGIC_DEPLOY_CLASS_NAME = "weblogic.deploy";
+
+ /** All the valid actions that weblogic.deploy permits **/
+ private static final String[] VALID_ACTIONS
+ = {ACTION_DELETE, ACTION_DEPLOY, ACTION_LIST, ACTION_UNDEPLOY, ACTION_UPDATE};
+
+ /** Represents the "-debug" flag from weblogic.deploy **/
+ private boolean debug;
+
+ /** The application name that is being deployed **/
+ private String application;
+
+ /** The component name:target(s) for the "-component" argument of weblogic.deploy **/
+ private String component;
+
+ /**
+ * Perform the actual deployment.
+ * For this implementation, a JVM is spawned and the weblogic.deploy
+ * tools is executed.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+ */
+ public void deploy() {
+ Java java = new Java(getTask());
+ java.setFork(true);
+ java.setFailonerror(true);
+ java.setClasspath(getClasspath());
+
+ java.setClassname(WEBLOGIC_DEPLOY_CLASS_NAME);
+ java.createArg().setLine(getArguments());
+ java.execute();
+ }
+
+ /**
+ * Validates the passed in attributes.
+ * <p>The rules are:
+ * <ol><li>If action is "deploy" or "update" the "application" and "source"
+ * attributes must be supplied.
+ * <li>If action is "delete" or "undeploy" the "application" attribute must
+ * be supplied.
+ * @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete
+ */
+ public void validateAttributes() throws BuildException {
+ super.validateAttributes();
+
+ String action = getTask().getAction();
+
+ // check that the password has been set
+ if ((getPassword() == null)) {
+ throw new BuildException("The password attribute must be set.");
+ }
+
+ // check for missing application on deploy & update
+ if ((action.equals(ACTION_DEPLOY) || action.equals(ACTION_UPDATE))
+ && application == null) {
+ throw new BuildException("The application attribute must be set "
+ + "if action = " + action);
+ }
+
+ // check for missing source on deploy & update
+ if ((action.equals(ACTION_DEPLOY) || action.equals(ACTION_UPDATE))
+ && getTask().getSource() == null) {
+ throw new BuildException("The source attribute must be set if "
+ + "action = " + action);
+ }
+
+ // check for missing application on delete & undeploy
+ if ((action.equals(ACTION_DELETE) || action.equals(ACTION_UNDEPLOY))
+ && application == null) {
+ throw new BuildException("The application attribute must be set if "
+ + "action = " + action);
+ }
+ }
+
+ /**
+ * Builds the arguments to pass to weblogic.deploy according to the
+ * supplied action.
+ * @return A String containing the arguments for the weblogic.deploy tool.
+ * @throws BuildException if there is an error.
+ */
+ public String getArguments() throws BuildException {
+ String action = getTask().getAction();
+ String args = null;
+
+ if (action.equals(ACTION_DEPLOY) || action.equals(ACTION_UPDATE)) {
+ args = buildDeployArgs();
+ } else if (action.equals(ACTION_DELETE) || action.equals(ACTION_UNDEPLOY)) {
+ args = buildUndeployArgs();
+ } else if (action.equals(ACTION_LIST)) {
+ args = buildListArgs();
+ }
+
+ return args;
+ }
+
+ /**
+ * Determines if the action supplied is valid.
+ * <p>Valid actions are contained in the static array VALID_ACTIONS
+ * @return true if the action attribute is valid, false if not.
+ */
+ protected boolean isActionValid() {
+ boolean valid = false;
+
+ String action = getTask().getAction();
+
+ for (int i = 0; i < VALID_ACTIONS.length; i++) {
+ if (action.equals(VALID_ACTIONS[i])) {
+ valid = true;
+ break;
+ }
+ }
+
+ return valid;
+ }
+
+ /**
+ * Builds the prefix arguments to pass to weblogic.deploy.
+ * These arguments are generic across all actions.
+ * @return A StringBuffer containing the prefix arguments.
+ * The action-specific build methods will append to this StringBuffer.
+ */
+ protected StringBuffer buildArgsPrefix() {
+ ServerDeploy task = getTask();
+ // constructs the "-url <url> -debug <action> <password>" portion
+ // of the commmand line
+ return new StringBuffer(STRING_BUFFER_SIZE)
+ .append((getServer() != null)
+ ? "-url " + getServer()
+ : "")
+ .append(" ")
+ .append(debug ? "-debug " : "")
+ .append((getUserName() != null)
+ ? "-username " + getUserName()
+ : "")
+ .append(" ")
+ .append(task.getAction()).append(" ")
+ .append(getPassword()).append(" ");
+ }
+
+ /**
+ * Builds the arguments to pass to weblogic.deploy for deployment actions
+ * ("deploy" and "update").
+ * @return A String containing the full argument string for weblogic.deploy.
+ */
+ protected String buildDeployArgs() {
+ String args = buildArgsPrefix()
+ .append(application).append(" ")
+ .append(getTask().getSource())
+ .toString();
+
+ if (component != null) {
+ args = "-component " + component + " " + args;
+ }
+
+ return args;
+ }
+
+ /**
+ * Builds the arguments to pass to weblogic.deploy for undeployment actions
+ * ("undeploy" and "delete").
+ * @return A String containing the full argument string for weblogic.deploy.
+ */
+ protected String buildUndeployArgs() {
+ return buildArgsPrefix()
+ .append(application).append(" ")
+ .toString();
+ }
+
+ /**
+ * Builds the arguments to pass to weblogic.deploy for the list action
+ * @return A String containing the full argument string for weblogic.deploy.
+ */
+ protected String buildListArgs() {
+ return buildArgsPrefix()
+ .toString();
+ }
+
+ /**
+ * If set to true, additional information will be
+ * printed during the deployment process; optional.
+ * @param debug A boolean representing weblogic.deploy "-debug" flag.
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * The name of the application being deployed; required.
+ * @param application A String representing the application portion of the
+ * weblogic.deploy command line.
+ */
+ public void setApplication(String application) {
+ this.application = application;
+ }
+
+ /**
+ * the component string for the deployment targets; optional.
+ * It is in the form <code>&lt;component&gt;:&lt;target1&gt;,&lt;target2&gt;...</code>
+ * Where component is the archive name (minus the .jar, .ear, .war
+ * extension). Targets are the servers where the components will be deployed
+
+ * @param component A String representing the value of the "-component"
+ * argument of the weblogic.deploy command line argument.
+ */
+ public void setComponent(String component) {
+ this.component = component;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java
new file mode 100644
index 00000000..a4dc0f48
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javacc;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Runs the JJDoc compiler compiler.
+ *
+ */
+public class JJDoc extends Task {
+
+ // keys to optional attributes
+ private static final String OUTPUT_FILE = "OUTPUT_FILE";
+ private static final String TEXT = "TEXT";
+ private static final String ONE_TABLE = "ONE_TABLE";
+
+ private final Hashtable optionalAttrs = new Hashtable();
+
+ private String outputFile = null;
+ private boolean plainText = false;
+
+ private static final String DEFAULT_SUFFIX_HTML = ".html";
+ private static final String DEFAULT_SUFFIX_TEXT = ".txt";
+
+ // required attributes
+ private File targetFile = null;
+ private File javaccHome = null;
+
+ private CommandlineJava cmdl = new CommandlineJava();
+
+ private String maxMemory = null;
+
+ /**
+ * Sets the TEXT BNF documentation option.
+ * @param plainText a <code>boolean</code> value.
+ */
+ public void setText(boolean plainText) {
+ optionalAttrs.put(TEXT, plainText ? Boolean.TRUE : Boolean.FALSE);
+ this.plainText = plainText;
+ }
+
+ /**
+ * Sets the ONE_TABLE documentation option.
+ * @param oneTable a <code>boolean</code> value.
+ */
+ public void setOnetable(boolean oneTable) {
+ optionalAttrs.put(ONE_TABLE, oneTable ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * The outputfile to write the generated BNF documentation file to.
+ * If not set, the file is written with the same name as
+ * the JavaCC grammar file with a suffix .html or .txt.
+ * @param outputFile the name of the output file.
+ */
+ public void setOutputfile(String outputFile) {
+ this.outputFile = outputFile;
+ }
+
+ /**
+ * The javacc grammar file to process.
+ * @param target the grammar file.
+ */
+ public void setTarget(File target) {
+ this.targetFile = target;
+ }
+
+ /**
+ * The directory containing the JavaCC distribution.
+ * @param javaccHome the home directory.
+ */
+ public void setJavacchome(File javaccHome) {
+ this.javaccHome = javaccHome;
+ }
+
+ /**
+ * Corresponds -Xmx.
+ *
+ * @param max max memory parameter.
+ * @since Ant 1.8.3
+ */
+ public void setMaxmemory(String max) {
+ maxMemory = max;
+ }
+
+ /**
+ * Constructor
+ */
+ public JJDoc() {
+ cmdl.setVm(JavaEnvUtils.getJreExecutable("java"));
+ }
+
+ /**
+ * Do the task.
+ * @throws BuildException if there is an error.
+ */
+ public void execute() throws BuildException {
+
+ // load command line with optional attributes
+ Enumeration iter = optionalAttrs.keys();
+ while (iter.hasMoreElements()) {
+ String name = (String) iter.nextElement();
+ Object value = optionalAttrs.get(name);
+ cmdl.createArgument()
+ .setValue("-" + name + ":" + value.toString());
+ }
+
+ if (targetFile == null || !targetFile.isFile()) {
+ throw new BuildException("Invalid target: " + targetFile);
+ }
+
+ if (outputFile != null) {
+ cmdl.createArgument() .setValue("-" + OUTPUT_FILE + ":"
+ + outputFile.replace('\\', '/'));
+ }
+
+ // use the directory containing the target as the output directory
+ File javaFile = new File(createOutputFileName(targetFile, outputFile,
+ plainText));
+
+ if (javaFile.exists()
+ && targetFile.lastModified() < javaFile.lastModified()) {
+ log("Target is already built - skipping (" + targetFile + ")",
+ Project.MSG_VERBOSE);
+ return;
+ }
+
+ cmdl.createArgument().setValue(targetFile.getAbsolutePath());
+
+ final Path classpath = cmdl.createClasspath(getProject());
+ final File javaccJar = JavaCC.getArchiveFile(javaccHome);
+ classpath.createPathElement().setPath(javaccJar.getAbsolutePath());
+ classpath.addJavaRuntime();
+
+ cmdl.setClassname(JavaCC.getMainClass(classpath,
+ JavaCC.TASKDEF_TYPE_JJDOC));
+
+ cmdl.setMaxmemory(maxMemory);
+ final Commandline.Argument arg = cmdl.createVmArgument();
+ arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath());
+
+ final Execute process =
+ new Execute(new LogStreamHandler(this,
+ Project.MSG_INFO,
+ Project.MSG_INFO),
+ null);
+ log(cmdl.describeCommand(), Project.MSG_VERBOSE);
+ process.setCommandline(cmdl.getCommandline());
+
+ try {
+ if (process.execute() != 0) {
+ throw new BuildException("JJDoc failed.");
+ }
+ } catch (IOException e) {
+ throw new BuildException("Failed to launch JJDoc", e);
+ }
+ }
+
+ private String createOutputFileName(File destFile, String optionalOutputFile,
+ boolean plain) {
+ String suffix = DEFAULT_SUFFIX_HTML;
+ String javaccFile = destFile.getAbsolutePath().replace('\\', '/');
+
+ if (plain) {
+ suffix = DEFAULT_SUFFIX_TEXT;
+ }
+
+ if ((optionalOutputFile == null) || optionalOutputFile.equals("")) {
+ int filePos = javaccFile.lastIndexOf("/");
+
+ if (filePos >= 0) {
+ javaccFile = javaccFile.substring(filePos + 1);
+ }
+
+ int suffixPos = javaccFile.lastIndexOf('.');
+
+ if (suffixPos == -1) {
+ optionalOutputFile = javaccFile + suffix;
+ } else {
+ String currentSuffix = javaccFile.substring(suffixPos);
+
+ if (currentSuffix.equals(suffix)) {
+ optionalOutputFile = javaccFile + suffix;
+ } else {
+ optionalOutputFile = javaccFile.substring(0, suffixPos)
+ + suffix;
+ }
+ }
+ } else {
+ optionalOutputFile = optionalOutputFile.replace('\\', '/');
+ }
+
+ return (getProject().getBaseDir() + "/" + optionalOutputFile)
+ .replace('\\', '/');
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java
new file mode 100644
index 00000000..f5d126ee
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java
@@ -0,0 +1,416 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javacc;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Runs the JJTree compiler compiler.
+ *
+ */
+public class JJTree extends Task {
+
+ // keys to optional attributes
+ private static final String OUTPUT_FILE = "OUTPUT_FILE";
+ private static final String BUILD_NODE_FILES = "BUILD_NODE_FILES";
+ private static final String MULTI = "MULTI";
+ private static final String NODE_DEFAULT_VOID = "NODE_DEFAULT_VOID";
+ private static final String NODE_FACTORY = "NODE_FACTORY";
+ private static final String NODE_SCOPE_HOOK = "NODE_SCOPE_HOOK";
+ private static final String NODE_USES_PARSER = "NODE_USES_PARSER";
+ private static final String STATIC = "STATIC";
+ private static final String VISITOR = "VISITOR";
+
+ private static final String NODE_PACKAGE = "NODE_PACKAGE";
+ private static final String VISITOR_EXCEPTION = "VISITOR_EXCEPTION";
+ private static final String NODE_PREFIX = "NODE_PREFIX";
+
+ private final Hashtable optionalAttrs = new Hashtable();
+
+ private String outputFile = null;
+
+ private static final String DEFAULT_SUFFIX = ".jj";
+
+ // required attributes
+ private File outputDirectory = null;
+ private File targetFile = null;
+ private File javaccHome = null;
+
+ private CommandlineJava cmdl = new CommandlineJava();
+
+ private String maxMemory = null;
+
+ /**
+ * Sets the BUILD_NODE_FILES grammar option.
+ * @param buildNodeFiles a <code>boolean</code> value.
+ */
+ public void setBuildnodefiles(boolean buildNodeFiles) {
+ optionalAttrs.put(BUILD_NODE_FILES, buildNodeFiles ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the MULTI grammar option.
+ * @param multi a <code>boolean</code> value.
+ */
+ public void setMulti(boolean multi) {
+ optionalAttrs.put(MULTI, multi ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the NODE_DEFAULT_VOID grammar option.
+ * @param nodeDefaultVoid a <code>boolean</code> value.
+ */
+ public void setNodedefaultvoid(boolean nodeDefaultVoid) {
+ optionalAttrs.put(NODE_DEFAULT_VOID, nodeDefaultVoid ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the NODE_FACTORY grammar option.
+ * @param nodeFactory a <code>boolean</code> value.
+ */
+ public void setNodefactory(boolean nodeFactory) {
+ optionalAttrs.put(NODE_FACTORY, nodeFactory ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the NODE_SCOPE_HOOK grammar option.
+ * @param nodeScopeHook a <code>boolean</code> value.
+ */
+ public void setNodescopehook(boolean nodeScopeHook) {
+ optionalAttrs.put(NODE_SCOPE_HOOK, nodeScopeHook ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the NODE_USES_PARSER grammar option.
+ * @param nodeUsesParser a <code>boolean</code> value.
+ */
+ public void setNodeusesparser(boolean nodeUsesParser) {
+ optionalAttrs.put(NODE_USES_PARSER, nodeUsesParser ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the STATIC grammar option.
+ * @param staticParser a <code>boolean</code> value.
+ */
+ public void setStatic(boolean staticParser) {
+ optionalAttrs.put(STATIC, staticParser ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the VISITOR grammar option.
+ * @param visitor a <code>boolean</code> value.
+ */
+ public void setVisitor(boolean visitor) {
+ optionalAttrs.put(VISITOR, visitor ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the NODE_PACKAGE grammar option.
+ * @param nodePackage the option to use.
+ */
+ public void setNodepackage(String nodePackage) {
+ optionalAttrs.put(NODE_PACKAGE, nodePackage);
+ }
+
+ /**
+ * Sets the VISITOR_EXCEPTION grammar option.
+ * @param visitorException the option to use.
+ */
+ public void setVisitorException(String visitorException) {
+ optionalAttrs.put(VISITOR_EXCEPTION, visitorException);
+ }
+
+ /**
+ * Sets the NODE_PREFIX grammar option.
+ * @param nodePrefix the option to use.
+ */
+ public void setNodeprefix(String nodePrefix) {
+ optionalAttrs.put(NODE_PREFIX, nodePrefix);
+ }
+
+ /**
+ * The directory to write the generated JavaCC grammar and node files to.
+ * If not set, the files are written to the directory
+ * containing the grammar file.
+ * @param outputDirectory the output directory.
+ */
+ public void setOutputdirectory(File outputDirectory) {
+ this.outputDirectory = outputDirectory;
+ }
+
+ /**
+ * The outputfile to write the generated JavaCC grammar file to.
+ * If not set, the file is written with the same name as
+ * the JJTree grammar file with a suffix .jj.
+ * @param outputFile the output file name.
+ */
+ public void setOutputfile(String outputFile) {
+ this.outputFile = outputFile;
+ }
+
+ /**
+ * The jjtree grammar file to process.
+ * @param targetFile the grammar file.
+ */
+ public void setTarget(File targetFile) {
+ this.targetFile = targetFile;
+ }
+
+ /**
+ * The directory containing the JavaCC distribution.
+ * @param javaccHome the directory containing JavaCC.
+ */
+ public void setJavacchome(File javaccHome) {
+ this.javaccHome = javaccHome;
+ }
+
+ /**
+ * Corresponds -Xmx.
+ *
+ * @param max max memory parameter.
+ * @since Ant 1.8.3
+ */
+ public void setMaxmemory(String max) {
+ maxMemory = max;
+ }
+
+ /**
+ * Constructor
+ */
+ public JJTree() {
+ cmdl.setVm(JavaEnvUtils.getJreExecutable("java"));
+ }
+
+ /**
+ * Run the task.
+ * @throws BuildException on error.
+ */
+ public void execute() throws BuildException {
+
+ // load command line with optional attributes
+ Enumeration iter = optionalAttrs.keys();
+ while (iter.hasMoreElements()) {
+ String name = (String) iter.nextElement();
+ Object value = optionalAttrs.get(name);
+ cmdl.createArgument().setValue("-" + name + ":" + value.toString());
+ }
+
+ if (targetFile == null || !targetFile.isFile()) {
+ throw new BuildException("Invalid target: " + targetFile);
+ }
+
+ File javaFile = null;
+
+ // use the directory containing the target as the output directory
+ if (outputDirectory == null) {
+ // convert backslashes to slashes, otherwise jjtree will
+ // put this as comments and this seems to confuse javacc
+ cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:"
+ + getDefaultOutputDirectory());
+
+ javaFile = new File(createOutputFileName(targetFile, outputFile,
+ null));
+ } else {
+ if (!outputDirectory.isDirectory()) {
+ throw new BuildException("'outputdirectory' " + outputDirectory
+ + " is not a directory.");
+ }
+
+ // convert backslashes to slashes, otherwise jjtree will
+ // put this as comments and this seems to confuse javacc
+ cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:"
+ + outputDirectory.getAbsolutePath()
+ .replace('\\', '/'));
+
+ javaFile = new File(createOutputFileName(targetFile, outputFile,
+ outputDirectory
+ .getPath()));
+ }
+
+ if (javaFile.exists()
+ && targetFile.lastModified() < javaFile.lastModified()) {
+ log("Target is already built - skipping (" + targetFile + ")",
+ Project.MSG_VERBOSE);
+ return;
+ }
+
+ if (outputFile != null) {
+ cmdl.createArgument().setValue("-" + OUTPUT_FILE + ":"
+ + outputFile.replace('\\', '/'));
+ }
+
+ cmdl.createArgument().setValue(targetFile.getAbsolutePath());
+
+ final Path classpath = cmdl.createClasspath(getProject());
+ final File javaccJar = JavaCC.getArchiveFile(javaccHome);
+ classpath.createPathElement().setPath(javaccJar.getAbsolutePath());
+ classpath.addJavaRuntime();
+
+ cmdl.setClassname(JavaCC.getMainClass(classpath,
+ JavaCC.TASKDEF_TYPE_JJTREE));
+
+ cmdl.setMaxmemory(maxMemory);
+ final Commandline.Argument arg = cmdl.createVmArgument();
+ arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath());
+
+ final Execute process =
+ new Execute(new LogStreamHandler(this,
+ Project.MSG_INFO,
+ Project.MSG_INFO),
+ null);
+ log(cmdl.describeCommand(), Project.MSG_VERBOSE);
+ process.setCommandline(cmdl.getCommandline());
+
+ try {
+ if (process.execute() != 0) {
+ throw new BuildException("JJTree failed.");
+ }
+ } catch (IOException e) {
+ throw new BuildException("Failed to launch JJTree", e);
+ }
+ }
+
+ private String createOutputFileName(File destFile, String optionalOutputFile,
+ String outputDir) {
+ optionalOutputFile = validateOutputFile(optionalOutputFile,
+ outputDir);
+ String jjtreeFile = destFile.getAbsolutePath().replace('\\', '/');
+
+ if ((optionalOutputFile == null) || optionalOutputFile.equals("")) {
+ int filePos = jjtreeFile.lastIndexOf("/");
+
+ if (filePos >= 0) {
+ jjtreeFile = jjtreeFile.substring(filePos + 1);
+ }
+
+ int suffixPos = jjtreeFile.lastIndexOf('.');
+
+ if (suffixPos == -1) {
+ optionalOutputFile = jjtreeFile + DEFAULT_SUFFIX;
+ } else {
+ String currentSuffix = jjtreeFile.substring(suffixPos);
+
+ if (currentSuffix.equals(DEFAULT_SUFFIX)) {
+ optionalOutputFile = jjtreeFile + DEFAULT_SUFFIX;
+ } else {
+ optionalOutputFile = jjtreeFile.substring(0, suffixPos)
+ + DEFAULT_SUFFIX;
+ }
+ }
+ }
+
+ if ((outputDir == null) || outputDir.equals("")) {
+ outputDir = getDefaultOutputDirectory();
+ }
+
+ return (outputDir + "/" + optionalOutputFile).replace('\\', '/');
+ }
+
+ /**
+ * When running JJTree from an Ant taskdesk the -OUTPUT_DIRECTORY must
+ * always be set. But when -OUTPUT_DIRECTORY is set, -OUTPUT_FILE is
+ * handled as if relative of this -OUTPUT_DIRECTORY. Thus when the
+ * -OUTPUT_FILE is absolute or contains a drive letter we have a problem.
+ *
+ * @param destFile
+ * @param outputDir
+ * @return validation file, relative if possible; <tt>null</tt> if not set
+ * @throws BuildException
+ */
+ private String validateOutputFile(String destFile,
+ String outputDir)
+ throws BuildException {
+ if (destFile == null) {
+ return null;
+ }
+
+ if ((outputDir == null)
+ && (destFile.startsWith("/") || destFile.startsWith("\\"))) {
+ String relativeOutputFile = makeOutputFileRelative(destFile);
+ setOutputfile(relativeOutputFile);
+
+ return relativeOutputFile;
+ }
+
+ String root = getRoot(new File(destFile)).getAbsolutePath();
+
+ if ((root.length() > 1)
+ && destFile.startsWith(root.substring(0, root.length() - 1))) {
+ throw new BuildException("Drive letter in 'outputfile' not "
+ + "supported: " + destFile);
+ }
+
+ return destFile;
+ }
+
+ private String makeOutputFileRelative(String destFile) {
+ StringBuffer relativePath = new StringBuffer();
+ String defaultOutputDirectory = getDefaultOutputDirectory();
+ int nextPos = defaultOutputDirectory.indexOf('/');
+ int startPos = nextPos + 1;
+
+ while (startPos > -1 && startPos < defaultOutputDirectory.length()) {
+ relativePath.append("/..");
+ nextPos = defaultOutputDirectory.indexOf('/', startPos);
+
+ if (nextPos == -1) {
+ startPos = nextPos;
+ } else {
+ startPos = nextPos + 1;
+ }
+ }
+
+ relativePath.append(destFile);
+
+ return relativePath.toString();
+ }
+
+ private String getDefaultOutputDirectory() {
+ return getProject().getBaseDir().getAbsolutePath().replace('\\', '/');
+ }
+
+ /**
+ * Determine root directory for a given file.
+ *
+ * @param file
+ * @return file's root directory
+ */
+ private File getRoot(File file) {
+ File root = file.getAbsoluteFile();
+
+ while (root.getParent() != null) {
+ root = root.getParentFile();
+ }
+
+ return root;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java
new file mode 100644
index 00000000..219cc9c8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java
@@ -0,0 +1,579 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javacc;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * JavaCC compiler compiler task.
+ *
+ */
+public class JavaCC extends Task {
+
+ // keys to optional attributes
+ private static final String LOOKAHEAD = "LOOKAHEAD";
+ private static final String CHOICE_AMBIGUITY_CHECK = "CHOICE_AMBIGUITY_CHECK";
+ private static final String OTHER_AMBIGUITY_CHECK = "OTHER_AMBIGUITY_CHECK";
+
+ private static final String STATIC = "STATIC";
+ private static final String DEBUG_PARSER = "DEBUG_PARSER";
+ private static final String DEBUG_LOOKAHEAD = "DEBUG_LOOKAHEAD";
+ private static final String DEBUG_TOKEN_MANAGER = "DEBUG_TOKEN_MANAGER";
+ private static final String OPTIMIZE_TOKEN_MANAGER = "OPTIMIZE_TOKEN_MANAGER";
+ private static final String ERROR_REPORTING = "ERROR_REPORTING";
+ private static final String JAVA_UNICODE_ESCAPE = "JAVA_UNICODE_ESCAPE";
+ private static final String UNICODE_INPUT = "UNICODE_INPUT";
+ private static final String IGNORE_CASE = "IGNORE_CASE";
+ private static final String COMMON_TOKEN_ACTION = "COMMON_TOKEN_ACTION";
+ private static final String USER_TOKEN_MANAGER = "USER_TOKEN_MANAGER";
+ private static final String USER_CHAR_STREAM = "USER_CHAR_STREAM";
+ private static final String BUILD_PARSER = "BUILD_PARSER";
+ private static final String BUILD_TOKEN_MANAGER = "BUILD_TOKEN_MANAGER";
+ private static final String SANITY_CHECK = "SANITY_CHECK";
+ private static final String FORCE_LA_CHECK = "FORCE_LA_CHECK";
+ private static final String CACHE_TOKENS = "CACHE_TOKENS";
+ private static final String KEEP_LINE_COLUMN = "KEEP_LINE_COLUMN";
+ private static final String JDK_VERSION = "JDK_VERSION";
+
+ private final Hashtable optionalAttrs = new Hashtable();
+
+ // required attributes
+ private File outputDirectory = null;
+ private File targetFile = null;
+ private File javaccHome = null;
+
+ private CommandlineJava cmdl = new CommandlineJava();
+
+ protected static final int TASKDEF_TYPE_JAVACC = 1;
+ protected static final int TASKDEF_TYPE_JJTREE = 2;
+ protected static final int TASKDEF_TYPE_JJDOC = 3;
+
+ protected static final String[] ARCHIVE_LOCATIONS =
+ new String[] {
+ "JavaCC.zip",
+ "bin/lib/JavaCC.zip",
+ "bin/lib/javacc.jar",
+ "javacc.jar", // used by jpackage for JavaCC 3.x
+ };
+
+ protected static final int[] ARCHIVE_LOCATIONS_VS_MAJOR_VERSION =
+ new int[] {
+ 1,
+ 2,
+ 3,
+ 3,
+ };
+
+ protected static final String COM_PACKAGE = "COM.sun.labs.";
+ protected static final String COM_JAVACC_CLASS = "javacc.Main";
+ protected static final String COM_JJTREE_CLASS = "jjtree.Main";
+ protected static final String COM_JJDOC_CLASS = "jjdoc.JJDocMain";
+
+ protected static final String ORG_PACKAGE_3_0 = "org.netbeans.javacc.";
+ protected static final String ORG_PACKAGE_3_1 = "org.javacc.";
+ protected static final String ORG_JAVACC_CLASS = "parser.Main";
+ protected static final String ORG_JJTREE_CLASS = COM_JJTREE_CLASS;
+ protected static final String ORG_JJDOC_CLASS = COM_JJDOC_CLASS;
+
+ private String maxMemory = null;
+
+ /**
+ * Sets the LOOKAHEAD grammar option.
+ * @param lookahead an <code>int</code> value.
+ */
+ public void setLookahead(int lookahead) {
+ optionalAttrs.put(LOOKAHEAD, new Integer(lookahead));
+ }
+
+ /**
+ * Sets the CHOICE_AMBIGUITY_CHECK grammar option.
+ * @param choiceAmbiguityCheck an <code>int</code> value.
+ */
+ public void setChoiceambiguitycheck(int choiceAmbiguityCheck) {
+ optionalAttrs.put(CHOICE_AMBIGUITY_CHECK, new Integer(choiceAmbiguityCheck));
+ }
+
+ /**
+ * Sets the OTHER_AMBIGUITY_CHECK grammar option.
+ * @param otherAmbiguityCheck an <code>int</code> value.
+ */
+ public void setOtherambiguityCheck(int otherAmbiguityCheck) {
+ optionalAttrs.put(OTHER_AMBIGUITY_CHECK, new Integer(otherAmbiguityCheck));
+ }
+
+ /**
+ * Sets the STATIC grammar option.
+ * @param staticParser a <code>boolean</code> value.
+ */
+ public void setStatic(boolean staticParser) {
+ optionalAttrs.put(STATIC, staticParser ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the DEBUG_PARSER grammar option.
+ * @param debugParser a <code>boolean</code> value.
+ */
+ public void setDebugparser(boolean debugParser) {
+ optionalAttrs.put(DEBUG_PARSER, debugParser ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the DEBUG_LOOKAHEAD grammar option.
+ * @param debugLookahead a <code>boolean</code> value.
+ */
+ public void setDebuglookahead(boolean debugLookahead) {
+ optionalAttrs.put(DEBUG_LOOKAHEAD, debugLookahead ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the DEBUG_TOKEN_MANAGER grammar option.
+ * @param debugTokenManager a <code>boolean</code> value.
+ */
+ public void setDebugtokenmanager(boolean debugTokenManager) {
+ optionalAttrs.put(DEBUG_TOKEN_MANAGER, debugTokenManager ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the OPTIMIZE_TOKEN_MANAGER grammar option.
+ * @param optimizeTokenManager a <code>boolean</code> value.
+ */
+ public void setOptimizetokenmanager(boolean optimizeTokenManager) {
+ optionalAttrs.put(OPTIMIZE_TOKEN_MANAGER,
+ optimizeTokenManager ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the ERROR_REPORTING grammar option.
+ * @param errorReporting a <code>boolean</code> value.
+ */
+ public void setErrorreporting(boolean errorReporting) {
+ optionalAttrs.put(ERROR_REPORTING, errorReporting ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the JAVA_UNICODE_ESCAPE grammar option.
+ * @param javaUnicodeEscape a <code>boolean</code> value.
+ */
+ public void setJavaunicodeescape(boolean javaUnicodeEscape) {
+ optionalAttrs.put(JAVA_UNICODE_ESCAPE, javaUnicodeEscape ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the UNICODE_INPUT grammar option.
+ * @param unicodeInput a <code>boolean</code> value.
+ */
+ public void setUnicodeinput(boolean unicodeInput) {
+ optionalAttrs.put(UNICODE_INPUT, unicodeInput ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the IGNORE_CASE grammar option.
+ * @param ignoreCase a <code>boolean</code> value.
+ */
+ public void setIgnorecase(boolean ignoreCase) {
+ optionalAttrs.put(IGNORE_CASE, ignoreCase ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the COMMON_TOKEN_ACTION grammar option.
+ * @param commonTokenAction a <code>boolean</code> value.
+ */
+ public void setCommontokenaction(boolean commonTokenAction) {
+ optionalAttrs.put(COMMON_TOKEN_ACTION, commonTokenAction ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the USER_TOKEN_MANAGER grammar option.
+ * @param userTokenManager a <code>boolean</code> value.
+ */
+ public void setUsertokenmanager(boolean userTokenManager) {
+ optionalAttrs.put(USER_TOKEN_MANAGER, userTokenManager ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the USER_CHAR_STREAM grammar option.
+ * @param userCharStream a <code>boolean</code> value.
+ */
+ public void setUsercharstream(boolean userCharStream) {
+ optionalAttrs.put(USER_CHAR_STREAM, userCharStream ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the BUILD_PARSER grammar option.
+ * @param buildParser a <code>boolean</code> value.
+ */
+ public void setBuildparser(boolean buildParser) {
+ optionalAttrs.put(BUILD_PARSER, buildParser ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the BUILD_TOKEN_MANAGER grammar option.
+ * @param buildTokenManager a <code>boolean</code> value.
+ */
+ public void setBuildtokenmanager(boolean buildTokenManager) {
+ optionalAttrs.put(BUILD_TOKEN_MANAGER, buildTokenManager ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the SANITY_CHECK grammar option.
+ * @param sanityCheck a <code>boolean</code> value.
+ */
+ public void setSanitycheck(boolean sanityCheck) {
+ optionalAttrs.put(SANITY_CHECK, sanityCheck ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the FORCE_LA_CHECK grammar option.
+ * @param forceLACheck a <code>boolean</code> value.
+ */
+ public void setForcelacheck(boolean forceLACheck) {
+ optionalAttrs.put(FORCE_LA_CHECK, forceLACheck ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the CACHE_TOKENS grammar option.
+ * @param cacheTokens a <code>boolean</code> value.
+ */
+ public void setCachetokens(boolean cacheTokens) {
+ optionalAttrs.put(CACHE_TOKENS, cacheTokens ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the KEEP_LINE_COLUMN grammar option.
+ * @param keepLineColumn a <code>boolean</code> value.
+ */
+ public void setKeeplinecolumn(boolean keepLineColumn) {
+ optionalAttrs.put(KEEP_LINE_COLUMN, keepLineColumn ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Sets the JDK_VERSION option.
+ * @param jdkVersion the version to use.
+ * @since Ant1.7
+ */
+ public void setJDKversion(String jdkVersion) {
+ optionalAttrs.put(JDK_VERSION, jdkVersion);
+ }
+
+ /**
+ * The directory to write the generated files to.
+ * If not set, the files are written to the directory
+ * containing the grammar file.
+ * @param outputDirectory the output directory.
+ */
+ public void setOutputdirectory(File outputDirectory) {
+ this.outputDirectory = outputDirectory;
+ }
+
+ /**
+ * The grammar file to process.
+ * @param targetFile the grammar file.
+ */
+ public void setTarget(File targetFile) {
+ this.targetFile = targetFile;
+ }
+
+ /**
+ * The directory containing the JavaCC distribution.
+ * @param javaccHome the directory.
+ */
+ public void setJavacchome(File javaccHome) {
+ this.javaccHome = javaccHome;
+ }
+
+ /**
+ * Corresponds -Xmx.
+ *
+ * @param max max memory parameter.
+ * @since Ant 1.8.3
+ */
+ public void setMaxmemory(String max) {
+ maxMemory = max;
+ }
+
+ /**
+ * Constructor
+ */
+ public JavaCC() {
+ cmdl.setVm(JavaEnvUtils.getJreExecutable("java"));
+ }
+
+ /**
+ * Run the task.
+ * @throws BuildException on error.
+ */
+ public void execute() throws BuildException {
+
+ // load command line with optional attributes
+ Enumeration iter = optionalAttrs.keys();
+ while (iter.hasMoreElements()) {
+ String name = (String) iter.nextElement();
+ Object value = optionalAttrs.get(name);
+ cmdl.createArgument().setValue("-" + name + ":" + value.toString());
+ }
+
+ // check the target is a file
+ if (targetFile == null || !targetFile.isFile()) {
+ throw new BuildException("Invalid target: " + targetFile);
+ }
+
+ // use the directory containing the target as the output directory
+ if (outputDirectory == null) {
+ outputDirectory = new File(targetFile.getParent());
+ } else if (!outputDirectory.isDirectory()) {
+ throw new BuildException("Outputdir not a directory.");
+ }
+ cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:"
+ + outputDirectory.getAbsolutePath());
+
+ // determine if the generated java file is up-to-date
+ final File javaFile = getOutputJavaFile(outputDirectory, targetFile);
+ if (javaFile.exists()
+ && targetFile.lastModified() < javaFile.lastModified()) {
+ log("Target is already built - skipping (" + targetFile + ")",
+ Project.MSG_VERBOSE);
+ return;
+ }
+ cmdl.createArgument().setValue(targetFile.getAbsolutePath());
+
+ final Path classpath = cmdl.createClasspath(getProject());
+ final File javaccJar = JavaCC.getArchiveFile(javaccHome);
+ classpath.createPathElement().setPath(javaccJar.getAbsolutePath());
+ classpath.addJavaRuntime();
+
+ cmdl.setClassname(JavaCC.getMainClass(classpath,
+ JavaCC.TASKDEF_TYPE_JAVACC));
+
+ cmdl.setMaxmemory(maxMemory);
+ final Commandline.Argument arg = cmdl.createVmArgument();
+ arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath());
+
+ Execute.runCommand(this, cmdl.getCommandline());
+ }
+
+ /**
+ * Helper method to retrieve the path used to store the JavaCC.zip
+ * or javacc.jar which is different from versions.
+ *
+ * @param home the javacc home path directory.
+ * @throws BuildException thrown if the home directory is invalid
+ * or if the archive could not be found despite attempts to do so.
+ * @return the file object pointing to the JavaCC archive.
+ */
+ protected static File getArchiveFile(File home) throws BuildException {
+ return new File(home,
+ ARCHIVE_LOCATIONS[getArchiveLocationIndex(home)]);
+ }
+
+ /**
+ * Helper method to retrieve main class which is different from versions.
+ * @param home the javacc home path directory.
+ * @param type the taskdef.
+ * @throws BuildException thrown if the home directory is invalid
+ * or if the archive could not be found despite attempts to do so.
+ * @return the main class for the taskdef.
+ */
+ protected static String getMainClass(File home, int type)
+ throws BuildException {
+
+ Path p = new Path(null);
+ p.createPathElement().setLocation(getArchiveFile(home));
+ p.addJavaRuntime();
+ return getMainClass(p, type);
+ }
+
+ /**
+ * Helper method to retrieve main class which is different from versions.
+ * @param path classpath to search in.
+ * @param type the taskdef.
+ * @throws BuildException thrown if the home directory is invalid
+ * or if the archive could not be found despite attempts to do so.
+ * @return the main class for the taskdef.
+ * @since Ant 1.7
+ */
+ protected static String getMainClass(Path path, int type)
+ throws BuildException {
+ String packagePrefix = null;
+ String mainClass = null;
+
+ AntClassLoader l = null;
+ try {
+ l = AntClassLoader.newAntClassLoader(null, null,
+ path
+ .concatSystemClasspath("ignore"),
+ true);
+ String javaccClass = COM_PACKAGE + COM_JAVACC_CLASS;
+ InputStream is = l.getResourceAsStream(javaccClass.replace('.', '/')
+ + ".class");
+ if (is != null) {
+ packagePrefix = COM_PACKAGE;
+ switch (type) {
+ case TASKDEF_TYPE_JAVACC:
+ mainClass = COM_JAVACC_CLASS;
+
+ break;
+
+ case TASKDEF_TYPE_JJTREE:
+ mainClass = COM_JJTREE_CLASS;
+
+ break;
+
+ case TASKDEF_TYPE_JJDOC:
+ mainClass = COM_JJDOC_CLASS;
+
+ break;
+ default:
+ // Fall Through
+ }
+ } else {
+ javaccClass = ORG_PACKAGE_3_1 + ORG_JAVACC_CLASS;
+ is = l.getResourceAsStream(javaccClass.replace('.', '/')
+ + ".class");
+ if (is != null) {
+ packagePrefix = ORG_PACKAGE_3_1;
+ } else {
+ javaccClass = ORG_PACKAGE_3_0 + ORG_JAVACC_CLASS;
+ is = l.getResourceAsStream(javaccClass.replace('.', '/')
+ + ".class");
+ if (is != null) {
+ packagePrefix = ORG_PACKAGE_3_0;
+ }
+ }
+
+ if (is != null) {
+ switch (type) {
+ case TASKDEF_TYPE_JAVACC:
+ mainClass = ORG_JAVACC_CLASS;
+
+ break;
+
+ case TASKDEF_TYPE_JJTREE:
+ mainClass = ORG_JJTREE_CLASS;
+
+ break;
+
+ case TASKDEF_TYPE_JJDOC:
+ mainClass = ORG_JJDOC_CLASS;
+
+ break;
+ default:
+ // Fall Through
+ }
+ }
+ }
+
+ if (packagePrefix == null) {
+ throw new BuildException("failed to load JavaCC");
+ }
+ if (mainClass == null) {
+ throw new BuildException("unknown task type " + type);
+ }
+ return packagePrefix + mainClass;
+ } finally {
+ if (l != null) {
+ l.cleanup();
+ }
+ }
+ }
+
+ /**
+ * Helper method to determine the archive location index.
+ *
+ * @param home the javacc home path directory.
+ * @throws BuildException thrown if the home directory is invalid
+ * or if the archive could not be found despite attempts to do so.
+ * @return the archive location index
+ */
+ private static int getArchiveLocationIndex(File home)
+ throws BuildException {
+
+ if (home == null || !home.isDirectory()) {
+ throw new BuildException("JavaCC home must be a valid directory.");
+ }
+
+ for (int i = 0; i < ARCHIVE_LOCATIONS.length; i++) {
+ File f = new File(home, ARCHIVE_LOCATIONS[i]);
+
+ if (f.exists()) {
+ return i;
+ }
+ }
+
+ throw new BuildException("Could not find a path to JavaCC.zip "
+ + "or javacc.jar from '" + home + "'.");
+ }
+
+ /**
+ * Helper method to determine the major version number of JavaCC.
+ *
+ * @param home the javacc home path directory.
+ * @throws BuildException thrown if the home directory is invalid
+ * or if the archive could not be found despite attempts to do so.
+ * @return a the major version number
+ */
+ protected static int getMajorVersionNumber(File home)
+ throws BuildException {
+
+ return
+ ARCHIVE_LOCATIONS_VS_MAJOR_VERSION[getArchiveLocationIndex(home)];
+ }
+
+ /**
+ * Determines the output Java file to be generated by the given grammar
+ * file.
+ *
+ */
+ private File getOutputJavaFile(File outputdir, File srcfile) {
+ String path = srcfile.getPath();
+
+ // Extract file's base-name
+ int startBasename = path.lastIndexOf(File.separator);
+ if (startBasename != -1) {
+ path = path.substring(startBasename + 1);
+ }
+
+ // Replace the file's extension with '.java'
+ int startExtn = path.lastIndexOf('.');
+ if (startExtn != -1) {
+ path = path.substring(0, startExtn) + ".java";
+ } else {
+ path += ".java";
+ }
+
+ // Change the directory
+ if (outputdir != null) {
+ path = outputdir + File.separator + path;
+ }
+
+ return new File(path);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Gcjh.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Gcjh.java
new file mode 100644
index 00000000..712bb76a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Gcjh.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Adapter to the native gcjh compiler.
+ *
+ * @since Ant 1.8.2
+ */
+public class Gcjh implements JavahAdapter {
+
+ public static final String IMPLEMENTATION_NAME = "gcjh";
+
+ /**
+ * Performs the actual compilation.
+ */
+ public boolean compile(Javah javah) throws BuildException {
+ Commandline cmd = setupGcjhCommand(javah);
+ try {
+ Execute.runCommand(javah, cmd.getCommandline());
+ return true;
+ } catch (BuildException e) {
+ if (e.getMessage().indexOf("failed with return code") == -1) {
+ throw e;
+ }
+ }
+ return false;
+ }
+
+ private Commandline setupGcjhCommand(Javah javah) {
+ Commandline cmd = new Commandline();
+ cmd.setExecutable(JavaEnvUtils.getJdkExecutable("gcjh"));
+
+ if (javah.getDestdir() != null) {
+ cmd.createArgument().setValue("-d");
+ cmd.createArgument().setFile(javah.getDestdir());
+ }
+
+ if (javah.getOutputfile() != null) {
+ cmd.createArgument().setValue("-o");
+ cmd.createArgument().setFile(javah.getOutputfile());
+ }
+
+ Path cp = new Path(javah.getProject());
+ if (javah.getBootclasspath() != null) {
+ cp.append(javah.getBootclasspath());
+ }
+ cp = cp.concatSystemBootClasspath("ignore");
+ if (javah.getClasspath() != null) {
+ cp.append(javah.getClasspath());
+ }
+ if (cp.size() > 0) {
+ cmd.createArgument().setValue("--classpath");
+ cmd.createArgument().setPath(cp);
+ }
+
+ if (!javah.getOld()) {
+ cmd.createArgument().setValue("-jni");
+ }
+
+ cmd.addArguments(javah.getCurrentArgs());
+
+ javah.logAndAddFiles(cmd);
+ return cmd;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java
new file mode 100644
index 00000000..121fa429
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+
+/**
+ * Interface for different backend implementations of the Javah task.
+ *
+ * @since Ant 1.6.3
+ */
+public interface JavahAdapter {
+ /**
+ * Performs the actual compilation.
+ * @param javah the calling javah task.
+ * @return true if the compilation was successful.
+ * @throws BuildException if there is an error.
+ * @since Ant 1.6.3
+ */
+ boolean compile(Javah javah) throws BuildException;
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java
new file mode 100644
index 00000000..d98b4276
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Creates the JavahAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @since Ant 1.6.3
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class JavahAdapterFactory {
+
+ /**
+ * Determines the default choice of adapter based on the VM
+ * vendor.
+ *
+ * @return the default choice of adapter based on the VM
+ * vendor
+ */
+ public static String getDefault() {
+ if (JavaEnvUtils.isKaffe()) {
+ return Kaffeh.IMPLEMENTATION_NAME;
+ } else if (JavaEnvUtils.isGij()) {
+ return Gcjh.IMPLEMENTATION_NAME;
+ }
+ return SunJavah.IMPLEMENTATION_NAME;
+ }
+
+ /**
+ * Creates the JavahAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @param choice the user choice (if any).
+ * @param log a ProjectComponent instance used to access Ant's
+ * logging system.
+ * @return The adapter to use.
+ * @throws BuildException if there is an error.
+ */
+ public static JavahAdapter getAdapter(String choice,
+ ProjectComponent log)
+ throws BuildException {
+ return getAdapter(choice, log, null);
+ }
+
+ /**
+ * Creates the JavahAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @param choice the user choice (if any).
+ * @param log a ProjectComponent instance used to access Ant's
+ * logging system.
+ * @param classpath the classpath to use when looking up an
+ * adapter class
+ * @return The adapter to use.
+ * @throws BuildException if there is an error.
+ * @since Ant 1.8.0
+ */
+ public static JavahAdapter getAdapter(String choice,
+ ProjectComponent log,
+ Path classpath)
+ throws BuildException {
+ if ((JavaEnvUtils.isKaffe() && choice == null)
+ || Kaffeh.IMPLEMENTATION_NAME.equals(choice)) {
+ return new Kaffeh();
+ } else if ((JavaEnvUtils.isGij() && choice == null)
+ || Gcjh.IMPLEMENTATION_NAME.equals(choice)) {
+ return new Gcjh();
+ } else if (SunJavah.IMPLEMENTATION_NAME.equals(choice)) {
+ return new SunJavah();
+ } else if (choice != null) {
+ return resolveClassName(choice,
+ // Memory leak in line below
+ log.getProject()
+ .createClassLoader(classpath));
+ }
+
+ // This default has been good enough until Ant 1.6.3, so stick
+ // with it
+ return new SunJavah();
+ }
+
+ /**
+ * Tries to resolve the given classname into a javah adapter.
+ * Throws a fit if it can't.
+ *
+ * @param className The fully qualified classname to be created.
+ * @param loader the classloader to use
+ * @throws BuildException This is the fit that is thrown if className
+ * isn't an instance of JavahAdapter.
+ */
+ private static JavahAdapter resolveClassName(String className,
+ ClassLoader loader)
+ throws BuildException {
+ return (JavahAdapter) ClasspathUtils.newInstance(className,
+ loader != null ? loader :
+ JavahAdapterFactory.class.getClassLoader(), JavahAdapter.class);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java
new file mode 100644
index 00000000..d37f7717
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Adapter to the native kaffeh compiler.
+ *
+ * @since Ant 1.6.3
+ */
+public class Kaffeh implements JavahAdapter {
+
+ /** the name of the javah adapter - kaffeh */
+ public static final String IMPLEMENTATION_NAME = "kaffeh";
+
+ /**
+ * Performs the actual compilation.
+ * @param javah the calling javah task.
+ * @return true if the compilation was successful.
+ * @throws BuildException if there is an error.
+ * @since Ant 1.6.3
+ */
+ public boolean compile(Javah javah) throws BuildException {
+ Commandline cmd = setupKaffehCommand(javah);
+ try {
+ Execute.runCommand(javah, cmd.getCommandline());
+ return true;
+ } catch (BuildException e) {
+ if (e.getMessage().indexOf("failed with return code") == -1) {
+ throw e;
+ }
+ }
+ return false;
+ }
+
+ private Commandline setupKaffehCommand(Javah javah) {
+ Commandline cmd = new Commandline();
+ cmd.setExecutable(JavaEnvUtils.getJdkExecutable("kaffeh"));
+
+ if (javah.getDestdir() != null) {
+ cmd.createArgument().setValue("-d");
+ cmd.createArgument().setFile(javah.getDestdir());
+ }
+
+ if (javah.getOutputfile() != null) {
+ cmd.createArgument().setValue("-o");
+ cmd.createArgument().setFile(javah.getOutputfile());
+ }
+
+ Path cp = new Path(javah.getProject());
+ if (javah.getBootclasspath() != null) {
+ cp.append(javah.getBootclasspath());
+ }
+ cp = cp.concatSystemBootClasspath("ignore");
+ if (javah.getClasspath() != null) {
+ cp.append(javah.getClasspath());
+ }
+ if (cp.size() > 0) {
+ cmd.createArgument().setValue("-classpath");
+ cmd.createArgument().setPath(cp);
+ }
+
+ if (!javah.getOld()) {
+ cmd.createArgument().setValue("-jni");
+ }
+
+ cmd.addArguments(javah.getCurrentArgs());
+
+ javah.logAndAddFiles(cmd);
+ return cmd;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java
new file mode 100644
index 00000000..0b1655ad
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.launch.Locator;
+import org.apache.tools.ant.taskdefs.ExecuteJava;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+
+/**
+ * Adapter to com.sun.tools.javah.oldjavah.Main or com.sun.tools.javah.Main.
+ *
+ * @since Ant 1.6.3
+ */
+public class SunJavah implements JavahAdapter {
+
+ /** the name of the javah adapter - sun */
+ public static final String IMPLEMENTATION_NAME = "sun";
+
+ /**
+ * Performs the actual compilation.
+ * @param javah the calling javah task.
+ * @return true if the compilation was successful.
+ * @throws BuildException if there is an error.
+ * @since Ant 1.6.3
+ */
+ public boolean compile(Javah javah) throws BuildException {
+ Commandline cmd = setupJavahCommand(javah);
+ ExecuteJava ej = new ExecuteJava();
+ Class c = null;
+ try {
+ try {
+ // first search for the "old" javah class in 1.4.2 tools.jar
+ c = Class.forName("com.sun.tools.javah.oldjavah.Main");
+ } catch (ClassNotFoundException cnfe) {
+ // assume older than 1.4.2 tools.jar
+ c = Class.forName("com.sun.tools.javah.Main");
+ }
+ } catch (ClassNotFoundException ex) {
+ throw new BuildException(
+ "Can't load javah", ex, javah.getLocation());
+ }
+ cmd.setExecutable(c.getName());
+ ej.setJavaCommand(cmd);
+ File f = Locator.getClassSource(c);
+ if (f != null) {
+ ej.setClasspath(new Path(javah.getProject(), f.getPath()));
+ }
+ return ej.fork(javah) == 0;
+ }
+
+ private Commandline setupJavahCommand(Javah javah) {
+ Commandline cmd = new Commandline();
+
+ if (javah.getDestdir() != null) {
+ cmd.createArgument().setValue("-d");
+ cmd.createArgument().setFile(javah.getDestdir());
+ }
+
+ if (javah.getOutputfile() != null) {
+ cmd.createArgument().setValue("-o");
+ cmd.createArgument().setFile(javah.getOutputfile());
+ }
+
+ if (javah.getClasspath() != null) {
+ cmd.createArgument().setValue("-classpath");
+ cmd.createArgument().setPath(javah.getClasspath());
+ }
+
+ if (javah.getVerbose()) {
+ cmd.createArgument().setValue("-verbose");
+ }
+ if (javah.getOld()) {
+ cmd.createArgument().setValue("-old");
+ }
+ if (javah.getForce()) {
+ cmd.createArgument().setValue("-force");
+ }
+ if (javah.getStubs() && !javah.getOld()) {
+ throw new BuildException(
+ "stubs only available in old mode.", javah.getLocation());
+ }
+
+ if (javah.getStubs()) {
+ cmd.createArgument().setValue("-stubs");
+ }
+ Path bcp = new Path(javah.getProject());
+ if (javah.getBootclasspath() != null) {
+ bcp.append(javah.getBootclasspath());
+ }
+ bcp = bcp.concatSystemBootClasspath("ignore");
+ if (bcp.size() > 0) {
+ cmd.createArgument().setValue("-bootclasspath");
+ cmd.createArgument().setPath(bcp);
+ }
+
+ cmd.addArguments(javah.getCurrentArgs());
+
+ javah.logAndAddFiles(cmd);
+ return cmd;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java
new file mode 100644
index 00000000..21f03fe7
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java
@@ -0,0 +1,684 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jdepend;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteWatchdog;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+
+/**
+ * Runs JDepend tests.
+ *
+ * <p>JDepend is a tool to generate design quality metrics for each Java package.
+ * It has been initially created by Mike Clark. JDepend can be found at <a
+ * href="http://www.clarkware.com/software/JDepend.html">http://www.clarkware.com/software/JDepend.html</a>.
+ *
+ * The current implementation spawn a new Java VM.
+ *
+ */
+public class JDependTask extends Task {
+ //private CommandlineJava commandline = new CommandlineJava();
+
+ // required attributes
+ private Path sourcesPath; // Deprecated!
+ private Path classesPath; // Use this going forward
+
+ // optional attributes
+ private File outputFile;
+ private File dir;
+ private Path compileClasspath;
+ private boolean haltonerror = false;
+ private boolean fork = false;
+ private Long timeout = null;
+
+ private String jvm = null;
+ private String format = "text";
+ private PatternSet defaultPatterns = new PatternSet();
+
+ private static Constructor packageFilterC;
+ private static Method setFilter;
+
+ private boolean includeRuntime = false;
+ private Path runtimeClasses = null;
+
+ static {
+ try {
+ Class packageFilter =
+ Class.forName("jdepend.framework.PackageFilter");
+ packageFilterC =
+ packageFilter.getConstructor(new Class[] {java.util.Collection.class});
+ setFilter =
+ jdepend.textui.JDepend.class.getDeclaredMethod("setFilter",
+ new Class[] {packageFilter});
+ } catch (Throwable t) {
+ if (setFilter == null) {
+ packageFilterC = null;
+ }
+ }
+ }
+
+ /**
+ * If true,
+ * include jdepend.jar in the forked VM.
+ *
+ * @param b include ant run time yes or no
+ * @since Ant 1.6
+ */
+ public void setIncluderuntime(boolean b) {
+ includeRuntime = b;
+ }
+
+ /**
+ * Set the timeout value (in milliseconds).
+ *
+ * <p>If the operation is running for more than this value, the jdepend
+ * will be canceled. (works only when in 'fork' mode).</p>
+ * @param value the maximum time (in milliseconds) allowed before
+ * declaring the test as 'timed-out'
+ * @see #setFork(boolean)
+ */
+ public void setTimeout(Long value) {
+ timeout = value;
+ }
+
+ /**
+ * @return the timeout value
+ */
+ public Long getTimeout() {
+ return timeout;
+ }
+
+ /**
+ * The output file name.
+ *
+ * @param outputFile the output file name
+ */
+ public void setOutputFile(File outputFile) {
+ this.outputFile = outputFile;
+ }
+
+ /**
+ * @return the output file name
+ */
+ public File getOutputFile() {
+ return outputFile;
+ }
+
+ /**
+ * Whether or not to halt on failure. Default: false.
+ * @param haltonerror the value to set
+ */
+ public void setHaltonerror(boolean haltonerror) {
+ this.haltonerror = haltonerror;
+ }
+
+ /**
+ * @return the value of the haltonerror attribute
+ */
+ public boolean getHaltonerror() {
+ return haltonerror;
+ }
+
+ /**
+ * If true, forks into a new JVM. Default: false.
+ *
+ * @param value <tt>true</tt> if a JVM should be forked,
+ * otherwise <tt>false<tt>
+ */
+ public void setFork(boolean value) {
+ fork = value;
+ }
+
+ /**
+ * @return the value of the fork attribute
+ */
+ public boolean getFork() {
+ return fork;
+ }
+
+ /**
+ * The command used to invoke a forked Java Virtual Machine.
+ *
+ * Default is <tt>java</tt>. Ignored if no JVM is forked.
+ * @param value the new VM to use instead of <tt>java</tt>
+ * @see #setFork(boolean)
+ */
+ public void setJvm(String value) {
+ jvm = value;
+
+ }
+
+ /**
+ * Adds a path to source code to analyze.
+ * @return a source path
+ * @deprecated since 1.6.x.
+ */
+ public Path createSourcespath() {
+ if (sourcesPath == null) {
+ sourcesPath = new Path(getProject());
+ }
+ return sourcesPath.createPath();
+ }
+
+ /**
+ * Gets the sourcepath.
+ * @return the sources path
+ * @deprecated since 1.6.x.
+ */
+ public Path getSourcespath() {
+ return sourcesPath;
+ }
+
+ /**
+ * Adds a path to class code to analyze.
+ * @return a classes path
+ */
+ public Path createClassespath() {
+ if (classesPath == null) {
+ classesPath = new Path(getProject());
+ }
+ return classesPath.createPath();
+ }
+
+ /**
+ * Gets the classespath.
+ * @return the classes path
+ */
+ public Path getClassespath() {
+ return classesPath;
+ }
+
+ /**
+ * The directory to invoke the VM in. Ignored if no JVM is forked.
+ * @param dir the directory to invoke the JVM from.
+ * @see #setFork(boolean)
+ */
+ public void setDir(File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * @return the dir attribute
+ */
+ public File getDir() {
+ return dir;
+ }
+
+ /**
+ * Set the classpath to be used for this compilation.
+ * @param classpath a class path to be used
+ */
+ public void setClasspath(Path classpath) {
+ if (compileClasspath == null) {
+ compileClasspath = classpath;
+ } else {
+ compileClasspath.append(classpath);
+ }
+ }
+
+ /**
+ * Gets the classpath to be used for this compilation.
+ * @return the class path used for compilation
+ */
+ public Path getClasspath() {
+ return compileClasspath;
+ }
+
+ /**
+ * Adds a path to the classpath.
+ * @return a classpath
+ */
+ public Path createClasspath() {
+ if (compileClasspath == null) {
+ compileClasspath = new Path(getProject());
+ }
+ return compileClasspath.createPath();
+ }
+
+ /**
+ * Create a new JVM argument. Ignored if no JVM is forked.
+ * @param commandline the commandline to create the argument on
+ * @return create a new JVM argument so that any argument can
+ * be passed to the JVM.
+ * @see #setFork(boolean)
+ */
+ public Commandline.Argument createJvmarg(CommandlineJava commandline) {
+ return commandline.createVmArgument();
+ }
+
+ /**
+ * Adds a reference to a classpath defined elsewhere.
+ * @param r a classpath reference
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * add a name entry on the exclude list
+ * @return a pattern for the excludes
+ */
+ public PatternSet.NameEntry createExclude() {
+ return defaultPatterns.createExclude();
+ }
+
+ /**
+ * @return the excludes patterns
+ */
+ public PatternSet getExcludes() {
+ return defaultPatterns;
+ }
+
+ /**
+ * The format to write the output in, "xml" or "text".
+ *
+ * @param ea xml or text
+ */
+ public void setFormat(FormatAttribute ea) {
+ format = ea.getValue();
+ }
+
+ /**
+ * A class for the enumerated attribute format,
+ * values are xml and text.
+ * @see EnumeratedAttribute
+ */
+ public static class FormatAttribute extends EnumeratedAttribute {
+ private String [] formats = new String[]{"xml", "text"};
+
+ /**
+ * @return the enumerated values
+ */
+ public String[] getValues() {
+ return formats;
+ }
+ }
+
+ /**
+ * No problems with this test.
+ */
+ private static final int SUCCESS = 0;
+ /**
+ * An error occurred.
+ */
+ private static final int ERRORS = 1;
+
+ /**
+ * Search for the given resource and add the directory or archive
+ * that contains it to the classpath.
+ *
+ * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+ * getResource doesn't contain the name of the archive.</p>
+ *
+ * @param resource resource that one wants to lookup
+ * @since Ant 1.6
+ */
+ private void addClasspathEntry(String resource) {
+ /*
+ * pre Ant 1.6 this method used to call getClass().getResource
+ * while Ant 1.6 will call ClassLoader.getResource().
+ *
+ * The difference is that Class.getResource expects a leading
+ * slash for "absolute" resources and will strip it before
+ * delegating to ClassLoader.getResource - so we now have to
+ * emulate Class's behavior.
+ */
+ if (resource.startsWith("/")) {
+ resource = resource.substring(1);
+ } else {
+ resource = "org/apache/tools/ant/taskdefs/optional/jdepend/"
+ + resource;
+ }
+
+ File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
+ resource);
+ if (f != null) {
+ log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
+ runtimeClasses.createPath().setLocation(f);
+ } else {
+ log("Couldn\'t find " + resource, Project.MSG_DEBUG);
+ }
+ }
+
+ /**
+ * execute the task
+ *
+ * @exception BuildException if an error occurs
+ */
+ public void execute() throws BuildException {
+
+ CommandlineJava commandline = new CommandlineJava();
+
+ if ("text".equals(format)) {
+ commandline.setClassname("jdepend.textui.JDepend");
+ } else
+ if ("xml".equals(format)) {
+ commandline.setClassname("jdepend.xmlui.JDepend");
+ }
+
+ if (jvm != null) {
+ commandline.setVm(jvm);
+ }
+ if (getSourcespath() == null && getClassespath() == null) {
+ throw new BuildException("Missing classespath required argument");
+ } else if (getClassespath() == null) {
+ String msg =
+ "sourcespath is deprecated in JDepend >= 2.5 "
+ + "- please convert to classespath";
+ log(msg);
+ }
+
+ // execute the test and get the return code
+ int exitValue = JDependTask.ERRORS;
+ boolean wasKilled = false;
+ if (!getFork()) {
+ exitValue = executeInVM(commandline);
+ } else {
+ ExecuteWatchdog watchdog = createWatchdog();
+ exitValue = executeAsForked(commandline, watchdog);
+ // null watchdog means no timeout, you'd better not check with null
+ if (watchdog != null) {
+ wasKilled = watchdog.killedProcess();
+ }
+ }
+
+ // if there is an error/failure and that it should halt, stop
+ // everything otherwise just log a statement
+ boolean errorOccurred = exitValue == JDependTask.ERRORS || wasKilled;
+
+ if (errorOccurred) {
+ String errorMessage = "JDepend FAILED"
+ + (wasKilled ? " - Timed out" : "");
+
+ if (getHaltonerror()) {
+ throw new BuildException(errorMessage, getLocation());
+ } else {
+ log(errorMessage, Project.MSG_ERR);
+ }
+ }
+ }
+
+ // this comment extract from JUnit Task may also apply here
+ // "in VM is not very nice since it could probably hang the
+ // whole build. IMHO this method should be avoided and it would be best
+ // to remove it in future versions. TBD. (SBa)"
+
+ /**
+ * Execute inside VM.
+ *
+ * @param commandline the command line
+ * @return the return value of the mvm
+ * @exception BuildException if an error occurs
+ */
+ public int executeInVM(CommandlineJava commandline) throws BuildException {
+ jdepend.textui.JDepend jdepend;
+
+ if ("xml".equals(format)) {
+ jdepend = new jdepend.xmlui.JDepend();
+ } else {
+ jdepend = new jdepend.textui.JDepend();
+ }
+
+ FileWriter fw = null;
+ PrintWriter pw = null;
+ if (getOutputFile() != null) {
+ try {
+ fw = new FileWriter(getOutputFile().getPath());
+ } catch (IOException e) {
+ String msg = "JDepend Failed when creating the output file: "
+ + e.getMessage();
+ log(msg);
+ throw new BuildException(msg);
+ }
+ pw = new PrintWriter(fw);
+ jdepend.setWriter(pw);
+ log("Output to be stored in " + getOutputFile().getPath());
+ }
+
+
+ try {
+ if (getClassespath() != null) {
+ // This is the new, better way - use classespath instead
+ // of sourcespath. The code is currently the same - you
+ // need class files in a directory to use this or jar files.
+ String[] cP = getClassespath().list();
+ for (int i = 0; i < cP.length; i++) {
+ File f = new File(cP[i]);
+ // not necessary as JDepend would fail, but why loose
+ // some time?
+ if (!f.exists()) {
+ String msg = "\""
+ + f.getPath()
+ + "\" does not represent a valid"
+ + " file or directory. JDepend would fail.";
+ log(msg);
+ throw new BuildException(msg);
+ }
+ try {
+ jdepend.addDirectory(f.getPath());
+ } catch (IOException e) {
+ String msg =
+ "JDepend Failed when adding a class directory: "
+ + e.getMessage();
+ log(msg);
+ throw new BuildException(msg);
+ }
+ }
+
+ } else if (getSourcespath() != null) {
+
+ // This is the old way and is deprecated - classespath is
+ // the right way to do this and is above
+ String[] sP = getSourcespath().list();
+ for (int i = 0; i < sP.length; i++) {
+ File f = new File(sP[i]);
+
+ // not necessary as JDepend would fail, but why loose
+ // some time?
+ if (!f.exists() || !f.isDirectory()) {
+ String msg = "\""
+ + f.getPath()
+ + "\" does not represent a valid"
+ + " directory. JDepend would fail.";
+ log(msg);
+ throw new BuildException(msg);
+ }
+ try {
+ jdepend.addDirectory(f.getPath());
+ } catch (IOException e) {
+ String msg =
+ "JDepend Failed when adding a source directory: "
+ + e.getMessage();
+ log(msg);
+ throw new BuildException(msg);
+ }
+ }
+ }
+
+ // This bit turns <exclude> child tags into patters to ignore
+ String[] patterns = defaultPatterns.getExcludePatterns(getProject());
+ if (patterns != null && patterns.length > 0) {
+ if (setFilter != null) {
+ Vector v = new Vector();
+ for (int i = 0; i < patterns.length; i++) {
+ v.addElement(patterns[i]);
+ }
+ try {
+ Object o = packageFilterC.newInstance(new Object[] {v});
+ setFilter.invoke(jdepend, new Object[] {o});
+ } catch (Throwable e) {
+ log("excludes will be ignored as JDepend doesn't like me: "
+ + e.getMessage(), Project.MSG_WARN);
+ }
+ } else {
+ log("Sorry, your version of JDepend doesn't support excludes",
+ Project.MSG_WARN);
+ }
+ }
+
+ jdepend.analyze();
+ if (pw.checkError()) {
+ throw new IOException("Encountered an error writing JDepend"
+ + " output");
+ }
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ } finally {
+ FileUtils.close(pw);
+ FileUtils.close(fw);
+ }
+ return SUCCESS;
+ }
+
+
+ /**
+ * Execute the task by forking a new JVM. The command will block until
+ * it finishes. To know if the process was destroyed or not, use the
+ * <tt>killedProcess()</tt> method of the watchdog class.
+ * @param commandline the commandline for forked jvm
+ * @param watchdog the watchdog in charge of cancelling the test if it
+ * exceeds a certain amount of time. Can be <tt>null</tt>.
+ * @return the result of running the jdepend
+ * @throws BuildException in case of error
+ */
+ // JL: comment extracted from JUnitTask (and slightly modified)
+ public int executeAsForked(CommandlineJava commandline,
+ ExecuteWatchdog watchdog) throws BuildException {
+ runtimeClasses = new Path(getProject());
+ addClasspathEntry("/jdepend/textui/JDepend.class");
+
+ // if not set, auto-create the ClassPath from the project
+ createClasspath();
+
+ // not sure whether this test is needed but cost nothing to put.
+ // hope it will be reviewed by anybody competent
+ if (getClasspath().toString().length() > 0) {
+ createJvmarg(commandline).setValue("-classpath");
+ createJvmarg(commandline).setValue(getClasspath().toString());
+ }
+
+ if (includeRuntime) {
+ Map/*<String, String>*/ env = Execute.getEnvironmentVariables();
+ String cp = (String) env.get("CLASSPATH");
+ if (cp != null) {
+ commandline.createClasspath(getProject()).createPath()
+ .append(new Path(getProject(), cp));
+ }
+ log("Implicitly adding " + runtimeClasses + " to CLASSPATH",
+ Project.MSG_VERBOSE);
+ commandline.createClasspath(getProject()).createPath()
+ .append(runtimeClasses);
+ }
+
+ if (getOutputFile() != null) {
+ // having a space between the file and its path causes commandline
+ // to add quotes around the argument thus making JDepend not taking
+ // it into account. Thus we split it in two
+ commandline.createArgument().setValue("-file");
+ commandline.createArgument().setValue(outputFile.getPath());
+ // we have to find a cleaner way to put this output
+ }
+
+ if (getSourcespath() != null) {
+ // This is deprecated - use classespath in the future
+ String[] sP = getSourcespath().list();
+ for (int i = 0; i < sP.length; i++) {
+ File f = new File(sP[i]);
+
+ // not necessary as JDepend would fail, but why loose
+ // some time?
+ if (!f.exists() || !f.isDirectory()) {
+ throw new BuildException("\"" + f.getPath()
+ + "\" does not represent a valid"
+ + " directory. JDepend would"
+ + " fail.");
+ }
+ commandline.createArgument().setValue(f.getPath());
+ }
+ }
+
+ if (getClassespath() != null) {
+ // This is the new way - use classespath - code is the
+ // same for now
+ String[] cP = getClassespath().list();
+ for (int i = 0; i < cP.length; i++) {
+ File f = new File(cP[i]);
+ // not necessary as JDepend would fail, but why loose
+ // some time?
+ if (!f.exists()) {
+ throw new BuildException("\"" + f.getPath()
+ + "\" does not represent a valid"
+ + " file or directory. JDepend would"
+ + " fail.");
+ }
+ commandline.createArgument().setValue(f.getPath());
+ }
+ }
+
+ Execute execute = new Execute(new LogStreamHandler(this,
+ Project.MSG_INFO, Project.MSG_WARN), watchdog);
+ execute.setCommandline(commandline.getCommandline());
+ if (getDir() != null) {
+ execute.setWorkingDirectory(getDir());
+ execute.setAntRun(getProject());
+ }
+
+ if (getOutputFile() != null) {
+ log("Output to be stored in " + getOutputFile().getPath());
+ }
+ log(commandline.describeCommand(), Project.MSG_VERBOSE);
+ try {
+ return execute.execute();
+ } catch (IOException e) {
+ throw new BuildException("Process fork failed.", e, getLocation());
+ }
+ }
+
+ /**
+ * @return <tt>null</tt> if there is a timeout value, otherwise the
+ * watchdog instance.
+ * @throws BuildException in case of error
+ */
+ protected ExecuteWatchdog createWatchdog() throws BuildException {
+ if (getTimeout() == null) {
+ return null;
+ }
+ return new ExecuteWatchdog(getTimeout().longValue());
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java
new file mode 100644
index 00000000..20e9fc51
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jlink;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Reads just enough of a class file to determine the class' full name.
+ *
+ * <p>Extremely minimal constant pool implementation, mainly to support extracting
+ * strings from a class file.
+ */
+class ConstantPool {
+ // CheckStyle:VisibilityModifier OFF - bc
+ static final
+ byte UTF8 = 1, UNUSED = 2, INTEGER = 3, FLOAT = 4, LONG = 5, DOUBLE = 6,
+ CLASS = 7, STRING = 8, FIELDREF = 9, METHODREF = 10,
+ INTERFACEMETHODREF = 11, NAMEANDTYPE = 12;
+
+ byte[] types;
+
+ Object[] values;
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Create a constant pool.
+ * @param data the data input containing the class.
+ * @throws IOException if there is an error.
+ */
+ ConstantPool(DataInput data) throws IOException {
+ super();
+
+ int count = data.readUnsignedShort();
+ types = new byte [ count ];
+ values = new Object [ count ];
+ // read in all constant pool entries.
+ for (int i = 1; i < count; i++) {
+ byte type = data.readByte();
+ types[i] = type;
+ switch (type) {
+ case UTF8 :
+ values[i] = data.readUTF();
+ break;
+
+ case UNUSED :
+ break;
+
+ case INTEGER :
+ values[i] = new Integer(data.readInt());
+ break;
+
+ case FLOAT :
+ values[i] = new Float(data.readFloat());
+ break;
+
+ case LONG :
+ values[i] = new Long(data.readLong());
+ ++i;
+ break;
+
+ case DOUBLE :
+ values[i] = new Double(data.readDouble());
+ ++i;
+ break;
+
+ case CLASS :
+ case STRING :
+ values[i] = new Integer(data.readUnsignedShort());
+ break;
+
+ case FIELDREF :
+ case METHODREF :
+ case INTERFACEMETHODREF :
+ case NAMEANDTYPE :
+ values[i] = new Integer(data.readInt());
+ break;
+ default:
+ // Do nothing
+ }
+ }
+ }
+}
+
+/**
+ * Provides a quick and dirty way to determine the true name of a class
+ * given just an InputStream. Reads in just enough to perform this
+ * minimal task only.
+ */
+public class ClassNameReader extends Object {
+ private static final int CLASS_MAGIC_NUMBER = 0xCAFEBABE;
+
+ /**
+ * Get the class name of a class in an input stream.
+ *
+ * @param input an <code>InputStream</code> value
+ * @return the name of the class
+ * @exception IOException if an error occurs
+ */
+ public static String getClassName(InputStream input) throws IOException {
+ DataInputStream data = new DataInputStream(input);
+ // verify this is a valid class file.
+ int cookie = data.readInt();
+ if (cookie != CLASS_MAGIC_NUMBER) {
+ return null;
+ }
+ /* int version = */ data.readInt();
+ // read the constant pool.
+ ConstantPool constants = new ConstantPool(data);
+ Object[] values = constants.values;
+ // read access flags and class index.
+ /* int accessFlags = */ data.readUnsignedShort();
+ int classIndex = data.readUnsignedShort();
+ Integer stringIndex = (Integer) values[classIndex];
+ String className = (String) values[stringIndex.intValue()];
+ return className;
+ }
+
+
+}
+
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java
new file mode 100644
index 00000000..f5767e67
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jlink;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * This class defines objects that can link together various jar and
+ * zip files.
+ *
+ * <p>It is basically a wrapper for the jlink code written originally
+ * by <a href="mailto:beard@netscape.com">Patrick Beard</a>. The
+ * classes org.apache.tools.ant.taskdefs.optional.jlink.Jlink and
+ * org.apache.tools.ant.taskdefs.optional.jlink.ClassNameReader
+ * support this class.</p>
+ *
+ * <p>For example:
+ * <code>
+ * <pre>
+ * &lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;/&gt;
+ * &lt;mergefiles&gt;
+ * &lt;pathelement path=&quot;${build.dir}/mergefoo.jar&quot;/&gt;
+ * &lt;pathelement path=&quot;${build.dir}/mergebar.jar&quot;/&gt;
+ * &lt;/mergefiles&gt;
+ * &lt;addfiles&gt;
+ * &lt;pathelement path=&quot;${build.dir}/mac.jar&quot;/&gt;
+ * &lt;pathelement path=&quot;${build.dir}/pc.zip&quot;/&gt;
+ * &lt;/addfiles&gt;
+ * &lt;/jlink&gt;
+ * </pre>
+ * </code>
+ *
+ * @ant.task ignore="true"
+ */
+public class JlinkTask extends MatchingTask {
+
+ /**
+ * The output file for this run of jlink. Usually a jar or zip file.
+ * @param outfile the output file
+ */
+ public void setOutfile(File outfile) {
+ this.outfile = outfile;
+ }
+
+ /**
+ * Establishes the object that contains the files to
+ * be merged into the output.
+ * @return a path to be configured
+ */
+ public Path createMergefiles() {
+ if (this.mergefiles == null) {
+ this.mergefiles = new Path(getProject());
+ }
+ return this.mergefiles.createPath();
+ }
+
+ /**
+ * Sets the files to be merged into the output.
+ * @param mergefiles a path
+ */
+ public void setMergefiles(Path mergefiles) {
+ if (this.mergefiles == null) {
+ this.mergefiles = mergefiles;
+ } else {
+ this.mergefiles.append(mergefiles);
+ }
+ }
+
+ /**
+ * Establishes the object that contains the files to
+ * be added to the output.
+ * @return a path to be configured
+ */
+ public Path createAddfiles() {
+ if (this.addfiles == null) {
+ this.addfiles = new Path(getProject());
+ }
+ return this.addfiles.createPath();
+ }
+
+ /**
+ * Sets the files to be added into the output.
+ * @param addfiles a path
+ */
+ public void setAddfiles(Path addfiles) {
+ if (this.addfiles == null) {
+ this.addfiles = addfiles;
+ } else {
+ this.addfiles.append(addfiles);
+ }
+ }
+
+ /**
+ * Defines whether or not the output should be compacted.
+ * @param compress a <code>boolean</code> value
+ */
+ public void setCompress(boolean compress) {
+ this.compress = compress;
+ }
+
+ /**
+ * Does the adding and merging.
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+ //Be sure everything has been set.
+ if (outfile == null) {
+ throw new BuildException("outfile attribute is required! "
+ + "Please set.");
+ }
+ if (!haveAddFiles() && !haveMergeFiles()) {
+ throw new BuildException("addfiles or mergefiles required! "
+ + "Please set.");
+ }
+ log("linking: " + outfile.getPath());
+ log("compression: " + compress, Project.MSG_VERBOSE);
+ jlink linker = new jlink();
+ linker.setOutfile(outfile.getPath());
+ linker.setCompression(compress);
+ if (haveMergeFiles()) {
+ log("merge files: " + mergefiles.toString(), Project.MSG_VERBOSE);
+ linker.addMergeFiles(mergefiles.list());
+ }
+ if (haveAddFiles()) {
+ log("add files: " + addfiles.toString(), Project.MSG_VERBOSE);
+ linker.addAddFiles(addfiles.list());
+ }
+ try {
+ linker.link();
+ } catch (Exception ex) {
+ throw new BuildException(ex, getLocation());
+ }
+ }
+
+ private boolean haveAddFiles() {
+ return haveEntries(addfiles);
+ }
+
+ private boolean haveMergeFiles() {
+ return haveEntries(mergefiles);
+ }
+
+ private boolean haveEntries(Path p) {
+ if (p == null) {
+ return false;
+ }
+ if (p.size() > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private File outfile = null;
+
+ private Path mergefiles = null;
+
+ private Path addfiles = null;
+
+ private boolean compress = false;
+
+}
+
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java
new file mode 100644
index 00000000..499cca27
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java
@@ -0,0 +1,458 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+/**
+ * jlink.java links together multiple .jar files Original code by Patrick
+ * Beard. Modifications to work with ANT by Matthew Kuperus Heun.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jlink;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.tools.ant.util.FileUtils;
+
+// CheckStyle:TypeNameCheck OFF - bc
+/**
+ * jlink links together multiple .jar files.
+ */
+public class jlink {
+ private static final int BUFFER_SIZE = 8192;
+ private static final int VECTOR_INIT_SIZE = 10;
+
+ private String outfile = null;
+
+ private Vector mergefiles = new Vector(VECTOR_INIT_SIZE);
+
+ private Vector addfiles = new Vector(VECTOR_INIT_SIZE);
+
+ private boolean compression = false;
+
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ /** The file that will be created by this instance of jlink.
+ * @param outfile the file to create.
+ */
+ public void setOutfile(String outfile) {
+ if (outfile == null) {
+ return;
+ }
+ this.outfile = outfile;
+ }
+
+
+ /**
+ * Adds a file to be merged into the output.
+ * @param fileToMerge the file to merge into the output.
+ */
+ public void addMergeFile(String fileToMerge) {
+ if (fileToMerge == null) {
+ return;
+ }
+ mergefiles.addElement(fileToMerge);
+ }
+
+
+ /** Adds a file to be added into the output.
+ * @param fileToAdd the file to add to the output.
+ */
+ public void addAddFile(String fileToAdd) {
+ if (fileToAdd == null) {
+ return;
+ }
+ addfiles.addElement(fileToAdd);
+ }
+
+
+ /**
+ * Adds several files to be merged into the output.
+ * @param filesToMerge an array of files to merge into the output.
+ */
+ public void addMergeFiles(String[] filesToMerge) {
+ if (filesToMerge == null) {
+ return;
+ }
+ for (int i = 0; i < filesToMerge.length; i++) {
+ addMergeFile(filesToMerge[i]);
+ }
+ }
+
+
+ /**
+ * Adds several file to be added into the output.
+ * @param filesToAdd an array of files to add to the output.
+ */
+ public void addAddFiles(String[] filesToAdd) {
+ if (filesToAdd == null) {
+ return;
+ }
+ for (int i = 0; i < filesToAdd.length; i++) {
+ addAddFile(filesToAdd[i]);
+ }
+ }
+
+
+ /**
+ * Determines whether output will be compressed.
+ * @param compress if true use compression.
+ */
+ public void setCompression(boolean compress) {
+ this.compression = compress;
+ }
+
+
+ /**
+ * Performs the linking of files. Addfiles are added to the output as-is.
+ * For example, a jar file is added to the output as a jar file. However,
+ * mergefiles are first examined for their type. If it is a jar or zip
+ * file, the contents will be extracted from the mergefile and entered
+ * into the output. If a zip or jar file is encountered in a subdirectory
+ * it will be added, not merged. If a directory is encountered, it becomes
+ * the root entry of all the files below it. Thus, you can provide
+ * multiple, disjoint directories, as addfiles: they will all be added in
+ * a rational manner to outfile.
+ * @throws Exception on error.
+ */
+ public void link() throws Exception {
+ ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outfile));
+
+ if (compression) {
+ output.setMethod(ZipOutputStream.DEFLATED);
+ output.setLevel(Deflater.DEFAULT_COMPRESSION);
+ } else {
+ output.setMethod(ZipOutputStream.STORED);
+ }
+
+ Enumeration merges = mergefiles.elements();
+
+ while (merges.hasMoreElements()) {
+ String path = (String) merges.nextElement();
+ File f = new File(path);
+
+ if (f.getName().endsWith(".jar") || f.getName().endsWith(".zip")) {
+ //Do the merge
+ mergeZipJarContents(output, f);
+ } else {
+ //Add this file to the addfiles Vector and add it
+ //later at the top level of the output file.
+ addAddFile(path);
+ }
+ }
+
+ Enumeration adds = addfiles.elements();
+
+ while (adds.hasMoreElements()) {
+ String name = (String) adds.nextElement();
+ File f = new File(name);
+
+ if (f.isDirectory()) {
+ //System.out.println("in jlink: adding directory contents of " + f.getPath());
+ addDirContents(output, f, f.getName() + '/', compression);
+ } else {
+ addFile(output, f, "", compression);
+ }
+ }
+ FileUtils.close(output);
+ }
+
+
+ /**
+ * The command line entry point for jlink.
+ * @param args an array of arguments
+ */
+ public static void main(String[] args) {
+ // jlink output input1 ... inputN
+ if (args.length < 2) {
+ System.out.println("usage: jlink output input1 ... inputN");
+ System.exit(1);
+ }
+ jlink linker = new jlink();
+
+ linker.setOutfile(args[0]);
+ // To maintain compatibility with the command-line version,
+ // we will only add files to be merged.
+ for (int i = 1; i < args.length; i++) {
+ linker.addMergeFile(args[i]);
+ }
+ try {
+ linker.link();
+ } catch (Exception ex) {
+ System.err.print(ex.getMessage());
+ }
+ }
+
+
+ /*
+ * Actually performs the merging of f into the output.
+ * f should be a zip or jar file.
+ */
+ private void mergeZipJarContents(ZipOutputStream output, File f) throws IOException {
+ //Check to see that the file with name "name" exists.
+ if (!f.exists()) {
+ return;
+ }
+ ZipFile zipf = new ZipFile(f);
+ Enumeration entries = zipf.entries();
+
+ while (entries.hasMoreElements()) {
+ ZipEntry inputEntry = (ZipEntry) entries.nextElement();
+ //Ignore manifest entries. They're bound to cause conflicts between
+ //files that are being merged. User should supply their own
+ //manifest file when doing the merge.
+ String inputEntryName = inputEntry.getName();
+ int index = inputEntryName.indexOf("META-INF");
+
+ if (index < 0) {
+ //META-INF not found in the name of the entry. Go ahead and process it.
+ try {
+ output.putNextEntry(processEntry(zipf, inputEntry));
+ } catch (ZipException ex) {
+ //If we get here, it could be because we are trying to put a
+ //directory entry that already exists.
+ //For example, we're trying to write "com", but a previous
+ //entry from another mergefile was called "com".
+ //In that case, just ignore the error and go on to the
+ //next entry.
+ String mess = ex.getMessage();
+
+ if (mess.indexOf("duplicate") >= 0) {
+ //It was the duplicate entry.
+ continue;
+ } else {
+ // I hate to admit it, but we don't know what happened
+ // here. Throw the Exception.
+ throw ex;
+ }
+ }
+
+ InputStream in = zipf.getInputStream(inputEntry);
+ int len = buffer.length;
+ int count = -1;
+
+ while ((count = in.read(buffer, 0, len)) > 0) {
+ output.write(buffer, 0, count);
+ }
+ in.close();
+ output.closeEntry();
+ }
+ }
+ zipf.close();
+ }
+
+
+ /*
+ * Adds contents of a directory to the output.
+ */
+ private void addDirContents(ZipOutputStream output, File dir, String prefix,
+ boolean compress) throws IOException {
+ String[] contents = dir.list();
+
+ for (int i = 0; i < contents.length; ++i) {
+ String name = contents[i];
+ File file = new File(dir, name);
+
+ if (file.isDirectory()) {
+ addDirContents(output, file, prefix + name + '/', compress);
+ } else {
+ addFile(output, file, prefix, compress);
+ }
+ }
+ }
+
+
+ /*
+ * Gets the name of an entry in the file. This is the real name
+ * which for a class is the name of the package with the class
+ * name appended.
+ */
+ private String getEntryName(File file, String prefix) {
+ String name = file.getName();
+
+ if (!name.endsWith(".class")) {
+ // see if the file is in fact a .class file, and determine its actual name.
+ InputStream input = null;
+ try {
+ input = new FileInputStream(file);
+ String className = ClassNameReader.getClassName(input);
+
+ if (className != null) {
+ return className.replace('.', '/') + ".class";
+ }
+ } catch (IOException ioe) {
+ //do nothing
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ //do nothing
+ }
+ }
+ }
+ }
+ System.out.println("From " + file.getPath() + " and prefix " + prefix
+ + ", creating entry " + prefix + name);
+ return (prefix + name);
+ }
+
+
+ /*
+ * Adds a file to the output stream.
+ */
+ private void addFile(ZipOutputStream output, File file, String prefix,
+ boolean compress) throws IOException {
+ //Make sure file exists
+ if (!file.exists()) {
+ return;
+ }
+ ZipEntry entry = new ZipEntry(getEntryName(file, prefix));
+
+ entry.setTime(file.lastModified());
+ entry.setSize(file.length());
+ if (!compress) {
+ entry.setCrc(calcChecksum(file));
+ }
+ FileInputStream input = new FileInputStream(file);
+
+ addToOutputStream(output, input, entry);
+ }
+
+
+ /*
+ * A convenience method that several other methods might call.
+ */
+ private void addToOutputStream(ZipOutputStream output, InputStream input,
+ ZipEntry ze) throws IOException {
+ try {
+ output.putNextEntry(ze);
+ } catch (ZipException zipEx) {
+ //This entry already exists. So, go with the first one.
+ input.close();
+ return;
+ }
+
+ int numBytes = -1;
+
+ while ((numBytes = input.read(buffer)) > 0) {
+ output.write(buffer, 0, numBytes);
+ }
+ output.closeEntry();
+ input.close();
+ }
+
+
+ /*
+ * A method that does the work on a given entry in a mergefile.
+ * The big deal is to set the right parameters in the ZipEntry
+ * on the output stream.
+ */
+ private ZipEntry processEntry(ZipFile zip, ZipEntry inputEntry) {
+ /*
+ First, some notes.
+ On MRJ 2.2.2, getting the size, compressed size, and CRC32 from the
+ ZipInputStream does not work for compressed (deflated) files. Those calls return -1.
+ For uncompressed (stored) files, those calls do work.
+ However, using ZipFile.getEntries() works for both compressed and
+ uncompressed files.
+
+ Now, from some simple testing I did, it seems that the value of CRC-32 is
+ independent of the compression setting. So, it should be easy to pass this
+ information on to the output entry.
+ */
+ String name = inputEntry.getName();
+
+ if (!(inputEntry.isDirectory() || name.endsWith(".class"))) {
+ try {
+ InputStream input = zip.getInputStream(zip.getEntry(name));
+ String className = ClassNameReader.getClassName(input);
+
+ input.close();
+ if (className != null) {
+ name = className.replace('.', '/') + ".class";
+ }
+ } catch (IOException ioe) {
+ //do nothing
+ }
+ }
+ ZipEntry outputEntry = new ZipEntry(name);
+
+ outputEntry.setTime(inputEntry.getTime());
+ outputEntry.setExtra(inputEntry.getExtra());
+ outputEntry.setComment(inputEntry.getComment());
+ outputEntry.setTime(inputEntry.getTime());
+ if (compression) {
+ outputEntry.setMethod(ZipEntry.DEFLATED);
+ //Note, don't need to specify size or crc for compressed files.
+ } else {
+ outputEntry.setMethod(ZipEntry.STORED);
+ outputEntry.setCrc(inputEntry.getCrc());
+ outputEntry.setSize(inputEntry.getSize());
+ }
+ return outputEntry;
+ }
+
+
+ /*
+ * Necessary in the case where you add a entry that
+ * is not compressed.
+ */
+ private long calcChecksum(File f) throws IOException {
+ BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+
+ return calcChecksum(in);
+ }
+
+
+ /*
+ * Necessary in the case where you add a entry that
+ * is not compressed.
+ */
+ private long calcChecksum(InputStream in) throws IOException {
+ CRC32 crc = new CRC32();
+ int len = buffer.length;
+ int count = -1;
+ int haveRead = 0;
+
+ while ((count = in.read(buffer, 0, len)) > 0) {
+ haveRead += count;
+ crc.update(buffer, 0, count);
+ }
+ in.close();
+ return crc.getValue();
+ }
+
+
+}
+
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java
new file mode 100644
index 00000000..609938c9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+import java.io.File;
+
+/**
+ * this class implements the name mangling rules of the jasper in tomcat4.1.x
+ * which is likely to remain for some time
+ * @see "org.apache.jasper.JspCompilationContext"
+ */
+public class Jasper41Mangler implements JspMangler {
+
+
+ /**
+ * map from a jsp file to a java filename; does not do packages
+ *
+ * @param jspFile file
+ * @return java filename
+ */
+ public String mapJspToJavaName(File jspFile) {
+ String jspUri = jspFile.getAbsolutePath();
+ int start = jspUri.lastIndexOf(File.separatorChar) + 1;
+ int end = jspUri.length();
+ StringBuffer modifiedClassName;
+ modifiedClassName = new StringBuffer(jspUri.length() - start);
+ if (!Character.isJavaIdentifierStart(jspUri.charAt(start))
+ || jspUri.charAt(start) == '_') {
+ // If the first char is not a start of Java identifier or is _
+ // prepend a '_'.
+ modifiedClassName.append('_');
+ }
+ for (int i = start; i < end; i++) {
+ char ch = jspUri.charAt(i);
+ if (Character.isJavaIdentifierPart(ch)) {
+ modifiedClassName.append(ch);
+ } else if (ch == '.') {
+ modifiedClassName.append('_');
+ } else {
+ modifiedClassName.append(mangleChar(ch));
+ }
+ }
+ return modifiedClassName.toString();
+ }
+
+ /**
+ * Mangle the specified character to create a legal Java class name.
+ */
+ private static String mangleChar(char ch) {
+ // CheckStyle:MagicNumber OFF
+ String s = Integer.toHexString(ch);
+ int nzeros = 5 - s.length();
+ char[] result = new char[6];
+ result[0] = '_';
+ for (int i = 1; i <= nzeros; i++) {
+ result[i] = '0';
+ }
+ for (int i = nzeros + 1, j = 0; i < 6; i++, j++) {
+ result[i] = s.charAt(j);
+ }
+ return new String(result);
+ // CheckStyle:MagicNumber ON
+ }
+
+
+ /**
+ * taking in the substring representing the path relative to the source dir
+ * return a new string representing the destination path
+ * @param path not used.
+ * @return null as this is not implemented.
+ * @todo
+ */
+ public String mapPath(String path) {
+ return null;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java
new file mode 100644
index 00000000..4274bf0d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java
@@ -0,0 +1,709 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+import java.io.File;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapter;
+import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapterFactory;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Runs a JSP compiler.
+ *
+ * <p> This task takes the given jsp files and compiles them into java
+ * files. It is then up to the user to compile the java files into classes.
+ *
+ * <p> The task requires the srcdir and destdir attributes to be
+ * set. This Task is a MatchingTask, so the files to be compiled can be
+ * specified using includes/excludes attributes or nested include/exclude
+ * elements. Optional attributes are verbose (set the verbosity level passed
+ * to jasper), package (name of the destination package for generated java
+ * classes and classpath (the classpath to use when running the jsp
+ * compiler).
+ * <p> This task supports the nested elements classpath (A Path) and
+ * classpathref (A Reference) which can be used in preference to the
+ * attribute classpath, if the jsp compiler is not already in the ant
+ * classpath.
+ *
+ * <p><h4>Usage</h4>
+ * <pre>
+ * &lt;jspc srcdir="${basedir}/src/war"
+ * destdir="${basedir}/gensrc"
+ * package="com.i3sp.jsp"
+ * verbose="9"&gt;
+ * &lt;include name="**\/*.jsp" /&gt;
+ * &lt;/jspc&gt;
+ * </pre>
+ *
+ * <p> Large Amount of cutting and pasting from the Javac task...
+ * @since 1.5
+ */
+public class JspC extends MatchingTask {
+ private Path classpath;
+ private Path compilerClasspath;
+ private Path src;
+ private File destDir;
+ private String packageName;
+ /** name of the compiler to use */
+ private String compilerName = "jasper";
+
+ /**
+ * -ieplugin &lt;clsid&gt; Java Plugin classid for Internet Explorer
+ */
+ private String iepluginid;
+ private boolean mapped;
+ private int verbose = 0;
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected Vector compileList = new Vector();
+ Vector javaFiles = new Vector();
+
+ /**
+ * flag to control action on execution trouble
+ */
+ protected boolean failOnError = true;
+
+ /**
+ * -uriroot &lt;dir&gt; The root directory that uri files should be resolved
+ * against,
+ */
+ private File uriroot;
+
+ /**
+ * -webinc &lt;file&gt; Creates partial servlet mappings for the -webapp option
+ */
+ private File webinc;
+
+ /**
+ * -webxml &lt;file&gt; Creates a complete web.xml when using the -webapp option.
+ */
+
+ private File webxml;
+
+ /**
+ * web apps
+ */
+ protected WebAppParameter webApp;
+
+
+
+ private static final String FAIL_MSG
+ = "Compile failed, messages should have been provided.";
+
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Set the path for source JSP files.
+ * @param srcDir the source path.
+ */
+ public void setSrcDir(Path srcDir) {
+ if (src == null) {
+ src = srcDir;
+ } else {
+ src.append(srcDir);
+ }
+ }
+
+ /**
+ * Get the source dir.
+ * @return the source path.
+ */
+ public Path getSrcDir() {
+ return src;
+ }
+
+ /**
+ * Set the destination directory into which the JSP source
+ * files should be compiled.
+ * @param destDir the destination directory.
+ */
+ public void setDestdir(File destDir) {
+ this.destDir = destDir;
+ }
+
+ /**
+ * Get the destination directory.
+ * @return the directory.
+ */
+ public File getDestdir() {
+ return destDir;
+ }
+
+ /**
+ * Set the name of the package the compiled jsp files should be in.
+ * @param pkg the name of the package.
+ */
+ public void setPackage(String pkg) {
+ this.packageName = pkg;
+ }
+
+ /**
+ * Get the name of the package.
+ * @return the package.
+ */
+ public String getPackage() {
+ return packageName;
+ }
+
+ /**
+ * Set the verbose level of the compiler
+ * @param i the verbose level to use.
+ */
+ public void setVerbose(int i) {
+ verbose = i;
+ }
+
+ /**
+ * Get the verbose level.
+ * @return the level.
+ */
+ public int getVerbose() {
+ return verbose;
+ }
+
+ /**
+ * Whether or not the build should halt if compilation fails.
+ * Defaults to <code>true</code>.
+ * @param fail a <code>boolean</code> value.
+ */
+ public void setFailonerror(boolean fail) {
+ failOnError = fail;
+ }
+ /**
+ * Gets the failonerror flag.
+ * @return the flag.
+ */
+ public boolean getFailonerror() {
+ return failOnError;
+ }
+
+ /**
+ * Get the IE CLASSID value.
+ * @return the value.
+ */
+ public String getIeplugin() {
+ return iepluginid;
+ }
+ /**
+ * Java Plugin CLASSID for Internet Explorer
+ * @param iepluginid the id to use.
+ */
+ public void setIeplugin(String iepluginid) {
+ this.iepluginid = iepluginid;
+ }
+
+ /**
+ * If true, generate separate write() calls for each HTML line
+ * in the JSP.
+ * @return mapping status
+ */
+ public boolean isMapped() {
+ return mapped;
+ }
+
+ /**
+ * If true, generate separate write() calls for each HTML line
+ * in the JSP.
+ * @param mapped a <code>boolean</code> value.
+ */
+ public void setMapped(boolean mapped) {
+ this.mapped = mapped;
+ }
+
+ /**
+ * The URI context of relative URI references in the JSP pages.
+ * If it does not exist then it is derived from the location
+ * of the file relative to the declared or derived value of uriroot.
+ *
+ * @param uribase The new Uribase value
+ */
+ public void setUribase(File uribase) {
+ log("Uribase is currently an unused parameter", Project.MSG_WARN);
+ }
+
+ /**
+ * Get the uri base value.
+ * @return the value.
+ */
+ public File getUribase() {
+ return uriroot;
+ }
+
+ /**
+ * The root directory that uri files should be resolved
+ * against. (Default is the directory jspc is invoked from)
+ *
+ * @param uriroot The new Uribase value
+ */
+ public void setUriroot(File uriroot) {
+ this.uriroot = uriroot;
+ }
+
+ /**
+ * Get the uri root value.
+ * @return the value.
+ */
+ public File getUriroot() {
+ return uriroot;
+ }
+
+
+ /**
+ * Set the classpath to be used for this compilation.
+ * @param cp the path to be used.
+ */
+ public void setClasspath(Path cp) {
+ if (classpath == null) {
+ classpath = cp;
+ } else {
+ classpath.append(cp);
+ }
+ }
+
+ /**
+ * Adds a path to the classpath.
+ * @return a path to be configured.
+ */
+ public Path createClasspath() {
+ if (classpath == null) {
+ classpath = new Path(getProject());
+ }
+ return classpath.createPath();
+ }
+
+ /**
+ * Adds a reference to a classpath defined elsewhere
+ * @param r a reference to a classpath.
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * Get the classpath.
+ * @return the classpath.
+ */
+ public Path getClasspath() {
+ return classpath;
+ }
+
+ /**
+ * Set the classpath to be used to find this compiler adapter
+ * @param cp the compiler classpath.
+ */
+ public void setCompilerclasspath(Path cp) {
+ if (compilerClasspath == null) {
+ compilerClasspath = cp;
+ } else {
+ compilerClasspath.append(cp);
+ }
+ }
+
+ /**
+ * get the classpath used to find the compiler adapter
+ * @return the compiler classpath.
+ */
+ public Path getCompilerclasspath() {
+ return compilerClasspath;
+ }
+
+ /**
+ * Support nested compiler classpath, used to locate compiler adapter
+ * @return a path to be configured.
+ */
+ public Path createCompilerclasspath() {
+ if (compilerClasspath == null) {
+ compilerClasspath = new Path(getProject());
+ }
+ return compilerClasspath.createPath();
+ }
+
+ /**
+ * Filename for web.xml.
+ *
+ * @param webxml The new Webxml value
+ */
+ public void setWebxml(File webxml) {
+ this.webxml = webxml;
+ }
+
+ /**
+ * Filename for web.xml.
+ * @return The filename for web.xml.
+ */
+ public File getWebxml() {
+ return this.webxml;
+ }
+
+ /**
+ * output filename for the fraction of web.xml that lists
+ * servlets.
+ * @param webinc The new Webinc value
+ */
+ public void setWebinc(File webinc) {
+ this.webinc = webinc;
+ }
+
+ /**
+ * Get the webinc attribute.
+ * @return the webinc attribute.
+ */
+ public File getWebinc() {
+ return this.webinc;
+ }
+
+ /**
+ * Adds a single webapp.
+ *
+ * @param webappParam add a web app parameter
+ * @throws BuildException if more than one webapp is specified.
+ */
+ public void addWebApp(WebAppParameter webappParam)
+ throws BuildException {
+ //demand create vector of filesets
+ if (webApp == null) {
+ webApp = webappParam;
+ } else {
+ throw new BuildException("Only one webapp can be specified");
+ }
+ }
+
+ /**
+ * Get the web app.
+ * @return the web app attribute.
+ */
+ public WebAppParameter getWebApp() {
+ return webApp;
+ }
+
+ /**
+ * Class name of a JSP compiler adapter.
+ * @param compiler the compiler class name.
+ */
+ public void setCompiler(String compiler) {
+ this.compilerName = compiler;
+ }
+
+ /**
+ * get the list of files to compile
+ * @return the list of files.
+ */
+ public Vector getCompileList() {
+ return compileList;
+ }
+
+ /**
+ * execute by building up a list of files that
+ * have changed and hand them off to a jsp compiler
+ * @throws BuildException on error.
+ */
+ public void execute()
+ throws BuildException {
+
+ // make sure that we've got a destdir
+ if (destDir == null) {
+ throw new BuildException("destdir attribute must be set!",
+ getLocation());
+ }
+
+ if (!destDir.isDirectory()) {
+ throw new BuildException("destination directory \"" + destDir
+ + "\" does not exist or is not a directory",
+ getLocation());
+ }
+
+ File dest = getActualDestDir();
+
+ AntClassLoader al = null;
+ try {
+ //bind to a compiler
+ JspCompilerAdapter compiler =
+ JspCompilerAdapterFactory
+ .getCompiler(compilerName, this,
+ al = getProject().createClassLoader(compilerClasspath));
+
+ //if we are a webapp, hand off to the compiler, which had
+ //better handle it
+ if (webApp != null) {
+ doCompilation(compiler);
+ return;
+ }
+
+ // make sure that we've got a srcdir
+ if (src == null) {
+ throw new BuildException("srcdir attribute must be set!",
+ getLocation());
+ }
+ String [] list = src.list();
+ if (list.length == 0) {
+ throw new BuildException("srcdir attribute must be set!",
+ getLocation());
+ }
+
+
+ // if the compiler does its own dependency stuff, we just
+ // call it right now
+ if (compiler.implementsOwnDependencyChecking()) {
+ doCompilation(compiler);
+ return;
+ }
+
+ //the remainder of this method is only for compilers that
+ //need their dependency work done
+ JspMangler mangler = compiler.createMangler();
+
+ // scan source directories and dest directory to build up both copy
+ // lists and compile lists
+ resetFileLists();
+ int filecount = 0;
+ for (int i = 0; i < list.length; i++) {
+ File srcDir = getProject().resolveFile(list[i]);
+ if (!srcDir.exists()) {
+ throw new BuildException("srcdir \"" + srcDir.getPath()
+ + "\" does not exist!",
+ getLocation());
+ }
+ DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+ String[] files = ds.getIncludedFiles();
+ filecount = files.length;
+ scanDir(srcDir, dest, mangler, files);
+ }
+
+ // compile the source files
+
+ log("compiling " + compileList.size() + " files",
+ Project.MSG_VERBOSE);
+
+ if (compileList.size() > 0) {
+
+ log("Compiling " + compileList.size() + " source file"
+ + (compileList.size() == 1 ? "" : "s")
+ + " to "
+ + dest);
+ doCompilation(compiler);
+
+ } else {
+ if (filecount == 0) {
+ log("there were no files to compile", Project.MSG_INFO);
+ } else {
+ log("all files are up to date", Project.MSG_VERBOSE);
+ }
+ }
+ } finally {
+ if (al != null) {
+ al.cleanup();
+ }
+ }
+ }
+
+ /**
+ * calculate where the files will end up:
+ * this is destDir or it id destDir + the package name
+ */
+ private File getActualDestDir() {
+ File dest = null;
+ if (packageName == null) {
+ dest = destDir;
+ } else {
+ String path = destDir.getPath() + File.separatorChar
+ + packageName.replace('.', File.separatorChar);
+ dest = new File(path);
+ }
+ return dest;
+ }
+
+ /**
+ * do the compile
+ */
+ private void doCompilation(JspCompilerAdapter compiler)
+ throws BuildException {
+ // now we need to populate the compiler adapter
+ compiler.setJspc(this);
+
+ // finally, lets execute the compiler!!
+ if (!compiler.execute()) {
+ if (failOnError) {
+ throw new BuildException(FAIL_MSG, getLocation());
+ } else {
+ log(FAIL_MSG, Project.MSG_ERR);
+ }
+ }
+ }
+
+ /**
+ * Clear the list of files to be compiled and copied..
+ */
+ protected void resetFileLists() {
+ compileList.removeAllElements();
+ }
+
+ /**
+ * Scans the directory looking for source files to be compiled.
+ * The results are returned in the class variable compileList
+ * @param srcDir the source directory.
+ * @param dest the destination directory.
+ * @param mangler the jsp filename mangler.
+ * @param files the file names to mangle.
+ */
+ protected void scanDir(File srcDir, File dest, JspMangler mangler,
+ String[] files) {
+
+ long now = (new Date()).getTime();
+
+ for (int i = 0; i < files.length; i++) {
+ String filename = files[i];
+ File srcFile = new File(srcDir, filename);
+ File javaFile = mapToJavaFile(mangler, srcFile, srcDir, dest);
+ if (javaFile == null) {
+ continue;
+ }
+
+ if (srcFile.lastModified() > now) {
+ log("Warning: file modified in the future: " + filename,
+ Project.MSG_WARN);
+ }
+ boolean shouldCompile = false;
+ shouldCompile = isCompileNeeded(srcFile, javaFile);
+ if (shouldCompile) {
+ compileList.addElement(srcFile.getAbsolutePath());
+ javaFiles.addElement(javaFile);
+ }
+ }
+ }
+
+ /**
+ * Test whether or not compilation is needed. A return value of
+ * <code>true<code> means yes, <code>false</code> means
+ * our tests do not indicate this, but as the TLDs are
+ * not used for dependency checking this is not guaranteed.
+ * The current tests are
+ * <ol>
+ * <li>no dest file
+ * <li>dest file out of date w.r.t source
+ * <li>dest file zero bytes long
+ * </ol>
+ * @param srcFile JSP source file
+ * @param javaFile JSP dest file
+ * @return true if a compile is definitely needed.
+ *
+ */
+ private boolean isCompileNeeded(File srcFile, File javaFile) {
+ boolean shouldCompile = false;
+ if (!javaFile.exists()) {
+ shouldCompile = true;
+ log("Compiling " + srcFile.getPath()
+ + " because java file " + javaFile.getPath()
+ + " does not exist", Project.MSG_VERBOSE);
+ } else {
+ if (srcFile.lastModified() > javaFile.lastModified()) {
+ shouldCompile = true;
+ log("Compiling " + srcFile.getPath()
+ + " because it is out of date with respect to "
+ + javaFile.getPath(),
+ Project.MSG_VERBOSE);
+ } else {
+ if (javaFile.length() == 0) {
+ shouldCompile = true;
+ log("Compiling " + srcFile.getPath()
+ + " because java file " + javaFile.getPath()
+ + " is empty", Project.MSG_VERBOSE);
+ }
+ }
+ }
+ return shouldCompile;
+ }
+
+
+ /**
+ * get a filename from our jsp file.
+ * @param mangler the jsp filename manager.
+ * @param srcFile the source file.
+ * @param srcDir the source directory.
+ * @param dest the destination directory.
+ * @return the filename.
+ * @todo support packages and subdirs
+ */
+ protected File mapToJavaFile(JspMangler mangler, File srcFile, File srcDir,
+ File dest) {
+ if (!srcFile.getName().endsWith(".jsp")) {
+ return null;
+ }
+ String javaFileName = mangler.mapJspToJavaName(srcFile);
+ // String srcFileDir=srcFile.getParent();
+ return new File(dest, javaFileName);
+ }
+
+ /**
+ * delete any java output files that are empty
+ * this is to get around a little defect in jasper: when it
+ * fails, it leaves incomplete files around.
+ */
+ public void deleteEmptyJavaFiles() {
+ if (javaFiles != null) {
+ Enumeration e = javaFiles.elements();
+ while (e.hasMoreElements()) {
+ File file = (File) e.nextElement();
+ if (file.exists() && file.length() == 0) {
+ log("deleting empty output file " + file);
+ file.delete();
+ }
+ }
+ }
+ }
+
+ /**
+ * static inner class used as a parameter element
+ */
+ public static class WebAppParameter {
+
+ /**
+ * the sole option
+ */
+ private File directory;
+
+ /**
+ * query current directory
+ * @return the directory.
+ */
+ public File getDirectory() {
+ return directory;
+ }
+
+ /**
+ * set directory; alternate syntax
+ * @param directory the base dir.
+ */
+ public void setBaseDir(File directory) {
+ this.directory = directory;
+ }
+ //end inner class
+ }
+
+
+ //end class
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java
new file mode 100644
index 00000000..f62492c3
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+import java.io.File;
+
+/**
+ * This is an interface to the Mangler service that jspc needs to map
+ * JSP file names to java files.
+ * Note the complete lack of correlation
+ * with Jasper's mangler interface.
+ */
+public interface JspMangler {
+
+
+ /**
+ * map from a jsp file to a java filename; does not do packages
+ *
+ * @param jspFile file
+ * @return java filename
+ */
+ String mapJspToJavaName(File jspFile);
+
+ /**
+ * taking in the substring representing the path relative to the source dir
+ * return a new string representing the destination path
+ * @param path the path to map.
+ * @return the mapped path.
+ */
+ String mapPath(String path);
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java
new file mode 100644
index 00000000..6e08e7d5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp;
+import java.io.File;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * This is a class derived from the Jasper code
+ * (org.apache.jasper.compiler.CommandLineCompiler) to map from a JSP filename
+ * to a valid Java classname.
+ *
+ */
+public class JspNameMangler implements JspMangler {
+
+ // CheckStyle:ConstantNameCheck OFF - bc
+
+ /**
+ * this is the list of keywords which can not be used as classnames
+ */
+ public static final String[] keywords = {
+ "assert",
+ "abstract", "boolean", "break", "byte",
+ "case", "catch", "char", "class",
+ "const", "continue", "default", "do",
+ "double", "else", "extends", "final",
+ "finally", "float", "for", "goto",
+ "if", "implements", "import",
+ "instanceof", "int", "interface",
+ "long", "native", "new", "package",
+ "private", "protected", "public",
+ "return", "short", "static", "super",
+ "switch", "synchronized", "this",
+ "throw", "throws", "transient",
+ "try", "void", "volatile", "while"
+ };
+
+ // CheckStyle:ConstantNameCheck ON
+
+ /**
+ * map from a jsp file to a java filename; does not do packages
+ *
+ * @param jspFile file
+ * @return java filename
+ */
+ public String mapJspToJavaName(File jspFile) {
+ return mapJspToBaseName(jspFile) + ".java";
+ }
+
+
+ /**
+ * map from a jsp file to a base name; does not deal with extensions
+ *
+ * @param jspFile jspFile file
+ * @return exensionless potentially remapped name
+ */
+ private String mapJspToBaseName(File jspFile) {
+ String className;
+ className = stripExtension(jspFile);
+
+ // since we don't mangle extensions like the servlet does,
+ // we need to check for keywords as class names
+ for (int i = 0; i < keywords.length; ++i) {
+ if (className.equals(keywords[i])) {
+ className += "%";
+ break;
+ }
+ }
+
+ // Fix for invalid characters. If you think of more add to the list.
+ StringBuffer modifiedClassName = new StringBuffer(className.length());
+ // first char is more restrictive than the rest
+ char firstChar = className.charAt(0);
+ if (Character.isJavaIdentifierStart(firstChar)) {
+ modifiedClassName.append(firstChar);
+ } else {
+ modifiedClassName.append(mangleChar(firstChar));
+ }
+ // this is the rest
+ for (int i = 1; i < className.length(); i++) {
+ char subChar = className.charAt(i);
+ if (Character.isJavaIdentifierPart(subChar)) {
+ modifiedClassName.append(subChar);
+ } else {
+ modifiedClassName.append(mangleChar(subChar));
+ }
+ }
+ return modifiedClassName.toString();
+ }
+
+
+ /**
+ * get short filename from file
+ *
+ * @param jspFile file in
+ * @return file without any jsp extension
+ */
+ private String stripExtension(File jspFile) {
+ return StringUtils.removeSuffix(jspFile.getName(), ".jsp");
+ }
+
+
+ /**
+ * definition of the char escaping algorithm
+ *
+ * @param ch char to mangle
+ * @return mangled string; 5 digit hex value
+ */
+ private static String mangleChar(char ch) {
+ // CheckStyle:MagicNumber OFF
+ if (ch == File.separatorChar) {
+ ch = '/';
+ }
+ String s = Integer.toHexString(ch);
+ int nzeros = 5 - s.length();
+ char[] result = new char[6];
+ result[0] = '_';
+ for (int i = 1; i <= nzeros; ++i) {
+ result[i] = '0';
+ }
+ int resultIndex = 0;
+ for (int i = nzeros + 1; i < 6; ++i) {
+ result[i] = s.charAt(resultIndex++);
+ }
+ return new String(result);
+ // CheckStyle:MagicNumber ON
+ }
+
+ /**
+ * taking in the substring representing the path relative to the source dir
+ * return a new string representing the destination path
+ * not supported, as jasper in tomcat4.0 doesn't either
+ * @param path not used
+ * @return null always.
+ */
+ public String mapPath(String path) {
+ return null;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java
new file mode 100644
index 00000000..45a427ad
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+//apache/ant imports
+import java.io.File;
+import java.util.Date;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Precompiles JSP's using WebLogic's JSP compiler (weblogic.jspc).
+ *
+ * Tested only on Weblogic 4.5.1 - NT4.0 and Solaris 5.7
+ *
+ * required attributes
+ * src : root of source tree for JSP, ie, the document root for your weblogic server
+ * dest : root of destination directory, what you have set as
+ * WorkingDir in the weblogic properties
+ * package : start package name under which your JSP's would be compiled
+ *
+ * other attributes
+ * classpath
+ *
+ * A classpath should be set which contains the weblogic classes as well as all
+ * application classes referenced by the JSP. The system classpath is also
+ * appended when the jspc is called, so you may choose to put everything in
+ * the classpath while calling Ant. However, since presumably the JSP's will
+ * reference classes being build by Ant, it would be better to explicitly add
+ * the classpath in the task
+ *
+ * The task checks timestamps on the JSP's and the generated classes, and compiles
+ * only those files that have changed.
+ *
+ * It follows the weblogic naming convention of putting classes in
+ * <b> _dirName/_fileName.class for dirname/fileName.jsp </b>
+ *
+ * Limitation: It compiles the files thru the Classic compiler only.
+ * Limitation: Since it is my experience that weblogic jspc throws out of
+ * memory error on being given too many files at one go, it is
+ * called multiple times with one jsp file each.
+ *
+ * <pre>
+ * example
+ * &lt;target name="jspcompile" depends="compile"&gt;
+ * &lt;wljspc src="c:\\weblogic\\myserver\\public_html"
+ * dest="c:\\weblogic\\myserver\\serverclasses" package="myapp.jsp"&gt;
+ * &lt;classpath&gt;
+ * &lt;pathelement location="${weblogic.classpath}" /&gt;
+ * &lt;pathelement path="${compile.dest}" /&gt;
+ * &lt;/classpath&gt;
+ *
+ * &lt;/wljspc&gt;
+ * &lt;/target&gt;
+ * </pre>
+ *
+ */
+
+public class WLJspc extends MatchingTask {
+ //TODO Test on other versions of weblogic
+ //TODO add more attributes to the task, to take care of all jspc options
+ //TODO Test on Unix
+
+ /** root of compiled files tree */
+ private File destinationDirectory;
+
+ /** root of source files tree */
+ private File sourceDirectory;
+
+ /** package under which resultant classes will reside */
+ private String destinationPackage;
+
+ /** classpath used to compile the jsp files. */
+ private Path compileClasspath;
+
+ //private String compilerPath; //fully qualified name for the compiler executable
+
+ private String pathToPackage = "";
+ private Vector filesToDo = new Vector();
+
+ /**
+ * Run the task.
+ * @throws BuildException if there is an error.
+ */
+ public void execute() throws BuildException {
+ if (!destinationDirectory.isDirectory()) {
+ throw new BuildException("destination directory "
+ + destinationDirectory.getPath() + " is not valid");
+ }
+
+ if (!sourceDirectory.isDirectory()) {
+ throw new BuildException("src directory "
+ + sourceDirectory.getPath() + " is not valid");
+ }
+
+ if (destinationPackage == null) {
+ throw new BuildException("package attribute must be present.",
+ getLocation());
+ }
+
+
+ pathToPackage
+ = this.destinationPackage.replace('.', File.separatorChar);
+ // get all the files in the sourceDirectory
+ DirectoryScanner ds = super.getDirectoryScanner(sourceDirectory);
+
+ //use the systemclasspath as well, to include the ant jar
+ if (compileClasspath == null) {
+ compileClasspath = new Path(getProject());
+ }
+
+ compileClasspath = compileClasspath.concatSystemClasspath();
+ String[] files = ds.getIncludedFiles();
+
+ //Weblogic.jspc calls System.exit() ... have to fork
+ // Therefore, takes loads of time
+ // Can pass directories at a time (*.jsp) but easily runs out of
+ // memory on hefty dirs (even on a Sun)
+ Java helperTask = new Java(this);
+ helperTask.setFork(true);
+ helperTask.setClassname("weblogic.jspc");
+ helperTask.setTaskName(getTaskName());
+ // CheckStyle:MagicNumber OFF
+ String[] args = new String[12];
+ // CheckStyle:MagicNumber ON
+
+ File jspFile = null;
+ String parents = "";
+ int j = 0;
+ //TODO this array stuff is a remnant of prev trials.. gotta remove.
+ args[j++] = "-d";
+ args[j++] = destinationDirectory.getAbsolutePath().trim();
+ args[j++] = "-docroot";
+ args[j++] = sourceDirectory.getAbsolutePath().trim();
+ args[j++] = "-keepgenerated";
+ //Call compiler as class... dont want to fork again
+ //Use classic compiler -- can be parameterised?
+ args[j++] = "-compilerclass";
+ args[j++] = "sun.tools.javac.Main";
+ //Weblogic jspc does not seem to work unless u explicitly set this...
+ // Does not take the classpath from the env....
+ // Am i missing something about the Java task??
+ args[j++] = "-classpath";
+ args[j++] = compileClasspath.toString();
+
+ this.scanDir(files);
+ log("Compiling " + filesToDo.size() + " JSP files");
+
+ final int size = filesToDo.size();
+ for (int i = 0; i < size; i++) {
+ //TODO
+ // All this to get package according to weblogic standards
+ // Can be written better... this is too hacky!
+ // Careful.. similar code in scanDir , but slightly different!!
+ String filename = (String) filesToDo.elementAt(i);
+ jspFile = new File(filename);
+ args[j] = "-package";
+ parents = jspFile.getParent();
+ if ((parents != null) && (!("").equals(parents))) {
+ parents = this.replaceString(parents, File.separator, "_.");
+ args[j + 1] = destinationPackage + "." + "_" + parents;
+ } else {
+ args[j + 1] = destinationPackage;
+ }
+
+
+ args[j + 2] = sourceDirectory + File.separator + filename;
+ helperTask.clearArgs();
+
+ // CheckStyle:MagicNumber OFF
+ for (int x = 0; x < j + 3; x++) {
+ helperTask.createArg().setValue(args[x]);
+ }
+ // CheckStyle:MagicNumber ON
+
+ helperTask.setClasspath(compileClasspath);
+ if (helperTask.executeJava() != 0) {
+ log(filename + " failed to compile", Project.MSG_WARN);
+ }
+ }
+ }
+
+
+
+ /**
+ * Set the classpath to be used for this compilation.
+ * @param classpath the classpath to use.
+ */
+ public void setClasspath(Path classpath) {
+ if (compileClasspath == null) {
+ compileClasspath = classpath;
+ } else {
+ compileClasspath.append(classpath);
+ }
+ }
+
+ /**
+ * Maybe creates a nested classpath element.
+ * @return a path to be configured.
+ */
+ public Path createClasspath() {
+ if (compileClasspath == null) {
+ compileClasspath = new Path(getProject());
+ }
+ return compileClasspath;
+ }
+
+ /**
+ * Set the directory containing the source jsp's
+ *
+ *
+ * @param dirName the directory containg the source jsp's
+ */
+ public void setSrc(File dirName) {
+
+ sourceDirectory = dirName;
+ }
+
+ /**
+ * Set the directory containing the source jsp's
+ *
+ *
+ * @param dirName the directory containg the source jsp's
+ */
+ public void setDest(File dirName) {
+
+ destinationDirectory = dirName;
+ }
+
+ /**
+ * Set the package under which the compiled classes go
+ *
+ * @param packageName the package name for the classes
+ */
+ public void setPackage(String packageName) {
+
+ destinationPackage = packageName;
+ }
+
+ /**
+ * Scan the array of files and add the jsp
+ * files that need to be compiled to the filesToDo field.
+ * @param files the files to scan.
+ */
+ protected void scanDir(String[] files) {
+
+ long now = (new Date()).getTime();
+ File jspFile = null;
+ String parents = null;
+ String pack = "";
+ for (int i = 0; i < files.length; i++) {
+ File srcFile = new File(this.sourceDirectory, files[i]);
+ //TODO
+ // All this to convert source to destination directory according
+ // to weblogic standards Can be written better... this is too hacky!
+ jspFile = new File(files[i]);
+ parents = jspFile.getParent();
+
+ if ((parents != null) && (!("").equals(parents))) {
+ parents = this.replaceString(parents, File.separator, "_/");
+ pack = pathToPackage + File.separator + "_" + parents;
+ } else {
+ pack = pathToPackage;
+ }
+
+ String filePath = pack + File.separator + "_";
+ int startingIndex = files[i].lastIndexOf(File.separator) != -1
+ ? files[i].lastIndexOf(File.separator) + 1 : 0;
+ int endingIndex = files[i].indexOf(".jsp");
+ if (endingIndex == -1) {
+ log("Skipping " + files[i] + ". Not a JSP",
+ Project.MSG_VERBOSE);
+ continue;
+ }
+
+ filePath += files[i].substring(startingIndex, endingIndex);
+ filePath += ".class";
+ File classFile = new File(this.destinationDirectory, filePath);
+
+ if (srcFile.lastModified() > now) {
+ log("Warning: file modified in the future: "
+ + files[i], Project.MSG_WARN);
+ }
+ if (srcFile.lastModified() > classFile.lastModified()) {
+ filesToDo.addElement(files[i]);
+ log("Recompiling File " + files[i], Project.MSG_VERBOSE);
+ }
+ }
+ }
+
+
+ /**
+ * Replace occurrences of a string with a replacement string.
+ * @param inpString the string to convert.
+ * @param escapeChars the string to replace.
+ * @param replaceChars the string to place.
+ * @return the converted string.
+ */
+ protected String replaceString(String inpString, String escapeChars,
+ String replaceChars) {
+ String localString = "";
+ int numTokens = 0;
+ StringTokenizer st = new StringTokenizer(inpString, escapeChars, true);
+ numTokens = st.countTokens();
+ for (int i = 0; i < numTokens; i++) {
+ String test = st.nextToken();
+ test = (test.equals(escapeChars) ? replaceChars : test);
+ localString += test;
+ }
+ return localString;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java
new file mode 100644
index 00000000..5c4d0e3b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspC;
+import org.apache.tools.ant.types.CommandlineJava;
+
+/**
+ * This is the default implementation for the JspCompilerAdapter interface.
+ * This is currently very light on the ground since only one compiler type is
+ * supported.
+ *
+ */
+public abstract class DefaultJspCompilerAdapter
+ implements JspCompilerAdapter {
+
+ private static String lSep = System.getProperty("line.separator");
+
+ /**
+ * Logs the compilation parameters, adds the files to compile and logs the
+ * &quot;niceSourceList&quot;
+ * @param jspc the compiler task for logging
+ * @param compileList the list of files to compile
+ * @param cmd the command line used
+ */
+ protected void logAndAddFilesToCompile(JspC jspc,
+ Vector compileList,
+ CommandlineJava cmd) {
+ jspc.log("Compilation " + cmd.describeJavaCommand(),
+ Project.MSG_VERBOSE);
+
+ StringBuffer niceSourceList = new StringBuffer("File");
+ if (compileList.size() != 1) {
+ niceSourceList.append("s");
+ }
+ niceSourceList.append(" to be compiled:");
+
+ niceSourceList.append(lSep);
+
+ Enumeration e = compileList.elements();
+ while (e.hasMoreElements()) {
+ String arg = (String) e.nextElement();
+ cmd.createArgument().setValue(arg);
+ niceSourceList.append(" ");
+ niceSourceList.append(arg);
+ niceSourceList.append(lSep);
+ }
+
+ jspc.log(niceSourceList.toString(), Project.MSG_VERBOSE);
+ }
+
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ /**
+ * our owner
+ */
+ protected JspC owner;
+
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * set the owner
+ * @param owner the owner JspC compiler
+ */
+ public void setJspc(JspC owner) {
+ this.owner = owner;
+ }
+
+ /** get the owner
+ * @return the owner; should never be null
+ */
+ public JspC getJspc() {
+ return owner;
+ }
+
+
+ /**
+ * add an argument oneple to the argument list, if the value aint null
+ * @param cmd the command line
+ * @param argument The argument
+ */
+ protected void addArg(CommandlineJava cmd, String argument) {
+ if (argument != null && argument.length() != 0) {
+ cmd.createArgument().setValue(argument);
+ }
+ }
+
+
+ /**
+ * add an argument tuple to the argument list, if the value aint null
+ * @param cmd the command line
+ * @param argument The argument
+ * @param value the parameter
+ */
+ protected void addArg(CommandlineJava cmd, String argument, String value) {
+ if (value != null) {
+ cmd.createArgument().setValue(argument);
+ cmd.createArgument().setValue(value);
+ }
+ }
+
+ /**
+ * add an argument tuple to the arg list, if the file parameter aint null
+ * @param cmd the command line
+ * @param argument The argument
+ * @param file the parameter
+ */
+ protected void addArg(CommandlineJava cmd, String argument, File file) {
+ if (file != null) {
+ cmd.createArgument().setValue(argument);
+ cmd.createArgument().setFile(file);
+ }
+ }
+
+ /**
+ * ask if compiler can sort out its own dependencies
+ * @return true if the compiler wants to do its own
+ * depends
+ */
+ public boolean implementsOwnDependencyChecking() {
+ return false;
+ }
+
+ /**
+ * get our project
+ * @return owner project data
+ */
+ public Project getProject() {
+ return getJspc().getProject();
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java
new file mode 100644
index 00000000..f0becacb
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import java.io.File;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspC;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspMangler;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The implementation of the jasper compiler.
+ * This is a cut-and-paste of the original Jspc task.
+ *
+ * @since ant1.5
+ */
+public class JasperC extends DefaultJspCompilerAdapter {
+
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ /**
+ * what produces java classes from .jsp files
+ */
+ JspMangler mangler;
+
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Constructor for JasperC.
+ * @param mangler a filename converter
+ */
+ public JasperC(JspMangler mangler) {
+ this.mangler = mangler;
+ }
+
+ /**
+ * Our execute method.
+ * @return true if successful
+ * @throws BuildException on error
+ */
+ public boolean execute()
+ throws BuildException {
+ getJspc().log("Using jasper compiler", Project.MSG_VERBOSE);
+ CommandlineJava cmd = setupJasperCommand();
+
+ try {
+ // Create an instance of the compiler, redirecting output to
+ // the project log
+ Java java = new Java(owner);
+ Path p = getClasspath();
+ if (getJspc().getClasspath() != null) {
+ getProject().log("using user supplied classpath: " + p,
+ Project.MSG_DEBUG);
+ } else {
+ getProject().log("using system classpath: " + p,
+ Project.MSG_DEBUG);
+ }
+ java.setClasspath(p);
+ java.setDir(getProject().getBaseDir());
+ java.setClassname("org.apache.jasper.JspC");
+ //this is really irritating; we need a way to set stuff
+ String []args = cmd.getJavaCommand().getArguments();
+ for (int i = 0; i < args.length; i++) {
+ java.createArg().setValue(args[i]);
+ }
+ java.setFailonerror(getJspc().getFailonerror());
+ //we are forking here to be sure that if JspC calls
+ //System.exit() it doesn't halt the build
+ java.setFork(true);
+ java.setTaskName("jasperc");
+ java.execute();
+ return true;
+ } catch (Exception ex) {
+ if (ex instanceof BuildException) {
+ throw (BuildException) ex;
+ } else {
+ throw new BuildException("Error running jsp compiler: ",
+ ex, getJspc().getLocation());
+ }
+ } finally {
+ getJspc().deleteEmptyJavaFiles();
+ }
+ }
+
+
+
+ /**
+ * build up a command line
+ * @return a command line for jasper
+ */
+ private CommandlineJava setupJasperCommand() {
+ CommandlineJava cmd = new CommandlineJava();
+ JspC jspc = getJspc();
+ addArg(cmd, "-d", jspc.getDestdir());
+ addArg(cmd, "-p", jspc.getPackage());
+
+ if (!isTomcat5x()) {
+ addArg(cmd, "-v" + jspc.getVerbose());
+ } else {
+ getProject().log("this task doesn't support Tomcat 5.x properly, "
+ + "please use the Tomcat provided jspc task "
+ + "instead");
+ }
+
+ addArg(cmd, "-uriroot", jspc.getUriroot());
+ addArg(cmd, "-uribase", jspc.getUribase());
+ addArg(cmd, "-ieplugin", jspc.getIeplugin());
+ addArg(cmd, "-webinc", jspc.getWebinc());
+ addArg(cmd, "-webxml", jspc.getWebxml());
+ addArg(cmd, "-die9");
+
+ if (jspc.isMapped()) {
+ addArg(cmd, "-mapped");
+ }
+ if (jspc.getWebApp() != null) {
+ File dir = jspc.getWebApp().getDirectory();
+ addArg(cmd, "-webapp", dir);
+ }
+ logAndAddFilesToCompile(getJspc(), getJspc().getCompileList(), cmd);
+ return cmd;
+ }
+
+ /**
+ * @return an instance of the mangler this compiler uses
+ */
+
+ public JspMangler createMangler() {
+ return mangler;
+ }
+
+ /**
+ * @since Ant 1.6.2
+ */
+ private Path getClasspath() {
+ Path p = getJspc().getClasspath();
+ if (p == null) {
+ p = new Path(getProject());
+ return p.concatSystemClasspath("only");
+ } else {
+ return p.concatSystemClasspath("ignore");
+ }
+ }
+
+ /**
+ * @since Ant 1.6.2
+ */
+ private boolean isTomcat5x() {
+ AntClassLoader l = null;
+ try {
+ l = getProject().createClassLoader(getClasspath());
+ l.loadClass("org.apache.jasper.tagplugins.jstl.If");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ } finally {
+ if (l != null) {
+ l.cleanup();
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java
new file mode 100644
index 00000000..16b67f9d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspC;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspMangler;
+
+/**
+ * The interface that all jsp compiler adapters must adher to.
+ *
+ * <p>A compiler adapter is an adapter that interprets the jspc's
+ * parameters in preparation to be passed off to the compiler this
+ * adapter represents. As all the necessary values are stored in the
+ * Jspc task itself, the only thing all adapters need is the jsp
+ * task, the execute command and a parameterless constructor (for
+ * reflection).</p>
+ *
+ */
+
+public interface JspCompilerAdapter {
+
+ /**
+ * Sets the compiler attributes, which are stored in the Jspc task.
+ * @param attributes the jsp compiler attributes
+ */
+ void setJspc(JspC attributes);
+
+ /**
+ * Executes the task.
+ *
+ * @return has the compilation been successful
+ * @throws BuildException on error
+ */
+ boolean execute() throws BuildException;
+
+ /**
+ * @return an instance of the mangler this compiler uses
+ */
+
+ JspMangler createMangler();
+
+ /**
+ * ask if compiler can sort out its own dependencies
+ * @return true if the compiler wants to do its own
+ * depends
+ */
+ boolean implementsOwnDependencyChecking();
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java
new file mode 100644
index 00000000..2876ba0c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.jsp.Jasper41Mangler;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspNameMangler;
+
+
+/**
+ * Creates the necessary compiler adapter, given basic criteria.
+ *
+ */
+public final class JspCompilerAdapterFactory {
+
+ /** This is a singleton -- can't create instances!! */
+ private JspCompilerAdapterFactory() {
+ }
+
+ /**
+ * Based on the parameter passed in, this method creates the necessary
+ * factory desired.
+ *
+ * The current mapping for compiler names are as follows:
+ * <ul><li>jasper = jasper compiler (the default)
+ * <li><i>a fully qualified classname</i> = the name of a jsp compiler
+ * adapter
+ * </ul>
+ *
+ * @param compilerType either the name of the desired compiler, or the
+ * full classname of the compiler's adapter.
+ * @param task a task to log through.
+ * @return the compiler
+ * @throws BuildException if the compiler type could not be resolved into
+ * a compiler adapter.
+ */
+ public static JspCompilerAdapter getCompiler(String compilerType, Task task)
+ throws BuildException {
+ return getCompiler(compilerType, task,
+ // Memory-Leak in line below
+ task.getProject().createClassLoader(null));
+ }
+
+ /**
+ * Based on the parameter passed in, this method creates the necessary
+ * factory desired.
+ *
+ * The current mapping for compiler names are as follows:
+ * <ul><li>jasper = jasper compiler (the default)
+ * <li><i>a fully qualified classname</i> = the name of a jsp compiler
+ * adapter
+ * </ul>
+ *
+ * @param compilerType either the name of the desired compiler, or the
+ * full classname of the compiler's adapter.
+ * @param task a task to log through.
+ * @param loader AntClassLoader with which the compiler should be loaded
+ * @return the compiler
+ * @throws BuildException if the compiler type could not be resolved into
+ * a compiler adapter.
+ */
+ public static JspCompilerAdapter getCompiler(String compilerType, Task task,
+ AntClassLoader loader)
+ throws BuildException {
+
+ if (compilerType.equalsIgnoreCase("jasper")) {
+ //tomcat4.0 gets the old mangler
+ return new JasperC(new JspNameMangler());
+ }
+ if (compilerType.equalsIgnoreCase("jasper41")) {
+ //tomcat4.1 gets the new one
+ return new JasperC(new Jasper41Mangler());
+ }
+ return resolveClassName(compilerType, loader);
+ }
+
+ /**
+ * Tries to resolve the given classname into a compiler adapter.
+ * Throws a fit if it can't.
+ *
+ * @param className The fully qualified classname to be created.
+ * @param classloader Classloader with which to load the class
+ * @throws BuildException This is the fit that is thrown if className
+ * isn't an instance of JspCompilerAdapter.
+ */
+ private static JspCompilerAdapter resolveClassName(String className,
+ AntClassLoader classloader)
+ throws BuildException {
+ try {
+ Class c = classloader.findClass(className);
+ Object o = c.newInstance();
+ return (JspCompilerAdapter) o;
+ } catch (ClassNotFoundException cnfe) {
+ throw new BuildException(className + " can\'t be found.", cnfe);
+ } catch (ClassCastException cce) {
+ throw new BuildException(className + " isn\'t the classname of "
+ + "a compiler adapter.", cce);
+ } catch (Throwable t) {
+ // for all other possibilities
+ throw new BuildException(className + " caused an interesting "
+ + "exception.", t);
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java
new file mode 100644
index 00000000..ec3506d4
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java
@@ -0,0 +1,346 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Delete;
+import org.apache.tools.ant.taskdefs.TempFile;
+import org.apache.tools.ant.taskdefs.XSLTProcess;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.URLResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.w3c.dom.Document;
+
+/**
+ * Transform a JUnit xml report.
+ * The default transformation generates an html report in either framed or non-framed
+ * style. The non-framed style is convenient to have a concise report via mail, the
+ * framed report is much more convenient if you want to browse into different
+ * packages or testcases since it is a Javadoc like report.
+ *
+ */
+public class AggregateTransformer {
+ /**
+ * name of the frames format.
+ */
+ public static final String FRAMES = "frames";
+
+ /**
+ * name of the no frames format.
+ */
+ public static final String NOFRAMES = "noframes";
+
+ /**
+ * defines acceptable formats.
+ */
+ public static class Format extends EnumeratedAttribute {
+ /**
+ * list authorized values.
+ * @return authorized values.
+ */
+ public String[] getValues() {
+ return new String[]{FRAMES, NOFRAMES};
+ }
+ }
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /** Task */
+ protected Task task;
+
+ /** the xml document to process */
+ protected Document document;
+
+ /** the style directory. XSLs should be read from here if necessary */
+ protected File styleDir;
+
+ /** the destination directory, this is the root from where html should be generated */
+ protected File toDir;
+
+ /**
+ * The internal XSLT task used to perform the transformation.
+ *
+ * @since Ant 1.9.5
+ */
+ private XSLTProcess xsltTask;
+
+ /**
+ * Instance of a utility class to use for file operations.
+ *
+ * @since Ant 1.7
+ */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * Used to ensure the uniqueness of a property
+ */
+ private static int counter = 0;
+
+ /** the format to use for the report. Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt> */
+ protected String format = FRAMES;
+
+ /** XML Parser factory */
+ private static DocumentBuilderFactory privateDBFactory;
+
+ /** XML Parser factory accessible to subclasses */
+ protected static DocumentBuilderFactory dbfactory;
+
+ static {
+ privateDBFactory = DocumentBuilderFactory.newInstance();
+ dbfactory = privateDBFactory;
+ }
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * constructor creating the transformer from the junitreport task.
+ * @param task task delegating to this class
+ */
+ public AggregateTransformer(Task task) {
+ this.task = task;
+ xsltTask = new XSLTProcess();
+ xsltTask.bindToOwner(task);
+ }
+
+ /**
+ * Get the Document Builder Factory
+ *
+ * @return the DocumentBuilderFactory instance in use
+ */
+ protected static DocumentBuilderFactory getDocumentBuilderFactory() {
+ return privateDBFactory;
+ }
+
+ /**
+ * sets the format.
+ * @param format Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt>
+ */
+ public void setFormat(Format format) {
+ this.format = format.getValue();
+ }
+
+ /**
+ * sets the input document.
+ * @param doc input dom tree
+ */
+ public void setXmlDocument(Document doc) {
+ this.document = doc;
+ }
+
+ /**
+ * Set the xml file to be processed. This is a helper if you want
+ * to set the file directly. Much more for testing purposes.
+ * @param xmlfile xml file to be processed
+ * @throws BuildException if the document cannot be parsed.
+ */
+ protected void setXmlfile(File xmlfile) throws BuildException {
+ try {
+ DocumentBuilder builder = privateDBFactory.newDocumentBuilder();
+ InputStream in = new FileInputStream(xmlfile);
+ try {
+ Document doc = builder.parse(in);
+ setXmlDocument(doc);
+ } finally {
+ in.close();
+ }
+ } catch (Exception e) {
+ throw new BuildException("Error while parsing document: " + xmlfile, e);
+ }
+ }
+
+ /**
+ * set the style directory. It is optional and will override the
+ * default xsl used.
+ * @param styledir the directory containing the xsl files if the user
+ * would like to override with its own style.
+ */
+ public void setStyledir(File styledir) {
+ this.styleDir = styledir;
+ }
+
+ /** set the destination directory.
+ * @param todir the destination directory
+ */
+ public void setTodir(File todir) {
+ this.toDir = todir;
+ }
+
+ /** set the extension of the output files
+ * @param ext extension.
+ */
+ public void setExtension(String ext) {
+ task.log("extension is not used anymore", Project.MSG_WARN);
+ }
+
+ /**
+ * Create an instance of an XSL parameter for configuration by Ant.
+ *
+ * @return an instance of the Param class to be configured.
+ * @since Ant 1.7
+ */
+ public XSLTProcess.Param createParam() {
+ return xsltTask.createParam();
+ }
+
+ /**
+ * Creates a classpath to be used for the internal XSLT task.
+ *
+ * @return the classpath to be configured
+ * @since Ant 1.9.5
+ */
+ public Path createClasspath() {
+ return xsltTask.createClasspath();
+ }
+
+ /**
+ * Creates a factory configuration to be used for the internal XSLT task.
+ *
+ * @return the factory description to be configured
+ * @since Ant 1.9.5
+ */
+ public XSLTProcess.Factory createFactory() {
+ return xsltTask.createFactory();
+ }
+
+ /**
+ * transformation
+ * @throws BuildException exception if something goes wrong with the transformation.
+ */
+ public void transform() throws BuildException {
+ checkOptions();
+ Project project = task.getProject();
+
+ TempFile tempFileTask = new TempFile();
+ tempFileTask.bindToOwner(task);
+
+ xsltTask.setXslResource(getStylesheet());
+
+ // acrobatic cast.
+ xsltTask.setIn(((XMLResultAggregator) task).getDestinationFile());
+ File outputFile = null;
+ if (format.equals(FRAMES)) {
+ String tempFileProperty = getClass().getName() + String.valueOf(counter++);
+ File tmp = FILE_UTILS.resolveFile(project.getBaseDir(), project
+ .getProperty("java.io.tmpdir"));
+ tempFileTask.setDestDir(tmp);
+ tempFileTask.setProperty(tempFileProperty);
+ tempFileTask.execute();
+ outputFile = new File(project.getProperty(tempFileProperty));
+ } else {
+ outputFile = new File(toDir, "junit-noframes.html");
+ }
+ xsltTask.setOut(outputFile);
+ XSLTProcess.Param paramx = xsltTask.createParam();
+ paramx.setProject(task.getProject());
+ paramx.setName("output.dir");
+ paramx.setExpression(toDir.getAbsolutePath());
+ final long t0 = System.currentTimeMillis();
+ try {
+ xsltTask.execute();
+ } catch (Exception e) {
+ throw new BuildException("Errors while applying transformations: " + e.getMessage(), e);
+ }
+ final long dt = System.currentTimeMillis() - t0;
+ task.log("Transform time: " + dt + "ms");
+ if (format.equals(FRAMES)) {
+ Delete delete = new Delete();
+ delete.bindToOwner(task);
+ delete.setFile(outputFile);
+ delete.execute();
+ }
+ }
+
+ /**
+ * access the stylesheet to be used as a resource.
+ * @return stylesheet as a resource
+ */
+ protected Resource getStylesheet() {
+ String xslname = "junit-frames.xsl";
+ if (NOFRAMES.equals(format)) {
+ xslname = "junit-noframes.xsl";
+ }
+ if (styleDir == null) {
+ // If style dir is not specified we have to retrieve
+ // the stylesheet from the classloader
+ URL stylesheetURL = getClass().getClassLoader().getResource(
+ "org/apache/tools/ant/taskdefs/optional/junit/xsl/" + xslname);
+ return new URLResource(stylesheetURL);
+ }
+ // If we are here, then the style dir is here and we
+ // should read the stylesheet from the filesystem
+ return new FileResource(new File(styleDir, xslname));
+ }
+
+ /** check for invalid options
+ * @throws BuildException if something goes wrong.
+ */
+ protected void checkOptions() throws BuildException {
+ // set the destination directory relative from the project if needed.
+ if (toDir == null) {
+ toDir = task.getProject().resolveFile(".");
+ } else if (!toDir.isAbsolute()) {
+ toDir = task.getProject().resolveFile(toDir.getPath());
+ }
+ }
+
+ /**
+ * Get the systemid of the appropriate stylesheet based on its
+ * name and styledir. If no styledir is defined it will load
+ * it as a java resource in the xsl child package, otherwise it
+ * will get it from the given directory.
+ * @return system ID of the stylesheet.
+ * @throws IOException thrown if the requested stylesheet does
+ * not exist.
+ */
+ protected String getStylesheetSystemId() throws IOException {
+ String xslname = "junit-frames.xsl";
+ if (NOFRAMES.equals(format)) {
+ xslname = "junit-noframes.xsl";
+ }
+ if (styleDir == null) {
+ URL url = getClass().getResource("xsl/" + xslname);
+ if (url == null) {
+ throw new FileNotFoundException("Could not find jar resource " + xslname);
+ }
+ return url.toExternalForm();
+ }
+ File file = new File(styleDir, xslname);
+ if (!file.exists()) {
+ throw new FileNotFoundException("Could not find file '" + file + "'");
+ }
+ return JAXPUtils.getSystemId(file);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java
new file mode 100644
index 00000000..55e7a5d5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.util.Vector;
+
+/**
+ * Baseclass for BatchTest and JUnitTest.
+ *
+ */
+public abstract class BaseTest {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected boolean haltOnError = false;
+ protected boolean haltOnFail = false;
+ protected boolean filtertrace = true;
+ protected boolean fork = false;
+ protected String ifProperty = null;
+ protected String unlessProperty = null;
+ protected Vector formatters = new Vector();
+ /** destination directory */
+ protected File destDir = null;
+
+ protected String failureProperty;
+ protected String errorProperty;
+ // CheckStyle:VisibilityModifier ON
+
+ private Object ifCond, unlessCond;
+ private boolean skipNonTests;
+
+ /**
+ * Set the filtertrace attribute.
+ * @param value a <code>boolean</code> value.
+ */
+ public void setFiltertrace(boolean value) {
+ filtertrace = value;
+ }
+
+ /**
+ * Get the filtertrace attribute.
+ * @return the attribute.
+ */
+ public boolean getFiltertrace() {
+ return filtertrace;
+ }
+
+ /**
+ * Set the fork attribute.
+ * @param value a <code>boolean</code> value.
+ */
+ public void setFork(boolean value) {
+ fork = value;
+ }
+
+ /**
+ * Get the fork attribute.
+ * @return the attribute.
+ */
+ public boolean getFork() {
+ return fork;
+ }
+
+ /**
+ * Set the haltonerror attribute.
+ * @param value a <code>boolean</code> value.
+ */
+ public void setHaltonerror(boolean value) {
+ haltOnError = value;
+ }
+
+ /**
+ * Set the haltonfailure attribute.
+ * @param value a <code>boolean</code> value.
+ */
+ public void setHaltonfailure(boolean value) {
+ haltOnFail = value;
+ }
+
+ /**
+ * Get the haltonerror attribute.
+ * @return the attribute.
+ */
+ public boolean getHaltonerror() {
+ return haltOnError;
+ }
+
+ /**
+ * Get the haltonfailure attribute.
+ * @return the attribute.
+ */
+ public boolean getHaltonfailure() {
+ return haltOnFail;
+ }
+
+ /**
+ * Set the if attribute.
+ * If this expression evaluates to true or the name of a property
+ * which is present in project, the test will be run.
+ * @param ifCondition the expression to evaluate
+ * @since Ant 1.8.0
+ */
+ public void setIf(Object ifCondition) {
+ ifCond = ifCondition;
+ ifProperty = ifCondition != null ? String.valueOf(ifCondition) : null;
+ }
+
+ /**
+ * Set the if attribute.
+ * If this expression evaluates to true or the name of a property
+ * which is present in project, the test will be run.
+ * @param propertyName the expression to evaluate
+ */
+ public void setIf(String propertyName) {
+ setIf((Object) propertyName);
+ }
+
+ /**
+ * The if expression
+ * @since Ant 1.8.0
+ */
+ public Object getIfCondition() {
+ return ifCond;
+ }
+
+ /**
+ * Set the unless attribute. If this expression evaluates to
+ * false or the name of a property which is not present in
+ * project, the test will be run.
+ * @param unlessCondition the expression to evaluate
+ * @since Ant 1.8.0
+ */
+ public void setUnless(Object unlessCondition) {
+ unlessCond = unlessCondition;
+ unlessProperty = unlessCondition != null
+ ? String.valueOf(unlessCondition) : null;
+ }
+
+ /**
+ * Set the unless attribute. If this expression evaluates to
+ * false or the name of a property which is not present in
+ * project, the test will be run.
+ * @param propertyName the expression to evaluate
+ */
+ public void setUnless(String propertyName) {
+ setUnless((Object) propertyName);
+ }
+
+ /**
+ * The unless expression
+ * @since Ant 1.8.0
+ */
+ public Object getUnlessCondition() {
+ return unlessCond;
+ }
+
+ /**
+ * Allow a formatter nested element.
+ * @param elem a formatter nested element.
+ */
+ public void addFormatter(FormatterElement elem) {
+ formatters.addElement(elem);
+ }
+
+ /**
+ * Sets the destination directory.
+ * @param destDir the destination directory.
+ */
+ public void setTodir(File destDir) {
+ this.destDir = destDir;
+ }
+
+ /**
+ * Get the destination directory.
+ * @return the destination directory as an absolute path if it exists
+ * otherwise return <tt>null</tt>
+ */
+ public String getTodir() {
+ if (destDir != null) {
+ return destDir.getAbsolutePath();
+ }
+ return null;
+ }
+
+ /**
+ * Get the failure property name.
+ * @return the name of the property to set on failure.
+ */
+ public String getFailureProperty() {
+ return failureProperty;
+ }
+
+ /**
+ * Set the name of the failure property.
+ * @param failureProperty the name of the property to set if
+ * the test fails.
+ */
+ public void setFailureProperty(String failureProperty) {
+ this.failureProperty = failureProperty;
+ }
+
+ /**
+ * Get the failure property name.
+ * @return the name of the property to set on failure.
+ */
+ public String getErrorProperty() {
+ return errorProperty;
+ }
+
+ /**
+ * Set the name of the error property.
+ * @param errorProperty the name of the property to set if
+ * the test has an error.
+ */
+ public void setErrorProperty(String errorProperty) {
+ this.errorProperty = errorProperty;
+ }
+
+ public void setSkipNonTests(boolean skipNonTests) {
+ this.skipNonTests = skipNonTests;
+ }
+
+ public boolean isSkipNonTests() {
+ return skipNonTests;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
new file mode 100644
index 00000000..f41b96f1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Resources;
+
+/**
+ * <p> Create then run <code>JUnitTest</code>'s based on the list of files
+ * given by the fileset attribute.
+ *
+ * <p> Every <code>.java</code> or <code>.class</code> file in the fileset is
+ * assumed to be a testcase.
+ * A <code>JUnitTest</code> is created for each of these named classes with
+ * basic setup inherited from the parent <code>BatchTest</code>.
+ *
+ * @see JUnitTest
+ */
+public final class BatchTest extends BaseTest {
+
+ /** the reference to the project */
+ private Project project;
+
+ /** the list of filesets containing the testcase filename rules */
+ private Resources resources = new Resources();
+
+ /**
+ * create a new batchtest instance
+ * @param project the project it depends on.
+ */
+ public BatchTest(Project project) {
+ this.project = project;
+ resources.setCache(true);
+ }
+
+ /**
+ * Add a new fileset instance to this batchtest. Whatever the fileset is,
+ * only filename that are <tt>.java</tt> or <tt>.class</tt> will be
+ * considered as 'candidates'.
+ * @param fs the new fileset containing the rules to get the testcases.
+ */
+ public void addFileSet(FileSet fs) {
+ add(fs);
+
+ // this one is here because the changes to support ResourceCollections
+ // have broken Magic's JUnitTestTask.
+ //
+ // The task adds a FileSet to a BatchTest instance using the
+ // Java API and without telling the FileSet about its project
+ // instance. The original code would pass in project on the
+ // call to getDirectoryScanner - which is now hidden deep into
+ // Resources.iterator() and not reachable.
+ if (fs.getProject() == null) {
+ fs.setProject(project);
+ }
+ }
+
+
+ /**
+ * Add a new ResourceCollection instance to this
+ * batchtest. Whatever the collection is, only names that are
+ * <tt>.java</tt> or <tt>.class</tt> will be considered as
+ * 'candidates'.
+ * @param rc the new ResourceCollection containing the rules to
+ * get the testcases.
+ * @since Ant 1.7
+ */
+ public void add(ResourceCollection rc) {
+ resources.add(rc);
+ }
+
+ /**
+ * Return all <tt>JUnitTest</tt> instances obtain by applying the fileset rules.
+ * @return an enumeration of all elements of this batchtest that are
+ * a <tt>JUnitTest</tt> instance.
+ */
+ public Enumeration elements() {
+ JUnitTest[] tests = createAllJUnitTest();
+ return Enumerations.fromArray(tests);
+ }
+
+ /**
+ * Convenient method to merge the <tt>JUnitTest</tt>s of this batchtest
+ * to a <tt>Vector</tt>.
+ * @param v the vector to which should be added all individual tests of this
+ * batch test.
+ */
+ void addTestsTo(Vector v) {
+ JUnitTest[] tests = createAllJUnitTest();
+ v.ensureCapacity(v.size() + tests.length);
+ for (int i = 0; i < tests.length; i++) {
+ v.addElement(tests[i]);
+ }
+ }
+
+ /**
+ * Create all <tt>JUnitTest</tt>s based on the filesets. Each instance
+ * is configured to match this instance properties.
+ * @return the array of all <tt>JUnitTest</tt>s that belongs to this batch.
+ */
+ private JUnitTest[] createAllJUnitTest() {
+ String[] filenames = getFilenames();
+ JUnitTest[] tests = new JUnitTest[filenames.length];
+ for (int i = 0; i < tests.length; i++) {
+ String classname = javaToClass(filenames[i]);
+ tests[i] = createJUnitTest(classname);
+ }
+ return tests;
+ }
+
+ /**
+ * Iterate over all filesets and return the filename of all files
+ * that end with <tt>.java</tt> or <tt>.class</tt>. This is to avoid
+ * wrapping a <tt>JUnitTest</tt> over an xml file for example. A Testcase
+ * is obviously a java file (compiled or not).
+ * @return an array of filenames without their extension. As they should
+ * normally be taken from their root, filenames should match their fully
+ * qualified class name (If it is not the case it will fail when running the test).
+ * For the class <tt>org/apache/Whatever.class</tt> it will return <tt>org/apache/Whatever</tt>.
+ */
+ private String[] getFilenames() {
+ Vector v = new Vector();
+ for (Resource r : resources) {
+ if (r.isExists()) {
+ String pathname = r.getName();
+ if (pathname.endsWith(".java")) {
+ v.addElement(pathname.substring(0, pathname.length() - ".java".length()));
+ } else if (pathname.endsWith(".class")) {
+ v.addElement(pathname.substring(0, pathname.length() - ".class".length()));
+ }
+ }
+ }
+
+ String[] files = new String[v.size()];
+ v.copyInto(files);
+ return files;
+ }
+
+ /**
+ * Convenient method to convert a pathname without extension to a
+ * fully qualified classname. For example <tt>org/apache/Whatever</tt> will
+ * be converted to <tt>org.apache.Whatever</tt>
+ * @param filename the filename to "convert" to a classname.
+ * @return the classname matching the filename.
+ */
+ public static String javaToClass(String filename) {
+ return filename.replace(File.separatorChar, '.').replace('/', '.')
+ .replace('\\', '.');
+ }
+
+ /**
+ * Create a <tt>JUnitTest</tt> that has the same property as this
+ * <tt>BatchTest</tt> instance.
+ * @param classname the name of the class that should be run as a
+ * <tt>JUnitTest</tt>. It must be a fully qualified name.
+ * @return the <tt>JUnitTest</tt> over the given classname.
+ */
+ private JUnitTest createJUnitTest(String classname) {
+ JUnitTest test = new JUnitTest();
+ test.setName(classname);
+ test.setHaltonerror(this.haltOnError);
+ test.setHaltonfailure(this.haltOnFail);
+ test.setFiltertrace(this.filtertrace);
+ test.setFork(this.fork);
+ test.setIf(getIfCondition());
+ test.setUnless(getUnlessCondition());
+ test.setTodir(this.destDir);
+ test.setFailureProperty(failureProperty);
+ test.setErrorProperty(errorProperty);
+ test.setSkipNonTests(isSkipNonTests());
+ Enumeration list = this.formatters.elements();
+ while (list.hasMoreElements()) {
+ test.addFormatter((FormatterElement) list.nextElement());
+ }
+ return test;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java
new file mode 100644
index 00000000..46d6c616
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Prints plain text output of the test to a specified Writer.
+ * Inspired by the PlainJUnitResultFormatter.
+ *
+ * @see FormatterElement
+ * @see PlainJUnitResultFormatter
+ */
+public class BriefJUnitResultFormatter implements JUnitResultFormatter, IgnoredTestListener {
+
+ private static final double ONE_SECOND = 1000.0;
+
+ /**
+ * Where to write the log to.
+ */
+ private OutputStream out;
+
+ /**
+ * Used for writing the results.
+ */
+ private BufferedWriter output;
+
+ /**
+ * Used as part of formatting the results.
+ */
+ private StringWriter results;
+
+ /**
+ * Used for writing formatted results to.
+ */
+ private BufferedWriter resultWriter;
+
+ /**
+ * Formatter for timings.
+ */
+ private NumberFormat numberFormat = NumberFormat.getInstance();
+
+ /**
+ * Output suite has written to System.out
+ */
+ private String systemOutput = null;
+
+ /**
+ * Output suite has written to System.err
+ */
+ private String systemError = null;
+
+ /**
+ * Constructor for BriefJUnitResultFormatter.
+ */
+ public BriefJUnitResultFormatter() {
+ results = new StringWriter();
+ resultWriter = new BufferedWriter(results);
+ }
+
+ /**
+ * Sets the stream the formatter is supposed to write its results to.
+ * @param out the output stream to write to
+ */
+ public void setOutput(OutputStream out) {
+ this.out = out;
+ output = new BufferedWriter(new java.io.OutputStreamWriter(out));
+ }
+
+ /**
+ * @see JUnitResultFormatter#setSystemOutput(String)
+ */
+ /** {@inheritDoc}. */
+ public void setSystemOutput(String out) {
+ systemOutput = out;
+ }
+
+ /**
+ * @see JUnitResultFormatter#setSystemError(String)
+ */
+ /** {@inheritDoc}. */
+ public void setSystemError(String err) {
+ systemError = err;
+ }
+
+
+ /**
+ * The whole testsuite started.
+ * @param suite the test suite
+ */
+ public void startTestSuite(JUnitTest suite) {
+ if (output == null) {
+ return; // Quick return - no output do nothing.
+ }
+ StringBuffer sb = new StringBuffer("Testsuite: ");
+ sb.append(suite.getName());
+ sb.append(StringUtils.LINE_SEP);
+ try {
+ output.write(sb.toString());
+ output.flush();
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ }
+ }
+
+ /**
+ * The whole testsuite ended.
+ * @param suite the test suite
+ */
+ public void endTestSuite(JUnitTest suite) {
+ StringBuffer sb = new StringBuffer("Tests run: ");
+ sb.append(suite.runCount());
+ sb.append(", Failures: ");
+ sb.append(suite.failureCount());
+ sb.append(", Errors: ");
+ sb.append(suite.errorCount());
+ sb.append(", Skipped: ");
+ sb.append(suite.skipCount());
+ sb.append(", Time elapsed: ");
+ sb.append(numberFormat.format(suite.getRunTime() / ONE_SECOND));
+ sb.append(" sec");
+ sb.append(StringUtils.LINE_SEP);
+ sb.append(StringUtils.LINE_SEP);
+
+ // append the err and output streams to the log
+ if (systemOutput != null && systemOutput.length() > 0) {
+ sb.append("------------- Standard Output ---------------")
+ .append(StringUtils.LINE_SEP)
+ .append(systemOutput)
+ .append("------------- ---------------- ---------------")
+ .append(StringUtils.LINE_SEP);
+ }
+
+ if (systemError != null && systemError.length() > 0) {
+ sb.append("------------- Standard Error -----------------")
+ .append(StringUtils.LINE_SEP)
+ .append(systemError)
+ .append("------------- ---------------- ---------------")
+ .append(StringUtils.LINE_SEP);
+ }
+
+ if (output != null) {
+ try {
+ output.write(sb.toString());
+ resultWriter.close();
+ output.write(results.toString());
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ } finally {
+ try {
+ output.flush();
+ } catch (IOException ex) {
+ // swallow, there has likely been an exception before this
+ }
+ if (out != System.out && out != System.err) {
+ FileUtils.close(out);
+ }
+ }
+ }
+ }
+
+ /**
+ * A test started.
+ * @param test a test
+ */
+ public void startTest(Test test) {
+ }
+
+ /**
+ * A test ended.
+ * @param test a test
+ */
+ public void endTest(Test test) {
+ }
+
+ /**
+ * Interface TestListener for JUnit &lt;= 3.4.
+ *
+ * <p>A Test failed.
+ * @param test a test
+ * @param t the exception thrown by the test
+ */
+ public void addFailure(Test test, Throwable t) {
+ formatError("\tFAILED", test, t);
+ }
+
+ /**
+ * Interface TestListener for JUnit &gt; 3.4.
+ *
+ * <p>A Test failed.
+ * @param test a test
+ * @param t the assertion failed by the test
+ */
+ public void addFailure(Test test, AssertionFailedError t) {
+ addFailure(test, (Throwable) t);
+ }
+
+ /**
+ * A test caused an error.
+ * @param test a test
+ * @param error the error thrown by the test
+ */
+ public void addError(Test test, Throwable error) {
+ formatError("\tCaused an ERROR", test, error);
+ }
+
+ /**
+ * Format the test for printing..
+ * @param test a test
+ * @return the formatted testname
+ */
+ protected String formatTest(Test test) {
+ if (test == null) {
+ return "Null Test: ";
+ } else {
+ return "Testcase: " + test.toString() + ":";
+ }
+ }
+
+ /**
+ * Format an error and print it.
+ * @param type the type of error
+ * @param test the test that failed
+ * @param error the exception that the test threw
+ */
+ protected synchronized void formatError(String type, Test test,
+ Throwable error) {
+ if (test != null) {
+ endTest(test);
+ }
+
+ try {
+ resultWriter.write(formatTest(test) + type);
+ resultWriter.newLine();
+ resultWriter.write(String.valueOf(error.getMessage()));
+ resultWriter.newLine();
+ String strace = JUnitTestRunner.getFilteredTrace(error);
+ resultWriter.write(strace);
+ resultWriter.newLine();
+ resultWriter.newLine();
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ }
+ }
+
+
+ public void testIgnored(Test test) {
+ formatSkip(test, JUnitVersionHelper.getIgnoreMessage(test));
+ }
+
+
+ public void formatSkip(Test test, String message) {
+ if (test != null) {
+ endTest(test);
+ }
+
+ try {
+ resultWriter.write(formatTest(test) + "SKIPPED");
+ if (message != null) {
+ resultWriter.write(": ");
+ resultWriter.write(message);
+ }
+ resultWriter.newLine();
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ }
+
+ }
+
+ public void testAssumptionFailure(Test test, Throwable cause) {
+ formatSkip(test, cause.getMessage());
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
new file mode 100644
index 00000000..368c72e2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+/**
+ * Constants, like filenames shared between various classes in this package.
+ */
+public class Constants {
+
+ private Constants() {
+ }
+
+ static final String METHOD_NAMES = "methods=";
+ static final String HALT_ON_ERROR = "haltOnError=";
+ static final String HALT_ON_FAILURE = "haltOnFailure=";
+ static final String FILTERTRACE = "filtertrace=";
+ static final String CRASHFILE = "crashfile=";
+ static final String BEFORE_FIRST_TEST = "BeforeFirstTest";
+ static final String PROPSFILE = "propsfile=";
+ static final String SHOWOUTPUT = "showoutput=";
+ static final String OUTPUT_TO_FORMATTERS = "outputtoformatters=";
+ static final String FORMATTER = "formatter=";
+ static final String LOGTESTLISTENEREVENTS = "logtestlistenerevents=";
+ static final String TESTSFILE = "testsfile=";
+ static final String TERMINATED_SUCCESSFULLY = "terminated successfully";
+ static final String LOG_FAILED_TESTS="logfailedtests=";
+ static final String SKIP_NON_TESTS = "skipNonTests=";
+ /** @since Ant 1.9.4 */
+ static final String THREADID="threadid=";
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java
new file mode 100644
index 00000000..8ad40dd6
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/CustomJUnit4TestAdapterCache.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.JUnit4TestAdapterCache;
+import junit.framework.TestResult;
+
+import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+
+/**
+ * Provides a custom implementation of the notifier for a JUnit4TestAdapter
+ * so that skipped and ignored tests can be reported to the existing
+ * <tt>TestListener</tt>s.
+ *
+ */
+public class CustomJUnit4TestAdapterCache extends JUnit4TestAdapterCache {
+
+ private static final CustomJUnit4TestAdapterCache INSTANCE = new CustomJUnit4TestAdapterCache();
+
+ public static CustomJUnit4TestAdapterCache getInstance() {
+ return INSTANCE;
+ }
+
+ private CustomJUnit4TestAdapterCache() {
+ super();
+ }
+
+ public RunNotifier getNotifier(final TestResult result, final JUnit4TestAdapter adapter) {
+ return getNotifier(result);
+ }
+
+ public RunNotifier getNotifier(final TestResult result) {
+
+ final IgnoredTestResult resultWrapper = (IgnoredTestResult) result;
+
+ RunNotifier notifier = new RunNotifier();
+ notifier.addListener(new RunListener() {
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ result.addError(asTest(failure.getDescription()), failure.getException());
+ }
+
+ @Override
+ public void testFinished(Description description) throws Exception {
+ result.endTest(asTest(description));
+ }
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ result.startTest(asTest(description));
+ }
+
+ @Override
+ public void testIgnored(Description description) throws Exception {
+ if (resultWrapper != null) {
+ resultWrapper.testIgnored(asTest(description));
+ }
+ }
+
+ @Override
+ public void testAssumptionFailure(Failure failure) {
+ if (resultWrapper != null) {
+ resultWrapper.testAssumptionFailure(asTest(failure.getDescription()), failure.getException());
+ }
+ }
+ });
+
+ return notifier;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java
new file mode 100644
index 00000000..325f44cf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Vector;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+
+/**
+ * Some utilities that might be useful when manipulating DOM trees.
+ *
+ */
+public final class DOMUtil {
+
+ /** unused constructor */
+ private DOMUtil() {
+ }
+
+ /**
+ * Filter interface to be applied when iterating over a DOM tree.
+ * Just think of it like a <tt>FileFilter</tt> clone.
+ */
+ public interface NodeFilter {
+ /**
+ * @param node the node to check for acceptance.
+ * @return <tt>true</tt> if the node is accepted by this filter,
+ * otherwise <tt>false</tt>
+ */
+ boolean accept(Node node);
+ }
+
+ /**
+ * list a set of node that match a specific filter. The list can be made
+ * recursively or not.
+ * @param parent the parent node to search from
+ * @param filter the filter that children should match.
+ * @param recurse <tt>true</tt> if you want the list to be made recursively
+ * otherwise <tt>false</tt>.
+ * @return the node list that matches the filter.
+ */
+ public static NodeList listChildNodes(Node parent, NodeFilter filter, boolean recurse) {
+ NodeListImpl matches = new NodeListImpl();
+ NodeList children = parent.getChildNodes();
+ if (children != null) {
+ final int len = children.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = children.item(i);
+ if (filter.accept(child)) {
+ matches.addElement(child);
+ }
+ if (recurse) {
+ NodeList recmatches = listChildNodes(child, filter, recurse);
+ final int reclength = recmatches.getLength();
+ for (int j = 0; j < reclength; j++) {
+ matches.addElement(recmatches.item(i));
+ }
+ }
+ }
+ }
+ return matches;
+ }
+
+ /** custom implementation of a nodelist */
+ public static class NodeListImpl extends Vector implements NodeList {
+ private static final long serialVersionUID = 3175749150080946423L;
+
+ /**
+ * Get the number of nodes in the list.
+ * @return the length of the list.
+ */
+ public int getLength() {
+ return size();
+ }
+ /**
+ * Get a particular node.
+ * @param i the index of the node to get.
+ * @return the node if the index is in bounds, null otherwise.
+ */
+ public Node item(int i) {
+ try {
+ return (Node) elementAt(i);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return null; // conforming to NodeList interface
+ }
+ }
+ }
+
+ /**
+ * return the attribute value of an element.
+ * @param node the node to get the attribute from.
+ * @param name the name of the attribute we are looking for the value.
+ * @return the value of the requested attribute or <tt>null</tt> if the
+ * attribute was not found or if <tt>node</tt> is not an <tt>Element</tt>.
+ */
+ public static String getNodeAttribute(Node node, String name) {
+ if (node instanceof Element) {
+ Element element = (Element) node;
+ return element.getAttribute(name);
+ }
+ return null;
+ }
+
+
+ /**
+ * Iterate over the children of a given node and return the first node
+ * that has a specific name.
+ * @param parent the node to search child from. Can be <tt>null</tt>.
+ * @param tagname the child name we are looking for. Cannot be <tt>null</tt>.
+ * @return the first child that matches the given name or <tt>null</tt> if
+ * the parent is <tt>null</tt> or if a child does not match the
+ * given name.
+ */
+ public static Element getChildByTagName (Node parent, String tagname) {
+ if (parent == null) {
+ return null;
+ }
+ NodeList childList = parent.getChildNodes();
+ final int len = childList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = childList.item(i);
+ if (child != null && child.getNodeType() == Node.ELEMENT_NODE
+ && child.getNodeName().equals(tagname)) {
+ return (Element) child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Simple tree walker that will clone recursively a node. This is to
+ * avoid using parser-specific API such as Sun's <tt>changeNodeOwner</tt>
+ * when we are dealing with DOM L1 implementations since <tt>cloneNode(boolean)</tt>
+ * will not change the owner document.
+ * <tt>changeNodeOwner</tt> is much faster and avoid the costly cloning process.
+ * <tt>importNode</tt> is in the DOM L2 interface.
+ * @param parent the node parent to which we should do the import to.
+ * @param child the node to clone recursively. Its clone will be
+ * appended to <tt>parent</tt>.
+ * @return the cloned node that is appended to <tt>parent</tt>
+ */
+ public static Node importNode(Node parent, Node child) {
+ Node copy = null;
+ final Document doc = parent.getOwnerDocument();
+
+ switch (child.getNodeType()) {
+ case Node.CDATA_SECTION_NODE:
+ copy = doc.createCDATASection(((CDATASection) child).getData());
+ break;
+ case Node.COMMENT_NODE:
+ copy = doc.createComment(((Comment) child).getData());
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ copy = doc.createDocumentFragment();
+ break;
+ case Node.ELEMENT_NODE:
+ final Element elem = doc.createElement(((Element) child).getTagName());
+ copy = elem;
+ final NamedNodeMap attributes = child.getAttributes();
+ if (attributes != null) {
+ final int size = attributes.getLength();
+ for (int i = 0; i < size; i++) {
+ final Attr attr = (Attr) attributes.item(i);
+ elem.setAttribute(attr.getName(), attr.getValue());
+ }
+ }
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ copy = doc.createEntityReference(child.getNodeName());
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ final ProcessingInstruction pi = (ProcessingInstruction) child;
+ copy = doc.createProcessingInstruction(pi.getTarget(), pi.getData());
+ break;
+ case Node.TEXT_NODE:
+ copy = doc.createTextNode(((Text) child).getData());
+ break;
+ default:
+ // this should never happen
+ throw new IllegalStateException("Invalid node type: " + child.getNodeType());
+ }
+
+ // okay we have a copy of the child, now the child becomes the parent
+ // and we are iterating recursively over its children.
+ try {
+ final NodeList children = child.getChildNodes();
+ if (children != null) {
+ final int size = children.getLength();
+ for (int i = 0; i < size; i++) {
+ final Node newChild = children.item(i);
+ if (newChild != null) {
+ importNode(copy, newChild);
+ }
+ }
+ }
+ } catch (DOMException ignored) {
+ // Ignore
+ }
+
+ // bingo append it. (this should normally not be done here)
+ parent.appendChild(copy);
+ return copy;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java
new file mode 100644
index 00000000..327547ef
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * A couple of methods related to enumerations that might be useful.
+ * This class should probably disappear once the required JDK is set to 1.2
+ * instead of 1.1.
+ *
+ */
+public final class Enumerations {
+
+ private Enumerations() {
+ }
+
+ /**
+ * creates an enumeration from an array of objects.
+ * @param array the array of object to enumerate.
+ * @return the enumeration over the array of objects.
+ */
+ public static Enumeration fromArray(Object[] array) {
+ return new ArrayEnumeration(array);
+ }
+
+ /**
+ * creates an enumeration from an array of enumeration. The created enumeration
+ * will sequentially enumerate over all elements of each enumeration and skip
+ * <tt>null</tt> enumeration elements in the array.
+ * @param enums the array of enumerations.
+ * @return the enumeration over the array of enumerations.
+ */
+ public static Enumeration fromCompound(Enumeration[] enums) {
+ return new CompoundEnumeration(enums);
+ }
+
+}
+
+
+/**
+ * Convenient enumeration over an array of objects.
+ */
+class ArrayEnumeration implements Enumeration {
+
+ /** object array */
+ private Object[] array;
+
+ /** current index */
+ private int pos;
+
+ /**
+ * Initialize a new enumeration that wraps an array.
+ * @param array the array of object to enumerate.
+ */
+ public ArrayEnumeration(Object[] array) {
+ this.array = array;
+ this.pos = 0;
+ }
+ /**
+ * Tests if this enumeration contains more elements.
+ *
+ * @return <code>true</code> if and only if this enumeration object
+ * contains at least one more element to provide;
+ * <code>false</code> otherwise.
+ */
+ public boolean hasMoreElements() {
+ return (pos < array.length);
+ }
+
+ /**
+ * Returns the next element of this enumeration if this enumeration
+ * object has at least one more element to provide.
+ *
+ * @return the next element of this enumeration.
+ * @throws NoSuchElementException if no more elements exist.
+ */
+ public Object nextElement() throws NoSuchElementException {
+ if (hasMoreElements()) {
+ Object o = array[pos];
+ pos++;
+ return o;
+ }
+ throw new NoSuchElementException();
+ }
+}
+/**
+ * Convenient enumeration over an array of enumeration. For example:
+ * <pre>
+ * Enumeration e1 = v1.elements();
+ * while (e1.hasMoreElements()) {
+ * // do something
+ * }
+ * Enumeration e2 = v2.elements();
+ * while (e2.hasMoreElements()) {
+ * // do the same thing
+ * }
+ * </pre>
+ * can be written as:
+ * <pre>
+ * Enumeration[] enums = { v1.elements(), v2.elements() };
+ * Enumeration e = Enumerations.fromCompound(enums);
+ * while (e.hasMoreElements()) {
+ * // do something
+ * }
+ * </pre>
+ * Note that the enumeration will skip null elements in the array. The following is
+ * thus possible:
+ * <pre>
+ * Enumeration[] enums = { v1.elements(), null, v2.elements() }; // a null enumeration in the array
+ * Enumeration e = Enumerations.fromCompound(enums);
+ * while (e.hasMoreElements()) {
+ * // do something
+ * }
+ * </pre>
+ */
+ class CompoundEnumeration implements Enumeration {
+
+ /** enumeration array */
+ private Enumeration[] enumArray;
+
+ /** index in the enums array */
+ private int index = 0;
+
+ public CompoundEnumeration(Enumeration[] enumarray) {
+ this.enumArray = enumarray;
+ }
+
+ /**
+ * Tests if this enumeration contains more elements.
+ *
+ * @return <code>true</code> if and only if this enumeration object
+ * contains at least one more element to provide;
+ * <code>false</code> otherwise.
+ */
+ public boolean hasMoreElements() {
+ while (index < enumArray.length) {
+ if (enumArray[index] != null && enumArray[index].hasMoreElements()) {
+ return true;
+ }
+ index++;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the next element of this enumeration if this enumeration
+ * object has at least one more element to provide.
+ *
+ * @return the next element of this enumeration.
+ * @throws NoSuchElementException if no more elements exist.
+ */
+ public Object nextElement() throws NoSuchElementException {
+ if (hasMoreElements()) {
+ return enumArray[index].nextElement();
+ }
+ throw new NoSuchElementException();
+ }
+}
+
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java
new file mode 100644
index 00000000..3046b75a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java
@@ -0,0 +1,448 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * <p>Collects all failing test <i>cases</i> and creates a new JUnit test class containing
+ * a suite() method which calls these failed tests.</p>
+ * <p>Having classes <i>A</i> ... <i>D</i> with each several testcases you could earn a new
+ * test class like
+ * <pre>
+ * // generated on: 2007.08.06 09:42:34,555
+ * import junit.framework.*;
+ * public class FailedTests extends TestCase {
+ * public FailedTests(String testname) {
+ * super(testname);
+ * }
+ * public static Test suite() {
+ * TestSuite suite = new TestSuite();
+ * suite.addTest( new B("test04") );
+ * suite.addTest( new org.D("test10") );
+ * return suite;
+ * }
+ * }
+ * </pre>
+ *
+ * Because each running test case gets its own formatter, we collect
+ * the failing test cases in a static list. Because we dont have a finalizer
+ * method in the formatters "lifecycle", we register this formatter as
+ * BuildListener and generate the new java source on taskFinished event.
+ *
+ * @since Ant 1.8.0
+ */
+public class FailureRecorder extends ProjectComponent implements JUnitResultFormatter, BuildListener {
+
+ /**
+ * This is the name of a magic System property ({@value}). The value of this
+ * <b>System</b> property should point to the location where to store the
+ * generated class (without suffix).
+ * Default location and name is defined in DEFAULT_CLASS_LOCATION.
+ * @see #DEFAULT_CLASS_LOCATION
+ */
+ public static final String MAGIC_PROPERTY_CLASS_LOCATION
+ = "ant.junit.failureCollector";
+
+ /** Default location and name for the generated JUnit class file,
+ * in the temp directory + FailedTests */
+ public static final String DEFAULT_CLASS_LOCATION
+ = System.getProperty("java.io.tmpdir") + "FailedTests";
+
+ /** Prefix for logging. {@value} */
+ private static final String LOG_PREFIX = " [junit]";
+
+ /** Class names of failed tests without duplicates. */
+ private static SortedSet/*<TestInfos>*/ failedTests = new TreeSet();
+
+ /** A writer for writing the generated source to. */
+ private BufferedWriter writer;
+
+ /**
+ * Location and name of the generated JUnit class.
+ * Lazy instantiated via getLocationName().
+ */
+ private static String locationName;
+
+ /**
+ * Returns the (lazy evaluated) location for the collector class.
+ * Order for evaluation: System property > Ant property > default value
+ * @return location for the collector class
+ * @see #MAGIC_PROPERTY_CLASS_LOCATION
+ * @see #DEFAULT_CLASS_LOCATION
+ */
+ private String getLocationName() {
+ if (locationName == null) {
+ String syspropValue = System.getProperty(MAGIC_PROPERTY_CLASS_LOCATION);
+ String antpropValue = getProject().getProperty(MAGIC_PROPERTY_CLASS_LOCATION);
+
+ if (syspropValue != null) {
+ locationName = syspropValue;
+ verbose("System property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' set, so use "
+ + "its value '" + syspropValue + "' as location for collector class.");
+ } else if (antpropValue != null) {
+ locationName = antpropValue;
+ verbose("Ant property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' set, so use "
+ + "its value '" + antpropValue + "' as location for collector class.");
+ } else {
+ locationName = DEFAULT_CLASS_LOCATION;
+ verbose("System property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' not set, so use "
+ + "value as location for collector class: '"
+ + DEFAULT_CLASS_LOCATION + "'");
+ }
+
+ File locationFile = new File(locationName);
+ if (!locationFile.isAbsolute()) {
+ File f = new File(getProject().getBaseDir(), locationName);
+ locationName = f.getAbsolutePath();
+ verbose("Location file is relative (" + locationFile + ")"
+ + " use absolute path instead (" + locationName + ")");
+ }
+ }
+
+ return locationName;
+ }
+
+ /**
+ * This method is called by the Ant runtime by reflection. We use the project reference for
+ * registration of this class as BuildListener.
+ *
+ * @param project
+ * project reference
+ */
+ public void setProject(Project project) {
+ // store project reference for logging
+ super.setProject(project);
+ // check if already registered
+ boolean alreadyRegistered = false;
+ Vector allListeners = project.getBuildListeners();
+ final int size = allListeners.size();
+ for (int i = 0; i < size; i++) {
+ Object listener = allListeners.get(i);
+ if (listener instanceof FailureRecorder) {
+ alreadyRegistered = true;
+ break;
+ }
+ }
+ // register if needed
+ if (!alreadyRegistered) {
+ verbose("Register FailureRecorder (@" + this.hashCode() + ") as BuildListener");
+ project.addBuildListener(this);
+ }
+ }
+
+ // ===== JUnitResultFormatter =====
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void endTestSuite(JUnitTest suite) throws BuildException {
+ }
+
+ /**
+ * Add the failed test to the list.
+ * @param test the test that errored.
+ * @param throwable the reason it errored.
+ * @see junit.framework.TestListener#addError(junit.framework.Test, java.lang.Throwable)
+ */
+ public void addError(Test test, Throwable throwable) {
+ failedTests.add(new TestInfos(test));
+ }
+
+ // CheckStyle:LineLengthCheck OFF - @see is long
+ /**
+ * Add the failed test to the list.
+ * @param test the test that failed.
+ * @param error the assertion that failed.
+ * @see junit.framework.TestListener#addFailure(junit.framework.Test, junit.framework.AssertionFailedError)
+ */
+ // CheckStyle:LineLengthCheck ON
+ public void addFailure(Test test, AssertionFailedError error) {
+ failedTests.add(new TestInfos(test));
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void setOutput(OutputStream out) {
+ // unused, close output file so it can be deleted before the VM exits
+ if (out != System.out) {
+ FileUtils.close(out);
+ }
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void setSystemError(String err) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void setSystemOutput(String out) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void startTestSuite(JUnitTest suite) throws BuildException {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void endTest(Test test) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void startTest(Test test) {
+ }
+
+ // ===== "Templates" for generating the JUnit class =====
+
+ private void writeJavaClass() {
+ try {
+ File sourceFile = new File((getLocationName() + ".java"));
+ verbose("Write collector class to '" + sourceFile.getAbsolutePath() + "'");
+
+ if (sourceFile.exists() && !sourceFile.delete()) {
+ throw new IOException("could not delete " + sourceFile);
+ }
+ writer = new BufferedWriter(new FileWriter(sourceFile));
+
+ createClassHeader();
+ createSuiteMethod();
+ createClassFooter();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ FileUtils.close(writer);
+ }
+ }
+
+ private void createClassHeader() throws IOException {
+ String className = getLocationName().replace('\\', '/');
+ if (className.indexOf('/') > -1) {
+ className = className.substring(className.lastIndexOf('/') + 1);
+ }
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS");
+ writer.write("// generated on: ");
+ writer.write(sdf.format(new Date()));
+ writer.newLine();
+ writer.write("import junit.framework.*;");
+ writer.newLine();
+ writer.write("public class ");
+ writer.write(className);
+ // If this class does not extend TC, Ant doesn't run these
+ writer.write(" extends TestCase {");
+ writer.newLine();
+ // standard String-constructor
+ writer.write(" public ");
+ writer.write(className);
+ writer.write("(String testname) {");
+ writer.newLine();
+ writer.write(" super(testname);");
+ writer.newLine();
+ writer.write(" }");
+ writer.newLine();
+ }
+
+ private void createSuiteMethod() throws IOException {
+ writer.write(" public static Test suite() {");
+ writer.newLine();
+ writer.write(" TestSuite suite = new TestSuite();");
+ writer.newLine();
+ for (Iterator iter = failedTests.iterator(); iter.hasNext();) {
+ TestInfos testInfos = (TestInfos) iter.next();
+ writer.write(" suite.addTest(");
+ writer.write(String.valueOf(testInfos));
+ writer.write(");");
+ writer.newLine();
+ }
+ writer.write(" return suite;");
+ writer.newLine();
+ writer.write(" }");
+ writer.newLine();
+ }
+
+ private void createClassFooter() throws IOException {
+ writer.write("}");
+ writer.newLine();
+ }
+
+ // ===== Helper classes and methods =====
+
+ /**
+ * Logging facade in INFO-mode.
+ * @param message Log-message
+ */
+ public void log(String message) {
+ getProject().log(LOG_PREFIX + " " + message, Project.MSG_INFO);
+ }
+
+ /**
+ * Logging facade in VERBOSE-mode.
+ * @param message Log-message
+ */
+ public void verbose(String message) {
+ getProject().log(LOG_PREFIX + " " + message, Project.MSG_VERBOSE);
+ }
+
+ /**
+ * TestInfos holds information about a given test for later use.
+ */
+ public static class TestInfos implements Comparable {
+
+ /** The class name of the test. */
+ private final String className;
+
+ /** The method name of the testcase. */
+ private final String methodName;
+
+ /**
+ * This constructor extracts the needed information from the given test.
+ * @param test Test to analyze
+ */
+ public TestInfos(Test test) {
+ className = test.getClass().getName();
+ String _methodName = test.toString();
+ methodName = _methodName.substring(0, _methodName.indexOf('('));
+ }
+
+ /**
+ * This String-Representation can directly be used for instantiation of
+ * the JUnit testcase.
+ * @return the string representation.
+ * @see java.lang.Object#toString()
+ * @see FailureRecorder#createSuiteMethod()
+ */
+ public String toString() {
+ return "new " + className + "(\"" + methodName + "\")";
+ }
+
+ /**
+ * The SortedMap needs comparable elements.
+ * @param other the object to compare to.
+ * @return the result of the comparison.
+ * @see java.lang.Comparable#compareTo
+ * @see SortedSet#comparator()
+ */
+ public int compareTo(Object other) {
+ if (other instanceof TestInfos) {
+ TestInfos otherInfos = (TestInfos) other;
+ return toString().compareTo(otherInfos.toString());
+ } else {
+ return -1;
+ }
+ }
+ public boolean equals(Object obj) {
+ return obj instanceof TestInfos && toString().equals(obj.toString());
+ }
+ public int hashCode() {
+ return toString().hashCode();
+ }
+ }
+
+ // ===== BuildListener =====
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void buildFinished(BuildEvent event) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void buildStarted(BuildEvent event) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void messageLogged(BuildEvent event) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void targetFinished(BuildEvent event) {
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void targetStarted(BuildEvent event) {
+ }
+
+ /**
+ * The task outside of this JUnitResultFormatter is the <junit> task. So all tests passed
+ * and we could create the new java class.
+ * @param event not used
+ * @see org.apache.tools.ant.BuildListener#taskFinished(org.apache.tools.ant.BuildEvent)
+ */
+ public void taskFinished(BuildEvent event) {
+ if (!failedTests.isEmpty()) {
+ writeJavaClass();
+ }
+ }
+
+ /**
+ * Not used
+ * {@inheritDoc}
+ */
+ public void taskStarted(BuildEvent event) {
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java
new file mode 100644
index 00000000..f9fbcb0a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java
@@ -0,0 +1,401 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.KeepAliveOutputStream;
+
+/**
+ * <p> A wrapper for the implementations of <code>JUnitResultFormatter</code>.
+ * In particular, used as a nested <code>&lt;formatter&gt;</code> element in
+ * a <code>&lt;junit&gt;</code> task.
+ * <p> For example,
+ * <code><pre>
+ * &lt;junit printsummary="no" haltonfailure="yes" fork="false"&gt;
+ * &lt;formatter type="plain" usefile="false" /&gt;
+ * &lt;test name="org.apache.ecs.InternationalCharTest" /&gt;
+ * &lt;/junit&gt;</pre></code>
+ * adds a <code>plain</code> type implementation
+ * (<code>PlainJUnitResultFormatter</code>) to display the results of the test.
+ *
+ * <p> Either the <code>type</code> or the <code>classname</code> attribute
+ * must be set.
+ *
+ * @see JUnitTask
+ * @see XMLJUnitResultFormatter
+ * @see BriefJUnitResultFormatter
+ * @see PlainJUnitResultFormatter
+ * @see FailureRecorder
+ * @see JUnitResultFormatter
+ */
+public class FormatterElement {
+
+ private String classname;
+ private String extension;
+ private OutputStream out = new KeepAliveOutputStream(System.out);
+ private File outFile;
+ private boolean useFile = true;
+ private Object ifCond;
+ private Object unlessCond;
+
+ /**
+ * Store the project reference for passing it to nested components.
+ * @since Ant 1.8
+ */
+ private Project project;
+
+ /** xml formatter class */
+ public static final String XML_FORMATTER_CLASS_NAME =
+ "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter";
+ /** brief formatter class */
+ public static final String BRIEF_FORMATTER_CLASS_NAME =
+ "org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter";
+ /** plain formatter class */
+ public static final String PLAIN_FORMATTER_CLASS_NAME =
+ "org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter";
+ /** failure recorder class */
+ public static final String FAILURE_RECORDER_CLASS_NAME =
+ "org.apache.tools.ant.taskdefs.optional.junit.FailureRecorder";
+
+ /**
+ * <p> Quick way to use a standard formatter.
+ *
+ * <p> At the moment, there are three supported standard formatters.
+ * <ul>
+ * <li> The <code>xml</code> type uses a <code>XMLJUnitResultFormatter</code>.
+ * <li> The <code>brief</code> type uses a <code>BriefJUnitResultFormatter</code>.
+ * <li> The <code>plain</code> type (the default) uses a <code>PlainJUnitResultFormatter</code>.
+ * <li> The <code>failure</code> type uses a <code>FailureRecorder</code>.
+ * </ul>
+ *
+ * <p> Sets <code>classname</code> attribute - so you can't use that
+ * attribute if you use this one.
+ * @param type the enumerated value to use.
+ */
+ public void setType(TypeAttribute type) {
+ if ("xml".equals(type.getValue())) {
+ setClassname(XML_FORMATTER_CLASS_NAME);
+ } else {
+ if ("brief".equals(type.getValue())) {
+ setClassname(BRIEF_FORMATTER_CLASS_NAME);
+ } else {
+ if ("failure".equals(type.getValue())) {
+ setClassname(FAILURE_RECORDER_CLASS_NAME);
+ } else { // must be plain, ensured by TypeAttribute
+ setClassname(PLAIN_FORMATTER_CLASS_NAME);
+ }
+ }
+ }
+ }
+
+ /**
+ * <p> Set name of class to be used as the formatter.
+ *
+ * <p> This class must implement <code>JUnitResultFormatter</code>
+ * @param classname the name of the formatter class.
+ */
+ public void setClassname(String classname) {
+ this.classname = classname;
+ if (XML_FORMATTER_CLASS_NAME.equals(classname)) {
+ setExtension(".xml");
+ } else if (PLAIN_FORMATTER_CLASS_NAME.equals(classname)) {
+ setExtension(".txt");
+ } else if (BRIEF_FORMATTER_CLASS_NAME.equals(classname)) {
+ setExtension(".txt");
+ }
+ }
+
+ /**
+ * Get name of class to be used as the formatter.
+ * @return the name of the class.
+ */
+ public String getClassname() {
+ return classname;
+ }
+
+ /**
+ * Set the extension to use for the report file.
+ * @param ext the extension to use.
+ */
+ public void setExtension(String ext) {
+ this.extension = ext;
+ }
+
+ /**
+ * Get the extension used for the report file.
+ * @return the extension.
+ */
+ public String getExtension() {
+ return extension;
+ }
+
+ /**
+ * <p> Set the file which the formatte should log to.
+ *
+ * <p> Note that logging to file must be enabled .
+ */
+ void setOutfile(File out) {
+ this.outFile = out;
+ }
+
+ /**
+ * <p> Set output stream for formatter to use.
+ *
+ * <p> Defaults to standard out.
+ * @param out the output stream to use.
+ */
+ public void setOutput(OutputStream out) {
+ if (out == System.out || out == System.err) {
+ out = new KeepAliveOutputStream(out);
+ }
+ this.out = out;
+ }
+
+ /**
+ * Set whether the formatter should log to file.
+ * @param useFile if true use a file, if false send
+ * to standard out.
+ */
+ public void setUseFile(boolean useFile) {
+ this.useFile = useFile;
+ }
+
+ /**
+ * Get whether the formatter should log to file.
+ */
+ boolean getUseFile() {
+ return useFile;
+ }
+
+ /**
+ * Set whether this formatter should be used. It will be used if
+ * the expression evaluates to true or the name of a property
+ * which has been set, otherwise it won't.
+ * @param ifCond name of property
+ * @since Ant 1.8.0
+ */
+ public void setIf(Object ifCond) {
+ this.ifCond = ifCond;
+ }
+
+ /**
+ * Set whether this formatter should be used. It will be used if
+ * the expression evaluates to true or the name of a property
+ * which has been set, otherwise it won't.
+ * @param ifCond name of property
+ */
+ public void setIf(String ifCond) {
+ setIf((Object) ifCond);
+ }
+
+ /**
+ * Set whether this formatter should NOT be used. It will be used
+ * if the expression evaluates to false or the name of a property
+ * which has not been set, orthwise it will not be used.
+ * @param unlessCond name of property
+ * @since Ant 1.8.0
+ */
+ public void setUnless(Object unlessCond) {
+ this.unlessCond = unlessCond;
+ }
+
+ /**
+ * Set whether this formatter should NOT be used. It will be used
+ * if the expression evaluates to false or the name of a property
+ * which has not been set, orthwise it will not be used.
+ * @param unlessCond name of property
+ */
+ public void setUnless(String unlessCond) {
+ setUnless((Object) unlessCond);
+ }
+
+ /**
+ * Ensures that the selector passes the conditions placed
+ * on it with <code>if</code> and <code>unless</code> properties.
+ * @param t the task the this formatter is used in.
+ * @return true if the formatter should be used.
+ */
+ public boolean shouldUse(Task t) {
+ PropertyHelper ph = PropertyHelper.getPropertyHelper(t.getProject());
+ return ph.testIfCondition(ifCond)
+ && ph.testUnlessCondition(unlessCond);
+ }
+
+ /**
+ * @since Ant 1.2
+ */
+ JUnitTaskMirror.JUnitResultFormatterMirror createFormatter() throws BuildException {
+ return createFormatter(null);
+ }
+
+ /**
+ * Store the project reference for passing it to nested components.
+ * @param project the reference
+ * @since Ant 1.8
+ */
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+
+ /**
+ * @since Ant 1.6
+ */
+ JUnitTaskMirror.JUnitResultFormatterMirror createFormatter(ClassLoader loader)
+ throws BuildException {
+
+ if (classname == null) {
+ throw new BuildException("you must specify type or classname");
+ }
+ //although this code appears to duplicate that of ClasspathUtils.newInstance,
+ //we cannot use that because this formatter may run in a forked process,
+ //without that class.
+ Class f = null;
+ try {
+ if (loader == null) {
+ f = Class.forName(classname);
+ } else {
+ f = Class.forName(classname, true, loader);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new BuildException(
+ "Using loader " + loader + " on class " + classname
+ + ": " + e, e);
+ } catch (NoClassDefFoundError e) {
+ throw new BuildException(
+ "Using loader " + loader + " on class " + classname
+ + ": " + e, e);
+ }
+
+ Object o = null;
+ try {
+ o = f.newInstance();
+ } catch (InstantiationException e) {
+ throw new BuildException(e);
+ } catch (IllegalAccessException e) {
+ throw new BuildException(e);
+ }
+
+ if (!(o instanceof JUnitTaskMirror.JUnitResultFormatterMirror)) {
+ throw new BuildException(classname + " is not a JUnitResultFormatter");
+ }
+ JUnitTaskMirror.JUnitResultFormatterMirror r =
+ (JUnitTaskMirror.JUnitResultFormatterMirror) o;
+ if (useFile && outFile != null) {
+ out = new DelayedFileOutputStream(outFile);
+ }
+ r.setOutput(out);
+
+
+ boolean needToSetProjectReference = true;
+ try {
+ Field field = r.getClass().getField("project");
+ Object value = field.get(r);
+ if (value instanceof Project) {
+ // there is already a project reference so dont overwrite this
+ needToSetProjectReference = false;
+ }
+ } catch (NoSuchFieldException e) {
+ // no field present, so no previous reference exists
+ } catch (IllegalAccessException e) {
+ throw new BuildException(e);
+ }
+
+ if (needToSetProjectReference) {
+ Method setter;
+ try {
+ setter = r.getClass().getMethod("setProject", new Class[] {Project.class});
+ setter.invoke(r, new Object[] {project});
+ } catch (NoSuchMethodException e) {
+ // no setProject to invoke; just ignore
+ } catch (IllegalAccessException e) {
+ throw new BuildException(e);
+ } catch (InvocationTargetException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ return r;
+ }
+
+ /**
+ * <p> Enumerated attribute with the values "plain", "xml", "brief" and "failure".
+ *
+ * <p> Use to enumerate options for <code>type</code> attribute.
+ */
+ public static class TypeAttribute extends EnumeratedAttribute {
+ /** {@inheritDoc}. */
+ public String[] getValues() {
+ return new String[] {"plain", "xml", "brief", "failure"};
+ }
+ }
+
+ /**
+ * A standard FileOutputStream creates a file as soon as it's opened. This
+ * class delays the creation of the file until the first time a caller attempts
+ * to write to it so we don't end up with empty files if the listeners don't use
+ * them.
+ */
+ private static class DelayedFileOutputStream extends OutputStream {
+
+ private BufferedOutputStream outputStream;
+ private final File file;
+
+ public DelayedFileOutputStream(File file) {
+ this.file = file;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ synchronized (this) {
+ if (outputStream == null) {
+ outputStream = new BufferedOutputStream(new FileOutputStream(file));
+ }
+ }
+ outputStream.write(b);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (outputStream != null) {
+ outputStream.flush();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java
new file mode 100644
index 00000000..6741912e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestListener.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.Test;
+import junit.framework.TestListener;
+
+/**
+ * Provides the functionality for TestListeners to be able to be notified of
+ * the necessary JUnit4 events for test being ignored (@Ignore annotation)
+ * or skipped (Assume failures). Tests written in JUnit4 will report against
+ * the methods in this interface alongside the methods in the existing TestListener
+ */
+public interface IgnoredTestListener extends TestListener {
+
+ /**
+ * Reports when a test has been marked with the @Ignore annotation. The parameter
+ * should normally be typed to JUnit's {@link junit.framework.JUnit4TestCaseFacade}
+ * so implementing classes should be able to get the details of the ignore by casting
+ * the argument and retrieving the descriptor from the test.
+ * @param test the details of the test and failure that have triggered this report.
+ */
+ void testIgnored(Test test);
+
+ /**
+ * Receive a report that a test has failed an assumption. Within JUnit4
+ * this is normally treated as a test being skipped, although how any
+ * listener handles this is up to that specific listener.<br />
+ * <b>Note:</b> Tests that throw assumption failures will still report
+ * the endTest method, which may differ from how the addError and addFailure
+ * methods work, it's up for any implementing classes to handle this.
+ * @param test the details of the test and failure that have triggered this report.
+ * @param exception the AssumptionViolatedException thrown from the current assumption failure.
+ */
+ void testAssumptionFailure(Test test, Throwable exception);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java
new file mode 100644
index 00000000..c3bb18da
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/IgnoredTestResult.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+
+/**
+ * Records ignored and skipped tests reported as part of the execution of
+ * JUnit 4 tests.
+ *
+ */
+public class IgnoredTestResult extends TestResult {
+
+
+ private List<IgnoredTestListener> listeners = new ArrayList<IgnoredTestListener>();
+ private List<TestIgnored> ignored = new ArrayList<TestIgnored>();
+ private List<TestIgnored> skipped = new ArrayList<TestIgnored>();
+
+ public IgnoredTestResult() {
+ super();
+ }
+
+
+ public synchronized void addListener(TestListener listener) {
+ if (listener instanceof IgnoredTestListener) {
+ listeners.add((IgnoredTestListener)listener);
+ }
+ super.addListener(listener);
+ }
+
+ public synchronized void removeListener(TestListener listener) {
+ if (listener instanceof IgnoredTestListener) {
+ listeners.remove(listener);
+ }
+ super.removeListener(listener);
+ }
+
+ /**
+ * Record a test as having been ignored, normally by the @Ignore annotation.
+ * @param test the test that was ignored.
+ * @throws Exception is the listener thrown an exception on handling the notification.
+ */
+ public synchronized void testIgnored(Test test) throws Exception {
+ ignored.add(new TestIgnored(test));
+ for (IgnoredTestListener listener : listeners) {
+ listener.testIgnored(test);
+ }
+ }
+
+ /**
+ * Report how many tests were ignored.
+ * @return the number of tests reported as ignored during the current execution.
+ */
+ public long ignoredCount() {
+ return ignored.size();
+ }
+
+ /**
+ * Records a test as having an assumption failure so JUnit will no longer be executing it.
+ * Under normal circumstances this would be counted as a skipped test.
+ * @param test the test to record
+ * @param cause the details of the test and assumption failure.
+ */
+ public void testAssumptionFailure(Test test, Throwable cause) {
+ skipped.add(new TestIgnored(test));
+ for (IgnoredTestListener listener : listeners) {
+ listener.testAssumptionFailure(test, cause);
+ }
+ }
+
+ /**
+ * Report how many tests has assumption failures.
+ * @return the number of tests that reported assumption failures during the current execution.
+ */
+ public long skippedCount() {
+ return skipped.size();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java
new file mode 100644
index 00000000..f03a409b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+
+/**
+ * Adapter between JUnit 3.8.x API and JUnit 4.x API for execution of tests
+ * and listening of events (test start, test finish, test failure, test skipped).
+ * The constructor is passed a JUnit 4 test class and a list of name of methods
+ * in it that should be executed. Method {@link #run run(TestResult)} executes
+ * the given JUnit-4-style test methods and notifies the given {@code TestResult}
+ * object using its old (JUnit 3.8.x style) API.
+ *
+ * @author Marian Petras
+ */
+public class JUnit4TestMethodAdapter implements Test {
+
+ private final Class testClass;
+ private final String[] methodNames;
+ private final Runner runner;
+ private final CustomJUnit4TestAdapterCache cache;
+
+ /**
+ * Creates a new adapter for the given class and a method within the class.
+ *
+ * @param testClass test class containing the method to be executed
+ * @param methodNames names of the test methods that are to be executed
+ * @exception java.lang.IllegalArgumentException
+ * if any of the arguments is {@code null}
+ * or if any of the given method names is {@code null} or empty
+ */
+ public JUnit4TestMethodAdapter(final Class testClass,
+ final String[] methodNames) {
+ if (testClass == null) {
+ throw new IllegalArgumentException("testClass is <null>");
+ }
+ if (methodNames == null) {
+ throw new IllegalArgumentException("methodNames is <null>");
+ }
+ for (int i = 0; i < methodNames.length; i++) {
+ if (methodNames[i] == null) {
+ throw new IllegalArgumentException("method name #" + i + " is <null>");
+ }
+ if (methodNames[i].length() == 0) {
+ throw new IllegalArgumentException("method name #" + i + " is empty");
+ }
+ }
+ this.testClass = testClass;
+ this.methodNames = methodNames.clone();
+ this.cache = CustomJUnit4TestAdapterCache.getInstance();
+
+ // Warning: If 'testClass' is an old-style (pre-JUnit-4) class,
+ // then all its test methods will be executed by the returned runner!
+ Request request;
+ if (methodNames.length == 1) {
+ request = Request.method(testClass, methodNames[0]);
+ } else {
+ request = Request.aClass(testClass).filterWith(
+ new MultipleMethodsFilter(testClass, methodNames));
+ }
+ runner = request.getRunner();
+ }
+
+ public int countTestCases() {
+ return runner.testCount();
+ }
+
+ public Description getDescription() {
+ return runner.getDescription();
+ }
+
+ public List/*<Test>*/ getTests() {
+ return cache.asTestList(getDescription());
+ }
+
+ public Class getTestClass() {
+ return testClass;
+ }
+
+ public void run(final TestResult result) {
+ runner.run(cache.getNotifier(result));
+ }
+
+ @Override
+ public String toString() {
+ String testClassName = testClass.getName();
+ StringBuilder buf = new StringBuilder(testClassName.length()
+ + 12 * methodNames.length)
+ .append(':');
+ if (methodNames.length != 0) {
+ buf.append(methodNames[0]);
+ for (int i = 1; i < methodNames.length; i++) {
+ buf.append(',')
+ .append(methodNames[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+ private static final class MultipleMethodsFilter extends Filter {
+
+ private final Description methodsListDescription;
+ private final Class testClass;
+ private final String[] methodNames;
+
+ private MultipleMethodsFilter(Class testClass, String[] methodNames) {
+ if (testClass == null) {
+ throw new IllegalArgumentException("testClass is <null>");
+ }
+ if (methodNames == null) {
+ throw new IllegalArgumentException("methodNames is <null>");
+ }
+ methodsListDescription = Description.createSuiteDescription(testClass);
+ for (int i = 0; i < methodNames.length; i++) {
+ methodsListDescription.addChild(
+ Description.createTestDescription(testClass, methodNames[i]));
+ }
+ this.testClass = testClass;
+ this.methodNames = methodNames;
+ }
+
+ @Override
+ public boolean shouldRun(Description description) {
+ if (methodNames.length == 0) {
+ return false;
+ }
+ if (description.isTest()) {
+ Iterator/*<Description>*/ it = methodsListDescription.getChildren().iterator();
+ while (it.hasNext()) {
+ Description methodDescription = (Description) it.next();
+ if (methodDescription.equals(description)) {
+ return true;
+ }
+ }
+ } else {
+ Iterator/*<Description>*/ it = description.getChildren().iterator();
+ while (it.hasNext()) {
+ Description each = (Description) it.next();
+ if (shouldRun(each)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String describe() {
+ StringBuilder buf = new StringBuilder(40);
+ if (methodNames.length == 0) {
+ buf.append("No methods");
+ } else {
+ buf.append(methodNames.length == 1 ? "Method" : "Methods");
+ buf.append(' ');
+ buf.append(methodNames[0]);
+ for (int i = 1; i < methodNames.length; i++) {
+ buf.append(',').append(methodNames[i]);
+ }
+ }
+ buf.append('(').append(testClass.getName()).append(')');
+ return buf.toString();
+ }
+
+ }
+
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java
new file mode 100644
index 00000000..2119fc94
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+
+import junit.framework.TestListener;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * This Interface describes classes that format the results of a JUnit
+ * testrun.
+ *
+ */
+public interface JUnitResultFormatter
+ extends TestListener, JUnitTaskMirror.JUnitResultFormatterMirror {
+ /**
+ * The whole testsuite started.
+ * @param suite the suite.
+ * @throws BuildException on error.
+ */
+ void startTestSuite(JUnitTest suite) throws BuildException;
+
+ /**
+ * The whole testsuite ended.
+ * @param suite the suite.
+ * @throws BuildException on error.
+ */
+ void endTestSuite(JUnitTest suite) throws BuildException;
+
+ /**
+ * Sets the stream the formatter is supposed to write its results to.
+ * @param out the output stream to use.
+ */
+ void setOutput(OutputStream out);
+
+ /**
+ * This is what the test has written to System.out
+ * @param out the string to write.
+ */
+ void setSystemOutput(String out);
+
+ /**
+ * This is what the test has written to System.err
+ * @param err the string to write.
+ */
+ void setSystemError(String err);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
new file mode 100644
index 00000000..459bd3d5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
@@ -0,0 +1,2283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteWatchdog;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.types.Assertions;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Permissions;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+import org.apache.tools.ant.util.SplitClassLoader;
+
+/**
+ * Runs JUnit tests.
+ *
+ * <p> JUnit is a framework to create unit tests. It has been initially
+ * created by Erich Gamma and Kent Beck. JUnit can be found at <a
+ * href="http://www.junit.org">http://www.junit.org</a>.
+ *
+ * <p> <code>JUnitTask</code> can run a single specific
+ * <code>JUnitTest</code> using the <code>test</code> element.</p>
+ * For example, the following target <code><pre>
+ * &lt;target name="test-int-chars" depends="jar-test"&gt;
+ * &lt;echo message="testing international characters"/&gt;
+ * &lt;junit printsummary="no" haltonfailure="yes" fork="false"&gt;
+ * &lt;classpath refid="classpath"/&gt;
+ * &lt;formatter type="plain" usefile="false" /&gt;
+ * &lt;test name="org.apache.ecs.InternationalCharTest" /&gt;
+ * &lt;/junit&gt;
+ * &lt;/target&gt;
+ * </pre></code>
+ * <p>runs a single junit test
+ * (<code>org.apache.ecs.InternationalCharTest</code>) in the current
+ * VM using the path with id <code>classpath</code> as classpath and
+ * presents the results formatted using the standard
+ * <code>plain</code> formatter on the command line.</p>
+ *
+ * <p> This task can also run batches of tests. The
+ * <code>batchtest</code> element creates a <code>BatchTest</code>
+ * based on a fileset. This allows, for example, all classes found in
+ * directory to be run as testcases.</p>
+ *
+ * <p>For example,</p><code><pre>
+ * &lt;target name="run-tests" depends="dump-info,compile-tests" if="junit.present"&gt;
+ * &lt;junit printsummary="no" haltonfailure="yes" fork="${junit.fork}"&gt;
+ * &lt;jvmarg value="-classic"/&gt;
+ * &lt;classpath refid="tests-classpath"/&gt;
+ * &lt;sysproperty key="build.tests" value="${build.tests}"/&gt;
+ * &lt;formatter type="brief" usefile="false" /&gt;
+ * &lt;batchtest&gt;
+ * &lt;fileset dir="${tests.dir}"&gt;
+ * &lt;include name="**&#047;*Test*" /&gt;
+ * &lt;/fileset&gt;
+ * &lt;/batchtest&gt;
+ * &lt;/junit&gt;
+ * &lt;/target&gt;
+ * </pre></code>
+ * <p>this target finds any classes with a <code>test</code> directory
+ * anywhere in their path (under the top <code>${tests.dir}</code>, of
+ * course) and creates <code>JUnitTest</code>'s for each one.</p>
+ *
+ * <p> Of course, <code>&lt;junit&gt;</code> and
+ * <code>&lt;batch&gt;</code> elements can be combined for more
+ * complex tests. For an example, see the ant <code>build.xml</code>
+ * target <code>run-tests</code> (the second example is an edited
+ * version).</p>
+ *
+ * <p> To spawn a new Java VM to prevent interferences between
+ * different testcases, you need to enable <code>fork</code>. A
+ * number of attributes and elements allow you to set up how this JVM
+ * runs.
+ *
+ *
+ * @since Ant 1.2
+ *
+ * @see JUnitTest
+ * @see BatchTest
+ */
+public class JUnitTask extends Task {
+
+ private static final String LINE_SEP
+ = System.getProperty("line.separator");
+ private static final String CLASSPATH = "CLASSPATH";
+ private CommandlineJava commandline;
+ private final Vector<JUnitTest> tests = new Vector<JUnitTest>();
+ private final Vector<BatchTest> batchTests = new Vector<BatchTest>();
+ private final Vector<FormatterElement> formatters = new Vector<FormatterElement>();
+ private File dir = null;
+
+ private Integer timeout = null;
+ private boolean summary = false;
+ private boolean reloading = true;
+ private String summaryValue = "";
+ private JUnitTaskMirror.JUnitTestRunnerMirror runner = null;
+
+ private boolean newEnvironment = false;
+ private final Environment env = new Environment();
+
+ private boolean includeAntRuntime = true;
+ private Path antRuntimeClasses = null;
+
+ // Do we send output to System.out/.err in addition to the formatters?
+ private boolean showOutput = false;
+
+ // Do we send output to the formatters ?
+ private boolean outputToFormatters = true;
+
+ private boolean logFailedTests = true;
+
+ private File tmpDir;
+ private AntClassLoader classLoader = null;
+ private Permissions perm = null;
+ private ForkMode forkMode = new ForkMode("perTest");
+
+ private boolean splitJUnit = false;
+ private boolean enableTestListenerEvents = false;
+ private JUnitTaskMirror delegate;
+ private ClassLoader mirrorLoader;
+
+ /** A boolean on whether to get the forked path for ant classes */
+ private boolean forkedPathChecked = false;
+
+ /* set when a test fails/errs with haltonfailure/haltonerror and >1 thread to stop other threads */
+ private volatile BuildException caughtBuildException = null;
+
+ // Attributes for basetest
+ private boolean haltOnError = false;
+ private boolean haltOnFail = false;
+ private boolean filterTrace = true;
+ private boolean fork = false;
+ private int threads = 1;
+ private String failureProperty;
+ private String errorProperty;
+
+ private static final int STRING_BUFFER_SIZE = 128;
+ /**
+ * @since Ant 1.7
+ */
+ public static final String TESTLISTENER_PREFIX =
+ "junit.framework.TestListener: ";
+
+ /**
+ * Name of magic property that enables test listener events.
+ */
+ public static final String ENABLE_TESTLISTENER_EVENTS =
+ "ant.junit.enabletestlistenerevents";
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * If true, force ant to re-classload all classes for each JUnit TestCase
+ *
+ * @param value force class reloading for each test case
+ */
+ public void setReloading(final boolean value) {
+ reloading = value;
+ }
+
+ /**
+ * If true, smartly filter the stack frames of
+ * JUnit errors and failures before reporting them.
+ *
+ * <p>This property is applied on all BatchTest (batchtest) and
+ * JUnitTest (test) however it can possibly be overridden by their
+ * own properties.</p>
+ * @param value <tt>false</tt> if it should not filter, otherwise
+ * <tt>true<tt>
+ *
+ * @since Ant 1.5
+ */
+ public void setFiltertrace(final boolean value) {
+ this.filterTrace = value;
+ }
+
+ /**
+ * If true, stop the build process when there is an error in a test.
+ * This property is applied on all BatchTest (batchtest) and JUnitTest
+ * (test) however it can possibly be overridden by their own
+ * properties.
+ * @param value <tt>true</tt> if it should halt, otherwise
+ * <tt>false</tt>
+ *
+ * @since Ant 1.2
+ */
+ public void setHaltonerror(final boolean value) {
+ this.haltOnError = value;
+ }
+
+ /**
+ * Property to set to "true" if there is a error in a test.
+ *
+ * <p>This property is applied on all BatchTest (batchtest) and
+ * JUnitTest (test), however, it can possibly be overridden by
+ * their own properties.</p>
+ * @param propertyName the name of the property to set in the
+ * event of an error.
+ *
+ * @since Ant 1.4
+ */
+ public void setErrorProperty(final String propertyName) {
+ this.errorProperty = propertyName;
+ }
+
+ /**
+ * If true, stop the build process if a test fails
+ * (errors are considered failures as well).
+ * This property is applied on all BatchTest (batchtest) and
+ * JUnitTest (test) however it can possibly be overridden by their
+ * own properties.
+ * @param value <tt>true</tt> if it should halt, otherwise
+ * <tt>false</tt>
+ *
+ * @since Ant 1.2
+ */
+ public void setHaltonfailure(final boolean value) {
+ this.haltOnFail = value;
+ }
+
+ /**
+ * Property to set to "true" if there is a failure in a test.
+ *
+ * <p>This property is applied on all BatchTest (batchtest) and
+ * JUnitTest (test), however, it can possibly be overridden by
+ * their own properties.</p>
+ * @param propertyName the name of the property to set in the
+ * event of an failure.
+ *
+ * @since Ant 1.4
+ */
+ public void setFailureProperty(final String propertyName) {
+ this.failureProperty = propertyName;
+ }
+
+ /**
+ * If true, JVM should be forked for each test.
+ *
+ * <p>It avoids interference between testcases and possibly avoids
+ * hanging the build. this property is applied on all BatchTest
+ * (batchtest) and JUnitTest (test) however it can possibly be
+ * overridden by their own properties.</p>
+ * @param value <tt>true</tt> if a JVM should be forked, otherwise
+ * <tt>false</tt>
+ * @see #setTimeout
+ *
+ * @since Ant 1.2
+ */
+ public void setFork(final boolean value) {
+ this.fork = value;
+ }
+
+ /**
+ * Set the behavior when {@link #setFork fork} fork has been enabled.
+ *
+ * <p>Possible values are "once", "perTest" and "perBatch". If
+ * set to "once", only a single Java VM will be forked for all
+ * tests, with "perTest" (the default) each test will run in a
+ * fresh Java VM and "perBatch" will run all tests from the same
+ * &lt;batchtest&gt; in the same Java VM.</p>
+ *
+ * <p>This attribute will be ignored if tests run in the same VM
+ * as Ant.</p>
+ *
+ * <p>Only tests with the same configuration of haltonerror,
+ * haltonfailure, errorproperty, failureproperty and filtertrace
+ * can share a forked Java VM, so even if you set the value to
+ * "once", Ant may need to fork multiple VMs.</p>
+ * @param mode the mode to use.
+ * @since Ant 1.6.2
+ */
+ public void setForkMode(final ForkMode mode) {
+ this.forkMode = mode;
+ }
+
+ /**
+ * Set the number of test threads to be used for parallel test
+ * execution. The default is 1, which is the same behavior as
+ * before parallel test execution was possible.
+ *
+ * <p>This attribute will be ignored if tests run in the same VM
+ * as Ant.</p>
+ *
+ * @since Ant 1.9.4
+ */
+ public void setThreads(final int threads) {
+ if (threads >= 0) {
+ this.threads = threads;
+ }
+ }
+
+ /**
+ * If true, print one-line statistics for each test, or "withOutAndErr"
+ * to also show standard output and error.
+ *
+ * Can take the values on, off, and withOutAndErr.
+ * @param value <tt>true</tt> to print a summary,
+ * <tt>withOutAndErr</tt> to include the test&apos;s output as
+ * well, <tt>false</tt> otherwise.
+ * @see SummaryJUnitResultFormatter
+ *
+ * @since Ant 1.2
+ */
+ public void setPrintsummary(final SummaryAttribute value) {
+ summaryValue = value.getValue();
+ summary = value.asBoolean();
+ }
+
+ /**
+ * Print summary enumeration values.
+ */
+ public static class SummaryAttribute extends EnumeratedAttribute {
+ /**
+ * list the possible values
+ * @return array of allowed values
+ */
+ @Override
+ public String[] getValues() {
+ return new String[] {"true", "yes", "false", "no",
+ "on", "off", "withOutAndErr"};
+ }
+
+ /**
+ * gives the boolean equivalent of the authorized values
+ * @return boolean equivalent of the value
+ */
+ public boolean asBoolean() {
+ final String v = getValue();
+ return "true".equals(v)
+ || "on".equals(v)
+ || "yes".equals(v)
+ || "withOutAndErr".equals(v);
+ }
+ }
+
+ /**
+ * Set the timeout value (in milliseconds).
+ *
+ * <p>If the test is running for more than this value, the test
+ * will be canceled. (works only when in 'fork' mode).</p>
+ * @param value the maximum time (in milliseconds) allowed before
+ * declaring the test as 'timed-out'
+ * @see #setFork(boolean)
+ *
+ * @since Ant 1.2
+ */
+ public void setTimeout(final Integer value) {
+ timeout = value;
+ }
+
+ /**
+ * Set the maximum memory to be used by all forked JVMs.
+ * @param max the value as defined by <tt>-mx</tt> or <tt>-Xmx</tt>
+ * in the java command line options.
+ *
+ * @since Ant 1.2
+ */
+ public void setMaxmemory(final String max) {
+ getCommandline().setMaxmemory(max);
+ }
+
+ /**
+ * The command used to invoke the Java Virtual Machine,
+ * default is 'java'. The command is resolved by
+ * java.lang.Runtime.exec(). Ignored if fork is disabled.
+ *
+ * @param value the new VM to use instead of <tt>java</tt>
+ * @see #setFork(boolean)
+ *
+ * @since Ant 1.2
+ */
+ public void setJvm(final String value) {
+ getCommandline().setVm(value);
+ }
+
+ /**
+ * Adds a JVM argument; ignored if not forking.
+ *
+ * @return create a new JVM argument so that any argument can be
+ * passed to the JVM.
+ * @see #setFork(boolean)
+ *
+ * @since Ant 1.2
+ */
+ public Commandline.Argument createJvmarg() {
+ return getCommandline().createVmArgument();
+ }
+
+ /**
+ * The directory to invoke the VM in. Ignored if no JVM is forked.
+ * @param dir the directory to invoke the JVM from.
+ * @see #setFork(boolean)
+ *
+ * @since Ant 1.2
+ */
+ public void setDir(final File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * Adds a system property that tests can access.
+ * This might be useful to transfer Ant properties to the
+ * testcases when JVM forking is not enabled.
+ *
+ * @since Ant 1.3
+ * @deprecated since ant 1.6
+ * @param sysp environment variable to add
+ */
+ @Deprecated
+ public void addSysproperty(final Environment.Variable sysp) {
+
+ getCommandline().addSysproperty(sysp);
+ }
+
+ /**
+ * Adds a system property that tests can access.
+ * This might be useful to transfer Ant properties to the
+ * testcases when JVM forking is not enabled.
+ * @param sysp new environment variable to add
+ * @since Ant 1.6
+ */
+ public void addConfiguredSysproperty(final Environment.Variable sysp) {
+ // get a build exception if there is a missing key or value
+ // see bugzilla report 21684
+ final String testString = sysp.getContent();
+ getProject().log("sysproperty added : " + testString, Project.MSG_DEBUG);
+ getCommandline().addSysproperty(sysp);
+ }
+
+ /**
+ * Adds a set of properties that will be used as system properties
+ * that tests can access.
+ *
+ * This might be useful to transfer Ant properties to the
+ * testcases when JVM forking is not enabled.
+ *
+ * @param sysp set of properties to be added
+ * @since Ant 1.6
+ */
+ public void addSyspropertyset(final PropertySet sysp) {
+ getCommandline().addSyspropertyset(sysp);
+ }
+
+ /**
+ * Adds path to classpath used for tests.
+ *
+ * @return reference to the classpath in the embedded java command line
+ * @since Ant 1.2
+ */
+ public Path createClasspath() {
+ return getCommandline().createClasspath(getProject()).createPath();
+ }
+
+ /**
+ * Adds a path to the bootclasspath.
+ * @return reference to the bootclasspath in the embedded java command line
+ * @since Ant 1.6
+ */
+ public Path createBootclasspath() {
+ return getCommandline().createBootclasspath(getProject()).createPath();
+ }
+
+ /**
+ * Adds an environment variable; used when forking.
+ *
+ * <p>Will be ignored if we are not forking a new VM.</p>
+ * @param var environment variable to be added
+ * @since Ant 1.5
+ */
+ public void addEnv(final Environment.Variable var) {
+ env.addVariable(var);
+ }
+
+ /**
+ * If true, use a new environment when forked.
+ *
+ * <p>Will be ignored if we are not forking a new VM.</p>
+ *
+ * @param newenv boolean indicating if setting a new environment is wished
+ * @since Ant 1.5
+ */
+ public void setNewenvironment(final boolean newenv) {
+ newEnvironment = newenv;
+ }
+
+ /**
+ * Preset the attributes of the test
+ * before configuration in the build
+ * script.
+ * This allows attributes in the <junit> task
+ * be be defaults for the tests, but allows
+ * individual tests to override the defaults.
+ */
+ private void preConfigure(final BaseTest test) {
+ test.setFiltertrace(filterTrace);
+ test.setHaltonerror(haltOnError);
+ if (errorProperty != null) {
+ test.setErrorProperty(errorProperty);
+ }
+ test.setHaltonfailure(haltOnFail);
+ if (failureProperty != null) {
+ test.setFailureProperty(failureProperty);
+ }
+ test.setFork(fork);
+ }
+
+ /**
+ * Add a new single testcase.
+ * @param test a new single testcase
+ * @see JUnitTest
+ *
+ * @since Ant 1.2
+ */
+ public void addTest(final JUnitTest test) {
+ tests.addElement(test);
+ preConfigure(test);
+ }
+
+ /**
+ * Adds a set of tests based on pattern matching.
+ *
+ * @return a new instance of a batch test.
+ * @see BatchTest
+ *
+ * @since Ant 1.2
+ */
+ public BatchTest createBatchTest() {
+ final BatchTest test = new BatchTest(getProject());
+ batchTests.addElement(test);
+ preConfigure(test);
+ return test;
+ }
+
+ /**
+ * Add a new formatter to all tests of this task.
+ *
+ * @param fe formatter element
+ * @since Ant 1.2
+ */
+ public void addFormatter(final FormatterElement fe) {
+ formatters.addElement(fe);
+ }
+
+ /**
+ * If true, include ant.jar, optional.jar and junit.jar in the forked VM.
+ *
+ * @param b include ant run time yes or no
+ * @since Ant 1.5
+ */
+ public void setIncludeantruntime(final boolean b) {
+ includeAntRuntime = b;
+ }
+
+ /**
+ * If true, send any output generated by tests to Ant's logging system
+ * as well as to the formatters.
+ * By default only the formatters receive the output.
+ *
+ * <p>Output will always be passed to the formatters and not by
+ * shown by default. This option should for example be set for
+ * tests that are interactive and prompt the user to do
+ * something.</p>
+ *
+ * @param showOutput if true, send output to Ant's logging system too
+ * @since Ant 1.5
+ */
+ public void setShowOutput(final boolean showOutput) {
+ this.showOutput = showOutput;
+ }
+
+ /**
+ * If true, send any output generated by tests to the formatters.
+ *
+ * @param outputToFormatters if true, send output to formatters (Default
+ * is true).
+ * @since Ant 1.7.0
+ */
+ public void setOutputToFormatters(final boolean outputToFormatters) {
+ this.outputToFormatters = outputToFormatters;
+ }
+
+ /**
+ * If true, write a single "FAILED" line for failed tests to Ant's
+ * log system.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setLogFailedTests(final boolean logFailedTests) {
+ this.logFailedTests = logFailedTests;
+ }
+
+ /**
+ * Assertions to enable in this program (if fork=true)
+ * @since Ant 1.6
+ * @param asserts assertion set
+ */
+ public void addAssertions(final Assertions asserts) {
+ if (getCommandline().getAssertions() != null) {
+ throw new BuildException("Only one assertion declaration is allowed");
+ }
+ getCommandline().setAssertions(asserts);
+ }
+
+ /**
+ * Sets the permissions for the application run inside the same JVM.
+ * @since Ant 1.6
+ * @return .
+ */
+ public Permissions createPermissions() {
+ if (perm == null) {
+ perm = new Permissions();
+ }
+ return perm;
+ }
+
+ /**
+ * If set, system properties will be copied to the cloned VM - as
+ * well as the bootclasspath unless you have explicitly specified
+ * a bootclasspath.
+ *
+ * <p>Doesn't have any effect unless fork is true.</p>
+ * @param cloneVm a <code>boolean</code> value.
+ * @since Ant 1.7
+ */
+ public void setCloneVm(final boolean cloneVm) {
+ getCommandline().setCloneVm(cloneVm);
+ }
+
+ /**
+ * Creates a new JUnitRunner and enables fork of a new Java VM.
+ *
+ * @throws Exception under ??? circumstances
+ * @since Ant 1.2
+ */
+ public JUnitTask() throws Exception {
+ }
+
+ /**
+ * Where Ant should place temporary files.
+ *
+ * @param tmpDir location where temporary files should go to
+ * @since Ant 1.6
+ */
+ public void setTempdir(final File tmpDir) {
+ if (tmpDir != null) {
+ if (!tmpDir.exists() || !tmpDir.isDirectory()) {
+ throw new BuildException(tmpDir.toString()
+ + " is not a valid temp directory");
+ }
+ }
+ this.tmpDir = tmpDir;
+ }
+
+ /**
+ * Whether test listener events shall be generated.
+ *
+ * <p>Defaults to false.</p>
+ *
+ * <p>This value will be overridden by the magic property
+ * ant.junit.enabletestlistenerevents if it has been set.</p>
+ *
+ * @since Ant 1.8.2
+ */
+ public void setEnableTestListenerEvents(final boolean b) {
+ enableTestListenerEvents = b;
+ }
+
+ /**
+ * Whether test listener events shall be generated.
+ * @since Ant 1.8.2
+ */
+ public boolean getEnableTestListenerEvents() {
+ final String e = getProject().getProperty(ENABLE_TESTLISTENER_EVENTS);
+ if (e != null) {
+ return Project.toBoolean(e);
+ }
+ return enableTestListenerEvents;
+ }
+
+ /**
+ * Adds the jars or directories containing Ant, this task and
+ * JUnit to the classpath - this should make the forked JVM work
+ * without having to specify them directly.
+ *
+ * @since Ant 1.4
+ */
+ @Override
+ public void init() {
+ antRuntimeClasses = new Path(getProject());
+ splitJUnit = !addClasspathResource("/junit/framework/TestCase.class");
+ addClasspathEntry("/org/apache/tools/ant/launch/AntMain.class");
+ addClasspathEntry("/org/apache/tools/ant/Task.class");
+ addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class");
+ addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.class");
+ }
+
+ private static JUnitTaskMirror createMirror(final JUnitTask task, final ClassLoader loader) {
+ try {
+ loader.loadClass("junit.framework.Test"); // sanity check
+ } catch (final ClassNotFoundException e) {
+ throw new BuildException(
+ "The <classpath> for <junit> must include junit.jar "
+ + "if not in Ant's own classpath",
+ e, task.getLocation());
+ }
+ try {
+ final Class c = loader.loadClass(JUnitTaskMirror.class.getName() + "Impl");
+ if (c.getClassLoader() != loader) {
+ throw new BuildException("Overdelegating loader", task.getLocation());
+ }
+ final Constructor cons = c.getConstructor(new Class[] {JUnitTask.class});
+ return (JUnitTaskMirror) cons.newInstance(new Object[] {task});
+ } catch (final Exception e) {
+ throw new BuildException(e, task.getLocation());
+ }
+ }
+
+ /**
+ * Sets up the delegate that will actually run the tests.
+ *
+ * <p>Will be invoked implicitly once the delegate is needed.</p>
+ *
+ * @since Ant 1.7.1
+ */
+ protected void setupJUnitDelegate() {
+ final ClassLoader myLoader = JUnitTask.class.getClassLoader();
+ if (splitJUnit) {
+ final Path path = new Path(getProject());
+ path.add(antRuntimeClasses);
+ final Path extra = getCommandline().getClasspath();
+ if (extra != null) {
+ path.add(extra);
+ }
+ mirrorLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return new SplitClassLoader(myLoader, path, getProject(),
+ new String[] {
+ "BriefJUnitResultFormatter",
+ "JUnit4TestMethodAdapter",
+ "JUnitResultFormatter",
+ "JUnitTaskMirrorImpl",
+ "JUnitTestRunner",
+ "JUnitVersionHelper",
+ "OutErrSummaryJUnitResultFormatter",
+ "PlainJUnitResultFormatter",
+ "SummaryJUnitResultFormatter",
+ "TearDownOnVmCrash",
+ "XMLJUnitResultFormatter",
+ "IgnoredTestListener",
+ "IgnoredTestResult",
+ "CustomJUnit4TestAdapterCache",
+ "TestListenerWrapper"
+ });
+ }
+ });
+ } else {
+ mirrorLoader = myLoader;
+ }
+ delegate = createMirror(this, mirrorLoader);
+ }
+
+ /**
+ * Runs the testcase.
+ *
+ * @throws BuildException in case of test failures or errors
+ * @since Ant 1.2
+ */
+ @Override
+ public void execute() throws BuildException {
+ checkMethodLists();
+
+ setupJUnitDelegate();
+
+ final List<List> testLists = new ArrayList<List>();
+ /* parallel test execution is only supported for multi-process execution */
+ final int threads = ((!fork) || (forkMode.getValue().equals(ForkMode.ONCE))
+ ? 1
+ : this.threads);
+
+ final boolean forkPerTest = forkMode.getValue().equals(ForkMode.PER_TEST);
+ if (forkPerTest || forkMode.getValue().equals(ForkMode.ONCE)) {
+ testLists.addAll(executeOrQueue(getIndividualTests(),
+ forkPerTest));
+ } else { /* forkMode.getValue().equals(ForkMode.PER_BATCH) */
+ final int count = batchTests.size();
+ for (int i = 0; i < count; i++) {
+ final BatchTest batchtest = batchTests.elementAt(i);
+ testLists.addAll(executeOrQueue(batchtest.elements(), false));
+ }
+ testLists.addAll(executeOrQueue(tests.elements(), forkPerTest));
+ }
+
+ try {
+ /* prior to parallel the code in 'oneJunitThread' used to be here. */
+ runTestsInThreads(testLists, threads);
+ } finally {
+ cleanup();
+ }
+ }
+
+ /*
+ * When the list of tests is established, an array of threads is created to pick the
+ * tests off the list one at a time and execute them until the list is empty. Tests are
+ * not assigned to threads until the thread is available.
+ *
+ * This class is the runnable thread subroutine that takes care of passing the shared
+ * list iterator and the handle back to the main class to the test execution subroutine
+ * code 'runTestsInThreads'. One object is created for each thread and each one gets
+ * a unique thread id that can be useful for tracing test starts and stops.
+ *
+ * Because the threads are picking tests off the same list, it is the list *iterator*
+ * that must be shared, not the list itself - and the iterator must have a thread-safe
+ * ability to pop the list - hence the synchronized 'getNextTest'.
+ */
+ private class JunitTestThread implements Runnable {
+
+ JunitTestThread(final JUnitTask master, final Iterator<List> iterator, final int id) {
+ this.masterTask = master;
+ this.iterator = iterator;
+ this.id = id;
+ }
+
+ public void run() {
+ try {
+ masterTask.oneJunitThread(iterator, id);
+ } catch (final BuildException b) {
+ /* saved to rethrow in main thread to be like single-threaded case */
+ caughtBuildException = b;
+ }
+ }
+
+ private final JUnitTask masterTask;
+ private final Iterator<List> iterator;
+ private final int id;
+ }
+
+ /*
+ * Because the threads are picking tests off the same list, it is the list *iterator*
+ * that must be shared, not the list itself - and the iterator must have a thread-safe
+ * ability to pop the list - hence the synchronized 'getNextTest'. We can't have two
+ * threads get the same test, or two threads simultaneously pop the list so that a test
+ * gets skipped!
+ */
+ private List getNextTest(final Iterator<List> iter) {
+ synchronized(iter) {
+ if (iter.hasNext()) {
+ return iter.next();
+ }
+ return null;
+ }
+ }
+
+ /*
+ * This code loops keeps executing the next test or test bunch (depending on fork mode)
+ * on the list of test cases until none are left. Basically this body of code used to
+ * be in the execute routine above; now, several copies (one for each test thread) execute
+ * simultaneously. The while loop was modified to call the new thread-safe atomic list
+ * popping subroutine and the logging messages were added.
+ *
+ * If one thread aborts due to a BuildException (haltOnError, haltOnFailure, or any other
+ * fatal reason, no new tests/batches will be started but the running threads will be
+ * permitted to complete. Additional tests may start in already-running batch-test threads.
+ */
+ private void oneJunitThread(final Iterator<List> iter, final int threadId) {
+
+ List l;
+ log("Starting test thread " + threadId, Project.MSG_VERBOSE);
+ while ((caughtBuildException == null) && ((l = getNextTest(iter)) != null)) {
+ log("Running test " + l.get(0).toString() + "(" + l.size() + ") in thread " + threadId, Project.MSG_VERBOSE);
+ if (l.size() == 1) {
+ execute((JUnitTest) l.get(0), threadId);
+ } else {
+ execute(l, threadId);
+ }
+ }
+ log("Ending test thread " + threadId, Project.MSG_VERBOSE);
+ }
+
+
+ private void runTestsInThreads(final List<List> testList, final int numThreads) {
+
+ Iterator<List> iter = testList.iterator();
+
+ if (numThreads == 1) {
+ /* with just one thread just run the test - don't create any threads */
+ oneJunitThread(iter, 0);
+ } else {
+ final Thread[] threads = new Thread[numThreads];
+ int i;
+ boolean exceptionOccurred;
+
+ /* Need to split apart tests, which are still grouped in batches */
+ /* is there a simpler Java mechanism to do this? */
+ /* I assume we don't want to do this with "per batch" forking. */
+ List<List> newlist = new ArrayList<List>();
+ if (forkMode.getValue().equals(ForkMode.PER_TEST)) {
+ final Iterator<List> i1 = testList.iterator();
+ while (i1.hasNext()) {
+ final List l = i1.next();
+ if (l.size() == 1) {
+ newlist.add(l);
+ } else {
+ final Iterator i2 = l.iterator();
+ while (i2.hasNext()) {
+ final List tmpSingleton = new ArrayList();
+ tmpSingleton.add(i2.next());
+ newlist.add(tmpSingleton);
+ }
+ }
+ }
+ } else {
+ newlist = testList;
+ }
+ iter = newlist.iterator();
+
+ /* create 1 thread using the passthrough class, and let each thread start */
+ for (i = 0; i < numThreads; i++) {
+ threads[i] = new Thread(new JunitTestThread(this, iter, i+1));
+ threads[i].start();
+ }
+
+ /* wait for all of the threads to complete. Not sure if the exception can actually occur in this use case. */
+ do {
+ exceptionOccurred = false;
+
+ try {
+ for (i = 0; i < numThreads; i++) {
+ threads[i].join();
+ }
+ } catch (final InterruptedException e) {
+ exceptionOccurred = true;
+ }
+ } while (exceptionOccurred);
+
+ /* an exception occurred in one of the threads - usually a haltOnError/Failure.
+ throw the exception again so it behaves like the single-thread case */
+ if (caughtBuildException != null) {
+ throw new BuildException(caughtBuildException);
+ }
+
+ /* all threads are completed - that's all there is to do. */
+ /* control will flow back to the test cleanup call and then execute is done. */
+ }
+ }
+
+ /**
+ * Run the tests.
+ * @param arg one JUnitTest
+ * @param thread Identifies which thread is test running in (0 for single-threaded runs)
+ * @throws BuildException in case of test failures or errors
+ */
+ protected void execute(final JUnitTest arg, final int thread) throws BuildException {
+ validateTestName(arg.getName());
+
+ final JUnitTest test = (JUnitTest) arg.clone();
+ test.setThread(thread);
+
+ // set the default values if not specified
+ //@todo should be moved to the test class instead.
+ if (test.getTodir() == null) {
+ test.setTodir(getProject().resolveFile("."));
+ }
+
+ if (test.getOutfile() == null) {
+ test.setOutfile("TEST-" + test.getName());
+ }
+
+ // execute the test and get the return code
+ TestResultHolder result = null;
+ if (!test.getFork()) {
+ result = executeInVM(test);
+ } else {
+ final ExecuteWatchdog watchdog = createWatchdog();
+ result = executeAsForked(test, watchdog, null);
+ // null watchdog means no timeout, you'd better not check with null
+ }
+ actOnTestResult(result, test, "Test " + test.getName());
+ }
+
+ /**
+ * Run the tests.
+ * @param arg one JUnitTest
+ * @throws BuildException in case of test failures or errors
+ */
+ protected void execute(final JUnitTest arg) throws BuildException {
+ execute(arg, 0);
+ }
+
+ /**
+ * Throws a <code>BuildException</code> if the given test name is invalid.
+ * Validity is defined as not <code>null</code>, not empty, and not the
+ * string &quot;null&quot;.
+ * @param testName the test name to be validated
+ * @throws BuildException if <code>testName</code> is not a valid test name
+ */
+ private void validateTestName(final String testName) throws BuildException {
+ if (testName == null || testName.length() == 0
+ || testName.equals("null")) {
+ throw new BuildException("test name must be specified");
+ }
+ }
+
+ /**
+ * Execute a list of tests in a single forked Java VM.
+ * @param testList the list of tests to execute.
+ * @param thread Identifies which thread is test running in (0 for single-threaded runs)
+ * @throws BuildException on error.
+ */
+ protected void execute(final List testList, final int thread) throws BuildException {
+ JUnitTest test = null;
+ // Create a temporary file to pass the test cases to run to
+ // the runner (one test case per line)
+ final File casesFile = createTempPropertiesFile("junittestcases");
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(casesFile));
+
+ log("Creating casesfile '" + casesFile.getAbsolutePath()
+ + "' with content: ", Project.MSG_VERBOSE);
+ final PrintStream logWriter =
+ new PrintStream(new LogOutputStream(this, Project.MSG_VERBOSE));
+
+ final Iterator iter = testList.iterator();
+ while (iter.hasNext()) {
+ test = (JUnitTest) iter.next();
+ test.setThread(thread);
+ printDual(writer, logWriter, test.getName());
+ if (test.getMethods() != null) {
+ printDual(writer, logWriter, ":" + test.getMethodsString().replace(',', '+'));
+ }
+ if (test.getTodir() == null) {
+ printDual(writer, logWriter,
+ "," + getProject().resolveFile("."));
+ } else {
+ printDual(writer, logWriter, "," + test.getTodir());
+ }
+
+ if (test.getOutfile() == null) {
+ printlnDual(writer, logWriter,
+ "," + "TEST-" + test.getName());
+ } else {
+ printlnDual(writer, logWriter, "," + test.getOutfile());
+ }
+ }
+ writer.flush();
+ writer.close();
+ writer = null;
+
+ // execute the test and get the return code
+ final ExecuteWatchdog watchdog = createWatchdog();
+ final TestResultHolder result =
+ executeAsForked(test, watchdog, casesFile);
+ actOnTestResult(result, test, "Tests");
+ } catch (final IOException e) {
+ log(e.toString(), Project.MSG_ERR);
+ throw new BuildException(e);
+ } finally {
+ FileUtils.close(writer);
+
+ try {
+ FILE_UTILS.tryHardToDelete(casesFile);
+ } catch (final Exception e) {
+ log(e.toString(), Project.MSG_ERR);
+ }
+ }
+ }
+
+ /**
+ * Execute a list of tests in a single forked Java VM.
+ * @param testList the list of tests to execute.
+ * @throws BuildException on error.
+ */
+ protected void execute(final List testList) throws BuildException {
+ execute(testList, 0);
+ }
+
+ /**
+ * Execute a testcase by forking a new JVM. The command will block
+ * until it finishes. To know if the process was destroyed or not
+ * or whether the forked Java VM exited abnormally, use the
+ * attributes of the returned holder object.
+ * @param test the testcase to execute.
+ * @param watchdog the watchdog in charge of cancelling the test if it
+ * exceeds a certain amount of time. Can be <tt>null</tt>, in this case
+ * the test could probably hang forever.
+ * @param casesFile list of test cases to execute. Can be <tt>null</tt>,
+ * in this case only one test is executed.
+ * @return the test results from the JVM itself.
+ * @throws BuildException in case of error creating a temporary property file,
+ * or if the junit process can not be forked
+ */
+ private TestResultHolder executeAsForked(JUnitTest test,
+ final ExecuteWatchdog watchdog,
+ final File casesFile)
+ throws BuildException {
+
+ if (perm != null) {
+ log("Permissions ignored when running in forked mode!",
+ Project.MSG_WARN);
+ }
+
+ CommandlineJava cmd;
+ try {
+ cmd = (CommandlineJava) (getCommandline().clone());
+ } catch (final CloneNotSupportedException e) {
+ throw new BuildException("This shouldn't happen", e, getLocation());
+ }
+ if (casesFile == null) {
+ cmd.createArgument().setValue(test.getName());
+ if (test.getMethods() != null) {
+ cmd.createArgument().setValue(Constants.METHOD_NAMES + test.getMethodsString());
+ }
+ } else {
+ log("Running multiple tests in the same VM", Project.MSG_VERBOSE);
+ cmd.createArgument().setValue(Constants.TESTSFILE + casesFile);
+ }
+
+ cmd.createArgument().setValue(Constants.SKIP_NON_TESTS + String.valueOf(test.isSkipNonTests()));
+ cmd.createArgument().setValue(Constants.FILTERTRACE + test.getFiltertrace());
+ cmd.createArgument().setValue(Constants.HALT_ON_ERROR + test.getHaltonerror());
+ cmd.createArgument().setValue(Constants.HALT_ON_FAILURE
+ + test.getHaltonfailure());
+ checkIncludeAntRuntime(cmd);
+
+ checkIncludeSummary(cmd);
+
+ cmd.createArgument().setValue(Constants.SHOWOUTPUT
+ + String.valueOf(showOutput));
+ cmd.createArgument().setValue(Constants.OUTPUT_TO_FORMATTERS
+ + String.valueOf(outputToFormatters));
+ cmd.createArgument().setValue(Constants.LOG_FAILED_TESTS
+ + String.valueOf(logFailedTests));
+ cmd.createArgument().setValue(Constants.THREADID
+ + String.valueOf(test.getThread()));
+
+ // #31885
+ cmd.createArgument().setValue(Constants.LOGTESTLISTENEREVENTS
+ + String.valueOf(getEnableTestListenerEvents()));
+
+ StringBuffer formatterArg = new StringBuffer(STRING_BUFFER_SIZE);
+ final FormatterElement[] feArray = mergeFormatters(test);
+ for (int i = 0; i < feArray.length; i++) {
+ final FormatterElement fe = feArray[i];
+ if (fe.shouldUse(this)) {
+ formatterArg.append(Constants.FORMATTER);
+ formatterArg.append(fe.getClassname());
+ final File outFile = getOutput(fe, test);
+ if (outFile != null) {
+ formatterArg.append(",");
+ formatterArg.append(outFile);
+ }
+ cmd.createArgument().setValue(formatterArg.toString());
+ formatterArg = new StringBuffer();
+ }
+ }
+
+ final File vmWatcher = createTempPropertiesFile("junitvmwatcher");
+ cmd.createArgument().setValue(Constants.CRASHFILE
+ + vmWatcher.getAbsolutePath());
+ final File propsFile = createTempPropertiesFile("junit");
+ cmd.createArgument().setValue(Constants.PROPSFILE
+ + propsFile.getAbsolutePath());
+ final Hashtable p = getProject().getProperties();
+ final Properties props = new Properties();
+ for (final Enumeration e = p.keys(); e.hasMoreElements();) {
+ final Object key = e.nextElement();
+ props.put(key, p.get(key));
+ }
+ try {
+ final FileOutputStream outstream = new FileOutputStream(propsFile);
+ props.store(outstream, "Ant JUnitTask generated properties file");
+ outstream.close();
+ } catch (final java.io.IOException e) {
+ FILE_UTILS.tryHardToDelete(propsFile);
+ throw new BuildException("Error creating temporary properties "
+ + "file.", e, getLocation());
+ }
+
+ final Execute execute = new Execute(
+ new JUnitLogStreamHandler(
+ this,
+ Project.MSG_INFO,
+ Project.MSG_WARN),
+ watchdog);
+ execute.setCommandline(cmd.getCommandline());
+ execute.setAntRun(getProject());
+ if (dir != null) {
+ execute.setWorkingDirectory(dir);
+ }
+
+ final String[] environment = env.getVariables();
+ if (environment != null) {
+ for (int i = 0; i < environment.length; i++) {
+ log("Setting environment variable: " + environment[i],
+ Project.MSG_VERBOSE);
+ }
+ }
+ execute.setNewenvironment(newEnvironment);
+ execute.setEnvironment(environment);
+
+ log(cmd.describeCommand(), Project.MSG_VERBOSE);
+
+ checkForkedPath(cmd);
+
+ final TestResultHolder result = new TestResultHolder();
+ try {
+ result.exitCode = execute.execute();
+ } catch (final IOException e) {
+ throw new BuildException("Process fork failed.", e, getLocation());
+ } finally {
+ String vmCrashString = "unknown";
+ BufferedReader br = null;
+ try {
+ if (vmWatcher.exists()) {
+ br = new BufferedReader(new FileReader(vmWatcher));
+ vmCrashString = br.readLine();
+ } else {
+ vmCrashString = "Monitor file ("
+ + vmWatcher.getAbsolutePath()
+ + ") missing, location not writable,"
+ + " testcase not started or mixing ant versions?";
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ // ignored.
+ } finally {
+ FileUtils.close(br);
+ if (vmWatcher.exists()) {
+ FILE_UTILS.tryHardToDelete(vmWatcher);
+ }
+ }
+
+ final boolean crash = (watchdog != null && watchdog.killedProcess())
+ || !Constants.TERMINATED_SUCCESSFULLY.equals(vmCrashString);
+
+ if (casesFile != null && crash) {
+ test = createDummyTestForBatchTest(test);
+ }
+
+ if (watchdog != null && watchdog.killedProcess()) {
+ result.timedOut = true;
+ logTimeout(feArray, test, vmCrashString);
+ } else if (crash) {
+ result.crashed = true;
+ logVmCrash(feArray, test, vmCrashString);
+ }
+
+ if (!FILE_UTILS.tryHardToDelete(propsFile)) {
+ throw new BuildException("Could not delete temporary "
+ + "properties file '"
+ + propsFile.getAbsolutePath() + "'.");
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Adding ant runtime.
+ * @param cmd command to run
+ */
+ private void checkIncludeAntRuntime(final CommandlineJava cmd) {
+ if (includeAntRuntime) {
+ final Map/*<String, String>*/ env = Execute.getEnvironmentVariables();
+ final String cp = (String) env.get(CLASSPATH);
+ if (cp != null) {
+ cmd.createClasspath(getProject()).createPath()
+ .append(new Path(getProject(), cp));
+ }
+ log("Implicitly adding " + antRuntimeClasses + " to CLASSPATH",
+ Project.MSG_VERBOSE);
+ cmd.createClasspath(getProject()).createPath()
+ .append(antRuntimeClasses);
+ }
+ }
+
+
+ /**
+ * check for the parameter being "withoutanderr" in a locale-independent way.
+ * @param summaryOption the summary option -can be null
+ * @return true if the run should be withoutput and error
+ */
+ private boolean equalsWithOutAndErr(final String summaryOption) {
+ return "withoutanderr".equalsIgnoreCase(summaryOption);
+ }
+
+ private void checkIncludeSummary(final CommandlineJava cmd) {
+ if (summary) {
+ String prefix = "";
+ if (equalsWithOutAndErr(summaryValue)) {
+ prefix = "OutErr";
+ }
+ cmd.createArgument()
+ .setValue(Constants.FORMATTER
+ + "org.apache.tools.ant.taskdefs.optional.junit."
+ + prefix + "SummaryJUnitResultFormatter");
+ }
+ }
+
+ /**
+ * Check the path for multiple different versions of
+ * ant.
+ * @param cmd command to execute
+ */
+ private void checkForkedPath(final CommandlineJava cmd) {
+ if (forkedPathChecked) {
+ return;
+ }
+ forkedPathChecked = true;
+ if (!cmd.haveClasspath()) {
+ return;
+ }
+ AntClassLoader loader = null;
+ try {
+ loader =
+ AntClassLoader.newAntClassLoader(null, getProject(),
+ cmd.createClasspath(getProject()),
+ true);
+ final String projectResourceName =
+ LoaderUtils.classNameToResource(Project.class.getName());
+ URL previous = null;
+ try {
+ for (final Enumeration e = loader.getResources(projectResourceName);
+ e.hasMoreElements();) {
+ final URL current = (URL) e.nextElement();
+ if (previous != null && !urlEquals(current, previous)) {
+ log("WARNING: multiple versions of ant detected "
+ + "in path for junit "
+ + LINE_SEP + " " + previous
+ + LINE_SEP + " and " + current,
+ Project.MSG_WARN);
+ return;
+ }
+ previous = current;
+ }
+ } catch (final Exception ex) {
+ // Ignore exception
+ }
+ } finally {
+ if (loader != null) {
+ loader.cleanup();
+ }
+ }
+ }
+
+ /**
+ * Compares URLs for equality but takes case-sensitivity into
+ * account when comparing file URLs and ignores the jar specific
+ * part of the URL if present.
+ */
+ private static boolean urlEquals(final URL u1, final URL u2) {
+ final String url1 = maybeStripJarAndClass(u1);
+ final String url2 = maybeStripJarAndClass(u2);
+ if (url1.startsWith("file:") && url2.startsWith("file:")) {
+ return new File(FILE_UTILS.fromURI(url1))
+ .equals(new File(FILE_UTILS.fromURI(url2)));
+ }
+ return url1.equals(url2);
+ }
+
+ private static String maybeStripJarAndClass(final URL u) {
+ String s = u.toString();
+ if (s.startsWith("jar:")) {
+ final int pling = s.indexOf('!');
+ s = s.substring(4, pling == -1 ? s.length() : pling);
+ }
+ return s;
+ }
+
+ /**
+ * Create a temporary file to pass the properties to a new process.
+ * Will auto-delete on (graceful) exit.
+ * The file will be in the project basedir unless tmpDir declares
+ * something else.
+ * @param prefix
+ * @return created file
+ */
+ private File createTempPropertiesFile(final String prefix) {
+ final File propsFile =
+ FILE_UTILS.createTempFile(prefix, ".properties",
+ tmpDir != null ? tmpDir : getProject().getBaseDir(), true, true);
+ return propsFile;
+ }
+
+
+ /**
+ * Pass output sent to System.out to the TestRunner so it can
+ * collect it for the formatters.
+ *
+ * @param output output coming from System.out
+ * @since Ant 1.5
+ */
+ @Override
+ protected void handleOutput(final String output) {
+ if (output.startsWith(TESTLISTENER_PREFIX)) {
+ log(output, Project.MSG_VERBOSE);
+ } else if (runner != null) {
+ if (outputToFormatters) {
+ runner.handleOutput(output);
+ }
+ if (showOutput) {
+ super.handleOutput(output);
+ }
+ } else {
+ super.handleOutput(output);
+ }
+ }
+
+ /**
+ * Handle an input request by this task.
+ * @see Task#handleInput(byte[], int, int)
+ * This implementation delegates to a runner if it
+ * present.
+ * @param buffer the buffer into which data is to be read.
+ * @param offset the offset into the buffer at which data is stored.
+ * @param length the amount of data to read.
+ *
+ * @return the number of bytes read.
+ * @exception IOException if the data cannot be read.
+ *
+ * @since Ant 1.6
+ */
+ @Override
+ protected int handleInput(final byte[] buffer, final int offset, final int length)
+ throws IOException {
+ if (runner != null) {
+ return runner.handleInput(buffer, offset, length);
+ } else {
+ return super.handleInput(buffer, offset, length);
+ }
+ }
+
+
+ /**
+ * Pass output sent to System.out to the TestRunner so it can
+ * collect ot for the formatters.
+ *
+ * @param output output coming from System.out
+ * @since Ant 1.5.2
+ */
+ @Override
+ protected void handleFlush(final String output) {
+ if (runner != null) {
+ runner.handleFlush(output);
+ if (showOutput) {
+ super.handleFlush(output);
+ }
+ } else {
+ super.handleFlush(output);
+ }
+ }
+
+ /**
+ * Pass output sent to System.err to the TestRunner so it can
+ * collect it for the formatters.
+ *
+ * @param output output coming from System.err
+ * @since Ant 1.5
+ */
+ @Override
+ public void handleErrorOutput(final String output) {
+ if (runner != null) {
+ runner.handleErrorOutput(output);
+ if (showOutput) {
+ super.handleErrorOutput(output);
+ }
+ } else {
+ super.handleErrorOutput(output);
+ }
+ }
+
+
+ /**
+ * Pass output sent to System.err to the TestRunner so it can
+ * collect it for the formatters.
+ *
+ * @param output coming from System.err
+ * @since Ant 1.5.2
+ */
+ @Override
+ public void handleErrorFlush(final String output) {
+ if (runner != null) {
+ runner.handleErrorFlush(output);
+ if (showOutput) {
+ super.handleErrorFlush(output);
+ }
+ } else {
+ super.handleErrorFlush(output);
+ }
+ }
+
+ // in VM is not very nice since it could probably hang the
+ // whole build. IMHO this method should be avoided and it would be best
+ // to remove it in future versions. TBD. (SBa)
+
+ /**
+ * Execute inside VM.
+ * @param arg one JUnitTest
+ * @throws BuildException under unspecified circumstances
+ * @return the results
+ */
+ private TestResultHolder executeInVM(final JUnitTest arg) throws BuildException {
+ if (delegate == null) {
+ setupJUnitDelegate();
+ }
+
+ final JUnitTest test = (JUnitTest) arg.clone();
+ test.setProperties(getProject().getProperties());
+ if (dir != null) {
+ log("dir attribute ignored if running in the same VM",
+ Project.MSG_WARN);
+ }
+
+ if (newEnvironment || null != env.getVariables()) {
+ log("Changes to environment variables are ignored if running in "
+ + "the same VM.", Project.MSG_WARN);
+ }
+
+ if (getCommandline().getBootclasspath() != null) {
+ log("bootclasspath is ignored if running in the same VM.",
+ Project.MSG_WARN);
+ }
+
+ final CommandlineJava.SysProperties sysProperties =
+ getCommandline().getSystemProperties();
+ if (sysProperties != null) {
+ sysProperties.setSystem();
+ }
+
+ try {
+ log("Using System properties " + System.getProperties(),
+ Project.MSG_VERBOSE);
+ if (splitJUnit) {
+ classLoader = (AntClassLoader) delegate.getClass().getClassLoader();
+ } else {
+ createClassLoader();
+ }
+ if (classLoader != null) {
+ classLoader.setThreadContextLoader();
+ }
+ runner = delegate.newJUnitTestRunner(test, test.getMethods(), test.getHaltonerror(),
+ test.getFiltertrace(),
+ test.getHaltonfailure(), false,
+ getEnableTestListenerEvents(),
+ classLoader);
+ if (summary) {
+
+ final JUnitTaskMirror.SummaryJUnitResultFormatterMirror f =
+ delegate.newSummaryJUnitResultFormatter();
+ f.setWithOutAndErr(equalsWithOutAndErr(summaryValue));
+ f.setOutput(getDefaultOutput());
+ runner.addFormatter(f);
+ }
+
+ runner.setPermissions(perm);
+
+ final FormatterElement[] feArray = mergeFormatters(test);
+ for (int i = 0; i < feArray.length; i++) {
+ final FormatterElement fe = feArray[i];
+ if (fe.shouldUse(this)) {
+ final File outFile = getOutput(fe, test);
+ if (outFile != null) {
+ fe.setOutfile(outFile);
+ } else {
+ fe.setOutput(getDefaultOutput());
+ }
+ runner.addFormatter(fe.createFormatter(classLoader));
+ }
+ }
+
+ runner.run();
+ final TestResultHolder result = new TestResultHolder();
+ result.exitCode = runner.getRetCode();
+ return result;
+ } finally {
+ if (sysProperties != null) {
+ sysProperties.restoreSystem();
+ }
+ if (classLoader != null) {
+ classLoader.resetThreadContextLoader();
+ }
+ }
+ }
+
+ /**
+ * @return <tt>null</tt> if there is a timeout value, otherwise the
+ * watchdog instance.
+ *
+ * @throws BuildException under unspecified circumstances
+ * @since Ant 1.2
+ */
+ protected ExecuteWatchdog createWatchdog() throws BuildException {
+ if (timeout == null) {
+ return null;
+ }
+ return new ExecuteWatchdog((long) timeout.intValue());
+ }
+
+ /**
+ * Get the default output for a formatter.
+ *
+ * @return default output stream for a formatter
+ * @since Ant 1.3
+ */
+ protected OutputStream getDefaultOutput() {
+ return new LogOutputStream(this, Project.MSG_INFO);
+ }
+
+ /**
+ * Merge all individual tests from the batchtest with all individual tests
+ * and return an enumeration over all <tt>JUnitTest</tt>.
+ *
+ * @return enumeration over individual tests
+ * @since Ant 1.3
+ */
+ protected Enumeration<JUnitTest> getIndividualTests() {
+ final int count = batchTests.size();
+ final Enumeration[] enums = new Enumeration[ count + 1];
+ for (int i = 0; i < count; i++) {
+ final BatchTest batchtest = batchTests.elementAt(i);
+ enums[i] = batchtest.elements();
+ }
+ enums[enums.length - 1] = tests.elements();
+ return Enumerations.fromCompound(enums);
+ }
+
+ /**
+ * Verifies all <code>test</code> elements having the <code>methods</code>
+ * attribute specified and having the <code>if</code>-condition resolved
+ * to true, that the value of the <code>methods</code> attribute is valid.
+ * @exception BuildException if some of the tests matching the described
+ * conditions has invalid value of the
+ * <code>methods</code> attribute
+ * @since 1.8.2
+ */
+ private void checkMethodLists() throws BuildException {
+ if (tests.isEmpty()) {
+ return;
+ }
+
+ final Enumeration<JUnitTest> testsEnum = tests.elements();
+ while (testsEnum.hasMoreElements()) {
+ final JUnitTest test = testsEnum.nextElement();
+ if (test.hasMethodsSpecified() && test.shouldRun(getProject())) {
+ test.resolveMethods();
+ }
+ }
+ }
+
+ /**
+ * return an enumeration listing each test, then each batchtest
+ * @return enumeration
+ * @since Ant 1.3
+ */
+ protected Enumeration<JUnitTest> allTests() {
+ final Enumeration[] enums = {tests.elements(), batchTests.elements()};
+ return Enumerations.fromCompound(enums);
+ }
+
+ /**
+ * @param test junit test
+ * @return array of FormatterElement
+ * @since Ant 1.3
+ */
+ private FormatterElement[] mergeFormatters(final JUnitTest test) {
+ final Vector<FormatterElement> feVector = (Vector<FormatterElement>) formatters.clone();
+ test.addFormattersTo(feVector);
+ final FormatterElement[] feArray = new FormatterElement[feVector.size()];
+ feVector.copyInto(feArray);
+ return feArray;
+ }
+
+ /**
+ * If the formatter sends output to a file, return that file.
+ * null otherwise.
+ * @param fe formatter element
+ * @param test one JUnit test
+ * @return file reference
+ * @since Ant 1.3
+ */
+ protected File getOutput(final FormatterElement fe, final JUnitTest test) {
+ if (fe.getUseFile()) {
+ String base = test.getOutfile();
+ if (base == null) {
+ base = JUnitTaskMirror.JUnitTestRunnerMirror.IGNORED_FILE_NAME;
+ }
+ final String filename = base + fe.getExtension();
+ final File destFile = new File(test.getTodir(), filename);
+ final String absFilename = destFile.getAbsolutePath();
+ return getProject().resolveFile(absFilename);
+ }
+ return null;
+ }
+
+ /**
+ * Search for the given resource and add the directory or archive
+ * that contains it to the classpath.
+ *
+ * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+ * getResource doesn't contain the name of the archive.</p>
+ *
+ * @param resource resource that one wants to lookup
+ * @since Ant 1.4
+ */
+ protected void addClasspathEntry(final String resource) {
+ addClasspathResource(resource);
+ }
+
+ /**
+ * Implementation of addClasspathEntry.
+ *
+ * @param resource resource that one wants to lookup
+ * @return true if something was in fact added
+ * @since Ant 1.7.1
+ */
+ private boolean addClasspathResource(String resource) {
+ /*
+ * pre Ant 1.6 this method used to call getClass().getResource
+ * while Ant 1.6 will call ClassLoader.getResource().
+ *
+ * The difference is that Class.getResource expects a leading
+ * slash for "absolute" resources and will strip it before
+ * delegating to ClassLoader.getResource - so we now have to
+ * emulate Class's behavior.
+ */
+ if (resource.startsWith("/")) {
+ resource = resource.substring(1);
+ } else {
+ resource = "org/apache/tools/ant/taskdefs/optional/junit/"
+ + resource;
+ }
+
+ final File f = LoaderUtils.getResourceSource(JUnitTask.class.getClassLoader(),
+ resource);
+ if (f != null) {
+ log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
+ antRuntimeClasses.createPath().setLocation(f);
+ return true;
+ } else {
+ log("Couldn\'t find " + resource, Project.MSG_DEBUG);
+ return false;
+ }
+ }
+
+ static final String TIMEOUT_MESSAGE =
+ "Timeout occurred. Please note the time in the report does"
+ + " not reflect the time until the timeout.";
+
+ /**
+ * Take care that some output is produced in report files if the
+ * watchdog kills the test.
+ *
+ * @since Ant 1.5.2
+ */
+ private void logTimeout(final FormatterElement[] feArray, final JUnitTest test,
+ final String testCase) {
+ logVmExit(feArray, test, TIMEOUT_MESSAGE, testCase);
+ }
+
+ /**
+ * Take care that some output is produced in report files if the
+ * forked machine exited before the test suite finished but the
+ * reason is not a timeout.
+ *
+ * @since Ant 1.7
+ */
+ private void logVmCrash(final FormatterElement[] feArray, final JUnitTest test, final String testCase) {
+ logVmExit(
+ feArray, test,
+ "Forked Java VM exited abnormally. Please note the time in the report"
+ + " does not reflect the time until the VM exit.",
+ testCase);
+ }
+
+ /**
+ * Take care that some output is produced in report files if the
+ * forked machine terminated before the test suite finished
+ *
+ * @since Ant 1.7
+ */
+ private void logVmExit(final FormatterElement[] feArray, final JUnitTest test,
+ final String message, final String testCase) {
+ if (delegate == null) {
+ setupJUnitDelegate();
+ }
+
+ try {
+ log("Using System properties " + System.getProperties(),
+ Project.MSG_VERBOSE);
+ if (splitJUnit) {
+ classLoader = (AntClassLoader) delegate.getClass().getClassLoader();
+ } else {
+ createClassLoader();
+ }
+ if (classLoader != null) {
+ classLoader.setThreadContextLoader();
+ }
+
+ test.setCounts(1, 0, 1, 0);
+ test.setProperties(getProject().getProperties());
+ for (int i = 0; i < feArray.length; i++) {
+ final FormatterElement fe = feArray[i];
+ if (fe.shouldUse(this)) {
+ final JUnitTaskMirror.JUnitResultFormatterMirror formatter =
+ fe.createFormatter(classLoader);
+ if (formatter != null) {
+ OutputStream out = null;
+ final File outFile = getOutput(fe, test);
+ if (outFile != null) {
+ try {
+ out = new FileOutputStream(outFile);
+ } catch (final IOException e) {
+ // ignore
+ }
+ }
+ if (out == null) {
+ out = getDefaultOutput();
+ }
+ delegate.addVmExit(test, formatter, out, message,
+ testCase);
+ }
+ }
+ }
+ if (summary) {
+ final JUnitTaskMirror.SummaryJUnitResultFormatterMirror f =
+ delegate.newSummaryJUnitResultFormatter();
+ f.setWithOutAndErr(equalsWithOutAndErr(summaryValue));
+ delegate.addVmExit(test, f, getDefaultOutput(), message, testCase);
+ }
+ } finally {
+ if (classLoader != null) {
+ classLoader.resetThreadContextLoader();
+ }
+ }
+ }
+
+ /**
+ * Creates and configures an AntClassLoader instance from the
+ * nested classpath element.
+ *
+ * @since Ant 1.6
+ */
+ private void createClassLoader() {
+ final Path userClasspath = getCommandline().getClasspath();
+ if (userClasspath != null) {
+ if (reloading || classLoader == null) {
+ deleteClassLoader();
+ final Path classpath = (Path) userClasspath.clone();
+ if (includeAntRuntime) {
+ log("Implicitly adding " + antRuntimeClasses
+ + " to CLASSPATH", Project.MSG_VERBOSE);
+ classpath.append(antRuntimeClasses);
+ }
+ classLoader = getProject().createClassLoader(classpath);
+ if (getClass().getClassLoader() != null
+ && getClass().getClassLoader() != Project.class.getClassLoader()) {
+ classLoader.setParent(getClass().getClassLoader());
+ }
+ classLoader.setParentFirst(false);
+ classLoader.addJavaLibraries();
+ log("Using CLASSPATH " + classLoader.getClasspath(),
+ Project.MSG_VERBOSE);
+ // make sure the test will be accepted as a TestCase
+ classLoader.addSystemPackageRoot("junit");
+ // make sure the test annotation are accepted
+ classLoader.addSystemPackageRoot("org.junit");
+ // will cause trouble in JDK 1.1 if omitted
+ classLoader.addSystemPackageRoot("org.apache.tools.ant");
+ }
+ }
+ }
+
+ /**
+ * Removes resources.
+ *
+ * <p>Is invoked in {@link #execute execute}. Subclasses that
+ * don't invoke execute should invoke this method in a finally
+ * block.</p>
+ *
+ * @since Ant 1.7.1
+ */
+ protected void cleanup() {
+ deleteClassLoader();
+ delegate = null;
+ }
+
+ /**
+ * Removes a classloader if needed.
+ * @since Ant 1.7
+ */
+ private void deleteClassLoader() {
+ if (classLoader != null) {
+ classLoader.cleanup();
+ classLoader = null;
+ }
+ if (mirrorLoader instanceof SplitClassLoader) {
+ ((SplitClassLoader) mirrorLoader).cleanup();
+ }
+ mirrorLoader = null;
+ }
+
+ /**
+ * Get the command line used to run the tests.
+ * @return the command line.
+ * @since Ant 1.6.2
+ */
+ protected CommandlineJava getCommandline() {
+ if (commandline == null) {
+ commandline = new CommandlineJava();
+ commandline.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
+ }
+ return commandline;
+ }
+
+ /**
+ * Forked test support
+ * @since Ant 1.6.2
+ */
+ private static final class ForkedTestConfiguration {
+ private final boolean filterTrace;
+ private final boolean haltOnError;
+ private final boolean haltOnFailure;
+ private final String errorProperty;
+ private final String failureProperty;
+
+ /**
+ * constructor for forked test configuration
+ * @param filterTrace
+ * @param haltOnError
+ * @param haltOnFailure
+ * @param errorProperty
+ * @param failureProperty
+ */
+ ForkedTestConfiguration(final boolean filterTrace, final boolean haltOnError,
+ final boolean haltOnFailure, final String errorProperty,
+ final String failureProperty) {
+ this.filterTrace = filterTrace;
+ this.haltOnError = haltOnError;
+ this.haltOnFailure = haltOnFailure;
+ this.errorProperty = errorProperty;
+ this.failureProperty = failureProperty;
+ }
+
+ /**
+ * configure from a test; sets member variables to attributes of the test
+ * @param test
+ */
+ ForkedTestConfiguration(final JUnitTest test) {
+ this(test.getFiltertrace(),
+ test.getHaltonerror(),
+ test.getHaltonfailure(),
+ test.getErrorProperty(),
+ test.getFailureProperty());
+ }
+
+ /**
+ * equality test checks all the member variables
+ * @param other
+ * @return true if everything is equal
+ */
+ @Override
+ public boolean equals(final Object other) {
+ if (other == null
+ || other.getClass() != ForkedTestConfiguration.class) {
+ return false;
+ }
+ final ForkedTestConfiguration o = (ForkedTestConfiguration) other;
+ return filterTrace == o.filterTrace
+ && haltOnError == o.haltOnError
+ && haltOnFailure == o.haltOnFailure
+ && ((errorProperty == null && o.errorProperty == null)
+ ||
+ (errorProperty != null
+ && errorProperty.equals(o.errorProperty)))
+ && ((failureProperty == null && o.failureProperty == null)
+ ||
+ (failureProperty != null
+ && failureProperty.equals(o.failureProperty)));
+ }
+
+ /**
+ * hashcode is based only on the boolean members, and returns a value
+ * in the range 0-7.
+ * @return hash code value
+ */
+ @Override
+ public int hashCode() {
+ // CheckStyle:MagicNumber OFF
+ return (filterTrace ? 1 : 0)
+ + (haltOnError ? 2 : 0)
+ + (haltOnFailure ? 4 : 0);
+ // CheckStyle:MagicNumber ON
+ }
+ }
+
+ /**
+ * These are the different forking options
+ * @since 1.6.2
+ */
+ public static final class ForkMode extends EnumeratedAttribute {
+
+ /**
+ * fork once only
+ */
+ public static final String ONCE = "once";
+ /**
+ * fork once per test class
+ */
+ public static final String PER_TEST = "perTest";
+ /**
+ * fork once per batch of tests
+ */
+ public static final String PER_BATCH = "perBatch";
+
+ /** No arg constructor. */
+ public ForkMode() {
+ super();
+ }
+
+ /**
+ * Constructor using a value.
+ * @param value the value to use - once, perTest or perBatch.
+ */
+ public ForkMode(final String value) {
+ super();
+ setValue(value);
+ }
+
+ /** {@inheritDoc}. */
+ @Override
+ public String[] getValues() {
+ return new String[] {ONCE, PER_TEST, PER_BATCH};
+ }
+ }
+
+ /**
+ * Executes all tests that don't need to be forked (or all tests
+ * if the runIndividual argument is true. Returns a collection of
+ * lists of tests that share the same VM configuration and haven't
+ * been executed yet.
+ * @param testList the list of tests to be executed or queued.
+ * @param runIndividual if true execute each test individually.
+ * @return a list of tasks to be executed.
+ * @since 1.6.2
+ */
+ protected Collection<List> executeOrQueue(final Enumeration<JUnitTest> testList,
+ final boolean runIndividual) {
+ final Map<ForkedTestConfiguration, List> testConfigurations = new HashMap<ForkedTestConfiguration, List>();
+ while (testList.hasMoreElements()) {
+ final JUnitTest test = testList.nextElement();
+ if (test.shouldRun(getProject())) {
+ /* with multi-threaded runs need to defer execution of even */
+ /* individual tests so the threads can pick tests off the queue. */
+ if ((runIndividual || !test.getFork()) && (threads == 1)) {
+ execute(test, 0);
+ } else {
+ final ForkedTestConfiguration c =
+ new ForkedTestConfiguration(test);
+ List<JUnitTest> l = testConfigurations.get(c);
+ if (l == null) {
+ l = new ArrayList<JUnitTest>();
+ testConfigurations.put(c, l);
+ }
+ l.add(test);
+ }
+ }
+ }
+ return testConfigurations.values();
+ }
+
+ /**
+ * Logs information about failed tests, potentially stops
+ * processing (by throwing a BuildException) if a failure/error
+ * occurred or sets a property.
+ * @param exitValue the exitValue of the test.
+ * @param wasKilled if true, the test had been killed.
+ * @param test the test in question.
+ * @param name the name of the test.
+ * @since Ant 1.6.2
+ */
+ protected void actOnTestResult(final int exitValue, final boolean wasKilled,
+ final JUnitTest test, final String name) {
+ final TestResultHolder t = new TestResultHolder();
+ t.exitCode = exitValue;
+ t.timedOut = wasKilled;
+ actOnTestResult(t, test, name);
+ }
+
+ /**
+ * Logs information about failed tests, potentially stops
+ * processing (by throwing a BuildException) if a failure/error
+ * occurred or sets a property.
+ * @param result the result of the test.
+ * @param test the test in question.
+ * @param name the name of the test.
+ * @since Ant 1.7
+ */
+ protected void actOnTestResult(final TestResultHolder result, final JUnitTest test,
+ final String name) {
+ // if there is an error/failure and that it should halt, stop
+ // everything otherwise just log a statement
+ final boolean fatal = result.timedOut || result.crashed;
+ final boolean errorOccurredHere =
+ result.exitCode == JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS || fatal;
+ final boolean failureOccurredHere =
+ result.exitCode != JUnitTaskMirror.JUnitTestRunnerMirror.SUCCESS || fatal;
+ if (errorOccurredHere || failureOccurredHere) {
+ if ((errorOccurredHere && test.getHaltonerror())
+ || (failureOccurredHere && test.getHaltonfailure())) {
+ throw new BuildException(name + " failed"
+ + (result.timedOut ? " (timeout)" : "")
+ + (result.crashed ? " (crashed)" : ""), getLocation());
+ } else {
+ if (logFailedTests) {
+ log(name + " FAILED"
+ + (result.timedOut ? " (timeout)" : "")
+ + (result.crashed ? " (crashed)" : ""),
+ Project.MSG_ERR);
+ }
+ if (errorOccurredHere && test.getErrorProperty() != null) {
+ getProject().setNewProperty(test.getErrorProperty(), "true");
+ }
+ if (failureOccurredHere && test.getFailureProperty() != null) {
+ getProject().setNewProperty(test.getFailureProperty(), "true");
+ }
+ }
+ }
+ }
+
+ /**
+ * A value class that contains the result of a test.
+ */
+ protected static class TestResultHolder {
+ // CheckStyle:VisibilityModifier OFF - bc
+ /** the exit code of the test. */
+ public int exitCode = JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS;
+ /** true if the test timed out */
+ public boolean timedOut = false;
+ /** true if the test crashed */
+ public boolean crashed = false;
+ // CheckStyle:VisibilityModifier ON
+ }
+
+ /**
+ * A stream handler for handling the junit task.
+ * @since Ant 1.7
+ */
+ protected static class JUnitLogOutputStream extends LogOutputStream {
+ private final Task task; // local copy since LogOutputStream.task is private
+
+ /**
+ * Constructor.
+ * @param task the task being logged.
+ * @param level the log level used to log data written to this stream.
+ */
+ public JUnitLogOutputStream(final Task task, final int level) {
+ super(task, level);
+ this.task = task;
+ }
+
+ /**
+ * Logs a line.
+ * If the line starts with junit.framework.TestListener: set the level
+ * to MSG_VERBOSE.
+ * @param line the line to log.
+ * @param level the logging level to use.
+ */
+ @Override
+ protected void processLine(final String line, final int level) {
+ if (line.startsWith(TESTLISTENER_PREFIX)) {
+ task.log(line, Project.MSG_VERBOSE);
+ } else {
+ super.processLine(line, level);
+ }
+ }
+ }
+
+ /**
+ * A log stream handler for junit.
+ * @since Ant 1.7
+ */
+ protected static class JUnitLogStreamHandler extends PumpStreamHandler {
+ /**
+ * Constructor.
+ * @param task the task to log.
+ * @param outlevel the level to use for standard output.
+ * @param errlevel the level to use for error output.
+ */
+ public JUnitLogStreamHandler(final Task task, final int outlevel, final int errlevel) {
+ super(new JUnitLogOutputStream(task, outlevel),
+ new LogOutputStream(task, errlevel));
+ }
+ }
+
+ static final String NAME_OF_DUMMY_TEST = "Batch-With-Multiple-Tests";
+
+ /**
+ * Creates a JUnitTest instance that shares all flags with the
+ * passed in instance but has a more meaningful name.
+ *
+ * <p>If a VM running multiple tests crashes, we don't know which
+ * test failed. Prior to Ant 1.8.0 Ant would log the error with
+ * the last test of the batch test, which caused some confusion
+ * since the log might look as if a test had been executed last
+ * that was never started. With Ant 1.8.0 the test's name will
+ * indicate that something went wrong with a test inside the batch
+ * without giving it a real name.</p>
+ *
+ * @see "https://issues.apache.org/bugzilla/show_bug.cgi?id=45227"
+ */
+ private static JUnitTest createDummyTestForBatchTest(final JUnitTest test) {
+ final JUnitTest t = (JUnitTest) test.clone();
+ final int index = test.getName().lastIndexOf('.');
+ // make sure test looks as if it was in the same "package" as
+ // the last test of the batch
+ final String pack = index > 0 ? test.getName().substring(0, index + 1) : "";
+ t.setName(pack + NAME_OF_DUMMY_TEST);
+ return t;
+ }
+
+ private static void printDual(final BufferedWriter w, final PrintStream s, final String text)
+ throws IOException {
+ w.write(String.valueOf(text));
+ s.print(text);
+ }
+
+ private static void printlnDual(final BufferedWriter w, final PrintStream s, final String text)
+ throws IOException {
+ w.write(String.valueOf(text));
+ w.newLine();
+ s.println(text);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
new file mode 100644
index 00000000..694e1d8c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.types.Permissions;
+
+/**
+ * Handles the portions of {@link JUnitTask} which need to directly access
+ * actual JUnit classes, so that junit.jar need not be on Ant's startup classpath.
+ * Neither JUnitTask.java nor JUnitTaskMirror.java nor their transitive static
+ * deps may import any junit.** classes!
+ * Specifically, need to not refer to
+ * - JUnitResultFormatter or its subclasses
+ * - JUnitVersionHelper
+ * - JUnitTestRunner
+ * Cf. JUnitTask.SplitLoader#isSplit(String)
+ * Public only to permit access from classes in this package; do not use directly.
+ *
+ * @since 1.7
+ * @see "bug #38799"
+ */
+public interface JUnitTaskMirror {
+
+ /**
+ * Add the formatter to be called when the jvm exits before
+ * the test suite finishes.
+ * @param test the test.
+ * @param formatter the formatter to use.
+ * @param out the output stream to use.
+ * @param message the message to write out.
+ * @param testCase the name of the test.
+ */
+ void addVmExit(JUnitTest test, JUnitResultFormatterMirror formatter,
+ OutputStream out, String message, String testCase);
+
+ /**
+ * Create a new test runner for a test.
+ * @param test the test to run.
+ * @param methods names of the test methods to be run.
+ * @param haltOnError if true halt the tests if an error occurs.
+ * @param filterTrace if true filter the stack traces.
+ * @param haltOnFailure if true halt the test if a failure occurs.
+ * @param showOutput if true show output.
+ * @param logTestListenerEvents if true log test listener events.
+ * @param classLoader the classloader to use to create the runner.
+ * @return the test runner.
+ */
+ JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
+ boolean filterTrace, boolean haltOnFailure, boolean showOutput,
+ boolean logTestListenerEvents, AntClassLoader classLoader);
+
+ /**
+ * Create a summary result formatter.
+ * @return the created formatter.
+ */
+ SummaryJUnitResultFormatterMirror newSummaryJUnitResultFormatter();
+
+
+ /** The interface that JUnitResultFormatter extends. */
+ public interface JUnitResultFormatterMirror {
+ /**
+ * Set the output stream.
+ * @param outputStream the stream to use.
+ */
+ void setOutput(OutputStream outputStream);
+ }
+
+ /** The interface that SummaryJUnitResultFormatter extends. */
+ public interface SummaryJUnitResultFormatterMirror
+ extends JUnitResultFormatterMirror {
+
+ /**
+ * Set where standard out and standard error should be included.
+ * @param value if true include the outputs in the summary.
+ */
+ void setWithOutAndErr(boolean value);
+ }
+
+ /** Interface that test runners implement. */
+ public interface JUnitTestRunnerMirror {
+
+ /**
+ * Used in formatter arguments as a placeholder for the basename
+ * of the output file (which gets replaced by a test specific
+ * output file name later).
+ *
+ * @since Ant 1.6.3
+ */
+ String IGNORED_FILE_NAME = "IGNORETHIS";
+
+ /**
+ * No problems with this test.
+ */
+ int SUCCESS = 0;
+
+ /**
+ * Some tests failed.
+ */
+ int FAILURES = 1;
+
+ /**
+ * An error occurred.
+ */
+ int ERRORS = 2;
+
+ /**
+ * Permissions for the test run.
+ * @param perm the permissions to use.
+ */
+ void setPermissions(Permissions perm);
+
+ /** Run the test. */
+ void run();
+
+ /**
+ * Add a formatter to the test.
+ * @param formatter the formatter to use.
+ */
+ void addFormatter(JUnitResultFormatterMirror formatter);
+
+ /**
+ * Returns what System.exit() would return in the standalone version.
+ *
+ * @return 2 if errors occurred, 1 if tests failed else 0.
+ */
+ int getRetCode();
+
+ /**
+ * Handle output sent to System.err.
+ *
+ * @param output coming from System.err
+ */
+ void handleErrorFlush(String output);
+
+ /**
+ * Handle output sent to System.err.
+ *
+ * @param output output for System.err
+ */
+ void handleErrorOutput(String output);
+
+ /**
+ * Handle output sent to System.out.
+ *
+ * @param output output for System.out.
+ */
+ void handleOutput(String output);
+
+ /**
+ * Handle an input request.
+ *
+ * @param buffer the buffer into which data is to be read.
+ * @param offset the offset into the buffer at which data is stored.
+ * @param length the amount of data to read.
+ *
+ * @return the number of bytes read.
+ *
+ * @exception IOException if the data cannot be read.
+ */
+ int handleInput(byte[] buffer, int offset, int length) throws IOException;
+
+ /**
+ * Handle output sent to System.out.
+ *
+ * @param output output for System.out.
+ */
+ void handleFlush(String output);
+
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
new file mode 100644
index 00000000..c7dae258
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+import org.apache.tools.ant.AntClassLoader;
+
+/**
+ * Implementation of the part of the junit task which can directly refer to junit.* classes.
+ * Public only to permit use of reflection; do not use directly.
+ * @see JUnitTaskMirror
+ * @see "bug #38799"
+ * @since 1.7
+ */
+public final class JUnitTaskMirrorImpl implements JUnitTaskMirror {
+
+ private final JUnitTask task;
+
+ /**
+ * Constructor.
+ * @param task the junittask that uses this mirror.
+ */
+ public JUnitTaskMirrorImpl(JUnitTask task) {
+ this.task = task;
+ }
+
+ /** {@inheritDoc}. */
+ public void addVmExit(JUnitTest test, JUnitTaskMirror.JUnitResultFormatterMirror aFormatter,
+ OutputStream out, String message, String testCase) {
+ JUnitResultFormatter formatter = (JUnitResultFormatter) aFormatter;
+ formatter.setOutput(out);
+ formatter.startTestSuite(test);
+ //the trick to integrating test output to the formatter, is to
+ //create a special test class that asserts an error
+ //and tell the formatter that it raised.
+ TestCase t = new VmExitErrorTest(message, test, testCase);
+ formatter.startTest(t);
+ formatter.addError(t, new AssertionFailedError(message));
+ formatter.endTestSuite(test);
+ }
+
+ /** {@inheritDoc}. */
+ public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test,
+ String[] methods,
+ boolean haltOnError, boolean filterTrace, boolean haltOnFailure,
+ boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) {
+ return new JUnitTestRunner(test, methods, haltOnError, filterTrace, haltOnFailure,
+ showOutput, logTestListenerEvents, classLoader);
+ }
+
+ /** {@inheritDoc}. */
+ public JUnitTaskMirror.SummaryJUnitResultFormatterMirror newSummaryJUnitResultFormatter() {
+ return new SummaryJUnitResultFormatter();
+ }
+
+ static class VmExitErrorTest extends TestCase {
+
+ private String message;
+ private JUnitTest test;
+ private String testCase;
+
+ VmExitErrorTest(String aMessage, JUnitTest anOriginalTest, String aTestCase) {
+ message = aMessage;
+ test = anOriginalTest;
+ testCase = aTestCase;
+ }
+
+ public int countTestCases() {
+ return 1;
+ }
+
+ public void run(TestResult r) {
+ throw new AssertionFailedError(message);
+ }
+
+ public String getName() {
+ return testCase;
+ }
+
+ String getClassName() {
+ return test.getName();
+ }
+
+ public String toString() {
+ return test.getName() + ":" + testCase;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
new file mode 100644
index 00000000..835c013b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
@@ -0,0 +1,542 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+
+/**
+ * <p> Run a single JUnit test.
+ *
+ * <p> The JUnit test is actually run by {@link JUnitTestRunner}.
+ * So read the doc comments for that class :)
+ *
+ * @since Ant 1.2
+ *
+ * @see JUnitTask
+ * @see JUnitTestRunner
+ */
+public class JUnitTest extends BaseTest implements Cloneable {
+
+ /** the name of the test case */
+ private String name = null;
+
+ /**
+ * whether the list of test methods has been specified
+ * @see #setMethods(java.lang.String)
+ * @see #setMethods(java.lang.String[])
+ */
+ private boolean methodsSpecified = false;
+
+ /** comma-separated list of names of test methods to execute */
+ private String methodsList = null;
+
+ /** the names of test methods to execute */
+ private String[] methods = null;
+
+ /** the name of the result file */
+ private String outfile = null;
+
+ // @todo this is duplicating TestResult information. Only the time is not
+ // part of the result. So we'd better derive a new class from TestResult
+ // and deal with it. (SB)
+ private long runs, failures, errors;
+ /**
+ @since Ant 1.9.0
+ */
+ private long skips;
+
+ private long runTime;
+
+ private int antThreadID;
+
+ // Snapshot of the system properties
+ private Properties props = null;
+
+ /** No arg constructor. */
+ public JUnitTest() {
+ }
+
+ /**
+ * Constructor with name.
+ * @param name the name of the test.
+ */
+ public JUnitTest(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Constructor with options.
+ * @param name the name of the test.
+ * @param haltOnError if true halt the tests if there is an error.
+ * @param haltOnFailure if true halt the tests if there is a failure.
+ * @param filtertrace if true filter stack traces.
+ */
+ public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
+ boolean filtertrace) {
+ this(name, haltOnError, haltOnFailure, filtertrace, null, 0);
+ }
+
+ /**
+ * Constructor with options.
+ * @param name the name of the test.
+ * @param haltOnError if true halt the tests if there is an error.
+ * @param haltOnFailure if true halt the tests if there is a failure.
+ * @param filtertrace if true filter stack traces.
+ * @param methods if non-null run only these test methods
+ * @since 1.8.2
+ */
+ public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
+ boolean filtertrace, String[] methods) {
+ this(name, haltOnError, haltOnFailure, filtertrace, methods, 0);
+ }
+
+ /**
+ * Constructor with options.
+ * @param name the name of the test.
+ * @param haltOnError if true halt the tests if there is an error.
+ * @param haltOnFailure if true halt the tests if there is a failure.
+ * @param filtertrace if true filter stack traces.
+ * @param methods if non-null run only these test methods
+ * @param thread Ant thread ID in which test is currently running
+ * @since 1.9.4
+ */
+ public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
+ boolean filtertrace, String[] methods, int thread) {
+ this.name = name;
+ this.haltOnError = haltOnError;
+ this.haltOnFail = haltOnFailure;
+ this.filtertrace = filtertrace;
+ this.methodsSpecified = methods != null;
+ this.methods = methodsSpecified ? (String[]) methods.clone() : null;
+ this.antThreadID = thread;
+ }
+
+ /**
+ * Sets names of individual test methods to be executed.
+ * @param value comma-separated list of names of individual test methods
+ * to be executed,
+ * or <code>null</code> if all test methods should be executed
+ * @since 1.8.2
+ */
+ public void setMethods(String value) {
+ methodsList = value;
+ methodsSpecified = (value != null);
+ methods = null;
+ }
+
+ /**
+ * Sets names of individual test methods to be executed.
+ * @param value non-empty array of names of test methods to be executed
+ * @see #setMethods(String)
+ * @since 1.8.2
+ */
+ void setMethods(String[] value) {
+ methods = value;
+ methodsSpecified = (value != null);
+ methodsList = null;
+ }
+
+ /**
+ * Set the name of the test class.
+ * @param value the name to use.
+ */
+ public void setName(String value) {
+ name = value;
+ }
+
+ /**
+ * Set the thread id
+ * @param thread the Ant id of the thread running this test
+ * (this is not the system process or thread id)
+ * (this will be 0 in single-threaded mode).
+ * @since Ant 1.9.4
+ */
+ public void setThread(int thread) {
+ this.antThreadID = thread;
+ }
+
+ /**
+ * Set the name of the output file.
+ * @param value the name of the output file to use.
+ */
+ public void setOutfile(String value) {
+ outfile = value;
+ }
+
+ /**
+ * Informs whether a list of test methods has been specified in this test.
+ * @return <code>true</code> if test methods to be executed have been
+ * specified, <code>false</code> otherwise
+ * @see #setMethods(java.lang.String)
+ * @see #setMethods(java.lang.String[])
+ * @since 1.8.2
+ */
+ boolean hasMethodsSpecified() {
+ return methodsSpecified;
+ }
+
+ /**
+ * Get names of individual test methods to be executed.
+ *
+ * @return array of names of the individual test methods to be executed,
+ * or <code>null</code> if all test methods in the suite
+ * defined by the test class will be executed
+ * @since 1.8.2
+ */
+ String[] getMethods() {
+ if (methodsSpecified && (methods == null)) {
+ resolveMethods();
+ }
+ return methods;
+ }
+
+ /**
+ * Gets a comma-separated list of names of methods that are to be executed
+ * by this test.
+ * @return the comma-separated list of test method names, or an empty
+ * string of no method is to be executed, or <code>null</code>
+ * if no method is specified
+ * @since 1.8.2
+ */
+ String getMethodsString() {
+ if ((methodsList == null) && methodsSpecified) {
+ if (methods.length == 0) {
+ methodsList = "";
+ } else if (methods.length == 1) {
+ methodsList = methods[0];
+ } else {
+ StringBuffer buf = new StringBuffer(methods.length * 16);
+ buf.append(methods[0]);
+ for (int i = 1; i < methods.length; i++) {
+ buf.append(',').append(methods[i]);
+ }
+ methodsList = buf.toString();
+ }
+ }
+ return methodsList;
+ }
+
+ /**
+ * Computes the value of the {@link #methods} field from the value
+ * of the {@link #methodsList} field, if it has not been computed yet.
+ * @exception BuildException if the value of the {@link #methodsList} field
+ * was invalid
+ * @since 1.8.2
+ */
+ void resolveMethods() {
+ if ((methods == null) && methodsSpecified) {
+ try {
+ methods = parseTestMethodNamesList(methodsList);
+ } catch (IllegalArgumentException ex) {
+ throw new BuildException(
+ "Invalid specification of test methods: \""
+ + methodsList
+ + "\"; expected: comma-separated list of valid Java identifiers",
+ ex);
+ }
+ }
+ }
+
+ /**
+ * Parses a comma-separated list of method names and check their validity.
+ * @param methodNames comma-separated list of method names to be parsed
+ * @return array of individual test method names
+ * @exception java.lang.IllegalArgumentException
+ * if the given string is <code>null</code> or if it is not
+ * a comma-separated list of valid Java identifiers;
+ * an empty string is acceptable and is handled as an empty
+ * list
+ * @since 1.8.2
+ */
+ public static String[] parseTestMethodNamesList(String methodNames)
+ throws IllegalArgumentException {
+ if (methodNames == null) {
+ throw new IllegalArgumentException("methodNames is <null>");
+ }
+
+ methodNames = methodNames.trim();
+
+ int length = methodNames.length();
+ if (length == 0) {
+ return new String[0];
+ }
+
+ /* strip the trailing comma, if any */
+ if (methodNames.charAt(length - 1) == ',') {
+ methodNames = methodNames.substring(0, length - 1).trim();
+ length = methodNames.length();
+ if (length == 0) {
+ throw new IllegalArgumentException("Empty method name");
+ }
+ }
+
+ final char[] chars = methodNames.toCharArray();
+ /* easy detection of one particular case of illegal string: */
+ if (chars[0] == ',') {
+ throw new IllegalArgumentException("Empty method name");
+ }
+ /* count number of method names: */
+ int wordCount = 1;
+ for (int i = 1; i < chars.length; i++) {
+ if (chars[i] == ',') {
+ wordCount++;
+ }
+ }
+ /* prepare the resulting array: */
+ String[] result = new String[wordCount];
+ /* parse the string: */
+ final int stateBeforeWord = 1;
+ final int stateInsideWord = 2;
+ final int stateAfterWord = 3;
+ //
+ int state = stateBeforeWord;
+ int wordStartIndex = -1;
+ int wordIndex = 0;
+ for (int i = 0; i < chars.length; i++) {
+ char c = chars[i];
+ switch (state) {
+ case stateBeforeWord:
+ if (c == ',') {
+ throw new IllegalArgumentException("Empty method name");
+ } else if (c == ' ') {
+ // remain in the same state
+ } else if (Character.isJavaIdentifierStart(c)) {
+ wordStartIndex = i;
+ state = stateInsideWord;
+ } else {
+ throw new IllegalArgumentException("Illegal start of method name: " + c);
+ }
+ break;
+ case stateInsideWord:
+ if (c == ',') {
+ result[wordIndex++] = methodNames.substring(wordStartIndex, i);
+ state = stateBeforeWord;
+ } else if (c == ' ') {
+ result[wordIndex++] = methodNames.substring(wordStartIndex, i);
+ state = stateAfterWord;
+ } else if (Character.isJavaIdentifierPart(c)) {
+ // remain in the same state
+ } else {
+ throw new IllegalArgumentException("Illegal character in method name: " + c);
+ }
+ break;
+ case stateAfterWord:
+ if (c == ',') {
+ state = stateBeforeWord;
+ } else if (c == ' ') {
+ // remain in the same state
+ } else {
+ throw new IllegalArgumentException("Space in method name");
+ }
+ break;
+ default:
+ // this should never happen
+ }
+ }
+ switch (state) {
+ case stateBeforeWord:
+ case stateAfterWord:
+ break;
+ case stateInsideWord:
+ result[wordIndex++] = methodNames.substring(wordStartIndex, chars.length);
+ break;
+ default:
+ // this should never happen
+ }
+ return result;
+ }
+
+ /**
+ * Get the name of the test class.
+ * @return the name of the test.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the Ant id of the thread running the test.
+ * @return the thread id
+ */
+ public int getThread() {
+ return antThreadID;
+ }
+
+ /**
+ * Get the name of the output file
+ *
+ * @return the name of the output file.
+ */
+ public String getOutfile() {
+ return outfile;
+ }
+
+ /**
+ * Set the number of runs, failures, errors, and skipped tests.
+ * @param runs the number of runs.
+ * @param failures the number of failures.
+ * @param errors the number of errors.
+ * Kept for backward compatibility with Ant 1.8.4
+ */
+ public void setCounts(long runs, long failures, long errors) {
+ this.runs = runs;
+ this.failures = failures;
+ this.errors = errors;
+ }
+ /**
+ * Set the number of runs, failures, errors, and skipped tests.
+ * @param runs the number of runs.
+ * @param failures the number of failures.
+ * @param errors the number of errors.
+ * @param skips the number of skipped tests.
+ * @since Ant 1.9.0
+ */
+ public void setCounts(long runs, long failures, long errors, long skips) {
+ this.runs = runs;
+ this.failures = failures;
+ this.errors = errors;
+ this.skips = skips;
+ }
+
+ /**
+ * Set the runtime.
+ * @param runTime the time in milliseconds.
+ */
+ public void setRunTime(long runTime) {
+ this.runTime = runTime;
+ }
+
+ /**
+ * Get the number of runs.
+ * @return the number of runs.
+ */
+ public long runCount() {
+ return runs;
+ }
+
+ /**
+ * Get the number of failures.
+ * @return the number of failures.
+ */
+ public long failureCount() {
+ return failures;
+ }
+
+ /**
+ * Get the number of errors.
+ * @return the number of errors.
+ */
+ public long errorCount() {
+ return errors;
+ }
+
+ /**
+ * Get the number of skipped tests.
+ * @return the number of skipped tests.
+ */
+ public long skipCount() {
+ return skips;
+ }
+
+ /**
+ * Get the run time.
+ * @return the run time in milliseconds.
+ */
+ public long getRunTime() {
+ return runTime;
+ }
+
+ /**
+ * Get the properties used in the test.
+ * @return the properties.
+ */
+ public Properties getProperties() {
+ return props;
+ }
+
+ /**
+ * Set the properties to be used in the test.
+ * @param p the properties.
+ * This is a copy of the projects ant properties.
+ */
+ public void setProperties(Hashtable p) {
+ props = new Properties();
+ for (Enumeration e = p.keys(); e.hasMoreElements();) {
+ Object key = e.nextElement();
+ props.put(key, p.get(key));
+ }
+ }
+
+ /**
+ * Check if this test should run based on the if and unless
+ * attributes.
+ * @param p the project to use to check if the if and unless
+ * properties exist in.
+ * @return true if this test or testsuite should be run.
+ */
+ public boolean shouldRun(Project p) {
+ PropertyHelper ph = PropertyHelper.getPropertyHelper(p);
+ return ph.testIfCondition(getIfCondition())
+ && ph.testUnlessCondition(getUnlessCondition());
+ }
+
+ /**
+ * Get the formatters set for this test.
+ * @return the formatters as an array.
+ */
+ public FormatterElement[] getFormatters() {
+ FormatterElement[] fes = new FormatterElement[formatters.size()];
+ formatters.copyInto(fes);
+ return fes;
+ }
+
+ /**
+ * Convenient method to add formatters to a vector
+ */
+ void addFormattersTo(Vector v) {
+ final int count = formatters.size();
+ for (int i = 0; i < count; i++) {
+ v.addElement(formatters.elementAt(i));
+ }
+ }
+
+ /**
+ * @since Ant 1.5
+ * @return a clone of this test.
+ */
+ @Override
+ public Object clone() {
+ try {
+ JUnitTest t = (JUnitTest) super.clone();
+ t.props = props == null ? null : (Properties) props.clone();
+ t.formatters = (Vector) formatters.clone();
+ return t;
+ } catch (CloneNotSupportedException e) {
+ // plain impossible
+ return this;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
new file mode 100644
index 00000000..a457375e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
@@ -0,0 +1,1297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Permissions;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+/**
+ * Simple Testrunner for JUnit that runs all tests of a testsuite.
+ *
+ * <p>This TestRunner expects a name of a TestCase class as its
+ * argument. If this class provides a static suite() method it will be
+ * called and the resulting Test will be run. So, the signature should be
+ * <pre><code>
+ * public static junit.framework.Test suite()
+ * </code></pre>
+ *
+ * <p> If no such method exists, all public methods starting with
+ * "test" and taking no argument will be run.
+ *
+ * <p> Summary output is generated at the end.
+ *
+ * @since Ant 1.2
+ */
+
+public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestRunnerMirror {
+
+ /**
+ * Holds the registered formatters.
+ */
+ private final Vector<JUnitTaskMirror.JUnitResultFormatterMirror> formatters = new Vector();
+
+ /**
+ * Collects TestResults.
+ */
+ private IgnoredTestResult res;
+
+ /**
+ * Do we filter junit.*.* stack frames out of failure and error exceptions.
+ */
+ private static boolean filtertrace = true;
+
+ /**
+ * Do we send output to System.out/.err in addition to the formatters?
+ */
+ private boolean showOutput = false;
+
+ private boolean outputToFormatters = true;
+
+ /**
+ * The permissions set for the test to run.
+ */
+ private Permissions perm = null;
+
+ private static final String JUNIT_4_TEST_ADAPTER
+ = "junit.framework.JUnit4TestAdapter";
+
+ private static final String[] DEFAULT_TRACE_FILTERS = new String[] {
+ "junit.framework.TestCase",
+ "junit.framework.TestResult",
+ "junit.framework.TestSuite",
+ "junit.framework.Assert.", // don't filter AssertionFailure
+ "junit.swingui.TestRunner",
+ "junit.awtui.TestRunner",
+ "junit.textui.TestRunner",
+ "java.lang.reflect.Method.invoke(",
+ "sun.reflect.",
+ "org.apache.tools.ant.",
+ // JUnit 4 support:
+ "org.junit.",
+ "junit.framework.JUnit4TestAdapter",
+ " more",
+ };
+
+
+ /**
+ * Do we stop on errors.
+ */
+ private boolean haltOnError = false;
+
+ /**
+ * Do we stop on test failures.
+ */
+ private boolean haltOnFailure = false;
+
+ /**
+ * Returncode
+ */
+ private int retCode = SUCCESS;
+
+ /**
+ * The TestSuite we are currently running.
+ */
+ private final JUnitTest junitTest;
+
+ /** output written during the test */
+ private PrintStream systemError;
+
+ /** Error output during the test */
+ private PrintStream systemOut;
+
+ /** is this runner running in forked mode? */
+ private boolean forked = false;
+
+ /** Running more than one test suite? */
+ private static boolean multipleTests = false;
+
+ /** ClassLoader passed in in non-forked mode. */
+ private final ClassLoader loader;
+
+ /** Do we print TestListener events? */
+ private boolean logTestListenerEvents = false;
+
+ /** Turned on if we are using JUnit 4 for this test suite. see #38811 */
+ private boolean junit4;
+
+ /**
+ * The file used to indicate that the build crashed.
+ * File will be empty in case the build did not crash.
+ */
+ private static String crashFile = null;
+
+ /** Names of test methods to execute */
+ private String[] methods = null;
+
+ /**
+ * Constructor for fork=true or when the user hasn't specified a
+ * classpath.
+ * @param test the test to run.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ */
+ public JUnitTestRunner(final JUnitTest test, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure) {
+ this(test, haltOnError, filtertrace, haltOnFailure, false);
+ }
+
+ /**
+ * Constructor for fork=true or when the user hasn't specified a
+ * classpath.
+ * @param test the test to run.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param showOutput whether to send output to System.out/.err as well as formatters.
+ */
+ public JUnitTestRunner(final JUnitTest test, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final boolean showOutput) {
+ this(test, haltOnError, filtertrace, haltOnFailure, showOutput, false);
+ }
+
+ /**
+ * Constructor for fork=true or when the user hasn't specified a
+ * classpath.
+ * @param test the test to run.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param showOutput whether to send output to System.out/.err as well as formatters.
+ * @param logTestListenerEvents whether to print TestListener events.
+ * @since Ant 1.7
+ */
+ public JUnitTestRunner(final JUnitTest test, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final boolean showOutput, final boolean logTestListenerEvents) {
+ this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput,
+ logTestListenerEvents, null);
+ }
+
+ /**
+ * Constructor for fork=true or when the user hasn't specified a
+ * classpath.
+ * @param test the test to run.
+ * @param methods names of methods of the test to be executed.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param showOutput whether to send output to System.out/.err as well as formatters.
+ * @param logTestListenerEvents whether to print TestListener events.
+ * @since 1.8.2
+ */
+ public JUnitTestRunner(final JUnitTest test, final String[] methods, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final boolean showOutput, final boolean logTestListenerEvents) {
+ this(test, methods, haltOnError, filtertrace, haltOnFailure, showOutput,
+ logTestListenerEvents, null);
+ }
+
+ /**
+ * Constructor to use when the user has specified a classpath.
+ * @param test the test to run.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param loader the classloader to use running the test.
+ */
+ public JUnitTestRunner(final JUnitTest test, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final ClassLoader loader) {
+ this(test, haltOnError, filtertrace, haltOnFailure, false, loader);
+ }
+
+ /**
+ * Constructor to use when the user has specified a classpath.
+ * @param test the test to run.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param showOutput whether to send output to System.out/.err as well as formatters.
+ * @param loader the classloader to use running the test.
+ */
+ public JUnitTestRunner(final JUnitTest test, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final boolean showOutput, final ClassLoader loader) {
+ this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
+ false, loader);
+ }
+
+ /**
+ * Constructor to use when the user has specified a classpath.
+ * @param test the test to run.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param showOutput whether to send output to System.out/.err as well as formatters.
+ * @param logTestListenerEvents whether to print TestListener events.
+ * @param loader the classloader to use running the test.
+ * @since Ant 1.7
+ */
+ public JUnitTestRunner(final JUnitTest test, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final boolean showOutput, final boolean logTestListenerEvents,
+ final ClassLoader loader) {
+ this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput,
+ logTestListenerEvents, loader);
+ }
+
+
+ /**
+ * Constructor to use when the user has specified a classpath.
+ * @since 1.8.2
+ */
+ public JUnitTestRunner(final JUnitTest test, final String[] methods, final boolean haltOnError,
+ final boolean filtertrace, final boolean haltOnFailure,
+ final boolean showOutput, final boolean logTestListenerEvents,
+ final ClassLoader loader) {
+ super();
+ JUnitTestRunner.filtertrace = filtertrace; // TODO clumsy, should use instance field somehow
+ this.junitTest = test;
+ this.haltOnError = haltOnError;
+ this.haltOnFailure = haltOnFailure;
+ this.showOutput = showOutput;
+ this.logTestListenerEvents = logTestListenerEvents;
+ this.methods = methods != null ? (String[]) methods.clone() : null;
+ this.loader = loader;
+ }
+
+ private PrintStream savedOut = null;
+ private PrintStream savedErr = null;
+
+ private PrintStream createEmptyStream() {
+ return new PrintStream(
+ new OutputStream() {
+ @Override
+ public void write(final int b) {
+ }
+ });
+ }
+
+ private PrintStream createTeePrint(final PrintStream ps1, final PrintStream ps2) {
+ return new PrintStream(new TeeOutputStream(ps1, ps2));
+ }
+
+ private void setupIOStreams(final ByteArrayOutputStream o,
+ final ByteArrayOutputStream e) {
+ systemOut = new PrintStream(o);
+ systemError = new PrintStream(e);
+
+ if (forked) {
+ if (!outputToFormatters) {
+ if (!showOutput) {
+ savedOut = System.out;
+ savedErr = System.err;
+ System.setOut(createEmptyStream());
+ System.setErr(createEmptyStream());
+ }
+ } else {
+ savedOut = System.out;
+ savedErr = System.err;
+ if (!showOutput) {
+ System.setOut(systemOut);
+ System.setErr(systemError);
+ } else {
+ System.setOut(createTeePrint(savedOut, systemOut));
+ System.setErr(createTeePrint(savedErr, systemError));
+ }
+ perm = null;
+ }
+ } else {
+ if (perm != null) {
+ perm.setSecurityManager();
+ }
+ }
+ }
+
+ /**
+ * Run the test.
+ */
+ public void run() {
+ res = new IgnoredTestResult();
+ res.addListener(wrapListener(this));
+ final int size = formatters.size();
+ for (int i = 0; i < size; i++) {
+ res.addListener(wrapListener((TestListener) formatters.elementAt(i)));
+ }
+
+ final ByteArrayOutputStream errStrm = new ByteArrayOutputStream();
+ final ByteArrayOutputStream outStrm = new ByteArrayOutputStream();
+
+ setupIOStreams(outStrm, errStrm);
+
+ Test suite = null;
+ Throwable exception = null;
+ boolean startTestSuiteSuccess = false;
+
+ try {
+
+ try {
+ Class testClass = null;
+ if (loader == null) {
+ testClass = Class.forName(junitTest.getName());
+ } else {
+ testClass = Class.forName(junitTest.getName(), true,
+ loader);
+ }
+
+ final boolean testMethodsSpecified = (methods != null);
+
+ // check for a static suite method first, even when using
+ // JUnit 4
+ Method suiteMethod = null;
+ if (!testMethodsSpecified) {
+ try {
+ // check if there is a suite method
+ suiteMethod = testClass.getMethod("suite", new Class[0]);
+ } catch (final NoSuchMethodException e) {
+ // no appropriate suite method found. We don't report any
+ // error here since it might be perfectly normal.
+ }
+ }
+
+ if (suiteMethod != null) {
+ // if there is a suite method available, then try
+ // to extract the suite from it. If there is an error
+ // here it will be caught below and reported.
+ suite = (Test) suiteMethod.invoke(null, new Object[0]);
+
+ } else {
+ Class junit4TestAdapterClass = null;
+ Class junit4TestAdapterCacheClass = null;
+ boolean useSingleMethodAdapter = false;
+
+ if (junit.framework.TestCase.class.isAssignableFrom(testClass)) {
+ // Do not use JUnit 4 API for running JUnit 3.x
+ // tests - it is not able to run individual test
+ // methods.
+ //
+ // Technical details:
+ // org.junit.runner.Request.method(Class, String).getRunner()
+ // would return a runner which always executes all
+ // test methods. The reason is that the Runner would be
+ // an instance of class
+ // org.junit.internal.runners.OldTestClassRunner
+ // that does not implement interface Filterable - so it
+ // is unable to filter out test methods not matching
+ // the requested name.
+ } else {
+ // Check for JDK 5 first. Will *not* help on JDK 1.4
+ // if only junit-4.0.jar in CP because in that case
+ // linkage of whole task will already have failed! But
+ // will help if CP has junit-3.8.2.jar:junit-4.0.jar.
+
+ // In that case first C.fN will fail with CNFE and we
+ // will avoid UnsupportedClassVersionError.
+
+ try {
+ Class.forName("java.lang.annotation.Annotation");
+ junit4TestAdapterCacheClass = Class.forName("org.apache.tools.ant.taskdefs.optional.junit.CustomJUnit4TestAdapterCache");
+ if (loader == null) {
+ junit4TestAdapterClass =
+ Class.forName(JUNIT_4_TEST_ADAPTER);
+ if (testMethodsSpecified) {
+ /*
+ * We cannot try to load the JUnit4TestAdapter
+ * before trying to load JUnit4TestMethodAdapter
+ * because it might fail with
+ * NoClassDefFoundException, instead of plain
+ * ClassNotFoundException.
+ */
+ junit4TestAdapterClass = Class.forName(
+ "org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter");
+ useSingleMethodAdapter = true;
+ }
+ } else {
+ junit4TestAdapterClass =
+ Class.forName(JUNIT_4_TEST_ADAPTER,
+ true, loader);
+ if (testMethodsSpecified) {
+ junit4TestAdapterClass =
+ Class.forName(
+ "org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter",
+ true, loader);
+ useSingleMethodAdapter = true;
+ }
+ }
+ } catch (final ClassNotFoundException e) {
+ // OK, fall back to JUnit 3.
+ }
+ }
+ junit4 = junit4TestAdapterClass != null;
+
+ if (junitTest.isSkipNonTests()) {
+ if (!containsTests(testClass, junit4)) {
+ return;
+ }
+ }
+
+
+ if (junit4) {
+ // Let's use it!
+ Class[] formalParams;
+ Object[] actualParams;
+ if (useSingleMethodAdapter) {
+ formalParams = new Class[] {Class.class, String[].class};
+ actualParams = new Object[] {testClass, methods};
+ } else {
+ formalParams = new Class[] {Class.class, Class.forName("junit.framework.JUnit4TestAdapterCache")};
+ actualParams = new Object[] {testClass, junit4TestAdapterCacheClass.getMethod("getInstance").invoke(null)};
+ }
+ suite =
+ (Test) junit4TestAdapterClass
+ .getConstructor(formalParams).
+ newInstance(actualParams);
+ } else {
+ // Use JUnit 3.
+
+ // try to extract a test suite automatically this
+ // will generate warnings if the class is no
+ // suitable Test
+ if (!testMethodsSpecified) {
+ suite = new TestSuite(testClass);
+ } else if (methods.length == 1) {
+ suite = TestSuite.createTest(testClass, methods[0]);
+ } else {
+ final TestSuite testSuite = new TestSuite(testClass.getName());
+ for (int i = 0; i < methods.length; i++) {
+ testSuite.addTest(
+ TestSuite.createTest(testClass, methods[i]));
+ }
+ suite = testSuite;
+ }
+ }
+
+ }
+
+ } catch (final Throwable e) {
+ retCode = ERRORS;
+ exception = e;
+ }
+
+ final long start = System.currentTimeMillis();
+
+ fireStartTestSuite();
+ startTestSuiteSuccess = true;
+ if (exception != null) { // had an exception constructing suite
+ final int formatterSize = formatters.size();
+ for (int i = 0; i < formatterSize; i++) {
+ ((TestListener) formatters.elementAt(i))
+ .addError(null, exception);
+ }
+ junitTest.setCounts(1, 0, 1, 0);
+ junitTest.setRunTime(0);
+ } else {
+ try {
+ logTestListenerEvent("tests to run: " + suite.countTestCases());
+ suite.run(res);
+ } finally {
+ if (junit4 ||
+ suite.getClass().getName().equals(JUNIT_4_TEST_ADAPTER)) {
+ final int[] cnts = findJUnit4FailureErrorCount(res);
+ junitTest.setCounts(res.runCount() + res.ignoredCount(), cnts[0], cnts[1], res.ignoredCount() + res.skippedCount());
+ } else {
+ junitTest.setCounts(res.runCount() + res.ignoredCount(), res.failureCount(),
+ res.errorCount(), res.ignoredCount() + res.skippedCount());
+ }
+ junitTest.setRunTime(System.currentTimeMillis() - start);
+ }
+ }
+ } finally {
+ if (perm != null) {
+ perm.restoreSecurityManager();
+ }
+ if (savedOut != null) {
+ System.setOut(savedOut);
+ }
+ if (savedErr != null) {
+ System.setErr(savedErr);
+ }
+
+ systemError.close();
+ systemError = null;
+ systemOut.close();
+ systemOut = null;
+ if (startTestSuiteSuccess) {
+ String out, err;
+ try {
+ out = new String(outStrm.toByteArray());
+ } catch (final OutOfMemoryError ex) {
+ out = "out of memory on output stream";
+ }
+ try {
+ err = new String(errStrm.toByteArray());
+ } catch (final OutOfMemoryError ex) {
+ err = "out of memory on error stream";
+ }
+ sendOutAndErr(out, err);
+ }
+ }
+ fireEndTestSuite();
+
+ // junitTest has the correct counts for JUnit4, while res doesn't
+ if (retCode != SUCCESS || junitTest.errorCount() != 0) {
+ retCode = ERRORS;
+ } else if (junitTest.failureCount() != 0) {
+ retCode = FAILURES;
+ }
+ }
+
+ private static boolean containsTests(final Class<?> testClass, final boolean isJUnit4) {
+ Class testAnnotation = null;
+ Class suiteAnnotation = null;
+ Class runWithAnnotation = null;
+
+ try {
+ testAnnotation = Class.forName("org.junit.Test");
+ } catch (final ClassNotFoundException e) {
+ if (isJUnit4) {
+ // odd - we think we're JUnit4 but don't support the test annotation. We therefore can't have any tests!
+ return false;
+ }
+ // else... we're a JUnit3 test and don't need the annotation
+ }
+
+ try {
+ suiteAnnotation = Class.forName("org.junit.Suite.SuiteClasses");
+ } catch(final ClassNotFoundException ex) {
+ // ignore - we don't have this annotation so make sure we don't check for it
+ }
+ try {
+ runWithAnnotation = Class.forName("org.junit.runner.RunWith");
+ } catch(final ClassNotFoundException ex) {
+ // also ignore as this annotation doesn't exist so tests can't use it
+ }
+
+
+ if (!isJUnit4 && !TestCase.class.isAssignableFrom(testClass)) {
+ //a test we think is JUnit3 but does not extend TestCase. Can't really be a test.
+ return false;
+ }
+
+ // check if we have any inner classes that contain suitable test methods
+ for (final Class<?> innerClass : testClass.getDeclaredClasses()) {
+ if (containsTests(innerClass, isJUnit4) || containsTests(innerClass, !isJUnit4)) {
+ return true;
+ }
+ }
+
+ if (Modifier.isAbstract(testClass.getModifiers()) || Modifier.isInterface(testClass.getModifiers())) {
+ // can't instantiate class and no inner classes are tests either
+ return false;
+ }
+
+ if (isJUnit4) {
+ if (suiteAnnotation != null && testClass.getAnnotation(suiteAnnotation) != null) {
+ // class is marked as a suite. Let JUnit try and work its magic on it.
+ return true;
+ }
+ if (runWithAnnotation != null && testClass.getAnnotation(runWithAnnotation) != null) {
+ /* Class is marked with @RunWith. If this class is badly written (no test methods, multiple
+ * constructors, private constructor etc) then the class is automatically run and fails in the
+ * IDEs I've tried... so I'm happy handing the class to JUnit to try and run, and let JUnit
+ * report a failure if a bad test case is provided. Trying to do anything else is likely to
+ * result in us filtering out cases that could be valid for future versions of JUnit so would
+ * just increase future maintenance work.
+ */
+ return true;
+ }
+ }
+
+ for (final Method m : testClass.getMethods()) {
+ if (isJUnit4) {
+ // check if suspected JUnit4 classes have methods with @Test annotation
+ if (m.getAnnotation(testAnnotation) != null) {
+ return true;
+ }
+ } else {
+ // check if JUnit3 class have public or protected no-args methods starting with names starting with test
+ if (m.getName().startsWith("test") && m.getParameterTypes().length == 0
+ && (Modifier.isProtected(m.getModifiers()) || Modifier.isPublic(m.getModifiers()))) {
+ return true;
+ }
+ }
+ // check if JUnit3 or JUnit4 test have a public or protected, static,
+ // no-args 'suite' method
+ if (m.getName().equals("suite") && m.getParameterTypes().length == 0
+ && (Modifier.isProtected(m.getModifiers()) || Modifier.isPublic(m.getModifiers()))
+ && Modifier.isStatic(m.getModifiers())) {
+ return true;
+ }
+ }
+
+ // no test methods found
+ return false;
+ }
+
+ /**
+ * Returns what System.exit() would return in the standalone version.
+ *
+ * @return 2 if errors occurred, 1 if tests failed else 0.
+ */
+ public int getRetCode() {
+ return retCode;
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A new Test is started.
+ * @param t the test.
+ */
+ public void startTest(final Test t) {
+ final String testName = JUnitVersionHelper.getTestCaseName(t);
+ logTestListenerEvent("startTest(" + testName + ")");
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A Test is finished.
+ * @param test the test.
+ */
+ public void endTest(final Test test) {
+ final String testName = JUnitVersionHelper.getTestCaseName(test);
+ logTestListenerEvent("endTest(" + testName + ")");
+ }
+
+ private void logTestListenerEvent(String msg) {
+ if (logTestListenerEvents) {
+ final PrintStream out = savedOut != null ? savedOut : System.out;
+ out.flush();
+ if (msg == null) {
+ msg = "null";
+ }
+ final StringTokenizer msgLines = new StringTokenizer(msg, "\r\n", false);
+ while (msgLines.hasMoreTokens()) {
+ out.println(JUnitTask.TESTLISTENER_PREFIX
+ + msgLines.nextToken());
+ }
+ out.flush();
+ }
+ }
+
+ /**
+ * Interface TestListener for JUnit &lt;= 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the exception thrown by the test.
+ */
+ public void addFailure(final Test test, final Throwable t) {
+ final String testName = JUnitVersionHelper.getTestCaseName(test);
+ logTestListenerEvent("addFailure(" + testName + ", " + t.getMessage() + ")");
+ if (haltOnFailure) {
+ res.stop();
+ }
+ }
+
+ /**
+ * Interface TestListener for JUnit &gt; 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the assertion thrown by the test.
+ */
+ public void addFailure(final Test test, final AssertionFailedError t) {
+ addFailure(test, (Throwable) t);
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>An error occurred while running the test.
+ * @param test the test.
+ * @param t the error thrown by the test.
+ */
+ public void addError(final Test test, final Throwable t) {
+ final String testName = JUnitVersionHelper.getTestCaseName(test);
+ logTestListenerEvent("addError(" + testName + ", " + t.getMessage() + ")");
+ if (haltOnError) {
+ res.stop();
+ }
+ }
+
+ /**
+ * Permissions for the test run.
+ * @since Ant 1.6
+ * @param permissions the permissions to use.
+ */
+ public void setPermissions(final Permissions permissions) {
+ perm = permissions;
+ }
+
+ /**
+ * Handle a string destined for standard output.
+ * @param output the string to output
+ */
+ public void handleOutput(final String output) {
+ if (!logTestListenerEvents && output.startsWith(JUnitTask.TESTLISTENER_PREFIX)) {
+ // ignore
+ } else if (systemOut != null) {
+ systemOut.print(output);
+ }
+ }
+
+ /**
+ * Handle input.
+ * @param buffer not used.
+ * @param offset not used.
+ * @param length not used.
+ * @return -1 always.
+ * @throws IOException never.
+ * @see org.apache.tools.ant.Task#handleInput(byte[], int, int)
+ *
+ * @since Ant 1.6
+ */
+ public int handleInput(final byte[] buffer, final int offset, final int length)
+ throws IOException {
+ return -1;
+ }
+
+ /** {@inheritDoc}. */
+ public void handleErrorOutput(final String output) {
+ if (systemError != null) {
+ systemError.print(output);
+ }
+ }
+
+ /** {@inheritDoc}. */
+ public void handleFlush(final String output) {
+ if (systemOut != null) {
+ systemOut.print(output);
+ }
+ }
+
+ /** {@inheritDoc}. */
+ public void handleErrorFlush(final String output) {
+ if (systemError != null) {
+ systemError.print(output);
+ }
+ }
+
+ private void sendOutAndErr(final String out, final String err) {
+ final int size = formatters.size();
+ for (int i = 0; i < size; i++) {
+ final JUnitResultFormatter formatter =
+ ((JUnitResultFormatter) formatters.elementAt(i));
+
+ formatter.setSystemOutput(out);
+ formatter.setSystemError(err);
+ }
+ }
+
+ private void fireStartTestSuite() {
+ final int size = formatters.size();
+ for (int i = 0; i < size; i++) {
+ ((JUnitResultFormatter) formatters.elementAt(i))
+ .startTestSuite(junitTest);
+ }
+ }
+
+ private void fireEndTestSuite() {
+ final int size = formatters.size();
+ for (int i = 0; i < size; i++) {
+ ((JUnitResultFormatter) formatters.elementAt(i))
+ .endTestSuite(junitTest);
+ }
+ }
+
+ /**
+ * Add a formatter.
+ * @param f the formatter to add.
+ */
+ public void addFormatter(final JUnitResultFormatter f) {
+ formatters.addElement(f);
+ }
+
+ /** {@inheritDoc}. */
+ public void addFormatter(final JUnitTaskMirror.JUnitResultFormatterMirror f) {
+ formatters.addElement(f);
+ }
+
+ /**
+ * Entry point for standalone (forked) mode.
+ *
+ * Parameters: testcaseclassname plus parameters in the format
+ * key=value, none of which is required.
+ *
+ * <table cols="4" border="1">
+ * <tr><th>key</th><th>description</th><th>default value</th></tr>
+ *
+ * <tr><td>haltOnError</td><td>halt test on
+ * errors?</td><td>false</td></tr>
+ *
+ * <tr><td>haltOnFailure</td><td>halt test on
+ * failures?</td><td>false</td></tr>
+ *
+ * <tr><td>formatter</td><td>A JUnitResultFormatter given as
+ * classname,filename. If filename is omitted, System.out is
+ * assumed.</td><td>none</td></tr>
+ *
+ * <tr><td>showoutput</td><td>send output to System.err/.out as
+ * well as to the formatters?</td><td>false</td></tr>
+ *
+ * <tr><td>logtestlistenerevents</td><td>log TestListener events to
+ * System.out.</td><td>false</td></tr>
+ *
+ * <tr><td>methods</td><td>Comma-separated list of names of individual
+ * test methods to execute.
+ * </td><td>null</td></tr>
+ *
+ * </table>
+ * @param args the command line arguments.
+ * @throws IOException on error.
+ */
+ public static void main(final String[] args) throws IOException {
+ String[] methods = null;
+ boolean haltError = false;
+ boolean haltFail = false;
+ boolean stackfilter = true;
+ final Properties props = new Properties();
+ boolean showOut = false;
+ boolean outputToFormat = true;
+ boolean logFailedTests = true;
+ boolean logTestListenerEvents = false;
+ boolean skipNonTests = false;
+ int antThreadID = 0; /* Ant id of thread running this unit test, 0 in single-threaded mode */
+
+ if (args.length == 0) {
+ System.err.println("required argument TestClassName missing");
+ System.exit(ERRORS);
+ }
+
+ if (args[0].startsWith(Constants.TESTSFILE)) {
+ multipleTests = true;
+ args[0] = args[0].substring(Constants.TESTSFILE.length());
+ }
+
+ for (int i = 1; i < args.length; i++) {
+ if (args[i].startsWith(Constants.METHOD_NAMES)) {
+ try {
+ final String methodsList = args[i].substring(Constants.METHOD_NAMES.length());
+ methods = JUnitTest.parseTestMethodNamesList(methodsList);
+ } catch (final IllegalArgumentException ex) {
+ System.err.println("Invalid specification of test method names: " + args[i]);
+ System.exit(ERRORS);
+ }
+ } else if (args[i].startsWith(Constants.HALT_ON_ERROR)) {
+ haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length()));
+ } else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) {
+ haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length()));
+ } else if (args[i].startsWith(Constants.FILTERTRACE)) {
+ stackfilter = Project.toBoolean(args[i].substring(Constants.FILTERTRACE.length()));
+ } else if (args[i].startsWith(Constants.CRASHFILE)) {
+ crashFile = args[i].substring(Constants.CRASHFILE.length());
+ registerTestCase(Constants.BEFORE_FIRST_TEST);
+ } else if (args[i].startsWith(Constants.FORMATTER)) {
+ try {
+ createAndStoreFormatter(args[i].substring(Constants.FORMATTER.length()));
+ } catch (final BuildException be) {
+ System.err.println(be.getMessage());
+ System.exit(ERRORS);
+ }
+ } else if (args[i].startsWith(Constants.PROPSFILE)) {
+ final FileInputStream in = new FileInputStream(args[i]
+ .substring(Constants.PROPSFILE.length()));
+ props.load(in);
+ in.close();
+ } else if (args[i].startsWith(Constants.SHOWOUTPUT)) {
+ showOut = Project.toBoolean(args[i].substring(Constants.SHOWOUTPUT.length()));
+ } else if (args[i].startsWith(Constants.LOGTESTLISTENEREVENTS)) {
+ logTestListenerEvents = Project.toBoolean(
+ args[i].substring(Constants.LOGTESTLISTENEREVENTS.length()));
+ } else if (args[i].startsWith(Constants.OUTPUT_TO_FORMATTERS)) {
+ outputToFormat = Project.toBoolean(
+ args[i].substring(Constants.OUTPUT_TO_FORMATTERS.length()));
+ } else if (args[i].startsWith(Constants.LOG_FAILED_TESTS)) {
+ logFailedTests = Project.toBoolean(
+ args[i].substring(Constants.LOG_FAILED_TESTS.length()));
+ } else if (args[i].startsWith(Constants.SKIP_NON_TESTS)) {
+ skipNonTests = Project.toBoolean(
+ args[i].substring(Constants.SKIP_NON_TESTS.length()));
+ } else if (args[i].startsWith(Constants.THREADID)) {
+ antThreadID = Integer.parseInt(args[i].substring(Constants.THREADID.length()));
+ }
+ }
+
+ // Add/overlay system properties on the properties from the Ant project
+ final Hashtable p = System.getProperties();
+ for (final Enumeration e = p.keys(); e.hasMoreElements();) {
+ final Object key = e.nextElement();
+ props.put(key, p.get(key));
+ }
+
+ int returnCode = SUCCESS;
+ if (multipleTests) {
+ try {
+ final java.io.BufferedReader reader =
+ new java.io.BufferedReader(new java.io.FileReader(args[0]));
+ String testCaseName;
+ String[] testMethodNames;
+ int code = 0;
+ boolean errorOccurred = false;
+ boolean failureOccurred = false;
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ final StringTokenizer st = new StringTokenizer(line, ",");
+ final String testListSpec = st.nextToken();
+ final int colonIndex = testListSpec.indexOf(':');
+ if (colonIndex == -1) {
+ testCaseName = testListSpec;
+ testMethodNames = null;
+ } else {
+ testCaseName = testListSpec.substring(0, colonIndex);
+ testMethodNames = JUnitTest.parseTestMethodNamesList(
+ testListSpec
+ .substring(colonIndex + 1)
+ .replace('+', ','));
+ }
+ final JUnitTest t = new JUnitTest(testCaseName);
+ t.setTodir(new File(st.nextToken()));
+ t.setOutfile(st.nextToken());
+ t.setProperties(props);
+ t.setSkipNonTests(skipNonTests);
+ t.setThread(antThreadID);
+ code = launch(t, testMethodNames, haltError, stackfilter, haltFail,
+ showOut, outputToFormat,
+ logTestListenerEvents);
+ errorOccurred = (code == ERRORS);
+ failureOccurred = (code != SUCCESS);
+ if (errorOccurred || failureOccurred) {
+ if ((errorOccurred && haltError)
+ || (failureOccurred && haltFail)) {
+ registerNonCrash();
+ System.exit(code);
+ } else {
+ if (code > returnCode) {
+ returnCode = code;
+ }
+ if (logFailedTests) {
+ System.out.println("TEST " + t.getName()
+ + " FAILED");
+ }
+ }
+ }
+ }
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ final JUnitTest t = new JUnitTest(args[0]);
+ t.setThread(antThreadID);
+ t.setProperties(props);
+ t.setSkipNonTests(skipNonTests);
+ returnCode = launch(
+ t, methods, haltError, stackfilter, haltFail,
+ showOut, outputToFormat, logTestListenerEvents);
+ }
+
+ registerNonCrash();
+ System.exit(returnCode);
+ }
+
+ private static Vector fromCmdLine = new Vector();
+
+ private static void transferFormatters(final JUnitTestRunner runner,
+ final JUnitTest test) {
+ runner.addFormatter(new JUnitResultFormatter() {
+
+ public void startTestSuite(final JUnitTest suite) throws BuildException {
+ }
+
+ public void endTestSuite(final JUnitTest suite) throws BuildException {
+ }
+
+ public void setOutput(final OutputStream out) {
+ }
+
+ public void setSystemOutput(final String out) {
+ }
+
+ public void setSystemError(final String err) {
+ }
+
+ public void addError(final Test arg0, final Throwable arg1) {
+ }
+
+ public void addFailure(final Test arg0, final AssertionFailedError arg1) {
+ }
+
+ public void endTest(final Test arg0) {
+ }
+
+ public void startTest(final Test arg0) {
+ registerTestCase(JUnitVersionHelper.getTestCaseName(arg0));
+ }
+ });
+ final int size = fromCmdLine.size();
+ for (int i = 0; i < size; i++) {
+ final FormatterElement fe = (FormatterElement) fromCmdLine.elementAt(i);
+ if (multipleTests && fe.getUseFile()) {
+ final File destFile =
+ new File(test.getTodir(),
+ test.getOutfile() + fe.getExtension());
+ fe.setOutfile(destFile);
+ }
+ runner.addFormatter((JUnitResultFormatter) fe.createFormatter());
+ }
+ }
+
+ /**
+ * Line format is: formatter=<classname>(,<pathname>)?
+ */
+ private static void createAndStoreFormatter(final String line)
+ throws BuildException {
+ final FormatterElement fe = new FormatterElement();
+ final int pos = line.indexOf(',');
+ if (pos == -1) {
+ fe.setClassname(line);
+ fe.setUseFile(false);
+ } else {
+ fe.setClassname(line.substring(0, pos));
+ fe.setUseFile(true);
+ if (!multipleTests) {
+ fe.setOutfile(new File(line.substring(pos + 1)));
+ } else {
+ final int fName = line.indexOf(IGNORED_FILE_NAME);
+ if (fName > -1) {
+ fe.setExtension(line
+ .substring(fName
+ + IGNORED_FILE_NAME.length()));
+ }
+ }
+ }
+ fromCmdLine.addElement(fe);
+ }
+
+ /**
+ * Returns a filtered stack trace.
+ * This is ripped out of junit.runner.BaseTestRunner.
+ * @param t the exception to filter.
+ * @return the filtered stack trace.
+ */
+ public static String getFilteredTrace(final Throwable t) {
+ final String trace = StringUtils.getStackTrace(t);
+ return JUnitTestRunner.filterStack(trace);
+ }
+
+ /**
+ * Filters stack frames from internal JUnit and Ant classes
+ * @param stack the stack trace to filter.
+ * @return the filtered stack.
+ */
+ public static String filterStack(final String stack) {
+ if (!filtertrace) {
+ return stack;
+ }
+ final StringWriter sw = new StringWriter();
+ final BufferedWriter pw = new BufferedWriter(sw);
+ final StringReader sr = new StringReader(stack);
+ final BufferedReader br = new BufferedReader(sr);
+
+ String line;
+ try {
+ boolean firstLine = true;
+ while ((line = br.readLine()) != null) {
+ if (firstLine || !filterLine(line)) {
+ pw.write(line);
+ pw.newLine();
+ }
+ firstLine = false;
+ }
+ } catch (final Exception e) {
+ return stack; // return the stack unfiltered
+ } finally {
+ FileUtils.close(pw);
+ }
+ return sw.toString();
+ }
+
+ private static boolean filterLine(final String line) {
+ for (int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++) {
+ if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @since Ant 1.6.2
+ */
+ private static int launch(final JUnitTest t, final String[] methods, final boolean haltError,
+ final boolean stackfilter, final boolean haltFail,
+ final boolean showOut, final boolean outputToFormat,
+ final boolean logTestListenerEvents) {
+ final JUnitTestRunner runner =
+ new JUnitTestRunner(t, methods, haltError, stackfilter, haltFail, showOut,
+ logTestListenerEvents, null);
+ runner.forked = true;
+ runner.outputToFormatters = outputToFormat;
+ transferFormatters(runner, t);
+
+ runner.run();
+ return runner.getRetCode();
+ }
+
+ /**
+ * @since Ant 1.7
+ */
+ private static void registerNonCrash()
+ throws IOException {
+ if (crashFile != null) {
+ FileWriter out = null;
+ try {
+ out = new FileWriter(crashFile);
+ out.write(Constants.TERMINATED_SUCCESSFULLY + "\n");
+ out.flush();
+ } finally {
+ FileUtils.close(out);
+ }
+ }
+ }
+
+ private static void registerTestCase(final String testCase) {
+ if (crashFile != null) {
+ try {
+ FileWriter out = null;
+ try {
+ out = new FileWriter(crashFile);
+ out.write(testCase + "\n");
+ out.flush();
+ } finally {
+ FileUtils.close(out);
+ }
+ } catch (final IOException e) {
+ // ignored.
+ }
+ }
+ }
+
+ /**
+ * Modifies a TestListener when running JUnit 4: treats AssertionFailedError
+ * as a failure not an error.
+ *
+ * @since Ant 1.7
+ */
+ private TestListenerWrapper wrapListener(final TestListener testListener) {
+ return new TestListenerWrapper(testListener) {
+ @Override
+ public void addError(final Test test, final Throwable t) {
+ if (junit4 && t instanceof AssertionFailedError) {
+ // JUnit 4 does not distinguish between errors and failures
+ // even in the JUnit 3 adapter.
+ // So we need to help it a bit to retain compatibility for JUnit 3 tests.
+ testListener.addFailure(test, (AssertionFailedError) t);
+ } else if (junit4 && t instanceof AssertionError) {
+ // Not strictly necessary but probably desirable.
+ // JUnit 4-specific test GUIs will show just "failures".
+ // But Ant's output shows "failures" vs. "errors".
+ // We would prefer to show "failure" for things that logically are.
+ final String msg = t.getMessage();
+ final AssertionFailedError failure = msg != null
+ ? new AssertionFailedError(msg) : new AssertionFailedError();
+ failure.setStackTrace(t.getStackTrace());
+ testListener.addFailure(test, failure);
+ } else {
+ testListener.addError(test, t);
+ }
+ }
+ @Override
+ public void addFailure(final Test test, final AssertionFailedError t) {
+ testListener.addFailure(test, t);
+ }
+ public void addFailure(final Test test, final Throwable t) { // pre-3.4
+ if (t instanceof AssertionFailedError) {
+ testListener.addFailure(test, (AssertionFailedError) t);
+ } else {
+ testListener.addError(test, t);
+ }
+ }
+ @Override
+ public void endTest(final Test test) {
+ testListener.endTest(test);
+ }
+ @Override
+ public void startTest(final Test test) {
+ testListener.startTest(test);
+ }
+ };
+ }
+
+ /**
+ * Use instead of TestResult.get{Failure,Error}Count on JUnit 4,
+ * since the adapter claims that all failures are errors.
+ * @since Ant 1.7
+ */
+ private int[] findJUnit4FailureErrorCount(final TestResult result) {
+ int failures = 0;
+ int errors = 0;
+ Enumeration e = result.failures();
+ while (e.hasMoreElements()) {
+ e.nextElement();
+ failures++;
+ }
+ e = result.errors();
+ while (e.hasMoreElements()) {
+ final Throwable t = ((TestFailure) e.nextElement()).thrownException();
+ if (t instanceof AssertionFailedError
+ || t instanceof AssertionError) {
+ failures++;
+ } else {
+ errors++;
+ }
+ }
+ return new int[] {failures, errors};
+ }
+
+} // JUnitTestRunner
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
new file mode 100644
index 00000000..9a21caee
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Work around for some changes to the public JUnit API between
+ * different JUnit releases.
+ * @since Ant 1.7
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class JUnitVersionHelper {
+
+ private static Method testCaseName = null;
+
+ /**
+ * Name of the JUnit4 class we look for.
+ * {@value}
+ * @since Ant 1.7.1
+ */
+ public static final String JUNIT_FRAMEWORK_JUNIT4_TEST_CASE_FACADE
+ = "junit.framework.JUnit4TestCaseFacade";
+ private static final String UNKNOWN_TEST_CASE_NAME = "unknown";
+
+ static {
+ try {
+ testCaseName = TestCase.class.getMethod("getName", new Class[0]);
+ } catch (NoSuchMethodException e) {
+ // pre JUnit 3.7
+ try {
+ testCaseName = TestCase.class.getMethod("name", new Class[0]);
+ } catch (NoSuchMethodException ignored) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * JUnit 3.7 introduces TestCase.getName() and subsequent versions
+ * of JUnit remove the old name() method. This method provides
+ * access to the name of a TestCase via reflection that is
+ * supposed to work with version before and after JUnit 3.7.
+ *
+ * <p>since Ant 1.5.1 this method will invoke &quot;<code>public
+ * String getName()</code>&quot; on any implementation of Test if
+ * it exists.</p>
+ *
+ * <p>Since Ant 1.7 also checks for JUnit4TestCaseFacade explicitly.
+ * This is used by junit.framework.JUnit4TestAdapter.</p>
+ * @param t the test.
+ * @return the name of the test.
+ */
+ public static String getTestCaseName(Test t) {
+ if (t == null) {
+ return UNKNOWN_TEST_CASE_NAME;
+ }
+ if (t.getClass().getName().equals(JUNIT_FRAMEWORK_JUNIT4_TEST_CASE_FACADE)) {
+ // Self-describing as of JUnit 4 (#38811). But trim "(ClassName)".
+ String name = t.toString();
+ if (name.endsWith(")")) {
+ int paren = name.lastIndexOf('(');
+ return name.substring(0, paren);
+ } else {
+ return name;
+ }
+ }
+ if (t instanceof TestCase && testCaseName != null) {
+ try {
+ return (String) testCaseName.invoke(t, new Object[0]);
+ } catch (Throwable ignored) {
+ // ignore
+ }
+ } else {
+ try {
+ Method getNameMethod = null;
+ try {
+ getNameMethod =
+ t.getClass().getMethod("getName", new Class [0]);
+ } catch (NoSuchMethodException e) {
+ getNameMethod = t.getClass().getMethod("name",
+ new Class [0]);
+ }
+ if (getNameMethod != null
+ && getNameMethod.getReturnType() == String.class) {
+ return (String) getNameMethod.invoke(t, new Object[0]);
+ }
+ } catch (Throwable ignored) {
+ // ignore
+ }
+ }
+ return UNKNOWN_TEST_CASE_NAME;
+ }
+
+ /**
+ * Tries to find the name of the class which a test represents
+ * across JUnit 3 and 4. For JUnit4 it parses the toString() value of the
+ * test, and extracts it from there.
+ * @since Ant 1.7.1 (it was private until then)
+ * @param test test case to look at
+ * @return the extracted class name.
+ */
+ public static String getTestCaseClassName(Test test) {
+ String className = test.getClass().getName();
+ if (test instanceof JUnitTaskMirrorImpl.VmExitErrorTest) {
+ className = ((JUnitTaskMirrorImpl.VmExitErrorTest) test).getClassName();
+ } else
+ if (className.equals(JUNIT_FRAMEWORK_JUNIT4_TEST_CASE_FACADE)) {
+ // JUnit 4 wraps solo tests this way. We can extract
+ // the original test name with a little hack.
+ String name = test.toString();
+ int paren = name.lastIndexOf('(');
+ if (paren != -1 && name.endsWith(")")) {
+ className = name.substring(paren + 1, name.length() - 1);
+ }
+ }
+ return className;
+ }
+
+ public static String getIgnoreMessage(Test test) {
+ String message = null;
+
+ try {
+ Class<?> junit4FacadeClass = Class.forName("junit.framework.JUnit4TestCaseFacade");
+ if (test != null && test.getClass().isAssignableFrom(junit4FacadeClass)) {
+ //try and get the message coded as part of the ignore
+ /*
+ * org.junit.runner.Description contains a getAnnotation(Class) method... but this
+ * wasn't in older versions of JUnit4 so we have to try and do this by reflection
+ */
+ Class<?> testClass = Class.forName(JUnitVersionHelper.getTestCaseClassName(test));
+
+ Method testMethod = testClass.getMethod(JUnitVersionHelper.getTestCaseName(test));
+ Class ignoreAnnotation = Class.forName("org.junit.Ignore");
+ Annotation annotation = testMethod.getAnnotation(ignoreAnnotation);
+ if (annotation != null) {
+ Method valueMethod = annotation.getClass().getMethod("value");
+ String value = (String) valueMethod.invoke(annotation);
+ if (value != null && value.length() > 0) {
+ message = value;
+ }
+ }
+
+ }
+ } catch (NoSuchMethodException e) {
+ // silently ignore - we'll report a skip with no message
+ } catch (ClassNotFoundException e) {
+ // silently ignore - we'll report a skip with no message
+ } catch (InvocationTargetException e) {
+ // silently ignore - we'll report a skip with no message
+ } catch (IllegalAccessException e) {
+ // silently ignore - we'll report a skip with no message
+ }
+ return message;
+
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java
new file mode 100644
index 00000000..e0dc16c3
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+/**
+ * Used instead of SummaryJUnitResultFormatter in forked tests if
+ * withOutAndErr is requested.
+ */
+
+public class OutErrSummaryJUnitResultFormatter
+ extends SummaryJUnitResultFormatter {
+
+ /**
+ * Empty
+ */
+ public OutErrSummaryJUnitResultFormatter() {
+ super();
+ setWithOutAndErr(true);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java
new file mode 100644
index 00000000..3386ee50
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+import java.util.Hashtable;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+
+/**
+ * Prints plain text output of the test to a specified Writer.
+ *
+ */
+
+public class PlainJUnitResultFormatter implements JUnitResultFormatter, IgnoredTestListener {
+
+ private static final double ONE_SECOND = 1000.0;
+
+ /**
+ * Formatter for timings.
+ */
+ private NumberFormat nf = NumberFormat.getInstance();
+ /**
+ * Timing helper.
+ */
+ private Hashtable testStarts = new Hashtable();
+ /**
+ * Where to write the log to.
+ */
+ private OutputStream out;
+ /**
+ * Helper to store intermediate output.
+ */
+ private StringWriter inner;
+ /**
+ * Convenience layer on top of {@link #inner inner}.
+ */
+ private BufferedWriter wri;
+ /**
+ * Suppress endTest if testcase failed.
+ */
+ private Hashtable failed = new Hashtable();
+
+ private String systemOutput = null;
+ private String systemError = null;
+
+ /** No arg constructor */
+ public PlainJUnitResultFormatter() {
+ inner = new StringWriter();
+ wri = new BufferedWriter(inner);
+ }
+
+ /** {@inheritDoc}. */
+ public void setOutput(OutputStream out) {
+ this.out = out;
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemOutput(String out) {
+ systemOutput = out;
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemError(String err) {
+ systemError = err;
+ }
+
+ /**
+ * The whole testsuite started.
+ * @param suite the test suite
+ * @throws BuildException if unable to write the output
+ */
+ public void startTestSuite(JUnitTest suite) throws BuildException {
+ if (out == null) {
+ return; // Quick return - no output do nothing.
+ }
+ StringBuffer sb = new StringBuffer("Testsuite: ");
+ sb.append(suite.getName());
+ sb.append(StringUtils.LINE_SEP);
+ try {
+ out.write(sb.toString().getBytes());
+ out.flush();
+ } catch (IOException ex) {
+ throw new BuildException("Unable to write output", ex);
+ }
+ }
+
+ /**
+ * The whole testsuite ended.
+ * @param suite the test suite
+ * @throws BuildException if unable to write the output
+ */
+ public void endTestSuite(JUnitTest suite) throws BuildException {
+ try {
+ StringBuffer sb = new StringBuffer("Tests run: ");
+ sb.append(suite.runCount());
+ sb.append(", Failures: ");
+ sb.append(suite.failureCount());
+ sb.append(", Errors: ");
+ sb.append(suite.errorCount());
+ sb.append(", Skipped: ");
+ sb.append(suite.skipCount());
+ sb.append(", Time elapsed: ");
+ sb.append(nf.format(suite.getRunTime() / ONE_SECOND));
+ sb.append(" sec");
+ sb.append(StringUtils.LINE_SEP);
+ write(sb.toString());
+
+ // write the err and output streams to the log
+ if (systemOutput != null && systemOutput.length() > 0) {
+ write("------------- Standard Output ---------------");
+ write(StringUtils.LINE_SEP);
+ write(systemOutput);
+ write("------------- ---------------- ---------------");
+ write(StringUtils.LINE_SEP);
+ }
+
+ if (systemError != null && systemError.length() > 0) {
+ write("------------- Standard Error -----------------");
+ write(StringUtils.LINE_SEP);
+ write(systemError);
+ write("------------- ---------------- ---------------");
+ write(StringUtils.LINE_SEP);
+ }
+
+ write(StringUtils.LINE_SEP);
+ if (out != null) {
+ try {
+ wri.flush();
+ write(inner.toString());
+ } catch (IOException ioex) {
+ throw new BuildException("Unable to write output", ioex);
+ }
+ }
+ } finally {
+ if (out != null) {
+ try {
+ wri.close();
+ } catch (IOException ioex) {
+ throw new BuildException("Unable to flush output", ioex);
+ } finally {
+ if (out != System.out && out != System.err) {
+ FileUtils.close(out);
+ }
+ wri = null;
+ out = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A new Test is started.
+ * @param t the test.
+ */
+ public void startTest(Test t) {
+ testStarts.put(t, new Long(System.currentTimeMillis()));
+ failed.put(t, Boolean.FALSE);
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A Test is finished.
+ * @param test the test.
+ */
+ public void endTest(Test test) {
+ if (Boolean.TRUE.equals(failed.get(test))) {
+ return;
+ }
+ synchronized (wri) {
+ try {
+ wri.write("Testcase: "
+ + JUnitVersionHelper.getTestCaseName(test));
+ Long l = (Long) testStarts.get(test);
+ double seconds = 0;
+ // can be null if an error occurred in setUp
+ if (l != null) {
+ seconds =
+ (System.currentTimeMillis() - l.longValue()) / ONE_SECOND;
+ }
+
+ wri.write(" took " + nf.format(seconds) + " sec");
+ wri.newLine();
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ }
+ }
+ }
+
+ /**
+ * Interface TestListener for JUnit &lt;= 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the exception.
+ */
+ public void addFailure(Test test, Throwable t) {
+ formatError("\tFAILED", test, t);
+ }
+
+ /**
+ * Interface TestListener for JUnit &gt; 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the assertion that failed.
+ */
+ public void addFailure(Test test, AssertionFailedError t) {
+ addFailure(test, (Throwable) t);
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>An error occurred while running the test.
+ * @param test the test.
+ * @param t the exception.
+ */
+ public void addError(Test test, Throwable t) {
+ formatError("\tCaused an ERROR", test, t);
+ }
+
+ private void formatError(String type, Test test, Throwable t) {
+ synchronized (wri) {
+ if (test != null) {
+ endTest(test);
+ failed.put(test, Boolean.TRUE);
+ }
+
+ try {
+ wri.write(type);
+ wri.newLine();
+ wri.write(String.valueOf(t.getMessage()));
+ wri.newLine();
+ String strace = JUnitTestRunner.getFilteredTrace(t);
+ wri.write(strace);
+ wri.newLine();
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ }
+ }
+ }
+
+ public void testIgnored(Test test) {
+ formatSkip(test, JUnitVersionHelper.getIgnoreMessage(test));
+ }
+
+
+ public void formatSkip(Test test, String message) {
+ if (test != null) {
+ endTest(test);
+ }
+
+ try {
+ wri.write("\tSKIPPED");
+ if (message != null) {
+ wri.write(": ");
+ wri.write(message);
+ }
+ wri.newLine();
+ } catch (IOException ex) {
+ throw new BuildException(ex);
+ }
+
+ }
+
+ public void testAssumptionFailure(Test test, Throwable throwable) {
+ formatSkip(test, throwable.getMessage());
+ }
+
+ /**
+ * Print out some text, and flush the output stream; encoding in the platform
+ * local default encoding.
+ * @param text text to write.
+ * @throws BuildException on IO Problems.
+ */
+ private void write(String text) {
+ if (out == null) {
+ return;
+ }
+ try {
+ out.write(text.getBytes());
+ out.flush();
+ } catch (IOException ex) {
+ throw new BuildException("Unable to write output " + ex, ex);
+ }
+ }
+} // PlainJUnitResultFormatter
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java
new file mode 100644
index 00000000..0b09fa20
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.NumberFormat;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Prints short summary output of the test to Ant's logging system.
+ *
+ */
+
+public class SummaryJUnitResultFormatter
+ implements JUnitResultFormatter, JUnitTaskMirror.SummaryJUnitResultFormatterMirror {
+
+ private static final double ONE_SECOND = 1000.0;
+
+ /**
+ * Formatter for timings.
+ */
+ private NumberFormat nf = NumberFormat.getInstance();
+ /**
+ * OutputStream to write to.
+ */
+ private OutputStream out;
+
+ private boolean withOutAndErr = false;
+ private String systemOutput = null;
+ private String systemError = null;
+
+ /**
+ * Empty
+ */
+ public SummaryJUnitResultFormatter() {
+ }
+
+ /**
+ * Insures that a line of log output is written and flushed as a single
+ * operation, to prevent lines from being spliced into other lines.
+ * (Hopefully this solves the issue of run on lines -
+ * [junit] Tests Run: 2 Failures: 2 [junit] Tests run: 5...
+ * synchronized doesn't seem to be to harsh a penalty since it only
+ * occurs twice per test - at the beginning and end. Note that message
+ * construction occurs outside the locked block.
+ *
+ * @param b data to be written as an unbroken block
+ */
+ private synchronized void writeOutputLine(byte[] b) {
+ try {
+ out.write(b);
+ out.flush();
+ } catch (IOException ioex) {
+ throw new BuildException("Unable to write summary output", ioex);
+ }
+ }
+
+ /**
+ * The testsuite started.
+ * @param suite the testsuite.
+ */
+ public void startTestSuite(JUnitTest suite) {
+ String newLine = System.getProperty("line.separator");
+ StringBuffer sb = new StringBuffer("Running ");
+ int antThreadID = suite.getThread();
+
+ sb.append(suite.getName());
+ /* only write thread id in multi-thread mode so default old way doesn't change output */
+ if (antThreadID > 0) {
+ sb.append(" in thread ");
+ sb.append(antThreadID);
+ }
+ sb.append(newLine);
+ writeOutputLine(sb.toString().getBytes());
+ }
+ /**
+ * Empty
+ * @param t not used.
+ */
+ public void startTest(Test t) {
+ }
+ /**
+ * Empty
+ * @param test not used.
+ */
+ public void endTest(Test test) {
+ }
+ /**
+ * Empty
+ * @param test not used.
+ * @param t not used.
+ */
+ public void addFailure(Test test, Throwable t) {
+ }
+ /**
+ * Interface TestListener for JUnit &gt; 3.4.
+ *
+ * <p>A Test failed.
+ * @param test not used.
+ * @param t not used.
+ */
+ public void addFailure(Test test, AssertionFailedError t) {
+ addFailure(test, (Throwable) t);
+ }
+ /**
+ * Empty
+ * @param test not used.
+ * @param t not used.
+ */
+ public void addError(Test test, Throwable t) {
+ }
+
+ /** {@inheritDoc}. */
+ public void setOutput(OutputStream out) {
+ this.out = out;
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemOutput(String out) {
+ systemOutput = out;
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemError(String err) {
+ systemError = err;
+ }
+
+ /**
+ * Should the output to System.out and System.err be written to
+ * the summary.
+ * @param value if true write System.out and System.err to the summary.
+ */
+ public void setWithOutAndErr(boolean value) {
+ withOutAndErr = value;
+ }
+
+ /**
+ * The whole testsuite ended.
+ * @param suite the testsuite.
+ * @throws BuildException if there is an error.
+ */
+ public void endTestSuite(JUnitTest suite) throws BuildException {
+ String newLine = System.getProperty("line.separator");
+ StringBuffer sb = new StringBuffer("Tests run: ");
+ sb.append(suite.runCount());
+ sb.append(", Failures: ");
+ sb.append(suite.failureCount());
+ sb.append(", Errors: ");
+ sb.append(suite.errorCount());
+ sb.append(", Skipped: ");
+ sb.append(suite.skipCount());
+ sb.append(", Time elapsed: ");
+ sb.append(nf.format(suite.getRunTime() / ONE_SECOND));
+ sb.append(" sec");
+
+ /* class name needed with multi-threaded execution because
+ results line may not appear immediately below start line.
+ only write thread id, class name in multi-thread mode so
+ the line still looks as much like the old line as possible. */
+ if (suite.getThread() > 0) {
+ sb.append(", Thread: ");
+ sb.append(suite.getThread());
+ sb.append(", Class: ");
+ sb.append(suite.getName());
+ }
+ sb.append(newLine);
+
+ if (withOutAndErr) {
+ if (systemOutput != null && systemOutput.length() > 0) {
+ sb.append("Output:").append(newLine).append(systemOutput)
+ .append(newLine);
+ }
+
+ if (systemError != null && systemError.length() > 0) {
+ sb.append("Error: ").append(newLine).append(systemError)
+ .append(newLine);
+ }
+ }
+
+ try {
+ writeOutputLine(sb.toString().getBytes());
+ } finally {
+ if (out != System.out && out != System.err) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TearDownOnVmCrash.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TearDownOnVmCrash.java
new file mode 100644
index 00000000..e381a70c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TearDownOnVmCrash.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+/**
+ * Formatter that doesn't create any output but tries to invoke the
+ * tearDown method on a testcase if that test was forked and caused a
+ * timeout or VM crash.
+ *
+ * <p>This formatter has some limitations, for details see the
+ * &lt;junit&gt; task's manual.</p>
+ *
+ * @since Ant 1.8.0
+ */
+public class TearDownOnVmCrash implements JUnitResultFormatter {
+
+ private String suiteName;
+
+ /**
+ * Records the suite's name to later determine the class to invoke
+ * tearDown on.
+ */
+ public void startTestSuite(final JUnitTest suite) {
+ suiteName = suite.getName();
+ if (suiteName != null &&
+ suiteName.endsWith(JUnitTask.NAME_OF_DUMMY_TEST)) {
+ // no way to know which class caused the timeout
+ suiteName = null;
+ }
+ }
+
+ /**
+ * Only invoke tearDown if the suite is known and not the dummy
+ * test we get when a Batch fails and the error is an actual
+ * error generated by Ant.
+ */
+ public void addError(final Test fakeTest, final Throwable t) {
+ if (suiteName != null
+ && fakeTest instanceof JUnitTaskMirrorImpl.VmExitErrorTest) {
+ tearDown();
+ }
+ }
+
+ // no need to implement the rest
+ public void addFailure(Test test, Throwable t) {}
+
+ public void addFailure(Test test, AssertionFailedError t) {}
+
+ public void startTest(Test test) {}
+
+ public void endTest(Test test) {}
+
+ public void endTestSuite(JUnitTest suite) {}
+
+ public void setOutput(OutputStream out) {}
+
+ public void setSystemOutput(String out) {}
+
+ public void setSystemError(String err) {}
+
+ private void tearDown() {
+ try {
+ // first try to load the class and let's hope it is on our
+ // classpath
+ Class testClass = null;
+ if (Thread.currentThread().getContextClassLoader() != null) {
+ try {
+ testClass = Thread.currentThread().getContextClassLoader()
+ .loadClass(suiteName);
+ } catch (ClassNotFoundException cnfe) {
+ // ignore
+ }
+ }
+ if (testClass == null && getClass().getClassLoader() != null) {
+ try {
+ testClass =
+ getClass().getClassLoader().loadClass(suiteName);
+ } catch (ClassNotFoundException cnfe) {
+ // ignore
+ }
+ }
+ if (testClass == null) {
+ // fall back to system classloader
+ testClass = Class.forName(suiteName);
+ }
+
+ // if the test has a suite method, then we can't know
+ // which test of the executed suite timed out, ignore it
+ try {
+ // check if there is a suite method
+ testClass.getMethod("suite", new Class[0]);
+ return;
+ } catch (NoSuchMethodException e) {
+ // no suite method
+ }
+
+ // a loadable class and no suite method
+ // no reason to check for JUnit 4 since JUnit4TestAdapter
+ // doesn't have any tearDown method.
+
+ try {
+ Method td = testClass.getMethod("tearDown", new Class[0]);
+ if (td.getReturnType() == Void.TYPE) {
+ td.invoke(testClass.newInstance(), new Object[0]);
+ }
+ } catch (NoSuchMethodException nsme) {
+ // no tearDown, fine
+ }
+
+ } catch (ClassNotFoundException cnfe) {
+ // class probably is not in our classpath, there is
+ // nothing we can do
+ } catch (InvocationTargetException ite) {
+ System.err.println("Caught an exception while trying to invoke"
+ + " tearDown: " + ite.getMessage());
+ } catch (Throwable t) {
+ System.err.println("Caught an exception while trying to invoke"
+ + " tearDown: " + t.getMessage());
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java
new file mode 100644
index 00000000..79a88785
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestIgnored.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.Test;
+
+public class TestIgnored {
+
+ private Test test;
+
+ public TestIgnored(Test test) {
+ this.test = test;
+ }
+
+ public Test getTest() {
+ return test;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java
new file mode 100644
index 00000000..692e4fc9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/TestListenerWrapper.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+
+
+public class TestListenerWrapper implements TestListener, IgnoredTestListener {
+
+ private TestListener wrapped;
+
+ public TestListenerWrapper(TestListener listener) {
+ super();
+ wrapped = listener;
+ }
+
+ public void addError(Test test, Throwable throwable) {
+ wrapped.addError(test, throwable);
+ }
+
+ public void addFailure(Test test, AssertionFailedError assertionFailedError) {
+ wrapped.addFailure(test, assertionFailedError);
+ }
+
+ public void endTest(Test test) {
+ wrapped.endTest(test);
+ }
+
+ public void startTest(Test test) {
+ wrapped.startTest(test);
+ }
+
+ public void testIgnored(Test test) {
+ if (wrapped instanceof IgnoredTestListener) {
+ ((IgnoredTestListener)wrapped).testIgnored(test);
+ }
+ }
+
+ public void testAssumptionFailure(Test test, Throwable throwable) {
+ if (wrapped instanceof IgnoredTestListener) {
+ ((IgnoredTestListener)wrapped).testAssumptionFailure(test, throwable);
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java
new file mode 100644
index 00000000..03760cc9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+/**
+ * <p> Interface groups XML constants.
+ * Interface that groups all constants used throughout the <tt>XML</tt>
+ * documents that are generated by the <tt>XMLJUnitResultFormatter</tt>.
+ * <p>
+ * As of now the DTD is:
+ * <code><pre>
+ * &lt;!ELEMENT testsuites (testsuite*)&gt;
+ *
+ * &lt;!ELEMENT testsuite (properties, testcase*,
+ * failure?, error?,
+ * system-out?, system-err?)&gt;
+ * &lt;!ATTLIST testsuite name CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite tests CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite failures CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite errors CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite time CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite package CDATA #IMPLIED&gt;
+ * &lt;!ATTLIST testsuite id CDATA #IMPLIED&gt;
+ *
+ *
+ * &lt;!ELEMENT properties (property*)&gt;
+ *
+ * &lt;!ELEMENT property EMPTY&gt;
+ * &lt;!ATTLIST property name CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST property value CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT testcase (failure?, error?)&gt;
+ * &lt;!ATTLIST testcase name CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testcase classname CDATA #IMPLIED&gt;
+ * &lt;!ATTLIST testcase time CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT failure (#PCDATA)&gt;
+ * &lt;!ATTLIST failure message CDATA #IMPLIED&gt;
+ * &lt;!ATTLIST failure type CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT error (#PCDATA)&gt;
+ * &lt;!ATTLIST error message CDATA #IMPLIED&gt;
+ * &lt;!ATTLIST error type CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT system-err (#PCDATA)&gt;
+ *
+ * &lt;!ELEMENT system-out (#PCDATA)&gt;
+ *
+ * </pre></code>
+ * @see XMLJUnitResultFormatter
+ * @see XMLResultAggregator
+ */
+// CheckStyle:InterfaceIsTypeCheck OFF (bc)
+public interface XMLConstants {
+ /** the testsuites element for the aggregate document */
+ String TESTSUITES = "testsuites";
+
+ /** the testsuite element */
+ String TESTSUITE = "testsuite";
+
+ /** the testcase element */
+ String TESTCASE = "testcase";
+
+ /** the error element */
+ String ERROR = "error";
+
+ /** the failure element */
+ String FAILURE = "failure";
+
+ /** the system-err element */
+ String SYSTEM_ERR = "system-err";
+
+ /** the system-out element */
+ String SYSTEM_OUT = "system-out";
+
+ /** package attribute for the aggregate document */
+ String ATTR_PACKAGE = "package";
+
+ /** name attribute for property, testcase and testsuite elements */
+ String ATTR_NAME = "name";
+
+ /** time attribute for testcase and testsuite elements */
+ String ATTR_TIME = "time";
+
+ /** errors attribute for testsuite elements */
+ String ATTR_ERRORS = "errors";
+
+ /** failures attribute for testsuite elements */
+ String ATTR_FAILURES = "failures";
+
+ /** tests attribute for testsuite elements */
+ String ATTR_TESTS = "tests";
+
+ String ATTR_SKIPPED = "skipped";
+
+ /** type attribute for failure and error elements */
+ String ATTR_TYPE = "type";
+
+ /** message attribute for failure elements */
+ String ATTR_MESSAGE = "message";
+
+ /** the properties element */
+ String PROPERTIES = "properties";
+
+ /** the property element */
+ String PROPERTY = "property";
+
+ /** value attribute for property elements */
+ String ATTR_VALUE = "value";
+
+ /** classname attribute for testcase elements */
+ String ATTR_CLASSNAME = "classname";
+
+ /** id attribute */
+ String ATTR_ID = "id";
+
+ /**
+ * timestamp of test cases
+ */
+ String TIMESTAMP = "timestamp";
+
+ /**
+ * name of host running the tests
+ */
+ String HOSTNAME = "hostname";
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java
new file mode 100644
index 00000000..416c10d4
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java
@@ -0,0 +1,366 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.DateUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+
+/**
+ * Prints XML output of the test to a specified Writer.
+ *
+ * @see FormatterElement
+ */
+
+public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants, IgnoredTestListener {
+
+ private static final double ONE_SECOND = 1000.0;
+
+ /** constant for unnnamed testsuites/cases */
+ private static final String UNKNOWN = "unknown";
+
+ private static DocumentBuilder getDocumentBuilder() {
+ try {
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (final Exception exc) {
+ throw new ExceptionInInitializerError(exc);
+ }
+ }
+
+ /**
+ * The XML document.
+ */
+ private Document doc;
+
+ /**
+ * The wrapper for the whole testsuite.
+ */
+ private Element rootElement;
+
+ /**
+ * Element for the current test.
+ *
+ * The keying of this map is a bit of a hack: tests are keyed by caseName(className) since
+ * the Test we get for Test-start isn't the same as the Test we get during test-assumption-fail,
+ * so we can't easily match Test objects without manually iterating over all keys and checking
+ * individual fields.
+ */
+ private final Hashtable<String, Element> testElements = new Hashtable<String, Element>();
+
+ /**
+ * tests that failed.
+ */
+ private final Hashtable failedTests = new Hashtable();
+
+ /**
+ * Tests that were skipped.
+ */
+ private final Hashtable<String, Test> skippedTests = new Hashtable<String, Test>();
+ /**
+ * Tests that were ignored. See the note above about the key being a bit of a hack.
+ */
+ private final Hashtable<String, Test> ignoredTests = new Hashtable<String, Test>();
+ /**
+ * Timing helper.
+ */
+ private final Hashtable<String, Long> testStarts = new Hashtable<String, Long>();
+ /**
+ * Where to write the log to.
+ */
+ private OutputStream out;
+
+ /** No arg constructor. */
+ public XMLJUnitResultFormatter() {
+ }
+
+ /** {@inheritDoc}. */
+ public void setOutput(final OutputStream out) {
+ this.out = out;
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemOutput(final String out) {
+ formatOutput(SYSTEM_OUT, out);
+ }
+
+ /** {@inheritDoc}. */
+ public void setSystemError(final String out) {
+ formatOutput(SYSTEM_ERR, out);
+ }
+
+ /**
+ * The whole testsuite started.
+ * @param suite the testsuite.
+ */
+ public void startTestSuite(final JUnitTest suite) {
+ doc = getDocumentBuilder().newDocument();
+ rootElement = doc.createElement(TESTSUITE);
+ final String n = suite.getName();
+ rootElement.setAttribute(ATTR_NAME, n == null ? UNKNOWN : n);
+
+ //add the timestamp
+ final String timestamp = DateUtils.format(new Date(),
+ DateUtils.ISO8601_DATETIME_PATTERN);
+ rootElement.setAttribute(TIMESTAMP, timestamp);
+ //and the hostname.
+ rootElement.setAttribute(HOSTNAME, getHostname());
+
+ // Output properties
+ final Element propsElement = doc.createElement(PROPERTIES);
+ rootElement.appendChild(propsElement);
+ final Properties props = suite.getProperties();
+ if (props != null) {
+ final Enumeration e = props.propertyNames();
+ while (e.hasMoreElements()) {
+ final String name = (String) e.nextElement();
+ final Element propElement = doc.createElement(PROPERTY);
+ propElement.setAttribute(ATTR_NAME, name);
+ propElement.setAttribute(ATTR_VALUE, props.getProperty(name));
+ propsElement.appendChild(propElement);
+ }
+ }
+ }
+
+ /**
+ * get the local hostname
+ * @return the name of the local host, or "localhost" if we cannot work it out
+ */
+ private String getHostname() {
+ String hostname = "localhost";
+ try {
+ final InetAddress localHost = InetAddress.getLocalHost();
+ if (localHost != null) {
+ hostname = localHost.getHostName();
+ }
+ } catch (final UnknownHostException e) {
+ // fall back to default 'localhost'
+ }
+ return hostname;
+ }
+
+ /**
+ * The whole testsuite ended.
+ * @param suite the testsuite.
+ * @throws BuildException on error.
+ */
+ public void endTestSuite(final JUnitTest suite) throws BuildException {
+ rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount());
+ rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount());
+ rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount());
+ rootElement.setAttribute(ATTR_SKIPPED, "" + suite.skipCount());
+ rootElement.setAttribute(
+ ATTR_TIME, "" + (suite.getRunTime() / ONE_SECOND));
+ if (out != null) {
+ Writer wri = null;
+ try {
+ wri = new BufferedWriter(new OutputStreamWriter(out, "UTF8"));
+ wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+ (new DOMElementWriter()).write(rootElement, wri, 0, " ");
+ } catch (final IOException exc) {
+ throw new BuildException("Unable to write log file", exc);
+ } finally {
+ if (wri != null) {
+ try {
+ wri.flush();
+ } catch (final IOException ex) {
+ // ignore
+ }
+ }
+ if (out != System.out && out != System.err) {
+ FileUtils.close(wri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A new Test is started.
+ * @param t the test.
+ */
+ public void startTest(final Test t) {
+ testStarts.put(createDescription(t), System.currentTimeMillis());
+ }
+
+ private static String createDescription(final Test test) throws BuildException {
+ return JUnitVersionHelper.getTestCaseName(test) + "(" + JUnitVersionHelper.getTestCaseClassName(test) + ")";
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>A Test is finished.
+ * @param test the test.
+ */
+ public void endTest(final Test test) {
+ final String testDescription = createDescription(test);
+
+ // Fix for bug #5637 - if a junit.extensions.TestSetup is
+ // used and throws an exception during setUp then startTest
+ // would never have been called
+ if (!testStarts.containsKey(testDescription)) {
+ startTest(test);
+ }
+ Element currentTest;
+ if (!failedTests.containsKey(test) && !skippedTests.containsKey(testDescription) && !ignoredTests.containsKey(testDescription)) {
+ currentTest = doc.createElement(TESTCASE);
+ final String n = JUnitVersionHelper.getTestCaseName(test);
+ currentTest.setAttribute(ATTR_NAME,
+ n == null ? UNKNOWN : n);
+ // a TestSuite can contain Tests from multiple classes,
+ // even tests with the same name - disambiguate them.
+ currentTest.setAttribute(ATTR_CLASSNAME,
+ JUnitVersionHelper.getTestCaseClassName(test));
+ rootElement.appendChild(currentTest);
+ testElements.put(createDescription(test), currentTest);
+ } else {
+ currentTest = testElements.get(testDescription);
+ }
+
+ final Long l = testStarts.get(createDescription(test));
+ currentTest.setAttribute(ATTR_TIME,
+ "" + ((System.currentTimeMillis() - l) / ONE_SECOND));
+ }
+
+ /**
+ * Interface TestListener for JUnit &lt;= 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the exception.
+ */
+ public void addFailure(final Test test, final Throwable t) {
+ formatError(FAILURE, test, t);
+ }
+
+ /**
+ * Interface TestListener for JUnit &gt; 3.4.
+ *
+ * <p>A Test failed.
+ * @param test the test.
+ * @param t the assertion.
+ */
+ public void addFailure(final Test test, final AssertionFailedError t) {
+ addFailure(test, (Throwable) t);
+ }
+
+ /**
+ * Interface TestListener.
+ *
+ * <p>An error occurred while running the test.
+ * @param test the test.
+ * @param t the error.
+ */
+ public void addError(final Test test, final Throwable t) {
+ formatError(ERROR, test, t);
+ }
+
+ private void formatError(final String type, final Test test, final Throwable t) {
+ if (test != null) {
+ endTest(test);
+ failedTests.put(test, test);
+ }
+
+ final Element nested = doc.createElement(type);
+ Element currentTest;
+ if (test != null) {
+ currentTest = testElements.get(createDescription(test));
+ } else {
+ currentTest = rootElement;
+ }
+
+ currentTest.appendChild(nested);
+
+ final String message = t.getMessage();
+ if (message != null && message.length() > 0) {
+ nested.setAttribute(ATTR_MESSAGE, t.getMessage());
+ }
+ nested.setAttribute(ATTR_TYPE, t.getClass().getName());
+
+ final String strace = JUnitTestRunner.getFilteredTrace(t);
+ final Text trace = doc.createTextNode(strace);
+ nested.appendChild(trace);
+ }
+
+ private void formatOutput(final String type, final String output) {
+ final Element nested = doc.createElement(type);
+ rootElement.appendChild(nested);
+ nested.appendChild(doc.createCDATASection(output));
+ }
+
+ public void testIgnored(final Test test) {
+ formatSkip(test, JUnitVersionHelper.getIgnoreMessage(test));
+ if (test != null) {
+ ignoredTests.put(createDescription(test), test);
+ }
+ }
+
+
+ public void formatSkip(final Test test, final String message) {
+ if (test != null) {
+ endTest(test);
+ }
+
+ final Element nested = doc.createElement("skipped");
+
+ if (message != null) {
+ nested.setAttribute("message", message);
+ }
+
+ Element currentTest;
+ if (test != null) {
+ currentTest = testElements.get(createDescription(test));
+ } else {
+ currentTest = rootElement;
+ }
+
+ currentTest.appendChild(nested);
+
+ }
+
+ public void testAssumptionFailure(final Test test, final Throwable failure) {
+ formatSkip(test, failure.getMessage());
+ skippedTests.put(createDescription(test), test);
+
+ }
+} // XMLJUnitResultFormatter
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java
new file mode 100644
index 00000000..4f76c968
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Aggregates all &lt;junit&gt; XML formatter testsuite data under
+ * a specific directory and transforms the results via XSLT.
+ * It is not particularly clean but
+ * should be helpful while I am thinking about another technique.
+ *
+ * <p> The main problem is due to the fact that a JVM can be forked for a testcase
+ * thus making it impossible to aggregate all testcases since the listener is
+ * (obviously) in the forked JVM. A solution could be to write a
+ * TestListener that will receive events from the TestRunner via sockets. This
+ * is IMHO the simplest way to do it to avoid this file hacking thing.
+ *
+ * @ant.task name="junitreport" category="testing"
+ */
+public class XMLResultAggregator extends Task implements XMLConstants {
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /** the list of all filesets, that should contains the xml to aggregate */
+ protected Vector filesets = new Vector();
+
+ /** the name of the result file */
+ protected String toFile;
+
+ /** the directory to write the file to */
+ protected File toDir;
+
+ protected Vector transformers = new Vector();
+
+ /** The default directory: <tt>&#046;</tt>. It is resolved from the project directory */
+ public static final String DEFAULT_DIR = ".";
+
+ /** the default file name: <tt>TESTS-TestSuites.xml</tt> */
+ public static final String DEFAULT_FILENAME = "TESTS-TestSuites.xml";
+
+ /** the current generated id */
+ protected int generatedId = 0;
+
+ /**
+ * text checked for in tests, {@value}
+ */
+ static final String WARNING_IS_POSSIBLY_CORRUPTED
+ = " is not a valid XML document. It is possibly corrupted.";
+ /**
+ * text checked for in tests, {@value}
+ */
+ static final String WARNING_INVALID_ROOT_ELEMENT
+ = " is not a valid testsuite XML document";
+ /**
+ * text checked for in tests, {@value}
+ */
+ static final String WARNING_EMPTY_FILE
+ = " is empty.\nThis can be caused by the test JVM exiting unexpectedly";
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Generate a report based on the document created by the merge.
+ * @return the report
+ */
+ public AggregateTransformer createReport() {
+ AggregateTransformer transformer = new AggregateTransformer(this);
+ transformers.addElement(transformer);
+ return transformer;
+ }
+
+ /**
+ * Set the name of the aggregegated results file. It must be relative
+ * from the <tt>todir</tt> attribute. If not set it will use {@link #DEFAULT_FILENAME}
+ * @param value the name of the file.
+ * @see #setTodir(File)
+ */
+ public void setTofile(String value) {
+ toFile = value;
+ }
+
+ /**
+ * Set the destination directory where the results should be written. If not
+ * set if will use {@link #DEFAULT_DIR}. When given a relative directory
+ * it will resolve it from the project directory.
+ * @param value the directory where to write the results, absolute or
+ * relative.
+ */
+ public void setTodir(File value) {
+ toDir = value;
+ }
+
+ /**
+ * Add a new fileset containing the XML results to aggregate
+ * @param fs the new fileset of xml results.
+ */
+ public void addFileSet(FileSet fs) {
+ filesets.addElement(fs);
+ }
+
+ /**
+ * Aggregate all testsuites into a single document and write it to the
+ * specified directory and file.
+ * @throws BuildException thrown if there is a serious error while writing
+ * the document.
+ */
+ public void execute() throws BuildException {
+ Element rootElement = createDocument();
+ File destFile = getDestinationFile();
+ // write the document
+ try {
+ writeDOMTree(rootElement.getOwnerDocument(), destFile);
+ } catch (IOException e) {
+ throw new BuildException("Unable to write test aggregate to '" + destFile + "'", e);
+ }
+ // apply transformation
+ Enumeration e = transformers.elements();
+ while (e.hasMoreElements()) {
+ AggregateTransformer transformer =
+ (AggregateTransformer) e.nextElement();
+ transformer.setXmlDocument(rootElement.getOwnerDocument());
+ transformer.transform();
+ }
+ }
+
+ /**
+ * Get the full destination file where to write the result. It is made of
+ * the <tt>todir</tt> and <tt>tofile</tt> attributes.
+ * @return the destination file where should be written the result file.
+ */
+ public File getDestinationFile() {
+ if (toFile == null) {
+ toFile = DEFAULT_FILENAME;
+ }
+ if (toDir == null) {
+ toDir = getProject().resolveFile(DEFAULT_DIR);
+ }
+ return new File(toDir, toFile);
+ }
+
+ /**
+ * Get all <code>.xml</code> files in the fileset.
+ *
+ * @return all files in the fileset that end with a '.xml'.
+ */
+ protected File[] getFiles() {
+ Vector v = new Vector();
+ final int size = filesets.size();
+ for (int i = 0; i < size; i++) {
+ FileSet fs = (FileSet) filesets.elementAt(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ ds.scan();
+ String[] f = ds.getIncludedFiles();
+ for (int j = 0; j < f.length; j++) {
+ String pathname = f[j];
+ if (pathname.endsWith(".xml")) {
+ File file = new File(ds.getBasedir(), pathname);
+ file = getProject().resolveFile(file.getPath());
+ v.addElement(file);
+ }
+ }
+ }
+
+ File[] files = new File[v.size()];
+ v.copyInto(files);
+ return files;
+ }
+
+ //----- from now, the methods are all related to DOM tree manipulation
+
+ /**
+ * Write the DOM tree to a file.
+ * @param doc the XML document to dump to disk.
+ * @param file the filename to write the document to. Should obviously be a .xml file.
+ * @throws IOException thrown if there is an error while writing the content.
+ */
+ protected void writeDOMTree(Document doc, File file) throws IOException {
+ OutputStream os = new FileOutputStream(file);
+ try {
+ PrintWriter wri = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(os), "UTF8"));
+ wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+ (new DOMElementWriter()).write(doc.getDocumentElement(), wri, 0, " ");
+ wri.flush();
+ // writers do not throw exceptions, so check for them.
+ if (wri.checkError()) {
+ throw new IOException("Error while writing DOM content");
+ }
+ } finally {
+ os.close();
+ }
+ }
+
+ /**
+ * <p> Create a DOM tree.
+ * Has 'testsuites' as firstchild and aggregates all
+ * testsuite results that exists in the base directory.
+ * @return the root element of DOM tree that aggregates all testsuites.
+ */
+ protected Element createDocument() {
+ // create the dom tree
+ DocumentBuilder builder = getDocumentBuilder();
+ Document doc = builder.newDocument();
+ Element rootElement = doc.createElement(TESTSUITES);
+ doc.appendChild(rootElement);
+
+ generatedId = 0;
+
+ // get all files and add them to the document
+ File[] files = getFiles();
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ try {
+ log("Parsing file: '" + file + "'", Project.MSG_VERBOSE);
+ if (file.length() > 0) {
+ Document testsuiteDoc
+ = builder.parse(
+ FileUtils.getFileUtils().toURI(files[i].getAbsolutePath()));
+ Element elem = testsuiteDoc.getDocumentElement();
+ // make sure that this is REALLY a testsuite.
+ if (TESTSUITE.equals(elem.getNodeName())) {
+ addTestSuite(rootElement, elem);
+ generatedId++;
+ } else {
+ //wrong root element name
+ // issue a warning.
+ log("the file " + file
+ + WARNING_INVALID_ROOT_ELEMENT,
+ Project.MSG_WARN);
+ }
+ } else {
+ log("the file " + file
+ + WARNING_EMPTY_FILE,
+ Project.MSG_WARN);
+ }
+ } catch (SAXException e) {
+ // a testcase might have failed and write a zero-length document,
+ // It has already failed, but hey.... mm. just put a warning
+ log("The file " + file + WARNING_IS_POSSIBLY_CORRUPTED, Project.MSG_WARN);
+ log(StringUtils.getStackTrace(e), Project.MSG_DEBUG);
+ } catch (IOException e) {
+ log("Error while accessing file " + file + ": "
+ + e.getMessage(), Project.MSG_ERR);
+ log("Error while accessing file " + file + ": "
+ + e.getMessage(), e, Project.MSG_VERBOSE);
+ }
+ }
+ return rootElement;
+ }
+
+ /**
+ * <p> Add a new testsuite node to the document.
+ * The main difference is that it
+ * split the previous fully qualified name into a package and a name.
+ * <p> For example: <tt>org.apache.Whatever</tt> will be split into
+ * <tt>org.apache</tt> and <tt>Whatever</tt>.
+ * @param root the root element to which the <tt>testsuite</tt> node should
+ * be appended.
+ * @param testsuite the element to append to the given root. It will slightly
+ * modify the original node to change the name attribute and add
+ * a package one.
+ */
+ protected void addTestSuite(Element root, Element testsuite) {
+ String fullclassname = testsuite.getAttribute(ATTR_NAME);
+ int pos = fullclassname.lastIndexOf('.');
+
+ // a missing . might imply no package at all. Don't get fooled.
+ String pkgName = (pos == -1) ? "" : fullclassname.substring(0, pos);
+ String classname = (pos == -1) ? fullclassname : fullclassname.substring(pos + 1);
+ Element copy = (Element) DOMUtil.importNode(root, testsuite);
+
+ // modify the name attribute and set the package
+ copy.setAttribute(ATTR_NAME, classname);
+ copy.setAttribute(ATTR_PACKAGE, pkgName);
+ copy.setAttribute(ATTR_ID, Integer.toString(generatedId));
+ }
+
+ /**
+ * Create a new document builder. Will issue an <tt>ExceptionInitializerError</tt>
+ * if something is going wrong. It is fatal anyway.
+ * @todo factorize this somewhere else. It is duplicated code.
+ * @return a new document builder to create a DOM
+ */
+ private static DocumentBuilder getDocumentBuilder() {
+ try {
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (Exception exc) {
+ throw new ExceptionInInitializerError(exc);
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java
new file mode 100644
index 00000000..3cd52afe
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * encapsulates the handling common to diffent Native2Asciiadapter
+ * implementations.
+ *
+ * @since Ant 1.6.3
+ */
+public abstract class DefaultNative2Ascii implements Native2AsciiAdapter {
+
+ /** No-arg constructor. */
+ public DefaultNative2Ascii() {
+ }
+
+ /**
+ * Splits the task into setting up the command line switches
+ * @param args the native 2 ascii arguments.
+ * @param srcFile the source file.
+ * @param destFile the destination file.
+ * @return run if the conversion was successful.
+ * @throws BuildException if there is a problem.
+ * (delegated to {@link #setup setup}), adding the file names
+ * (delegated to {@link #addFiles addFiles}) and running the tool
+ * (delegated to {@link #run run}).
+ */
+ public final boolean convert(Native2Ascii args, File srcFile,
+ File destFile) throws BuildException {
+ Commandline cmd = new Commandline();
+ setup(cmd, args);
+ addFiles(cmd, args, srcFile, destFile);
+ return run(cmd, args);
+ }
+
+ /**
+ * Sets up the initial command line.
+ *
+ * <p>only the -encoding argument and nested arg elements get
+ * handled here.</p>
+ *
+ * @param cmd Command line to add to
+ * @param args provides the user-setting and access to Ant's
+ * logging system.
+ * @throws BuildException if there was a problem.
+ */
+ protected void setup(Commandline cmd, Native2Ascii args)
+ throws BuildException {
+ if (args.getEncoding() != null) {
+ cmd.createArgument().setValue("-encoding");
+ cmd.createArgument().setValue(args.getEncoding());
+ }
+ cmd.addArguments(args.getCurrentArgs());
+ }
+
+ /**
+ * Adds source and dest files to the command line.
+ *
+ * <p>This implementation adds them without any leading
+ * qualifiers, source first.</p>
+ *
+ * @param cmd Command line to add to
+ * @param log provides access to Ant's logging system.
+ * @param src the source file
+ * @param dest the destination file
+ * @throws BuildException if there was a problem.
+ */
+ protected void addFiles(Commandline cmd, ProjectComponent log, File src,
+ File dest) throws BuildException {
+ cmd.createArgument().setFile(src);
+ cmd.createArgument().setFile(dest);
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @param cmd Command line to execute
+ * @param log provides access to Ant's logging system.
+ * @return whether execution was successful
+ * @throws BuildException if there was a problem.
+ */
+ protected abstract boolean run(Commandline cmd, ProjectComponent log)
+ throws BuildException;
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java
new file mode 100644
index 00000000..da4836fd
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.ExecuteJava;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Adapter to kaffe.tools.native2ascii.Native2Ascii.
+ *
+ * @since Ant 1.6.3
+ */
+public final class KaffeNative2Ascii extends DefaultNative2Ascii {
+
+ // sorted by newest Kaffe version first
+ private static final String[] N2A_CLASSNAMES = new String[] {
+ "gnu.classpath.tools.native2ascii.Native2ASCII",
+ // pre Kaffe 1.1.5
+ "kaffe.tools.native2ascii.Native2Ascii",
+ };
+
+ /**
+ * Identifies this adapter.
+ */
+ public static final String IMPLEMENTATION_NAME = "kaffe";
+
+ /** {@inheritDoc} */
+ protected void setup(Commandline cmd, Native2Ascii args)
+ throws BuildException {
+ if (args.getReverse()) {
+ throw new BuildException("-reverse is not supported by Kaffe");
+ }
+ super.setup(cmd, args);
+ }
+
+ /** {@inheritDoc} */
+ protected boolean run(Commandline cmd, ProjectComponent log)
+ throws BuildException {
+ ExecuteJava ej = new ExecuteJava();
+ Class c = getN2aClass();
+ if (c == null) {
+ throw new BuildException("Couldn't load Kaffe's Native2Ascii"
+ + " class");
+ }
+
+ cmd.setExecutable(c.getName());
+ ej.setJavaCommand(cmd);
+ ej.execute(log.getProject());
+ // otherwise ExecuteJava has thrown an exception
+ return true;
+ }
+
+ /**
+ * tries to load Kaffe Native2Ascii and falls back to the older
+ * class name if necessary.
+ *
+ * @return null if neither class can get loaded.
+ */
+ private static Class getN2aClass() {
+ for (int i = 0; i < N2A_CLASSNAMES.length; i++) {
+ try {
+ return Class.forName(N2A_CLASSNAMES[i]);
+ } catch (ClassNotFoundException cnfe) {
+ // Ignore
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java
new file mode 100644
index 00000000..af414004
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+
+/**
+ * Interface for an adapter to a native2ascii implementation.
+ *
+ * @since Ant 1.6.3
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public interface Native2AsciiAdapter {
+ /**
+ * Convert the encoding of srcFile writing to destFile.
+ *
+ * @param args Task that holds command line arguments and allows
+ * the implementation to send messages to Ant's logging system
+ * @param srcFile the source to convert
+ * @param destFile where to send output to
+ * @return whether the conversion has been successful.
+ * @throws BuildException if there was a problem.
+ */
+ boolean convert(Native2Ascii args, File srcFile, File destFile)
+ throws BuildException;
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java
new file mode 100644
index 00000000..ae419039
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Creates the Native2AsciiAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @since Ant 1.6.3
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class Native2AsciiAdapterFactory {
+
+ /**
+ * Determines the default choice of adapter based on the VM
+ * vendor.
+ *
+ * @return the default choice of adapter based on the VM
+ * vendor
+ */
+ public static String getDefault() {
+ if (JavaEnvUtils.isKaffe() || JavaEnvUtils.isClasspathBased()) {
+ return KaffeNative2Ascii.IMPLEMENTATION_NAME;
+ }
+ return SunNative2Ascii.IMPLEMENTATION_NAME;
+ }
+
+ /**
+ * Creates the Native2AsciiAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @param choice the user choice (if any).
+ * @param log a ProjectComponent instance used to access Ant's
+ * logging system.
+ * @return The adapter to use.
+ * @throws BuildException if there was a problem.
+ */
+ public static Native2AsciiAdapter getAdapter(String choice,
+ ProjectComponent log)
+ throws BuildException {
+ return getAdapter(choice, log, null);
+ }
+
+ /**
+ * Creates the Native2AsciiAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @param choice the user choice (if any).
+ * @param log a ProjectComponent instance used to access Ant's
+ * logging system.
+ * @param classpath the classpath to use when looking up an
+ * adapter class
+ * @return The adapter to use.
+ * @throws BuildException if there was a problem.
+ * @since Ant 1.8.0
+ */
+ public static Native2AsciiAdapter getAdapter(String choice,
+ ProjectComponent log,
+ Path classpath)
+ throws BuildException {
+ if (((JavaEnvUtils.isKaffe() || JavaEnvUtils.isClasspathBased()) && choice == null)
+ || KaffeNative2Ascii.IMPLEMENTATION_NAME.equals(choice)) {
+ return new KaffeNative2Ascii();
+ } else if (SunNative2Ascii.IMPLEMENTATION_NAME.equals(choice)) {
+ return new SunNative2Ascii();
+ } else if (choice != null) {
+ return resolveClassName(choice,
+ // Memory leak in line below
+ log.getProject()
+ .createClassLoader(classpath));
+ }
+
+ // This default has been good enough until Ant 1.6.3, so stick
+ // with it
+ return new SunNative2Ascii();
+ }
+
+ /**
+ * Tries to resolve the given classname into a native2ascii adapter.
+ * Throws a fit if it can't.
+ *
+ * @param className The fully qualified classname to be created.
+ * @param loader the classloader to use
+ * @throws BuildException This is the fit that is thrown if className
+ * isn't an instance of Native2AsciiAdapter.
+ */
+ private static Native2AsciiAdapter resolveClassName(String className,
+ ClassLoader loader)
+ throws BuildException {
+ return (Native2AsciiAdapter) ClasspathUtils.newInstance(className,
+ loader != null ? loader :
+ Native2AsciiAdapterFactory.class.getClassLoader(),
+ Native2AsciiAdapter.class);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java
new file mode 100644
index 00000000..fac94b18
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import java.lang.reflect.Method;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Adapter to sun.tools.native2ascii.Main.
+ *
+ * @since Ant 1.6.3
+ */
+public final class SunNative2Ascii extends DefaultNative2Ascii {
+
+ /**
+ * Identifies this adapter.
+ */
+ public static final String IMPLEMENTATION_NAME = "sun";
+
+ /** {@inheritDoc} */
+ protected void setup(Commandline cmd, Native2Ascii args)
+ throws BuildException {
+ if (args.getReverse()) {
+ cmd.createArgument().setValue("-reverse");
+ }
+ super.setup(cmd, args);
+ }
+
+ /** {@inheritDoc} */
+ protected boolean run(Commandline cmd, ProjectComponent log)
+ throws BuildException {
+ try {
+ Class n2aMain = Class.forName("sun.tools.native2ascii.Main");
+ Class[] param = new Class[] {String[].class};
+ Method convert = n2aMain.getMethod("convert", param);
+ if (convert == null) {
+ throw new BuildException("Could not find convert() method in "
+ + "sun.tools.native2ascii.Main");
+ }
+ Object o = n2aMain.newInstance();
+ return ((Boolean) convert.invoke(o,
+ new Object[] {cmd.getArguments()})
+ ).booleanValue();
+ } catch (BuildException ex) {
+ //rethrow
+ throw ex;
+ } catch (Exception ex) {
+ //wrap
+ throw new BuildException("Error starting Sun's native2ascii: ", ex);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java
new file mode 100644
index 00000000..cef9dda0
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java
@@ -0,0 +1,2725 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPClientConfig;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Delete;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.RetryHandler;
+import org.apache.tools.ant.util.Retryable;
+import org.apache.tools.ant.util.VectorSet;
+
+/**
+ * Basic FTP client. Performs the following actions:
+ * <ul>
+ * <li> <strong>send</strong> - send files to a remote server. This is the
+ * default action.</li>
+ * <li> <strong>get</strong> - retrieve files from a remote server.</li>
+ * <li> <strong>del</strong> - delete files from a remote server.</li>
+ * <li> <strong>list</strong> - create a file listing.</li>
+ * <li> <strong>chmod</strong> - change unix file permissions.</li>
+ * <li> <strong>rmdir</strong> - remove directories, if empty, from a
+ * remote server.</li>
+ * </ul>
+ * <strong>Note:</strong> Some FTP servers - notably the Solaris server - seem
+ * to hold data ports open after a "retr" operation, allowing them to timeout
+ * instead of shutting them down cleanly. This happens in active or passive
+ * mode, and the ports will remain open even after ending the FTP session. FTP
+ * "send" operations seem to close ports immediately. This behavior may cause
+ * problems on some systems when downloading large sets of files.
+ *
+ * @since Ant 1.3
+ */
+public class FTP extends Task implements FTPTaskConfig {
+ protected static final int SEND_FILES = 0;
+ protected static final int GET_FILES = 1;
+ protected static final int DEL_FILES = 2;
+ protected static final int LIST_FILES = 3;
+ protected static final int MK_DIR = 4;
+ protected static final int CHMOD = 5;
+ protected static final int RM_DIR = 6;
+ protected static final int SITE_CMD = 7;
+ /** return code of ftp */
+ private static final int CODE_521 = 521;
+ private static final int CODE_550 = 550;
+ private static final int CODE_553 = 553;
+
+ /** adjust uptodate calculations where server timestamps are HH:mm and client's
+ * are HH:mm:ss */
+ private static final long GRANULARITY_MINUTE = 60000L;
+
+ /** Date formatter used in logging, note not thread safe! */
+ private static final SimpleDateFormat TIMESTAMP_LOGGING_SDF =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ /** Default port for FTP */
+ public static final int DEFAULT_FTP_PORT = 21;
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ private String remotedir;
+ private String server;
+ private String userid;
+ private String password;
+ private String account;
+ private File listing;
+ private boolean binary = true;
+ private boolean passive = false;
+ private boolean verbose = false;
+ private boolean newerOnly = false;
+ private long timeDiffMillis = 0;
+ private long granularityMillis = 0L;
+ private boolean timeDiffAuto = false;
+ private int action = SEND_FILES;
+ private Vector filesets = new Vector();
+ private Set dirCache = new HashSet();
+ private int transferred = 0;
+ private String remoteFileSep = "/";
+ private int port = DEFAULT_FTP_PORT;
+ private boolean skipFailedTransfers = false;
+ private int skipped = 0;
+ private boolean ignoreNoncriticalErrors = false;
+ private boolean preserveLastModified = false;
+ private String chmod = null;
+ private String umask = null;
+ private FTPSystemType systemTypeKey = FTPSystemType.getDefault();
+ private String defaultDateFormatConfig = null;
+ private String recentDateFormatConfig = null;
+ private LanguageCode serverLanguageCodeConfig = LanguageCode.getDefault();
+ private String serverTimeZoneConfig = null;
+ private String shortMonthNamesConfig = null;
+ private Granularity timestampGranularity = Granularity.getDefault();
+ private boolean isConfigurationSet = false;
+ private int retriesAllowed = 0;
+ private String siteCommand = null;
+ private String initialSiteCommand = null;
+ private boolean enableRemoteVerification = true;
+
+ protected static final String[] ACTION_STRS = {
+ "sending",
+ "getting",
+ "deleting",
+ "listing",
+ "making directory",
+ "chmod",
+ "removing",
+ "site"
+ };
+
+ protected static final String[] COMPLETED_ACTION_STRS = {
+ "sent",
+ "retrieved",
+ "deleted",
+ "listed",
+ "created directory",
+ "mode changed",
+ "removed",
+ "site command executed"
+ };
+
+ protected static final String[] ACTION_TARGET_STRS = {
+ "files",
+ "files",
+ "files",
+ "files",
+ "directory",
+ "files",
+ "directories",
+ "site command"
+ };
+
+ /**
+ * internal class providing a File-like interface to some of the information
+ * available from the FTP server
+ *
+ */
+ protected static class FTPFileProxy extends File {
+
+ private final FTPFile file;
+ private final String[] parts;
+ private final String name;
+
+ /**
+ * creates a proxy to a FTP file
+ * @param file
+ */
+ public FTPFileProxy(FTPFile file) {
+ super(file.getName());
+ name = file.getName();
+ this.file = file;
+ parts = FileUtils.getPathStack(name);
+ }
+
+ /**
+ * creates a proxy to a FTP directory
+ * @param completePath the remote directory.
+ */
+ public FTPFileProxy(String completePath) {
+ super(completePath);
+ file = null;
+ name = completePath;
+ parts = FileUtils.getPathStack(completePath);
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#exists()
+ */
+ public boolean exists() {
+ return true;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getAbsolutePath()
+ */
+ public String getAbsolutePath() {
+ return name;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getName()
+ */
+ public String getName() {
+ return parts.length > 0 ? parts[parts.length - 1] : name;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getParent()
+ */
+ public String getParent() {
+ String result = "";
+ for(int i = 0; i < parts.length - 1; i++){
+ result += File.separatorChar + parts[i];
+ }
+ return result;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getPath()
+ */
+ public String getPath() {
+ return name;
+ }
+
+
+ /**
+ * FTP files are stored as absolute paths
+ * @return true
+ */
+ public boolean isAbsolute() {
+ return true;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#isDirectory()
+ */
+ public boolean isDirectory() {
+ return file == null;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#isFile()
+ */
+ public boolean isFile() {
+ return file != null;
+ }
+
+
+ /**
+ * FTP files cannot be hidden
+ *
+ * @return false
+ */
+ public boolean isHidden() {
+ return false;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#lastModified()
+ */
+ public long lastModified() {
+ if (file != null) {
+ return file.getTimestamp().getTimeInMillis();
+ }
+ return 0;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#length()
+ */
+ public long length() {
+ if (file != null) {
+ return file.getSize();
+ }
+ return 0;
+ }
+ }
+
+ /**
+ * internal class allowing to read the contents of a remote file system
+ * using the FTP protocol
+ * used in particular for ftp get operations
+ * differences with DirectoryScanner
+ * "" (the root of the fileset) is never included in the included directories
+ * followSymlinks defaults to false
+ */
+ protected class FTPDirectoryScanner extends DirectoryScanner {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected FTPClient ftp = null;
+ // CheckStyle:VisibilityModifier ON
+
+ private String rootPath = null;
+
+ /**
+ * since ant 1.6
+ * this flag should be set to true on UNIX and can save scanning time
+ */
+ private boolean remoteSystemCaseSensitive = false;
+ private boolean remoteSensitivityChecked = false;
+
+ /**
+ * constructor
+ * @param ftp ftpclient object
+ */
+ public FTPDirectoryScanner(FTPClient ftp) {
+ super();
+ this.ftp = ftp;
+ this.setFollowSymlinks(false);
+ }
+
+
+ /**
+ * scans the remote directory,
+ * storing internally the included files, directories, ...
+ */
+ public void scan() {
+ if (includes == null) {
+ // No includes supplied, so set it to 'matches all'
+ includes = new String[1];
+ includes[0] = "**";
+ }
+ if (excludes == null) {
+ excludes = new String[0];
+ }
+
+ filesIncluded = new VectorSet();
+ filesNotIncluded = new Vector();
+ filesExcluded = new VectorSet();
+ dirsIncluded = new VectorSet();
+ dirsNotIncluded = new Vector();
+ dirsExcluded = new VectorSet();
+
+ try {
+ String cwd = ftp.printWorkingDirectory();
+ // always start from the current ftp working dir
+ forceRemoteSensitivityCheck();
+
+ checkIncludePatterns();
+ clearCaches();
+ ftp.changeWorkingDirectory(cwd);
+ } catch (IOException e) {
+ throw new BuildException("Unable to scan FTP server: ", e);
+ }
+ }
+
+
+ /**
+ * this routine is actually checking all the include patterns in
+ * order to avoid scanning everything under base dir
+ * @since ant1.6
+ */
+ private void checkIncludePatterns() {
+
+ Hashtable newroots = new Hashtable();
+ // put in the newroots vector the include patterns without
+ // wildcard tokens
+ for (int icounter = 0; icounter < includes.length; icounter++) {
+ String newpattern =
+ SelectorUtils.rtrimWildcardTokens(includes[icounter]);
+ newroots.put(newpattern, includes[icounter]);
+ }
+ if (remotedir == null) {
+ try {
+ remotedir = ftp.printWorkingDirectory();
+ } catch (IOException e) {
+ throw new BuildException("could not read current ftp directory",
+ getLocation());
+ }
+ }
+ AntFTPFile baseFTPFile = new AntFTPRootFile(ftp, remotedir);
+ rootPath = baseFTPFile.getAbsolutePath();
+ // construct it
+ if (newroots.containsKey("")) {
+ // we are going to scan everything anyway
+ scandir(rootPath, "", true);
+ } else {
+ // only scan directories that can include matched files or
+ // directories
+ Enumeration enum2 = newroots.keys();
+
+ while (enum2.hasMoreElements()) {
+ String currentelement = (String) enum2.nextElement();
+ String originalpattern = (String) newroots.get(currentelement);
+ AntFTPFile myfile = new AntFTPFile(baseFTPFile, currentelement);
+ boolean isOK = true;
+ boolean traversesSymlinks = false;
+ String path = null;
+
+ if (myfile.exists()) {
+ forceRemoteSensitivityCheck();
+ if (remoteSensitivityChecked
+ && remoteSystemCaseSensitive && isFollowSymlinks()) {
+ // cool case,
+ //we do not need to scan all the subdirs in the relative path
+ path = myfile.getFastRelativePath();
+ } else {
+ // may be on a case insensitive file system. We want
+ // the results to show what's really on the disk, so
+ // we need to double check.
+ try {
+ path = myfile.getRelativePath();
+ traversesSymlinks = myfile.isTraverseSymlinks();
+ } catch (IOException be) {
+ throw new BuildException(be, getLocation());
+ } catch (BuildException be) {
+ isOK = false;
+ }
+ }
+ } else {
+ isOK = false;
+ }
+ if (isOK) {
+ currentelement = path.replace(remoteFileSep.charAt(0), File.separatorChar);
+ if (!isFollowSymlinks()
+ && traversesSymlinks) {
+ continue;
+ }
+
+ if (myfile.isDirectory()) {
+ if (isIncluded(currentelement)
+ && currentelement.length() > 0) {
+ accountForIncludedDir(currentelement, myfile, true);
+ } else {
+ if (currentelement.length() > 0) {
+ if (currentelement.charAt(currentelement
+ .length() - 1)
+ != File.separatorChar) {
+ currentelement =
+ currentelement + File.separatorChar;
+ }
+ }
+ scandir(myfile.getAbsolutePath(), currentelement, true);
+ }
+ } else {
+ if (isCaseSensitive
+ && originalpattern.equals(currentelement)) {
+ accountForIncludedFile(currentelement);
+ } else if (!isCaseSensitive
+ && originalpattern
+ .equalsIgnoreCase(currentelement)) {
+ accountForIncludedFile(currentelement);
+ }
+ }
+ }
+ }
+ }
+ }
+ /**
+ * scans a particular directory. populates the scannedDirs cache.
+ *
+ * @param dir directory to scan
+ * @param vpath relative path to the base directory of the remote fileset
+ * always ended with a File.separator
+ * @param fast seems to be always true in practice
+ */
+ protected void scandir(String dir, String vpath, boolean fast) {
+ // avoid double scanning of directories, can only happen in fast mode
+ if (fast && hasBeenScanned(vpath)) {
+ return;
+ }
+ try {
+ if (!ftp.changeWorkingDirectory(dir)) {
+ return;
+ }
+ String completePath = null;
+ if (!vpath.equals("")) {
+ completePath = rootPath + remoteFileSep
+ + vpath.replace(File.separatorChar, remoteFileSep.charAt(0));
+ } else {
+ completePath = rootPath;
+ }
+ FTPFile[] newfiles = listFiles(completePath, false);
+
+ if (newfiles == null) {
+ ftp.changeToParentDirectory();
+ return;
+ }
+ for (int i = 0; i < newfiles.length; i++) {
+ FTPFile file = newfiles[i];
+ if (file != null
+ && !file.getName().equals(".")
+ && !file.getName().equals("..")) {
+ String name = vpath + file.getName();
+ scannedDirs.put(name, new FTPFileProxy(file));
+ if (isFunctioningAsDirectory(ftp, dir, file)) {
+ boolean slowScanAllowed = true;
+ if (!isFollowSymlinks() && file.isSymbolicLink()) {
+ dirsExcluded.addElement(name);
+ slowScanAllowed = false;
+ } else if (isIncluded(name)) {
+ accountForIncludedDir(name,
+ new AntFTPFile(ftp, file, completePath) , fast);
+ } else {
+ dirsNotIncluded.addElement(name);
+ if (fast && couldHoldIncluded(name)) {
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ }
+ if (!fast && slowScanAllowed) {
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ } else {
+ if (!isFollowSymlinks() && file.isSymbolicLink()) {
+ filesExcluded.addElement(name);
+ } else if (isFunctioningAsFile(ftp, dir, file)) {
+ accountForIncludedFile(name);
+ }
+ }
+ }
+ }
+ ftp.changeToParentDirectory();
+ } catch (IOException e) {
+ throw new BuildException("Error while communicating with FTP "
+ + "server: ", e);
+ }
+ }
+ /**
+ * process included file
+ * @param name path of the file relative to the directory of the fileset
+ */
+ private void accountForIncludedFile(String name) {
+ if (!filesIncluded.contains(name)
+ && !filesExcluded.contains(name)) {
+
+ if (isIncluded(name)) {
+ if (!isExcluded(name)
+ && isSelected(name, (File) scannedDirs.get(name))) {
+ filesIncluded.addElement(name);
+ } else {
+ filesExcluded.addElement(name);
+ }
+ } else {
+ filesNotIncluded.addElement(name);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param name path of the directory relative to the directory of
+ * the fileset
+ * @param file directory as file
+ * @param fast
+ */
+ private void accountForIncludedDir(String name, AntFTPFile file, boolean fast) {
+ if (!dirsIncluded.contains(name)
+ && !dirsExcluded.contains(name)) {
+
+ if (!isExcluded(name)) {
+ if (fast) {
+ if (file.isSymbolicLink()) {
+ try {
+ file.getClient().changeWorkingDirectory(file.curpwd);
+ } catch (IOException ioe) {
+ throw new BuildException("could not change directory to curpwd");
+ }
+ scandir(file.getLink(),
+ name + File.separator, fast);
+ } else {
+ try {
+ file.getClient().changeWorkingDirectory(file.curpwd);
+ } catch (IOException ioe) {
+ throw new BuildException("could not change directory to curpwd");
+ }
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ }
+ dirsIncluded.addElement(name);
+ } else {
+ dirsExcluded.addElement(name);
+ if (fast && couldHoldIncluded(name)) {
+ try {
+ file.getClient().changeWorkingDirectory(file.curpwd);
+ } catch (IOException ioe) {
+ throw new BuildException("could not change directory to curpwd");
+ }
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ }
+ }
+ }
+ /**
+ * temporary table to speed up the various scanning methods below
+ *
+ * @since Ant 1.6
+ */
+ private Map fileListMap = new HashMap();
+ /**
+ * List of all scanned directories.
+ *
+ * @since Ant 1.6
+ */
+
+ private Map scannedDirs = new HashMap();
+
+ /**
+ * Has the directory with the given path relative to the base
+ * directory already been scanned?
+ *
+ * @since Ant 1.6
+ */
+ private boolean hasBeenScanned(String vpath) {
+ return scannedDirs.containsKey(vpath);
+ }
+
+ /**
+ * Clear internal caches.
+ *
+ * @since Ant 1.6
+ */
+ private void clearCaches() {
+ fileListMap.clear();
+ scannedDirs.clear();
+ }
+ /**
+ * list the files present in one directory.
+ * @param directory full path on the remote side
+ * @param changedir if true change to directory directory before listing
+ * @return array of FTPFile
+ */
+ public FTPFile[] listFiles(String directory, boolean changedir) {
+ //getProject().log("listing files in directory " + directory, Project.MSG_DEBUG);
+ String currentPath = directory;
+ if (changedir) {
+ try {
+ boolean result = ftp.changeWorkingDirectory(directory);
+ if (!result) {
+ return null;
+ }
+ currentPath = ftp.printWorkingDirectory();
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ }
+ }
+ if (fileListMap.containsKey(currentPath)) {
+ getProject().log("filelist map used in listing files", Project.MSG_DEBUG);
+ return ((FTPFile[]) fileListMap.get(currentPath));
+ }
+ FTPFile[] result = null;
+ try {
+ result = ftp.listFiles();
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ }
+ fileListMap.put(currentPath, result);
+ if (!remoteSensitivityChecked) {
+ checkRemoteSensitivity(result, directory);
+ }
+ return result;
+ }
+
+ private void forceRemoteSensitivityCheck() {
+ if (!remoteSensitivityChecked) {
+ try {
+ checkRemoteSensitivity(ftp.listFiles(), ftp.printWorkingDirectory());
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ }
+ }
+ }
+ /**
+ * cd into one directory and
+ * list the files present in one directory.
+ * @param directory full path on the remote side
+ * @return array of FTPFile
+ */
+ public FTPFile[] listFiles(String directory) {
+ return listFiles(directory, true);
+ }
+ private void checkRemoteSensitivity(FTPFile[] array, String directory) {
+ if (array == null) {
+ return;
+ }
+ boolean candidateFound = false;
+ String target = null;
+ for (int icounter = 0; icounter < array.length; icounter++) {
+ if (array[icounter] != null && array[icounter].isDirectory()) {
+ if (!array[icounter].getName().equals(".")
+ && !array[icounter].getName().equals("..")) {
+ candidateFound = true;
+ target = fiddleName(array[icounter].getName());
+ getProject().log("will try to cd to "
+ + target + " where a directory called " + array[icounter].getName()
+ + " exists", Project.MSG_DEBUG);
+ for (int pcounter = 0; pcounter < array.length; pcounter++) {
+ if (array[pcounter] != null
+ && pcounter != icounter
+ && target.equals(array[pcounter].getName())) {
+ candidateFound = false;
+ break;
+ }
+ }
+ if (candidateFound) {
+ break;
+ }
+ }
+ }
+ }
+ if (candidateFound) {
+ try {
+ getProject().log("testing case sensitivity, attempting to cd to "
+ + target, Project.MSG_DEBUG);
+ remoteSystemCaseSensitive = !ftp.changeWorkingDirectory(target);
+ } catch (IOException ioe) {
+ remoteSystemCaseSensitive = true;
+ } finally {
+ try {
+ ftp.changeWorkingDirectory(directory);
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ }
+ }
+ getProject().log("remote system is case sensitive : " + remoteSystemCaseSensitive,
+ Project.MSG_VERBOSE);
+ remoteSensitivityChecked = true;
+ }
+ }
+ private String fiddleName(String origin) {
+ StringBuffer result = new StringBuffer();
+ for (int icounter = 0; icounter < origin.length(); icounter++) {
+ if (Character.isLowerCase(origin.charAt(icounter))) {
+ result.append(Character.toUpperCase(origin.charAt(icounter)));
+ } else if (Character.isUpperCase(origin.charAt(icounter))) {
+ result.append(Character.toLowerCase(origin.charAt(icounter)));
+ } else {
+ result.append(origin.charAt(icounter));
+ }
+ }
+ return result.toString();
+ }
+ /**
+ * an AntFTPFile is a representation of a remote file
+ * @since Ant 1.6
+ */
+ protected class AntFTPFile {
+ /**
+ * ftp client
+ */
+ private FTPClient client;
+ /**
+ * parent directory of the file
+ */
+ private String curpwd;
+ /**
+ * the file itself
+ */
+ private FTPFile ftpFile;
+ /**
+ *
+ */
+ private AntFTPFile parent = null;
+ private boolean relativePathCalculated = false;
+ private boolean traversesSymlinks = false;
+ private String relativePath = "";
+ /**
+ * constructor
+ * @param client ftp client variable
+ * @param ftpFile the file
+ * @param curpwd absolute remote path where the file is found
+ */
+ public AntFTPFile(FTPClient client, FTPFile ftpFile, String curpwd) {
+ this.client = client;
+ this.ftpFile = ftpFile;
+ this.curpwd = curpwd;
+ }
+ /**
+ * other constructor
+ * @param parent the parent file
+ * @param path a relative path to the parent file
+ */
+ public AntFTPFile(AntFTPFile parent, String path) {
+ this.parent = parent;
+ this.client = parent.client;
+ Vector pathElements = SelectorUtils.tokenizePath(path);
+ try {
+ boolean result = this.client.changeWorkingDirectory(parent.getAbsolutePath());
+ //this should not happen, except if parent has been deleted by another process
+ if (!result) {
+ return;
+ }
+ this.curpwd = parent.getAbsolutePath();
+ } catch (IOException ioe) {
+ throw new BuildException("could not change working dir to "
+ + parent.curpwd);
+ }
+ final int size = pathElements.size();
+ for (int fcount = 0; fcount < size - 1; fcount++) {
+ String currentPathElement = (String) pathElements.elementAt(fcount);
+ try {
+ boolean result = this.client.changeWorkingDirectory(currentPathElement);
+ if (!result && !isCaseSensitive()
+ && (remoteSystemCaseSensitive || !remoteSensitivityChecked)) {
+ currentPathElement = findPathElementCaseUnsensitive(this.curpwd,
+ currentPathElement);
+ if (currentPathElement == null) {
+ return;
+ }
+ } else if (!result) {
+ return;
+ }
+ this.curpwd = getCurpwdPlusFileSep()
+ + currentPathElement;
+ } catch (IOException ioe) {
+ throw new BuildException("could not change working dir to "
+ + (String) pathElements.elementAt(fcount)
+ + " from " + this.curpwd);
+ }
+
+ }
+ String lastpathelement = (String) pathElements.elementAt(size - 1);
+ FTPFile [] theFiles = listFiles(this.curpwd);
+ this.ftpFile = getFile(theFiles, lastpathelement);
+ }
+ /**
+ * find a file in a directory in case unsensitive way
+ * @param parentPath where we are
+ * @param soughtPathElement what is being sought
+ * @return the first file found or null if not found
+ */
+ private String findPathElementCaseUnsensitive(String parentPath,
+ String soughtPathElement) {
+ // we are already in the right path, so the second parameter
+ // is false
+ FTPFile[] theFiles = listFiles(parentPath, false);
+ if (theFiles == null) {
+ return null;
+ }
+ for (int icounter = 0; icounter < theFiles.length; icounter++) {
+ if (theFiles[icounter] != null
+ && theFiles[icounter].getName().equalsIgnoreCase(soughtPathElement)) {
+ return theFiles[icounter].getName();
+ }
+ }
+ return null;
+ }
+ /**
+ * find out if the file exists
+ * @return true if the file exists
+ */
+ public boolean exists() {
+ return (ftpFile != null);
+ }
+ /**
+ * if the file is a symbolic link, find out to what it is pointing
+ * @return the target of the symbolic link
+ */
+ public String getLink() {
+ return ftpFile.getLink();
+ }
+ /**
+ * get the name of the file
+ * @return the name of the file
+ */
+ public String getName() {
+ return ftpFile.getName();
+ }
+ /**
+ * find out the absolute path of the file
+ * @return absolute path as string
+ */
+ public String getAbsolutePath() {
+ return getCurpwdPlusFileSep() + ftpFile.getName();
+ }
+ /**
+ * find out the relative path assuming that the path used to construct
+ * this AntFTPFile was spelled properly with regards to case.
+ * This is OK on a case sensitive system such as UNIX
+ * @return relative path
+ */
+ public String getFastRelativePath() {
+ String absPath = getAbsolutePath();
+ if (absPath.startsWith(rootPath + remoteFileSep)) {
+ return absPath.substring(rootPath.length() + remoteFileSep.length());
+ }
+ return null;
+ }
+ /**
+ * find out the relative path to the rootPath of the enclosing scanner.
+ * this relative path is spelled exactly like on disk,
+ * for instance if the AntFTPFile has been instantiated as ALPHA,
+ * but the file is really called alpha, this method will return alpha.
+ * If a symbolic link is encountered, it is followed, but the name of the link
+ * rather than the name of the target is returned.
+ * (ie does not behave like File.getCanonicalPath())
+ * @return relative path, separated by remoteFileSep
+ * @throws IOException if a change directory fails, ...
+ * @throws BuildException if one of the components of the relative path cannot
+ * be found.
+ */
+ public String getRelativePath() throws IOException, BuildException {
+ if (!relativePathCalculated) {
+ if (parent != null) {
+ traversesSymlinks = parent.isTraverseSymlinks();
+ relativePath = getRelativePath(parent.getAbsolutePath(),
+ parent.getRelativePath());
+ } else {
+ relativePath = getRelativePath(rootPath, "");
+ relativePathCalculated = true;
+ }
+ }
+ return relativePath;
+ }
+ /**
+ * get the relative path of this file
+ * @param currentPath base path
+ * @param currentRelativePath relative path of the base path with regards to remote dir
+ * @return relative path
+ */
+ private String getRelativePath(String currentPath, String currentRelativePath) {
+ Vector pathElements = SelectorUtils.tokenizePath(getAbsolutePath(), remoteFileSep);
+ Vector pathElements2 = SelectorUtils.tokenizePath(currentPath, remoteFileSep);
+ String relPath = currentRelativePath;
+ final int size = pathElements.size();
+ for (int pcount = pathElements2.size(); pcount < size; pcount++) {
+ String currentElement = (String) pathElements.elementAt(pcount);
+ FTPFile[] theFiles = listFiles(currentPath);
+ FTPFile theFile = null;
+ if (theFiles != null) {
+ theFile = getFile(theFiles, currentElement);
+ }
+ if (!relPath.equals("")) {
+ relPath = relPath + remoteFileSep;
+ }
+ if (theFile == null) {
+ // hit a hidden file assume not a symlink
+ relPath = relPath + currentElement;
+ currentPath = currentPath + remoteFileSep + currentElement;
+ log("Hidden file " + relPath
+ + " assumed to not be a symlink.",
+ Project.MSG_VERBOSE);
+ } else {
+ traversesSymlinks = traversesSymlinks || theFile.isSymbolicLink();
+ relPath = relPath + theFile.getName();
+ currentPath = currentPath + remoteFileSep + theFile.getName();
+ }
+ }
+ return relPath;
+ }
+ /**
+ * find a file matching a string in an array of FTPFile.
+ * This method will find "alpha" when requested for "ALPHA"
+ * if and only if the caseSensitive attribute is set to false.
+ * When caseSensitive is set to true, only the exact match is returned.
+ * @param theFiles array of files
+ * @param lastpathelement the file name being sought
+ * @return null if the file cannot be found, otherwise return the matching file.
+ */
+ public FTPFile getFile(FTPFile[] theFiles, String lastpathelement) {
+ if (theFiles == null) {
+ return null;
+ }
+ for (int fcount = 0; fcount < theFiles.length; fcount++) {
+ if (theFiles[fcount] != null) {
+ if (theFiles[fcount].getName().equals(lastpathelement)) {
+ return theFiles[fcount];
+ } else if (!isCaseSensitive()
+ && theFiles[fcount].getName().equalsIgnoreCase(
+ lastpathelement)) {
+ return theFiles[fcount];
+ }
+ }
+ }
+ return null;
+ }
+ /**
+ * tell if a file is a directory.
+ * note that it will return false for symbolic links pointing to directories.
+ * @return <code>true</code> for directories
+ */
+ public boolean isDirectory() {
+ return ftpFile.isDirectory();
+ }
+ /**
+ * tell if a file is a symbolic link
+ * @return <code>true</code> for symbolic links
+ */
+ public boolean isSymbolicLink() {
+ return ftpFile.isSymbolicLink();
+ }
+ /**
+ * return the attached FTP client object.
+ * Warning : this instance is really shared with the enclosing class.
+ * @return FTP client
+ */
+ protected FTPClient getClient() {
+ return client;
+ }
+
+ /**
+ * sets the current path of an AntFTPFile
+ * @param curpwd the current path one wants to set
+ */
+ protected void setCurpwd(String curpwd) {
+ this.curpwd = curpwd;
+ }
+ /**
+ * returns the path of the directory containing the AntFTPFile.
+ * of the full path of the file itself in case of AntFTPRootFile
+ * @return parent directory of the AntFTPFile
+ */
+ public String getCurpwd() {
+ return curpwd;
+ }
+ /**
+ * returns the path of the directory containing the AntFTPFile.
+ * of the full path of the file itself in case of AntFTPRootFile
+ * and appends the remote file separator if necessary.
+ * @return parent directory of the AntFTPFile
+ * @since Ant 1.8.2
+ */
+ public String getCurpwdPlusFileSep() {
+ return curpwd.endsWith(remoteFileSep) ? curpwd
+ : curpwd + remoteFileSep;
+ }
+ /**
+ * find out if a symbolic link is encountered in the relative path of this file
+ * from rootPath.
+ * @return <code>true</code> if a symbolic link is encountered in the relative path.
+ * @throws IOException if one of the change directory or directory listing operations
+ * fails
+ * @throws BuildException if a path component in the relative path cannot be found.
+ */
+ public boolean isTraverseSymlinks() throws IOException, BuildException {
+ if (!relativePathCalculated) {
+ // getRelativePath also finds about symlinks
+ getRelativePath();
+ }
+ return traversesSymlinks;
+ }
+
+ /**
+ * Get a string rep of this object.
+ * @return a string containing the pwd and the file.
+ */
+ public String toString() {
+ return "AntFtpFile: " + curpwd + "%" + ftpFile;
+ }
+ }
+ /**
+ * special class to represent the remote directory itself
+ * @since Ant 1.6
+ */
+ protected class AntFTPRootFile extends AntFTPFile {
+ private String remotedir;
+ /**
+ * constructor
+ * @param aclient FTP client
+ * @param remotedir remote directory
+ */
+ public AntFTPRootFile(FTPClient aclient, String remotedir) {
+ super(aclient, null, remotedir);
+ this.remotedir = remotedir;
+ try {
+ this.getClient().changeWorkingDirectory(this.remotedir);
+ this.setCurpwd(this.getClient().printWorkingDirectory());
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ }
+ }
+ /**
+ * find the absolute path
+ * @return absolute path
+ */
+ public String getAbsolutePath() {
+ return this.getCurpwd();
+ }
+ /**
+ * find out the relative path to root
+ * @return empty string
+ * @throws BuildException actually never
+ * @throws IOException actually never
+ */
+ public String getRelativePath() throws BuildException, IOException {
+ return "";
+ }
+ }
+ }
+ /**
+ * check FTPFiles to check whether they function as directories too
+ * the FTPFile API seem to make directory and symbolic links incompatible
+ * we want to find out if we can cd to a symbolic link
+ * @param dir the parent directory of the file to test
+ * @param file the file to test
+ * @return true if it is possible to cd to this directory
+ * @since ant 1.6
+ */
+ private boolean isFunctioningAsDirectory(FTPClient ftp, String dir, FTPFile file) {
+ boolean result = false;
+ String currentWorkingDir = null;
+ if (file.isDirectory()) {
+ return true;
+ } else if (file.isFile()) {
+ return false;
+ }
+ try {
+ currentWorkingDir = ftp.printWorkingDirectory();
+ } catch (IOException ioe) {
+ getProject().log("could not find current working directory " + dir
+ + " while checking a symlink",
+ Project.MSG_DEBUG);
+ }
+ if (currentWorkingDir != null) {
+ try {
+ result = ftp.changeWorkingDirectory(file.getLink());
+ } catch (IOException ioe) {
+ getProject().log("could not cd to " + file.getLink() + " while checking a symlink",
+ Project.MSG_DEBUG);
+ }
+ if (result) {
+ boolean comeback = false;
+ try {
+ comeback = ftp.changeWorkingDirectory(currentWorkingDir);
+ } catch (IOException ioe) {
+ getProject().log("could not cd back to " + dir + " while checking a symlink",
+ Project.MSG_ERR);
+ } finally {
+ if (!comeback) {
+ throw new BuildException("could not cd back to " + dir
+ + " while checking a symlink");
+ }
+ }
+ }
+ }
+ return result;
+ }
+ /**
+ * check FTPFiles to check whether they function as directories too
+ * the FTPFile API seem to make directory and symbolic links incompatible
+ * we want to find out if we can cd to a symbolic link
+ * @param dir the parent directory of the file to test
+ * @param file the file to test
+ * @return true if it is possible to cd to this directory
+ * @since ant 1.6
+ */
+ private boolean isFunctioningAsFile(FTPClient ftp, String dir, FTPFile file) {
+ if (file.isDirectory()) {
+ return false;
+ } else if (file.isFile()) {
+ return true;
+ }
+ return !isFunctioningAsDirectory(ftp, dir, file);
+ }
+ /**
+ * Sets the remote directory where files will be placed. This may be a
+ * relative or absolute path, and must be in the path syntax expected by
+ * the remote server. No correction of path syntax will be performed.
+ *
+ * @param dir the remote directory name.
+ */
+ public void setRemotedir(String dir) {
+ this.remotedir = dir;
+ }
+
+
+ /**
+ * Sets the FTP server to send files to.
+ *
+ * @param server the remote server name.
+ */
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+
+ /**
+ * Sets the FTP port used by the remote server.
+ *
+ * @param port the port on which the remote server is listening.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+
+ /**
+ * Sets the login user id to use on the specified server.
+ *
+ * @param userid remote system userid.
+ */
+ public void setUserid(String userid) {
+ this.userid = userid;
+ }
+
+
+ /**
+ * Sets the login password for the given user id.
+ *
+ * @param password the password on the remote system.
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Sets the login account to use on the specified server.
+ *
+ * @param pAccount the account name on remote system
+ * @since Ant 1.7
+ */
+ public void setAccount(String pAccount) {
+ this.account = pAccount;
+ }
+
+
+ /**
+ * If true, uses binary mode, otherwise text mode (default is binary).
+ *
+ * @param binary if true use binary mode in transfers.
+ */
+ public void setBinary(boolean binary) {
+ this.binary = binary;
+ }
+
+
+ /**
+ * Specifies whether to use passive mode. Set to true if you are behind a
+ * firewall and cannot connect without it. Passive mode is disabled by
+ * default.
+ *
+ * @param passive true is passive mode should be used.
+ */
+ public void setPassive(boolean passive) {
+ this.passive = passive;
+ }
+
+
+ /**
+ * Set to true to receive notification about each file as it is
+ * transferred.
+ *
+ * @param verbose true if verbose notifications are required.
+ */
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+
+ /**
+ * A synonym for <tt>depends</tt>. Set to true to transmit only new
+ * or changed files.
+ *
+ * See the related attributes timediffmillis and timediffauto.
+ *
+ * @param newer if true only transfer newer files.
+ */
+ public void setNewer(boolean newer) {
+ this.newerOnly = newer;
+ }
+
+ /**
+ * number of milliseconds to add to the time on the remote machine
+ * to get the time on the local machine.
+ *
+ * use in conjunction with <code>newer</code>
+ *
+ * @param timeDiffMillis number of milliseconds
+ *
+ * @since ant 1.6
+ */
+ public void setTimeDiffMillis(long timeDiffMillis) {
+ this.timeDiffMillis = timeDiffMillis;
+ }
+
+ /**
+ * &quot;true&quot; to find out automatically the time difference
+ * between local and remote machine.
+ *
+ * This requires right to create
+ * and delete a temporary file in the remote directory.
+ *
+ * @param timeDiffAuto true = find automatically the time diff
+ *
+ * @since ant 1.6
+ */
+ public void setTimeDiffAuto(boolean timeDiffAuto) {
+ this.timeDiffAuto = timeDiffAuto;
+ }
+
+ /**
+ * Set to true to preserve modification times for "gotten" files.
+ *
+ * @param preserveLastModified if true preserver modification times.
+ */
+ public void setPreserveLastModified(boolean preserveLastModified) {
+ this.preserveLastModified = preserveLastModified;
+ }
+
+
+ /**
+ * Set to true to transmit only files that are new or changed from their
+ * remote counterparts. The default is to transmit all files.
+ *
+ * @param depends if true only transfer newer files.
+ */
+ public void setDepends(boolean depends) {
+ this.newerOnly = depends;
+ }
+
+
+ /**
+ * Sets the remote file separator character. This normally defaults to the
+ * Unix standard forward slash, but can be manually overridden using this
+ * call if the remote server requires some other separator. Only the first
+ * character of the string is used.
+ *
+ * @param separator the file separator on the remote system.
+ */
+ public void setSeparator(String separator) {
+ remoteFileSep = separator;
+ }
+
+
+ /**
+ * Sets the file permission mode (Unix only) for files sent to the
+ * server.
+ *
+ * @param theMode unix style file mode for the files sent to the remote
+ * system.
+ */
+ public void setChmod(String theMode) {
+ this.chmod = theMode;
+ }
+
+
+ /**
+ * Sets the default mask for file creation on a unix server.
+ *
+ * @param theUmask unix style umask for files created on the remote server.
+ */
+ public void setUmask(String theUmask) {
+ this.umask = theUmask;
+ }
+
+
+ /**
+ * A set of files to upload or download
+ *
+ * @param set the set of files to be added to the list of files to be
+ * transferred.
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+
+ /**
+ * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
+ * "mkdir", "chmod", "list", and "site".
+ *
+ * @deprecated since 1.5.x.
+ * setAction(String) is deprecated and is replaced with
+ * setAction(FTP.Action) to make Ant's Introspection mechanism do the
+ * work and also to encapsulate operations on the type in its own
+ * class.
+ * @ant.attribute ignore="true"
+ *
+ * @param action the FTP action to be performed.
+ *
+ * @throws BuildException if the action is not a valid action.
+ */
+ public void setAction(String action) throws BuildException {
+ log("DEPRECATED - The setAction(String) method has been deprecated."
+ + " Use setAction(FTP.Action) instead.");
+
+ Action a = new Action();
+
+ a.setValue(action);
+ this.action = a.getAction();
+ }
+
+
+ /**
+ * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
+ * "mkdir", "chmod", "list", and "site".
+ *
+ * @param action the FTP action to be performed.
+ *
+ * @throws BuildException if the action is not a valid action.
+ */
+ public void setAction(Action action) throws BuildException {
+ this.action = action.getAction();
+ }
+
+
+ /**
+ * The output file for the "list" action. This attribute is ignored for
+ * any other actions.
+ *
+ * @param listing file in which to store the listing.
+ */
+ public void setListing(File listing) {
+ this.listing = listing;
+ }
+
+
+ /**
+ * If true, enables unsuccessful file put, delete and get
+ * operations to be skipped with a warning and the remainder
+ * of the files still transferred.
+ *
+ * @param skipFailedTransfers true if failures in transfers are ignored.
+ */
+ public void setSkipFailedTransfers(boolean skipFailedTransfers) {
+ this.skipFailedTransfers = skipFailedTransfers;
+ }
+
+
+ /**
+ * set the flag to skip errors on directory creation.
+ * (and maybe later other server specific errors)
+ *
+ * @param ignoreNoncriticalErrors true if non-critical errors should not
+ * cause a failure.
+ */
+ public void setIgnoreNoncriticalErrors(boolean ignoreNoncriticalErrors) {
+ this.ignoreNoncriticalErrors = ignoreNoncriticalErrors;
+ }
+
+ private void configurationHasBeenSet() {
+ this.isConfigurationSet = true;
+ }
+
+ /**
+ * Sets the systemTypeKey attribute.
+ * Method for setting <code>FTPClientConfig</code> remote system key.
+ *
+ * @param systemKey the key to be set - BUT if blank
+ * the default value of null (which signifies "autodetect") will be kept.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setSystemTypeKey(FTPSystemType systemKey) {
+ if (systemKey != null && !systemKey.getValue().equals("")) {
+ this.systemTypeKey = systemKey;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the defaultDateFormatConfig attribute.
+ * @param defaultDateFormat configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setDefaultDateFormatConfig(String defaultDateFormat) {
+ if (defaultDateFormat != null && !defaultDateFormat.equals("")) {
+ this.defaultDateFormatConfig = defaultDateFormat;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the recentDateFormatConfig attribute.
+ * @param recentDateFormat configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setRecentDateFormatConfig(String recentDateFormat) {
+ if (recentDateFormat != null && !recentDateFormat.equals("")) {
+ this.recentDateFormatConfig = recentDateFormat;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the serverLanguageCode attribute.
+ * @param serverLanguageCode configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setServerLanguageCodeConfig(LanguageCode serverLanguageCode) {
+ if (serverLanguageCode != null && !"".equals(serverLanguageCode.getValue())) {
+ this.serverLanguageCodeConfig = serverLanguageCode;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the serverTimeZoneConfig attribute.
+ * @param serverTimeZoneId configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setServerTimeZoneConfig(String serverTimeZoneId) {
+ if (serverTimeZoneId != null && !serverTimeZoneId.equals("")) {
+ this.serverTimeZoneConfig = serverTimeZoneId;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the shortMonthNamesConfig attribute
+ *
+ * @param shortMonthNames configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setShortMonthNamesConfig(String shortMonthNames) {
+ if (shortMonthNames != null && !shortMonthNames.equals("")) {
+ this.shortMonthNamesConfig = shortMonthNames;
+ configurationHasBeenSet();
+ }
+ }
+
+
+
+ /**
+ * Defines how many times to retry executing FTP command before giving up.
+ * Default is 0 - try once and if failure then give up.
+ *
+ * @param retriesAllowed number of retries to allow. -1 means
+ * keep trying forever. "forever" may also be specified as a
+ * synonym for -1.
+ */
+ public void setRetriesAllowed(String retriesAllowed) {
+ if ("FOREVER".equalsIgnoreCase(retriesAllowed)) {
+ this.retriesAllowed = Retryable.RETRY_FOREVER;
+ } else {
+ try {
+ int retries = Integer.parseInt(retriesAllowed);
+ if (retries < Retryable.RETRY_FOREVER) {
+ throw new BuildException(
+ "Invalid value for retriesAllowed attribute: "
+ + retriesAllowed);
+
+ }
+ this.retriesAllowed = retries;
+ } catch (NumberFormatException px) {
+ throw new BuildException(
+ "Invalid value for retriesAllowed attribute: "
+ + retriesAllowed);
+
+ }
+
+ }
+ }
+ /**
+ * @return Returns the systemTypeKey.
+ */
+ public String getSystemTypeKey() {
+ return systemTypeKey.getValue();
+ }
+ /**
+ * @return Returns the defaultDateFormatConfig.
+ */
+ public String getDefaultDateFormatConfig() {
+ return defaultDateFormatConfig;
+ }
+ /**
+ * @return Returns the recentDateFormatConfig.
+ */
+ public String getRecentDateFormatConfig() {
+ return recentDateFormatConfig;
+ }
+ /**
+ * @return Returns the serverLanguageCodeConfig.
+ */
+ public String getServerLanguageCodeConfig() {
+ return serverLanguageCodeConfig.getValue();
+ }
+ /**
+ * @return Returns the serverTimeZoneConfig.
+ */
+ public String getServerTimeZoneConfig() {
+ return serverTimeZoneConfig;
+ }
+ /**
+ * @return Returns the shortMonthNamesConfig.
+ */
+ public String getShortMonthNamesConfig() {
+ return shortMonthNamesConfig;
+ }
+ /**
+ * @return Returns the timestampGranularity.
+ */
+ Granularity getTimestampGranularity() {
+ return timestampGranularity;
+ }
+ /**
+ * Sets the timestampGranularity attribute
+ * @param timestampGranularity The timestampGranularity to set.
+ */
+ public void setTimestampGranularity(Granularity timestampGranularity) {
+ if (null == timestampGranularity || "".equals(timestampGranularity.getValue())) {
+ return;
+ }
+ this.timestampGranularity = timestampGranularity;
+ }
+ /**
+ * Sets the siteCommand attribute. This attribute
+ * names the command that will be executed if the action
+ * is "site".
+ * @param siteCommand The siteCommand to set.
+ */
+ public void setSiteCommand(String siteCommand) {
+ this.siteCommand = siteCommand;
+ }
+ /**
+ * Sets the initialSiteCommand attribute. This attribute
+ * names a site command that will be executed immediately
+ * after connection.
+ * @param initialCommand The initialSiteCommand to set.
+ */
+ public void setInitialSiteCommand(String initialCommand) {
+ this.initialSiteCommand = initialCommand;
+ }
+
+ /**
+ * Whether to verify that data and control connections are
+ * connected to the same remote host.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setEnableRemoteVerification(boolean b) {
+ enableRemoteVerification = b;
+ }
+
+ /**
+ * Checks to see that all required parameters are set.
+ *
+ * @throws BuildException if the configuration is not valid.
+ */
+ protected void checkAttributes() throws BuildException {
+ if (server == null) {
+ throw new BuildException("server attribute must be set!");
+ }
+ if (userid == null) {
+ throw new BuildException("userid attribute must be set!");
+ }
+ if (password == null) {
+ throw new BuildException("password attribute must be set!");
+ }
+
+ if ((action == LIST_FILES) && (listing == null)) {
+ throw new BuildException("listing attribute must be set for list "
+ + "action!");
+ }
+
+ if (action == MK_DIR && remotedir == null) {
+ throw new BuildException("remotedir attribute must be set for "
+ + "mkdir action!");
+ }
+
+ if (action == CHMOD && chmod == null) {
+ throw new BuildException("chmod attribute must be set for chmod "
+ + "action!");
+ }
+ if (action == SITE_CMD && siteCommand == null) {
+ throw new BuildException("sitecommand attribute must be set for site "
+ + "action!");
+ }
+
+
+ if (this.isConfigurationSet) {
+ try {
+ Class.forName("org.apache.commons.net.ftp.FTPClientConfig");
+ } catch (ClassNotFoundException e) {
+ throw new BuildException(
+ "commons-net.jar >= 1.4.0 is required for at least one"
+ + " of the attributes specified.");
+ }
+ }
+ }
+
+ /**
+ * Executable a retryable object.
+ * @param h the retry handler.
+ * @param r the object that should be retried until it succeeds
+ * or the number of retrys is reached.
+ * @param descr a description of the command that is being run.
+ * @throws IOException if there is a problem.
+ */
+ protected void executeRetryable(RetryHandler h, Retryable r, String descr)
+ throws IOException {
+ h.execute(r, descr);
+ }
+
+
+ /**
+ * For each file in the fileset, do the appropriate action: send, get,
+ * delete, or list.
+ *
+ * @param ftp the FTPClient instance used to perform FTP actions
+ * @param fs the fileset on which the actions are performed.
+ *
+ * @return the number of files to be transferred.
+ *
+ * @throws IOException if there is a problem reading a file
+ * @throws BuildException if there is a problem in the configuration.
+ */
+ protected int transferFiles(final FTPClient ftp, FileSet fs)
+ throws IOException, BuildException {
+ DirectoryScanner ds;
+ if (action == SEND_FILES) {
+ ds = fs.getDirectoryScanner(getProject());
+ } else {
+ ds = new FTPDirectoryScanner(ftp);
+ fs.setupDirectoryScanner(ds, getProject());
+ ds.setFollowSymlinks(fs.isFollowSymlinks());
+ ds.scan();
+ }
+
+ String[] dsfiles = null;
+ if (action == RM_DIR) {
+ dsfiles = ds.getIncludedDirectories();
+ } else {
+ dsfiles = ds.getIncludedFiles();
+ }
+ String dir = null;
+
+ if ((ds.getBasedir() == null)
+ && ((action == SEND_FILES) || (action == GET_FILES))) {
+ throw new BuildException("the dir attribute must be set for send "
+ + "and get actions");
+ } else {
+ if ((action == SEND_FILES) || (action == GET_FILES)) {
+ dir = ds.getBasedir().getAbsolutePath();
+ }
+ }
+
+ // If we are doing a listing, we need the output stream created now.
+ BufferedWriter bw = null;
+
+ try {
+ if (action == LIST_FILES) {
+ File pd = listing.getParentFile();
+
+ if (!pd.exists()) {
+ pd.mkdirs();
+ }
+ bw = new BufferedWriter(new FileWriter(listing));
+ }
+ RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+ if (action == RM_DIR) {
+ // to remove directories, start by the end of the list
+ // the trunk does not let itself be removed before the leaves
+ for (int i = dsfiles.length - 1; i >= 0; i--) {
+ final String dsfile = dsfiles[i];
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ rmDir(ftp, dsfile);
+ }
+ }, dsfile);
+ }
+ } else {
+ final BufferedWriter fbw = bw;
+ final String fdir = dir;
+ if (this.newerOnly) {
+ this.granularityMillis =
+ this.timestampGranularity.getMilliseconds(action);
+ }
+ for (int i = 0; i < dsfiles.length; i++) {
+ final String dsfile = dsfiles[i];
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ switch (action) {
+ case SEND_FILES:
+ sendFile(ftp, fdir, dsfile);
+ break;
+ case GET_FILES:
+ getFile(ftp, fdir, dsfile);
+ break;
+ case DEL_FILES:
+ delFile(ftp, dsfile);
+ break;
+ case LIST_FILES:
+ listFile(ftp, fbw, dsfile);
+ break;
+ case CHMOD:
+ doSiteCommand(ftp, "chmod " + chmod
+ + " " + resolveFile(dsfile));
+ transferred++;
+ break;
+ default:
+ throw new BuildException("unknown ftp action " + action);
+ }
+ }
+ }, dsfile);
+ }
+ }
+ } finally {
+ FileUtils.close(bw);
+ }
+
+ return dsfiles.length;
+ }
+
+
+ /**
+ * Sends all files specified by the configured filesets to the remote
+ * server.
+ *
+ * @param ftp the FTPClient instance used to perform FTP actions
+ *
+ * @throws IOException if there is a problem reading a file
+ * @throws BuildException if there is a problem in the configuration.
+ */
+ protected void transferFiles(FTPClient ftp)
+ throws IOException, BuildException {
+ transferred = 0;
+ skipped = 0;
+
+ if (filesets.size() == 0) {
+ throw new BuildException("at least one fileset must be specified.");
+ } else {
+ // get files from filesets
+ final int size = filesets.size();
+ for (int i = 0; i < size; i++) {
+ FileSet fs = (FileSet) filesets.elementAt(i);
+
+ if (fs != null) {
+ transferFiles(ftp, fs);
+ }
+ }
+ }
+
+ log(transferred + " " + ACTION_TARGET_STRS[action] + " "
+ + COMPLETED_ACTION_STRS[action]);
+ if (skipped != 0) {
+ log(skipped + " " + ACTION_TARGET_STRS[action]
+ + " were not successfully " + COMPLETED_ACTION_STRS[action]);
+ }
+ }
+
+
+ /**
+ * Correct a file path to correspond to the remote host requirements. This
+ * implementation currently assumes that the remote end can handle
+ * Unix-style paths with forward-slash separators. This can be overridden
+ * with the <code>separator</code> task parameter. No attempt is made to
+ * determine what syntax is appropriate for the remote host.
+ *
+ * @param file the remote file name to be resolved
+ *
+ * @return the filename as it will appear on the server.
+ */
+ protected String resolveFile(String file) {
+ return file.replace(System.getProperty("file.separator").charAt(0),
+ remoteFileSep.charAt(0));
+ }
+
+
+ /**
+ * Creates all parent directories specified in a complete relative
+ * pathname. Attempts to create existing directories will not cause
+ * errors.
+ *
+ * @param ftp the FTP client instance to use to execute FTP actions on
+ * the remote server.
+ * @param filename the name of the file whose parents should be created.
+ * @throws IOException under non documented circumstances
+ * @throws BuildException if it is impossible to cd to a remote directory
+ *
+ */
+ protected void createParents(FTPClient ftp, String filename)
+ throws IOException, BuildException {
+
+ File dir = new File(filename);
+ if (dirCache.contains(dir)) {
+ return;
+ }
+
+ Vector parents = new Vector();
+ String dirname;
+
+ while ((dirname = dir.getParent()) != null) {
+ File checkDir = new File(dirname);
+ if (dirCache.contains(checkDir)) {
+ break;
+ }
+ dir = checkDir;
+ parents.addElement(dir);
+ }
+
+ // find first non cached dir
+ int i = parents.size() - 1;
+
+ if (i >= 0) {
+ String cwd = ftp.printWorkingDirectory();
+ String parent = dir.getParent();
+ if (parent != null) {
+ if (!ftp.changeWorkingDirectory(resolveFile(parent))) {
+ throw new BuildException("could not change to "
+ + "directory: " + ftp.getReplyString());
+ }
+ }
+
+ while (i >= 0) {
+ dir = (File) parents.elementAt(i--);
+ // check if dir exists by trying to change into it.
+ if (!ftp.changeWorkingDirectory(dir.getName())) {
+ // could not change to it - try to create it
+ log("creating remote directory "
+ + resolveFile(dir.getPath()), Project.MSG_VERBOSE);
+ if (!ftp.makeDirectory(dir.getName())) {
+ handleMkDirFailure(ftp);
+ }
+ if (!ftp.changeWorkingDirectory(dir.getName())) {
+ throw new BuildException("could not change to "
+ + "directory: " + ftp.getReplyString());
+ }
+ }
+ dirCache.add(dir);
+ }
+ ftp.changeWorkingDirectory(cwd);
+ }
+ }
+ /**
+ * auto find the time difference between local and remote
+ * @param ftp handle to ftp client
+ * @return number of millis to add to remote time to make it comparable to local time
+ * @since ant 1.6
+ */
+ private long getTimeDiff(FTPClient ftp) {
+ long returnValue = 0;
+ File tempFile = findFileName(ftp);
+ try {
+ // create a local temporary file
+ FILE_UTILS.createNewFile(tempFile);
+ long localTimeStamp = tempFile.lastModified();
+ BufferedInputStream instream = new BufferedInputStream(new FileInputStream(tempFile));
+ ftp.storeFile(tempFile.getName(), instream);
+ instream.close();
+ boolean success = FTPReply.isPositiveCompletion(ftp.getReplyCode());
+ if (success) {
+ FTPFile [] ftpFiles = ftp.listFiles(tempFile.getName());
+ if (ftpFiles.length == 1) {
+ long remoteTimeStamp = ftpFiles[0].getTimestamp().getTime().getTime();
+ returnValue = localTimeStamp - remoteTimeStamp;
+ }
+ ftp.deleteFile(ftpFiles[0].getName());
+ }
+ // delegate the deletion of the local temp file to the delete task
+ // because of race conditions occurring on Windows
+ Delete mydelete = new Delete();
+ mydelete.bindToOwner(this);
+ mydelete.setFile(tempFile.getCanonicalFile());
+ mydelete.execute();
+ } catch (Exception e) {
+ throw new BuildException(e, getLocation());
+ }
+ return returnValue;
+ }
+ /**
+ * find a suitable name for local and remote temporary file
+ */
+ private File findFileName(FTPClient ftp) {
+ FTPFile [] theFiles = null;
+ final int maxIterations = 1000;
+ for (int counter = 1; counter < maxIterations; counter++) {
+ File localFile = FILE_UTILS.createTempFile(
+ "ant" + Integer.toString(counter), ".tmp",
+ null, false, false);
+ String fileName = localFile.getName();
+ boolean found = false;
+ try {
+ if (theFiles == null) {
+ theFiles = ftp.listFiles();
+ }
+ for (int counter2 = 0; counter2 < theFiles.length; counter2++) {
+ if (theFiles[counter2] != null
+ && theFiles[counter2].getName().equals(fileName)) {
+ found = true;
+ break;
+ }
+ }
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ }
+ if (!found) {
+ localFile.deleteOnExit();
+ return localFile;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks to see if the remote file is current as compared with the local
+ * file. Returns true if the target file is up to date.
+ * @param ftp ftpclient
+ * @param localFile local file
+ * @param remoteFile remote file
+ * @return true if the target file is up to date
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if the date of the remote files cannot be found and the action is
+ * GET_FILES
+ */
+ protected boolean isUpToDate(FTPClient ftp, File localFile,
+ String remoteFile)
+ throws IOException, BuildException {
+ log("checking date for " + remoteFile, Project.MSG_VERBOSE);
+
+ FTPFile[] files = ftp.listFiles(remoteFile);
+
+ // For Microsoft's Ftp-Service an Array with length 0 is
+ // returned if configured to return listings in "MS-DOS"-Format
+ if (files == null || files.length == 0) {
+ // If we are sending files, then assume out of date.
+ // If we are getting files, then throw an error
+
+ if (action == SEND_FILES) {
+ log("Could not date test remote file: " + remoteFile
+ + "assuming out of date.", Project.MSG_VERBOSE);
+ return false;
+ } else {
+ throw new BuildException("could not date test remote file: "
+ + ftp.getReplyString());
+ }
+ }
+
+ long remoteTimestamp = files[0].getTimestamp().getTime().getTime();
+ long localTimestamp = localFile.lastModified();
+ long adjustedRemoteTimestamp =
+ remoteTimestamp + this.timeDiffMillis + this.granularityMillis;
+
+ StringBuffer msg;
+ synchronized(TIMESTAMP_LOGGING_SDF) {
+ msg = new StringBuffer(" [")
+ .append(TIMESTAMP_LOGGING_SDF.format(new Date(localTimestamp)))
+ .append("] local");
+ }
+ log(msg.toString(), Project.MSG_VERBOSE);
+
+ synchronized(TIMESTAMP_LOGGING_SDF) {
+ msg = new StringBuffer(" [")
+ .append(TIMESTAMP_LOGGING_SDF.format(new Date(adjustedRemoteTimestamp)))
+ .append("] remote");
+ }
+ if (remoteTimestamp != adjustedRemoteTimestamp) {
+ synchronized(TIMESTAMP_LOGGING_SDF) {
+ msg.append(" - (raw: ")
+ .append(TIMESTAMP_LOGGING_SDF.format(new Date(remoteTimestamp)))
+ .append(")");
+ }
+ }
+ log(msg.toString(), Project.MSG_VERBOSE);
+
+
+
+ if (this.action == SEND_FILES) {
+ return adjustedRemoteTimestamp >= localTimestamp;
+ } else {
+ return localTimestamp >= adjustedRemoteTimestamp;
+ }
+ }
+
+
+ /**
+ * Sends a site command to the ftp server
+ * @param ftp ftp client
+ * @param theCMD command to execute
+ * @throws IOException in unknown circumstances
+ * @throws BuildException in unknown circumstances
+ */
+ protected void doSiteCommand(FTPClient ftp, String theCMD)
+ throws IOException, BuildException {
+ boolean rc;
+ String[] myReply = null;
+
+ log("Doing Site Command: " + theCMD, Project.MSG_VERBOSE);
+
+ rc = ftp.sendSiteCommand(theCMD);
+
+ if (!rc) {
+ log("Failed to issue Site Command: " + theCMD, Project.MSG_WARN);
+ } else {
+
+ myReply = ftp.getReplyStrings();
+
+ for (int x = 0; x < myReply.length; x++) {
+ if (myReply[x] != null && myReply[x].indexOf("200") == -1) {
+ log(myReply[x], Project.MSG_WARN);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Sends a single file to the remote host. <code>filename</code> may
+ * contain a relative path specification. When this is the case, <code>sendFile</code>
+ * will attempt to create any necessary parent directories before sending
+ * the file. The file will then be sent using the entire relative path
+ * spec - no attempt is made to change directories. It is anticipated that
+ * this may eventually cause problems with some FTP servers, but it
+ * simplifies the coding.
+ * @param ftp ftp client
+ * @param dir base directory of the file to be sent (local)
+ * @param filename relative path of the file to be send
+ * locally relative to dir
+ * remotely relative to the remotedir attribute
+ * @throws IOException in unknown circumstances
+ * @throws BuildException in unknown circumstances
+ */
+ protected void sendFile(FTPClient ftp, String dir, String filename)
+ throws IOException, BuildException {
+ InputStream instream = null;
+
+ try {
+ // TODO - why not simply new File(dir, filename)?
+ File file = getProject().resolveFile(new File(dir, filename).getPath());
+
+ if (newerOnly && isUpToDate(ftp, file, resolveFile(filename))) {
+ return;
+ }
+
+ if (verbose) {
+ log("transferring " + file.getAbsolutePath());
+ }
+
+ instream = new BufferedInputStream(new FileInputStream(file));
+
+ createParents(ftp, filename);
+
+ ftp.storeFile(resolveFile(filename), instream);
+
+ boolean success = FTPReply.isPositiveCompletion(ftp.getReplyCode());
+
+ if (!success) {
+ String s = "could not put file: " + ftp.getReplyString();
+
+ if (skipFailedTransfers) {
+ log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+
+ } else {
+ // see if we should issue a chmod command
+ if (chmod != null) {
+ doSiteCommand(ftp, "chmod " + chmod + " " + resolveFile(filename));
+ }
+ log("File " + file.getAbsolutePath() + " copied to " + server,
+ Project.MSG_VERBOSE);
+ transferred++;
+ }
+ } finally {
+ FileUtils.close(instream);
+ }
+ }
+
+
+ /**
+ * Delete a file from the remote host.
+ * @param ftp ftp client
+ * @param filename file to delete
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if skipFailedTransfers is set to false
+ * and the deletion could not be done
+ */
+ protected void delFile(FTPClient ftp, String filename)
+ throws IOException, BuildException {
+ if (verbose) {
+ log("deleting " + filename);
+ }
+
+ if (!ftp.deleteFile(resolveFile(filename))) {
+ String s = "could not delete file: " + ftp.getReplyString();
+
+ if (skipFailedTransfers) {
+ log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+ } else {
+ log("File " + filename + " deleted from " + server,
+ Project.MSG_VERBOSE);
+ transferred++;
+ }
+ }
+
+ /**
+ * Delete a directory, if empty, from the remote host.
+ * @param ftp ftp client
+ * @param dirname directory to delete
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if skipFailedTransfers is set to false
+ * and the deletion could not be done
+ */
+ protected void rmDir(FTPClient ftp, String dirname)
+ throws IOException, BuildException {
+ if (verbose) {
+ log("removing " + dirname);
+ }
+
+ if (!ftp.removeDirectory(resolveFile(dirname))) {
+ String s = "could not remove directory: " + ftp.getReplyString();
+
+ if (skipFailedTransfers) {
+ log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+ } else {
+ log("Directory " + dirname + " removed from " + server,
+ Project.MSG_VERBOSE);
+ transferred++;
+ }
+ }
+
+
+ /**
+ * Retrieve a single file from the remote host. <code>filename</code> may
+ * contain a relative path specification. <p>
+ *
+ * The file will then be retrieved using the entire relative path spec -
+ * no attempt is made to change directories. It is anticipated that this
+ * may eventually cause problems with some FTP servers, but it simplifies
+ * the coding.</p>
+ * @param ftp the ftp client
+ * @param dir local base directory to which the file should go back
+ * @param filename relative path of the file based upon the ftp remote directory
+ * and/or the local base directory (dir)
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if skipFailedTransfers is false
+ * and the file cannot be retrieved.
+ */
+ protected void getFile(FTPClient ftp, String dir, String filename)
+ throws IOException, BuildException {
+ OutputStream outstream = null;
+ try {
+ File file = getProject().resolveFile(new File(dir, filename).getPath());
+
+ if (newerOnly && isUpToDate(ftp, file, resolveFile(filename))) {
+ return;
+ }
+
+ if (verbose) {
+ log("transferring " + filename + " to "
+ + file.getAbsolutePath());
+ }
+
+ File pdir = file.getParentFile();
+
+ if (!pdir.exists()) {
+ pdir.mkdirs();
+ }
+ outstream = new BufferedOutputStream(new FileOutputStream(file));
+ ftp.retrieveFile(resolveFile(filename), outstream);
+
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ String s = "could not get file: " + ftp.getReplyString();
+
+ if (skipFailedTransfers) {
+ log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+
+ } else {
+ log("File " + file.getAbsolutePath() + " copied from "
+ + server, Project.MSG_VERBOSE);
+ transferred++;
+ if (preserveLastModified) {
+ outstream.close();
+ outstream = null;
+ FTPFile[] remote = ftp.listFiles(resolveFile(filename));
+ if (remote.length > 0) {
+ FILE_UTILS.setFileLastModified(file,
+ remote[0].getTimestamp()
+ .getTime().getTime());
+ }
+ }
+ }
+ } finally {
+ FileUtils.close(outstream);
+ }
+ }
+
+
+ /**
+ * List information about a single file from the remote host. <code>filename</code>
+ * may contain a relative path specification. <p>
+ *
+ * The file listing will then be retrieved using the entire relative path
+ * spec - no attempt is made to change directories. It is anticipated that
+ * this may eventually cause problems with some FTP servers, but it
+ * simplifies the coding.</p>
+ * @param ftp ftp client
+ * @param bw buffered writer
+ * @param filename the directory one wants to list
+ * @throws IOException in unknown circumstances
+ * @throws BuildException in unknown circumstances
+ */
+ protected void listFile(FTPClient ftp, BufferedWriter bw, String filename)
+ throws IOException, BuildException {
+ if (verbose) {
+ log("listing " + filename);
+ }
+ FTPFile[] ftpfiles = ftp.listFiles(resolveFile(filename));
+
+ if (ftpfiles != null && ftpfiles.length > 0) {
+ bw.write(ftpfiles[0].toString());
+ bw.newLine();
+ transferred++;
+ }
+ }
+
+
+ /**
+ * Create the specified directory on the remote host.
+ *
+ * @param ftp The FTP client connection
+ * @param dir The directory to create (format must be correct for host
+ * type)
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if ignoreNoncriticalErrors has not been set to true
+ * and a directory could not be created, for instance because it was
+ * already existing. Precisely, the codes 521, 550 and 553 will trigger
+ * a BuildException
+ */
+ protected void makeRemoteDir(FTPClient ftp, String dir)
+ throws IOException, BuildException {
+ String workingDirectory = ftp.printWorkingDirectory();
+ if (verbose) {
+ if (dir.startsWith("/") || workingDirectory == null) {
+ log("Creating directory: " + dir + " in /");
+ } else {
+ log("Creating directory: " + dir + " in " + workingDirectory);
+ }
+ }
+ if (dir.startsWith("/")) {
+ ftp.changeWorkingDirectory("/");
+ }
+ String subdir = "";
+ StringTokenizer st = new StringTokenizer(dir, "/");
+ while (st.hasMoreTokens()) {
+ subdir = st.nextToken();
+ log("Checking " + subdir, Project.MSG_DEBUG);
+ if (!ftp.changeWorkingDirectory(subdir)) {
+ if (!ftp.makeDirectory(subdir)) {
+ // codes 521, 550 and 553 can be produced by FTP Servers
+ // to indicate that an attempt to create a directory has
+ // failed because the directory already exists.
+ int rc = ftp.getReplyCode();
+ if (!(ignoreNoncriticalErrors
+ && (rc == CODE_550 || rc == CODE_553
+ || rc == CODE_521))) {
+ throw new BuildException("could not create directory: "
+ + ftp.getReplyString());
+ }
+ if (verbose) {
+ log("Directory already exists");
+ }
+ } else {
+ if (verbose) {
+ log("Directory created OK");
+ }
+ ftp.changeWorkingDirectory(subdir);
+ }
+ }
+ }
+ if (workingDirectory != null) {
+ ftp.changeWorkingDirectory(workingDirectory);
+ }
+ }
+
+ /**
+ * look at the response for a failed mkdir action, decide whether
+ * it matters or not. If it does, we throw an exception
+ * @param ftp current ftp connection
+ * @throws BuildException if this is an error to signal
+ */
+ private void handleMkDirFailure(FTPClient ftp)
+ throws BuildException {
+ int rc = ftp.getReplyCode();
+ if (!(ignoreNoncriticalErrors
+ && (rc == CODE_550 || rc == CODE_553 || rc == CODE_521))) {
+ throw new BuildException("could not create directory: "
+ + ftp.getReplyString());
+ }
+ }
+
+ /**
+ * Runs the task.
+ *
+ * @throws BuildException if the task fails or is not configured
+ * correctly.
+ */
+ public void execute() throws BuildException {
+ checkAttributes();
+
+ FTPClient ftp = null;
+
+ try {
+ log("Opening FTP connection to " + server, Project.MSG_VERBOSE);
+
+ ftp = new FTPClient();
+ if (this.isConfigurationSet) {
+ ftp = FTPConfigurator.configure(ftp, this);
+ }
+
+ ftp.setRemoteVerificationEnabled(enableRemoteVerification);
+ ftp.connect(server, port);
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("FTP connection failed: "
+ + ftp.getReplyString());
+ }
+
+ log("connected", Project.MSG_VERBOSE);
+ log("logging in to FTP server", Project.MSG_VERBOSE);
+
+ if ((this.account != null && !ftp.login(userid, password, account))
+ || (this.account == null && !ftp.login(userid, password))) {
+ throw new BuildException("Could not login to FTP server");
+ }
+
+ log("login succeeded", Project.MSG_VERBOSE);
+
+ if (binary) {
+ ftp.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not set transfer type: "
+ + ftp.getReplyString());
+ }
+ } else {
+ ftp.setFileType(org.apache.commons.net.ftp.FTP.ASCII_FILE_TYPE);
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not set transfer type: "
+ + ftp.getReplyString());
+ }
+ }
+
+ if (passive) {
+ log("entering passive mode", Project.MSG_VERBOSE);
+ ftp.enterLocalPassiveMode();
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not enter into passive "
+ + "mode: " + ftp.getReplyString());
+ }
+ }
+
+ // If an initial command was configured then send it.
+ // Some FTP servers offer different modes of operation,
+ // E.G. switching between a UNIX file system mode and
+ // a legacy file system.
+ if (this.initialSiteCommand != null) {
+ RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ doSiteCommand(lftp, FTP.this.initialSiteCommand);
+ }
+ }, "initial site command: " + this.initialSiteCommand);
+ }
+
+
+ // For a unix ftp server you can set the default mask for all files
+ // created.
+
+ if (umask != null) {
+ RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ doSiteCommand(lftp, "umask " + umask);
+ }
+ }, "umask " + umask);
+ }
+
+ // If the action is MK_DIR, then the specified remote
+ // directory is the directory to create.
+
+ if (action == MK_DIR) {
+ RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ makeRemoteDir(lftp, remotedir);
+ }
+ }, remotedir);
+ } else if (action == SITE_CMD) {
+ RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ doSiteCommand(lftp, FTP.this.siteCommand);
+ }
+ }, "Site Command: " + this.siteCommand);
+ } else {
+ if (remotedir != null) {
+ log("changing the remote directory to " + remotedir,
+ Project.MSG_VERBOSE);
+ ftp.changeWorkingDirectory(remotedir);
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not change remote "
+ + "directory: " + ftp.getReplyString());
+ }
+ }
+ if (newerOnly && timeDiffAuto) {
+ // in this case we want to find how much time span there is between local
+ // and remote
+ timeDiffMillis = getTimeDiff(ftp);
+ }
+ log(ACTION_STRS[action] + " " + ACTION_TARGET_STRS[action]);
+ transferFiles(ftp);
+ }
+
+ } catch (IOException ex) {
+ throw new BuildException("error during FTP transfer: " + ex, ex);
+ } finally {
+ if (ftp != null && ftp.isConnected()) {
+ try {
+ log("disconnecting", Project.MSG_VERBOSE);
+ ftp.logout();
+ ftp.disconnect();
+ } catch (IOException ex) {
+ // ignore it
+ }
+ }
+ }
+ }
+
+
+ /**
+ * an action to perform, one of
+ * "send", "put", "recv", "get", "del", "delete", "list", "mkdir", "chmod",
+ * "rmdir"
+ */
+ public static class Action extends EnumeratedAttribute {
+
+ private static final String[] VALID_ACTIONS = {
+ "send", "put", "recv", "get", "del", "delete", "list", "mkdir",
+ "chmod", "rmdir", "site"
+ };
+
+
+ /**
+ * Get the valid values
+ *
+ * @return an array of the valid FTP actions.
+ */
+ public String[] getValues() {
+ return VALID_ACTIONS;
+ }
+
+
+ /**
+ * Get the symbolic equivalent of the action value.
+ *
+ * @return the SYMBOL representing the given action.
+ */
+ public int getAction() {
+ String actionL = getValue().toLowerCase(Locale.ENGLISH);
+ if (actionL.equals("send") || actionL.equals("put")) {
+ return SEND_FILES;
+ } else if (actionL.equals("recv") || actionL.equals("get")) {
+ return GET_FILES;
+ } else if (actionL.equals("del") || actionL.equals("delete")) {
+ return DEL_FILES;
+ } else if (actionL.equals("list")) {
+ return LIST_FILES;
+ } else if (actionL.equals("chmod")) {
+ return CHMOD;
+ } else if (actionL.equals("mkdir")) {
+ return MK_DIR;
+ } else if (actionL.equals("rmdir")) {
+ return RM_DIR;
+ } else if (actionL.equals("site")) {
+ return SITE_CMD;
+ }
+ return SEND_FILES;
+ }
+ }
+ /**
+ * represents one of the valid timestamp adjustment values
+ * recognized by the <code>timestampGranularity</code> attribute.<p>
+
+ * A timestamp adjustment may be used in file transfers for checking
+ * uptodateness. MINUTE means to add one minute to the server
+ * timestamp. This is done because FTP servers typically list
+ * timestamps HH:mm and client FileSystems typically use HH:mm:ss.
+ *
+ * The default is to use MINUTE for PUT actions and NONE for GET
+ * actions, since GETs have the <code>preserveLastModified</code>
+ * option, which takes care of the problem in most use cases where
+ * this level of granularity is an issue.
+ *
+ */
+ public static class Granularity extends EnumeratedAttribute {
+
+ private static final String[] VALID_GRANULARITIES = {
+ "", "MINUTE", "NONE"
+ };
+
+ /**
+ * Get the valid values.
+ * @return the list of valid Granularity values
+ */
+ public String[] getValues() {
+ return VALID_GRANULARITIES;
+ }
+ /**
+ * returns the number of milliseconds associated with
+ * the attribute, which can vary in some cases depending
+ * on the value of the action parameter.
+ * @param action SEND_FILES or GET_FILES
+ * @return the number of milliseconds associated with
+ * the attribute, in the context of the supplied action
+ */
+ public long getMilliseconds(int action) {
+ String granularityU = getValue().toUpperCase(Locale.ENGLISH);
+ if ("".equals(granularityU)) {
+ if (action == SEND_FILES) {
+ return GRANULARITY_MINUTE;
+ }
+ } else if ("MINUTE".equals(granularityU)) {
+ return GRANULARITY_MINUTE;
+ }
+ return 0L;
+ }
+ static final Granularity getDefault() {
+ Granularity g = new Granularity();
+ g.setValue("");
+ return g;
+ }
+
+ }
+ /**
+ * one of the valid system type keys recognized by the systemTypeKey
+ * attribute.
+ */
+ public static class FTPSystemType extends EnumeratedAttribute {
+
+ private static final String[] VALID_SYSTEM_TYPES = {
+ "", "UNIX", "VMS", "WINDOWS", "OS/2", "OS/400",
+ "MVS"
+ };
+
+
+ /**
+ * Get the valid values.
+ * @return the list of valid system types.
+ */
+ public String[] getValues() {
+ return VALID_SYSTEM_TYPES;
+ }
+
+ static final FTPSystemType getDefault() {
+ FTPSystemType ftpst = new FTPSystemType();
+ ftpst.setValue("");
+ return ftpst;
+ }
+ }
+ /**
+ * Enumerated class for languages.
+ */
+ public static class LanguageCode extends EnumeratedAttribute {
+
+
+ private static final String[] VALID_LANGUAGE_CODES =
+ getValidLanguageCodes();
+
+ private static String[] getValidLanguageCodes() {
+ Collection c = FTPClientConfig.getSupportedLanguageCodes();
+ String[] ret = new String[c.size() + 1];
+ int i = 0;
+ ret[i++] = "";
+ for (Iterator it = c.iterator(); it.hasNext(); i++) {
+ ret[i] = (String) it.next();
+ }
+ return ret;
+ }
+
+
+ /**
+ * Return the value values.
+ * @return the list of valid language types.
+ */
+ public String[] getValues() {
+ return VALID_LANGUAGE_CODES;
+ }
+
+ static final LanguageCode getDefault() {
+ LanguageCode lc = new LanguageCode();
+ lc.setValue("");
+ return lc;
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java
new file mode 100644
index 00000000..0604dac9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPClientConfig;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * The sole purpose of this class is (note that it is package-private
+ * is to serve as a separate, static compilation unit for importing
+ * FTPClientConfig, to enable users who wish to use the FTP task
+ * without using its new features to avoid the need to
+ * upgrade to jakarta-commons-net 1.4.0, where FTPClientConfig was
+ * introduced.
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+class FTPConfigurator {
+ /**
+ * configures the supplied FTPClient with the various
+ * attributes set in the supplied FTP task.
+ * @param client the FTPClient to be configured
+ * @param task the FTP task whose attributes are used to
+ * configure the client
+ * @return the client as configured.
+ */
+ static FTPClient configure(FTPClient client, FTPTaskConfig task) {
+ task.log("custom configuration", Project.MSG_VERBOSE);
+ FTPClientConfig config;
+ String systemTypeKey = task.getSystemTypeKey();
+ if (systemTypeKey != null && !"".equals(systemTypeKey)) {
+ config = new FTPClientConfig(systemTypeKey);
+ task.log("custom config: system key = "
+ + systemTypeKey, Project.MSG_VERBOSE);
+ } else {
+ config = new FTPClientConfig();
+ task.log("custom config: system key = default (UNIX)",
+ Project.MSG_VERBOSE);
+ }
+
+ String defaultDateFormatConfig = task.getDefaultDateFormatConfig();
+ if (defaultDateFormatConfig != null) {
+ config.setDefaultDateFormatStr(defaultDateFormatConfig);
+ task.log("custom config: default date format = "
+ + defaultDateFormatConfig, Project.MSG_VERBOSE);
+ }
+
+ String recentDateFormatConfig = task.getRecentDateFormatConfig();
+ if (recentDateFormatConfig != null) {
+ config.setRecentDateFormatStr(recentDateFormatConfig);
+ task.log("custom config: recent date format = "
+ + recentDateFormatConfig, Project.MSG_VERBOSE);
+ }
+
+ String serverLanguageCodeConfig = task.getServerLanguageCodeConfig();
+ if (serverLanguageCodeConfig != null) {
+ if (!"".equals(serverLanguageCodeConfig)
+ && !FTPClientConfig.getSupportedLanguageCodes()
+ .contains(serverLanguageCodeConfig)) {
+ throw new BuildException("unsupported language code" +
+ serverLanguageCodeConfig);
+ }
+ config.setServerLanguageCode(serverLanguageCodeConfig);
+ task.log("custom config: server language code = "
+ + serverLanguageCodeConfig, Project.MSG_VERBOSE);
+ }
+
+ String serverTimeZoneConfig = task.getServerTimeZoneConfig();
+ if (serverTimeZoneConfig != null) {
+ config.setServerTimeZoneId(serverTimeZoneConfig);
+ task.log("custom config: server time zone ID = "
+ + serverTimeZoneConfig, Project.MSG_VERBOSE);
+ }
+
+ String shortMonthNamesConfig = task.getShortMonthNamesConfig();
+ if (shortMonthNamesConfig != null) {
+ config.setShortMonthNames(shortMonthNamesConfig);
+ task.log("custom config: short month names = "
+ + shortMonthNamesConfig, Project.MSG_VERBOSE);
+ }
+ client.configure(config);
+ return client;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTask.java
new file mode 100644
index 00000000..79780c78
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTask.java
@@ -0,0 +1,965 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.LoaderUtils;
+import org.apache.tools.ant.util.Retryable;
+import org.apache.tools.ant.util.SplitClassLoader;
+
+/**
+ * Basic FTP client. Performs the following actions:
+ * <ul>
+ * <li> <strong>send</strong> - send files to a remote server. This is the
+ * default action.</li>
+ * <li> <strong>get</strong> - retrieve files from a remote server.</li>
+ * <li> <strong>del</strong> - delete files from a remote server.</li>
+ * <li> <strong>list</strong> - create a file listing.</li>
+ * <li> <strong>chmod</strong> - change unix file permissions.</li>
+ * <li> <strong>rmdir</strong> - remove directories, if empty, from a
+ * remote server.</li>
+ * </ul>
+ * <strong>Note:</strong> Some FTP servers - notably the Solaris server - seem
+ * to hold data ports open after a "retr" operation, allowing them to timeout
+ * instead of shutting them down cleanly. This happens in active or passive
+ * mode, and the ports will remain open even after ending the FTP session. FTP
+ * "send" operations seem to close ports immediately. This behavior may cause
+ * problems on some systems when downloading large sets of files.
+ *
+ * @since Ant 1.3
+ */
+public class FTPTask extends Task implements FTPTaskConfig {
+ public static final int SEND_FILES = 0;
+ public static final int GET_FILES = 1;
+ public static final int DEL_FILES = 2;
+ public static final int LIST_FILES = 3;
+ public static final int MK_DIR = 4;
+ public static final int CHMOD = 5;
+ public static final int RM_DIR = 6;
+ public static final int SITE_CMD = 7;
+
+ /** adjust uptodate calculations where server timestamps are HH:mm and client's
+ * are HH:mm:ss */
+ private static final long GRANULARITY_MINUTE = 60000L;
+
+ /** Default port for FTP */
+ public static final int DEFAULT_FTP_PORT = 21;
+
+ private String remotedir;
+ private String server;
+ private String userid;
+ private String password;
+ private String account;
+ private File listing;
+ private boolean binary = true;
+ private boolean passive = false;
+ private boolean verbose = false;
+ private boolean newerOnly = false;
+ private long timeDiffMillis = 0;
+ private long granularityMillis = 0L;
+ private boolean timeDiffAuto = false;
+ private int action = SEND_FILES;
+ private Vector filesets = new Vector();
+ private String remoteFileSep = "/";
+ private int port = DEFAULT_FTP_PORT;
+ private boolean skipFailedTransfers = false;
+ private boolean ignoreNoncriticalErrors = false;
+ private boolean preserveLastModified = false;
+ private String chmod = null;
+ private String umask = null;
+ private FTPSystemType systemTypeKey = FTPSystemType.getDefault();
+ private String defaultDateFormatConfig = null;
+ private String recentDateFormatConfig = null;
+ private String serverLanguageCodeConfig = null;
+ private String serverTimeZoneConfig = null;
+ private String shortMonthNamesConfig = null;
+ private Granularity timestampGranularity = Granularity.getDefault();
+ private boolean isConfigurationSet = false;
+ private int retriesAllowed = 0;
+ private String siteCommand = null;
+ private String initialSiteCommand = null;
+ private boolean enableRemoteVerification = true;
+
+ private Path classpath;
+ private ClassLoader mirrorLoader;
+ private FTPTaskMirror delegate = null;
+
+ public static final String[] ACTION_STRS = {
+ "sending",
+ "getting",
+ "deleting",
+ "listing",
+ "making directory",
+ "chmod",
+ "removing",
+ "site"
+ };
+
+ public static final String[] COMPLETED_ACTION_STRS = {
+ "sent",
+ "retrieved",
+ "deleted",
+ "listed",
+ "created directory",
+ "mode changed",
+ "removed",
+ "site command executed"
+ };
+
+ public static final String[] ACTION_TARGET_STRS = {
+ "files",
+ "files",
+ "files",
+ "files",
+ "directory",
+ "files",
+ "directories",
+ "site command"
+ };
+
+ /**
+ * Sets the remote directory where files will be placed. This may be a
+ * relative or absolute path, and must be in the path syntax expected by
+ * the remote server. No correction of path syntax will be performed.
+ *
+ * @param dir the remote directory name.
+ */
+ public void setRemotedir(String dir) {
+ this.remotedir = dir;
+ }
+
+ public String getRemotedir() {
+ return remotedir;
+ }
+
+ /**
+ * Sets the FTP server to send files to.
+ *
+ * @param server the remote server name.
+ */
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ /**
+ * Sets the FTP port used by the remote server.
+ *
+ * @param port the port on which the remote server is listening.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Sets the login user id to use on the specified server.
+ *
+ * @param userid remote system userid.
+ */
+ public void setUserid(String userid) {
+ this.userid = userid;
+ }
+
+ public String getUserid() {
+ return userid;
+ }
+
+ /**
+ * Sets the login password for the given user id.
+ *
+ * @param password the password on the remote system.
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the login account to use on the specified server.
+ *
+ * @param pAccount the account name on remote system
+ * @since Ant 1.7
+ */
+ public void setAccount(String pAccount) {
+ this.account = pAccount;
+ }
+
+ public String getAccount() {
+ return account;
+ }
+
+ /**
+ * If true, uses binary mode, otherwise text mode (default is binary).
+ *
+ * @param binary if true use binary mode in transfers.
+ */
+ public void setBinary(boolean binary) {
+ this.binary = binary;
+ }
+
+ public boolean isBinary() {
+ return binary;
+ }
+
+ /**
+ * Specifies whether to use passive mode. Set to true if you are behind a
+ * firewall and cannot connect without it. Passive mode is disabled by
+ * default.
+ *
+ * @param passive true is passive mode should be used.
+ */
+ public void setPassive(boolean passive) {
+ this.passive = passive;
+ }
+
+ public boolean isPassive() {
+ return passive;
+ }
+
+ /**
+ * Set to true to receive notification about each file as it is
+ * transferred.
+ *
+ * @param verbose true if verbose notifications are required.
+ */
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public boolean isVerbose() {
+ return verbose;
+ }
+
+ /**
+ * A synonym for <tt>depends</tt>. Set to true to transmit only new
+ * or changed files.
+ *
+ * See the related attributes timediffmillis and timediffauto.
+ *
+ * @param newer if true only transfer newer files.
+ */
+ public void setNewer(boolean newer) {
+ this.newerOnly = newer;
+ }
+
+ public boolean isNewer() {
+ return newerOnly;
+ }
+
+ /**
+ * number of milliseconds to add to the time on the remote machine
+ * to get the time on the local machine.
+ *
+ * use in conjunction with <code>newer</code>
+ *
+ * @param timeDiffMillis number of milliseconds
+ *
+ * @since ant 1.6
+ */
+ public void setTimeDiffMillis(long timeDiffMillis) {
+ this.timeDiffMillis = timeDiffMillis;
+ }
+
+ public long getTimeDiffMillis() {
+ return timeDiffMillis;
+ }
+
+ /**
+ * &quot;true&quot; to find out automatically the time difference
+ * between local and remote machine.
+ *
+ * This requires right to create
+ * and delete a temporary file in the remote directory.
+ *
+ * @param timeDiffAuto true = find automatically the time diff
+ *
+ * @since ant 1.6
+ */
+ public void setTimeDiffAuto(boolean timeDiffAuto) {
+ this.timeDiffAuto = timeDiffAuto;
+ }
+
+ public boolean isTimeDiffAuto() {
+ return timeDiffAuto;
+ }
+
+ /**
+ * Set to true to preserve modification times for "gotten" files.
+ *
+ * @param preserveLastModified if true preserver modification times.
+ */
+ public void setPreserveLastModified(boolean preserveLastModified) {
+ this.preserveLastModified = preserveLastModified;
+ }
+
+ public boolean isPreserveLastModified() {
+ return preserveLastModified;
+ }
+
+ /**
+ * Set to true to transmit only files that are new or changed from their
+ * remote counterparts. The default is to transmit all files.
+ *
+ * @param depends if true only transfer newer files.
+ */
+ public void setDepends(boolean depends) {
+ this.newerOnly = depends;
+ }
+
+
+ /**
+ * Sets the remote file separator character. This normally defaults to the
+ * Unix standard forward slash, but can be manually overridden using this
+ * call if the remote server requires some other separator. Only the first
+ * character of the string is used.
+ *
+ * @param separator the file separator on the remote system.
+ */
+ public void setSeparator(String separator) {
+ remoteFileSep = separator;
+ }
+
+
+ public String getSeparator() {
+ return remoteFileSep;
+ }
+
+ /**
+ * Sets the file permission mode (Unix only) for files sent to the
+ * server.
+ *
+ * @param theMode unix style file mode for the files sent to the remote
+ * system.
+ */
+ public void setChmod(String theMode) {
+ this.chmod = theMode;
+ }
+
+ public String getChmod() {
+ return chmod;
+ }
+
+ /**
+ * Sets the default mask for file creation on a unix server.
+ *
+ * @param theUmask unix style umask for files created on the remote server.
+ */
+ public void setUmask(String theUmask) {
+ this.umask = theUmask;
+ }
+
+ public String getUmask() {
+ return umask;
+ }
+
+ /**
+ * A set of files to upload or download
+ *
+ * @param set the set of files to be added to the list of files to be
+ * transferred.
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ public Vector getFilesets() {
+ return filesets;
+ }
+
+ /**
+ * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
+ * "mkdir", "chmod", "list", and "site".
+ *
+ * @deprecated since 1.5.x.
+ * setAction(String) is deprecated and is replaced with
+ * setAction(FTP.Action) to make Ant's Introspection mechanism do the
+ * work and also to encapsulate operations on the type in its own
+ * class.
+ * @ant.attribute ignore="true"
+ *
+ * @param action the FTP action to be performed.
+ *
+ * @throws BuildException if the action is not a valid action.
+ */
+ public void setAction(String action) throws BuildException {
+ log("DEPRECATED - The setAction(String) method has been deprecated."
+ + " Use setAction(FTP.Action) instead.");
+
+ Action a = new Action();
+
+ a.setValue(action);
+ this.action = a.getAction();
+ }
+
+
+ /**
+ * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
+ * "mkdir", "chmod", "list", and "site".
+ *
+ * @param action the FTP action to be performed.
+ *
+ * @throws BuildException if the action is not a valid action.
+ */
+ public void setAction(Action action) throws BuildException {
+ this.action = action.getAction();
+ }
+
+ public int getAction() {
+ return this.action;
+ }
+
+ /**
+ * The output file for the "list" action. This attribute is ignored for
+ * any other actions.
+ *
+ * @param listing file in which to store the listing.
+ */
+ public void setListing(File listing) {
+ this.listing = listing;
+ }
+
+ public File getListing() {
+ return listing;
+ }
+
+ /**
+ * If true, enables unsuccessful file put, delete and get
+ * operations to be skipped with a warning and the remainder
+ * of the files still transferred.
+ *
+ * @param skipFailedTransfers true if failures in transfers are ignored.
+ */
+ public void setSkipFailedTransfers(boolean skipFailedTransfers) {
+ this.skipFailedTransfers = skipFailedTransfers;
+ }
+
+ public boolean isSkipFailedTransfers() {
+ return skipFailedTransfers;
+ }
+
+ /**
+ * set the flag to skip errors on directory creation.
+ * (and maybe later other server specific errors)
+ *
+ * @param ignoreNoncriticalErrors true if non-critical errors should not
+ * cause a failure.
+ */
+ public void setIgnoreNoncriticalErrors(boolean ignoreNoncriticalErrors) {
+ this.ignoreNoncriticalErrors = ignoreNoncriticalErrors;
+ }
+
+ public boolean isIgnoreNoncriticalErrors() {
+ return ignoreNoncriticalErrors;
+ }
+
+ private void configurationHasBeenSet() {
+ this.isConfigurationSet = true;
+ }
+
+ public boolean isConfigurationSet() {
+ return this.isConfigurationSet;
+ }
+
+ /**
+ * Sets the systemTypeKey attribute.
+ * Method for setting <code>FTPClientConfig</code> remote system key.
+ *
+ * @param systemKey the key to be set - BUT if blank
+ * the default value of null (which signifies "autodetect") will be kept.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setSystemTypeKey(FTPSystemType systemKey) {
+ if (systemKey != null && !systemKey.getValue().equals("")) {
+ this.systemTypeKey = systemKey;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the defaultDateFormatConfig attribute.
+ * @param defaultDateFormat configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setDefaultDateFormatConfig(String defaultDateFormat) {
+ if (defaultDateFormat != null && !defaultDateFormat.equals("")) {
+ this.defaultDateFormatConfig = defaultDateFormat;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the recentDateFormatConfig attribute.
+ * @param recentDateFormat configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setRecentDateFormatConfig(String recentDateFormat) {
+ if (recentDateFormat != null && !recentDateFormat.equals("")) {
+ this.recentDateFormatConfig = recentDateFormat;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the serverLanguageCode attribute.
+ * @param serverLanguageCode configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setServerLanguageCodeConfig(String serverLanguageCode) {
+ if (serverLanguageCode != null && !"".equals(serverLanguageCode)) {
+ this.serverLanguageCodeConfig = serverLanguageCode;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the serverTimeZoneConfig attribute.
+ * @param serverTimeZoneId configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setServerTimeZoneConfig(String serverTimeZoneId) {
+ if (serverTimeZoneId != null && !serverTimeZoneId.equals("")) {
+ this.serverTimeZoneConfig = serverTimeZoneId;
+ configurationHasBeenSet();
+ }
+ }
+
+ /**
+ * Sets the shortMonthNamesConfig attribute
+ *
+ * @param shortMonthNames configuration to be set, unless it is
+ * null or empty string, in which case ignored.
+ * @see org.apache.commons.net.ftp.FTPClientConfig
+ */
+ public void setShortMonthNamesConfig(String shortMonthNames) {
+ if (shortMonthNames != null && !shortMonthNames.equals("")) {
+ this.shortMonthNamesConfig = shortMonthNames;
+ configurationHasBeenSet();
+ }
+ }
+
+
+
+ /**
+ * Defines how many times to retry executing FTP command before giving up.
+ * Default is 0 - try once and if failure then give up.
+ *
+ * @param retriesAllowed number of retries to allow. -1 means
+ * keep trying forever. "forever" may also be specified as a
+ * synonym for -1.
+ */
+ public void setRetriesAllowed(String retriesAllowed) {
+ if ("FOREVER".equalsIgnoreCase(retriesAllowed)) {
+ this.retriesAllowed = Retryable.RETRY_FOREVER;
+ } else {
+ try {
+ int retries = Integer.parseInt(retriesAllowed);
+ if (retries < Retryable.RETRY_FOREVER) {
+ throw new BuildException(
+ "Invalid value for retriesAllowed attribute: "
+ + retriesAllowed);
+
+ }
+ this.retriesAllowed = retries;
+ } catch (NumberFormatException px) {
+ throw new BuildException(
+ "Invalid value for retriesAllowed attribute: "
+ + retriesAllowed);
+
+ }
+
+ }
+ }
+
+ public int getRetriesAllowed() {
+ return retriesAllowed;
+ }
+
+ /**
+ * @return Returns the systemTypeKey.
+ */
+ public String getSystemTypeKey() {
+ return systemTypeKey.getValue();
+ }
+ /**
+ * @return Returns the defaultDateFormatConfig.
+ */
+ public String getDefaultDateFormatConfig() {
+ return defaultDateFormatConfig;
+ }
+ /**
+ * @return Returns the recentDateFormatConfig.
+ */
+ public String getRecentDateFormatConfig() {
+ return recentDateFormatConfig;
+ }
+ /**
+ * @return Returns the serverLanguageCodeConfig.
+ */
+ public String getServerLanguageCodeConfig() {
+ return serverLanguageCodeConfig;
+ }
+ /**
+ * @return Returns the serverTimeZoneConfig.
+ */
+ public String getServerTimeZoneConfig() {
+ return serverTimeZoneConfig;
+ }
+ /**
+ * @return Returns the shortMonthNamesConfig.
+ */
+ public String getShortMonthNamesConfig() {
+ return shortMonthNamesConfig;
+ }
+ /**
+ * @return Returns the timestampGranularity.
+ */
+ public Granularity getTimestampGranularity() {
+ return timestampGranularity;
+ }
+ /**
+ * Sets the timestampGranularity attribute
+ * @param timestampGranularity The timestampGranularity to set.
+ */
+ public void setTimestampGranularity(Granularity timestampGranularity) {
+ if (null == timestampGranularity || "".equals(timestampGranularity.getValue())) {
+ return;
+ }
+ this.timestampGranularity = timestampGranularity;
+ }
+ /**
+ * Sets the siteCommand attribute. This attribute
+ * names the command that will be executed if the action
+ * is "site".
+ * @param siteCommand The siteCommand to set.
+ */
+ public void setSiteCommand(String siteCommand) {
+ this.siteCommand = siteCommand;
+ }
+
+ public String getSiteCommand() {
+ return siteCommand;
+ }
+
+ /**
+ * Sets the initialSiteCommand attribute. This attribute
+ * names a site command that will be executed immediately
+ * after connection.
+ * @param initialCommand The initialSiteCommand to set.
+ */
+ public void setInitialSiteCommand(String initialCommand) {
+ this.initialSiteCommand = initialCommand;
+ }
+
+ public String getInitialSiteCommand() {
+ return initialSiteCommand;
+ }
+
+ public long getGranularityMillis() {
+ return this.granularityMillis;
+ }
+
+ public void setGranularityMillis(long granularity) {
+ this.granularityMillis = granularity;
+ }
+
+ /**
+ * Whether to verify that data and control connections are
+ * connected to the same remote host.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setEnableRemoteVerification(boolean b) {
+ enableRemoteVerification = b;
+ }
+
+ public boolean getEnableRemoteVerification() {
+ return enableRemoteVerification;
+ }
+
+ /**
+ * Checks to see that all required parameters are set.
+ *
+ * @throws BuildException if the configuration is not valid.
+ */
+ protected void checkAttributes() throws BuildException {
+ if (server == null) {
+ throw new BuildException("server attribute must be set!");
+ }
+ if (userid == null) {
+ throw new BuildException("userid attribute must be set!");
+ }
+ if (password == null) {
+ throw new BuildException("password attribute must be set!");
+ }
+
+ if ((action == LIST_FILES) && (listing == null)) {
+ throw new BuildException("listing attribute must be set for list "
+ + "action!");
+ }
+
+ if (action == MK_DIR && remotedir == null) {
+ throw new BuildException("remotedir attribute must be set for "
+ + "mkdir action!");
+ }
+
+ if (action == CHMOD && chmod == null) {
+ throw new BuildException("chmod attribute must be set for chmod "
+ + "action!");
+ }
+ if (action == SITE_CMD && siteCommand == null) {
+ throw new BuildException("sitecommand attribute must be set for site "
+ + "action!");
+ }
+
+
+ if (this.isConfigurationSet) {
+ try {
+ Class.forName("org.apache.commons.net.ftp.FTPClientConfig");
+ } catch (ClassNotFoundException e) {
+ throw new BuildException(
+ "commons-net.jar >= 1.4.0 is required for at least one"
+ + " of the attributes specified.");
+ }
+ }
+ }
+
+ /**
+ * Runs the task.
+ *
+ * @throws BuildException if the task fails or is not configured
+ * correctly.
+ */
+ public void execute() throws BuildException {
+ checkAttributes();
+ try {
+ setupFTPDelegate();
+ delegate.doFTP();
+ } finally {
+ if (mirrorLoader instanceof SplitClassLoader) {
+ ((SplitClassLoader) mirrorLoader).cleanup();
+ }
+ mirrorLoader = null;
+ }
+ }
+
+ public Path createClasspath() {
+ if (classpath == null) {
+ classpath = new Path(getProject());
+ }
+ return classpath;
+ }
+
+ protected void setupFTPDelegate() {
+ ClassLoader myLoader = FTPTask.class.getClassLoader();
+ if (mustSplit()) {
+ mirrorLoader =
+ new SplitClassLoader(myLoader, classpath, getProject(),
+ new String[] {
+ "FTPTaskMirrorImpl",
+ "FTPConfigurator"
+ });
+ } else {
+ mirrorLoader = myLoader;
+ }
+ delegate = createMirror(this, mirrorLoader);
+ }
+
+ private static boolean mustSplit() {
+ return LoaderUtils.getResourceSource(FTPTask.class.getClassLoader(),
+ "/org/apache/commons/net/"
+ + "ftp/FTP.class")
+ == null;
+ }
+
+ private static FTPTaskMirror createMirror(FTPTask task,
+ ClassLoader loader) {
+ try {
+ loader.loadClass("org.apache.commons.net.ftp.FTP"); // sanity check
+ } catch (ClassNotFoundException e) {
+ throw new BuildException("The <classpath> for <ftp> must include"
+ + " commons-net.jar if not in Ant's own "
+ + " classpath", e, task.getLocation());
+ }
+ try {
+ Class c = loader.loadClass(FTPTaskMirror.class.getName() + "Impl");
+ if (c.getClassLoader() != loader) {
+ throw new BuildException("Overdelegating loader",
+ task.getLocation());
+ }
+ Constructor cons = c.getConstructor(new Class[] {FTPTask.class});
+ return (FTPTaskMirror) cons.newInstance(new Object[] {task});
+ } catch (Exception e) {
+ throw new BuildException(e, task.getLocation());
+ }
+ }
+
+ /**
+ * an action to perform, one of
+ * "send", "put", "recv", "get", "del", "delete", "list", "mkdir", "chmod",
+ * "rmdir"
+ */
+ public static class Action extends EnumeratedAttribute {
+
+ private static final String[] VALID_ACTIONS = {
+ "send", "put", "recv", "get", "del", "delete", "list", "mkdir",
+ "chmod", "rmdir", "site"
+ };
+
+
+ /**
+ * Get the valid values
+ *
+ * @return an array of the valid FTP actions.
+ */
+ public String[] getValues() {
+ return VALID_ACTIONS;
+ }
+
+
+ /**
+ * Get the symbolic equivalent of the action value.
+ *
+ * @return the SYMBOL representing the given action.
+ */
+ public int getAction() {
+ String actionL = getValue().toLowerCase(Locale.ENGLISH);
+ if (actionL.equals("send") || actionL.equals("put")) {
+ return SEND_FILES;
+ } else if (actionL.equals("recv") || actionL.equals("get")) {
+ return GET_FILES;
+ } else if (actionL.equals("del") || actionL.equals("delete")) {
+ return DEL_FILES;
+ } else if (actionL.equals("list")) {
+ return LIST_FILES;
+ } else if (actionL.equals("chmod")) {
+ return CHMOD;
+ } else if (actionL.equals("mkdir")) {
+ return MK_DIR;
+ } else if (actionL.equals("rmdir")) {
+ return RM_DIR;
+ } else if (actionL.equals("site")) {
+ return SITE_CMD;
+ }
+ return SEND_FILES;
+ }
+ }
+ /**
+ * represents one of the valid timestamp adjustment values
+ * recognized by the <code>timestampGranularity</code> attribute.<p>
+
+ * A timestamp adjustment may be used in file transfers for checking
+ * uptodateness. MINUTE means to add one minute to the server
+ * timestamp. This is done because FTP servers typically list
+ * timestamps HH:mm and client FileSystems typically use HH:mm:ss.
+ *
+ * The default is to use MINUTE for PUT actions and NONE for GET
+ * actions, since GETs have the <code>preserveLastModified</code>
+ * option, which takes care of the problem in most use cases where
+ * this level of granularity is an issue.
+ *
+ */
+ public static class Granularity extends EnumeratedAttribute {
+
+ private static final String[] VALID_GRANULARITIES = {
+ "", "MINUTE", "NONE"
+ };
+
+ /**
+ * Get the valid values.
+ * @return the list of valid Granularity values
+ */
+ public String[] getValues() {
+ return VALID_GRANULARITIES;
+ }
+ /**
+ * returns the number of milliseconds associated with
+ * the attribute, which can vary in some cases depending
+ * on the value of the action parameter.
+ * @param action SEND_FILES or GET_FILES
+ * @return the number of milliseconds associated with
+ * the attribute, in the context of the supplied action
+ */
+ public long getMilliseconds(int action) {
+ String granularityU = getValue().toUpperCase(Locale.ENGLISH);
+ if ("".equals(granularityU)) {
+ if (action == SEND_FILES) {
+ return GRANULARITY_MINUTE;
+ }
+ } else if ("MINUTE".equals(granularityU)) {
+ return GRANULARITY_MINUTE;
+ }
+ return 0L;
+ }
+ static final Granularity getDefault() {
+ Granularity g = new Granularity();
+ g.setValue("");
+ return g;
+ }
+
+ }
+ /**
+ * one of the valid system type keys recognized by the systemTypeKey
+ * attribute.
+ */
+ public static class FTPSystemType extends EnumeratedAttribute {
+
+ private static final String[] VALID_SYSTEM_TYPES = {
+ "", "UNIX", "VMS", "WINDOWS", "OS/2", "OS/400",
+ "MVS"
+ };
+
+
+ /**
+ * Get the valid values.
+ * @return the list of valid system types.
+ */
+ public String[] getValues() {
+ return VALID_SYSTEM_TYPES;
+ }
+
+ static final FTPSystemType getDefault() {
+ FTPSystemType ftpst = new FTPSystemType();
+ ftpst.setValue("");
+ return ftpst;
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskConfig.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskConfig.java
new file mode 100644
index 00000000..006df61f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskConfig.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+interface FTPTaskConfig {
+ void log(String msg, int level);
+ String getSystemTypeKey();
+ String getDefaultDateFormatConfig();
+ String getRecentDateFormatConfig();
+ String getServerLanguageCodeConfig();
+ String getServerTimeZoneConfig();
+ String getShortMonthNamesConfig();
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirror.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirror.java
new file mode 100644
index 00000000..5d09e6f6
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirror.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import org.apache.tools.ant.BuildException;
+
+public interface FTPTaskMirror {
+ void doFTP() throws BuildException;
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirrorImpl.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirrorImpl.java
new file mode 100644
index 00000000..a4f24130
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPTaskMirrorImpl.java
@@ -0,0 +1,1951 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Delete;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.RetryHandler;
+import org.apache.tools.ant.util.Retryable;
+import org.apache.tools.ant.util.VectorSet;
+
+public class FTPTaskMirrorImpl implements FTPTaskMirror {
+
+ /** return code of ftp */
+ private static final int CODE_521 = 521;
+ private static final int CODE_550 = 550;
+ private static final int CODE_553 = 553;
+
+ /** Date formatter used in logging, note not thread safe! */
+ private static final SimpleDateFormat TIMESTAMP_LOGGING_SDF =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ private final FTPTask task;
+ private Set dirCache = new HashSet();
+ private int transferred = 0;
+ private int skipped = 0;
+
+ /**
+ * Constructor.
+ * @param task the FTPTask that uses this mirror.
+ */
+ public FTPTaskMirrorImpl(FTPTask task) {
+ this.task = task;
+ }
+
+ /**
+ * internal class providing a File-like interface to some of the information
+ * available from the FTP server
+ *
+ */
+ protected static class FTPFileProxy extends File {
+
+ private final FTPFile file;
+ private final String[] parts;
+ private final String name;
+
+ /**
+ * creates a proxy to a FTP file
+ * @param file
+ */
+ public FTPFileProxy(FTPFile file) {
+ super(file.getName());
+ name = file.getName();
+ this.file = file;
+ parts = FileUtils.getPathStack(name);
+ }
+
+ /**
+ * creates a proxy to a FTP directory
+ * @param completePath the remote directory.
+ */
+ public FTPFileProxy(String completePath) {
+ super(completePath);
+ file = null;
+ name = completePath;
+ parts = FileUtils.getPathStack(completePath);
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#exists()
+ */
+ public boolean exists() {
+ return true;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getAbsolutePath()
+ */
+ public String getAbsolutePath() {
+ return name;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getName()
+ */
+ public String getName() {
+ return parts.length > 0 ? parts[parts.length - 1] : name;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getParent()
+ */
+ public String getParent() {
+ String result = "";
+ for(int i = 0; i < parts.length - 1; i++){
+ result += File.separatorChar + parts[i];
+ }
+ return result;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#getPath()
+ */
+ public String getPath() {
+ return name;
+ }
+
+
+ /**
+ * FTP files are stored as absolute paths
+ * @return true
+ */
+ public boolean isAbsolute() {
+ return true;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#isDirectory()
+ */
+ public boolean isDirectory() {
+ return file == null;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#isFile()
+ */
+ public boolean isFile() {
+ return file != null;
+ }
+
+
+ /**
+ * FTP files cannot be hidden
+ *
+ * @return false
+ */
+ public boolean isHidden() {
+ return false;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#lastModified()
+ */
+ public long lastModified() {
+ if (file != null) {
+ return file.getTimestamp().getTimeInMillis();
+ }
+ return 0;
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.io.File#length()
+ */
+ public long length() {
+ if (file != null) {
+ return file.getSize();
+ }
+ return 0;
+ }
+ }
+
+ /**
+ * internal class allowing to read the contents of a remote file system
+ * using the FTP protocol
+ * used in particular for ftp get operations
+ * differences with DirectoryScanner
+ * "" (the root of the fileset) is never included in the included directories
+ * followSymlinks defaults to false
+ */
+ protected class FTPDirectoryScanner extends DirectoryScanner {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected FTPClient ftp = null;
+ // CheckStyle:VisibilityModifier ON
+
+ private String rootPath = null;
+
+ /**
+ * since ant 1.6
+ * this flag should be set to true on UNIX and can save scanning time
+ */
+ private boolean remoteSystemCaseSensitive = false;
+ private boolean remoteSensitivityChecked = false;
+
+ /**
+ * constructor
+ * @param ftp ftpclient object
+ */
+ public FTPDirectoryScanner(FTPClient ftp) {
+ super();
+ this.ftp = ftp;
+ this.setFollowSymlinks(false);
+ }
+
+
+ /**
+ * scans the remote directory,
+ * storing internally the included files, directories, ...
+ */
+ public void scan() {
+ if (includes == null) {
+ // No includes supplied, so set it to 'matches all'
+ includes = new String[1];
+ includes[0] = "**";
+ }
+ if (excludes == null) {
+ excludes = new String[0];
+ }
+
+ filesIncluded = new VectorSet();
+ filesNotIncluded = new Vector();
+ filesExcluded = new VectorSet();
+ dirsIncluded = new VectorSet();
+ dirsNotIncluded = new Vector();
+ dirsExcluded = new VectorSet();
+
+ try {
+ String cwd = ftp.printWorkingDirectory();
+ // always start from the current ftp working dir
+ forceRemoteSensitivityCheck();
+
+ checkIncludePatterns();
+ clearCaches();
+ ftp.changeWorkingDirectory(cwd);
+ } catch (IOException e) {
+ throw new BuildException("Unable to scan FTP server: ", e);
+ }
+ }
+
+
+ /**
+ * this routine is actually checking all the include patterns in
+ * order to avoid scanning everything under base dir
+ * @since ant1.6
+ */
+ private void checkIncludePatterns() {
+
+ Hashtable newroots = new Hashtable();
+ // put in the newroots vector the include patterns without
+ // wildcard tokens
+ for (int icounter = 0; icounter < includes.length; icounter++) {
+ String newpattern =
+ SelectorUtils.rtrimWildcardTokens(includes[icounter]);
+ newroots.put(newpattern, includes[icounter]);
+ }
+ if (task.getRemotedir() == null) {
+ try {
+ task.setRemotedir(ftp.printWorkingDirectory());
+ } catch (IOException e) {
+ throw new BuildException("could not read current ftp directory",
+ task.getLocation());
+ }
+ }
+ AntFTPFile baseFTPFile = new AntFTPRootFile(ftp, task.getRemotedir());
+ rootPath = baseFTPFile.getAbsolutePath();
+ // construct it
+ if (newroots.containsKey("")) {
+ // we are going to scan everything anyway
+ scandir(rootPath, "", true);
+ } else {
+ // only scan directories that can include matched files or
+ // directories
+ Enumeration enum2 = newroots.keys();
+
+ while (enum2.hasMoreElements()) {
+ String currentelement = (String) enum2.nextElement();
+ String originalpattern = (String) newroots.get(currentelement);
+ AntFTPFile myfile = new AntFTPFile(baseFTPFile, currentelement);
+ boolean isOK = true;
+ boolean traversesSymlinks = false;
+ String path = null;
+
+ if (myfile.exists()) {
+ forceRemoteSensitivityCheck();
+ if (remoteSensitivityChecked
+ && remoteSystemCaseSensitive && isFollowSymlinks()) {
+ // cool case,
+ //we do not need to scan all the subdirs in the relative path
+ path = myfile.getFastRelativePath();
+ } else {
+ // may be on a case insensitive file system. We want
+ // the results to show what's really on the disk, so
+ // we need to double check.
+ try {
+ path = myfile.getRelativePath();
+ traversesSymlinks = myfile.isTraverseSymlinks();
+ } catch (IOException be) {
+ throw new BuildException(be, task.getLocation());
+ } catch (BuildException be) {
+ isOK = false;
+ }
+ }
+ } else {
+ isOK = false;
+ }
+ if (isOK) {
+ currentelement = path.replace(task.getSeparator().charAt(0), File.separatorChar);
+ if (!isFollowSymlinks()
+ && traversesSymlinks) {
+ continue;
+ }
+
+ if (myfile.isDirectory()) {
+ if (isIncluded(currentelement)
+ && currentelement.length() > 0) {
+ accountForIncludedDir(currentelement, myfile, true);
+ } else {
+ if (currentelement.length() > 0) {
+ if (currentelement.charAt(currentelement
+ .length() - 1)
+ != File.separatorChar) {
+ currentelement =
+ currentelement + File.separatorChar;
+ }
+ }
+ scandir(myfile.getAbsolutePath(), currentelement, true);
+ }
+ } else {
+ if (isCaseSensitive
+ && originalpattern.equals(currentelement)) {
+ accountForIncludedFile(currentelement);
+ } else if (!isCaseSensitive
+ && originalpattern
+ .equalsIgnoreCase(currentelement)) {
+ accountForIncludedFile(currentelement);
+ }
+ }
+ }
+ }
+ }
+ }
+ /**
+ * scans a particular directory. populates the scannedDirs cache.
+ *
+ * @param dir directory to scan
+ * @param vpath relative path to the base directory of the remote fileset
+ * always ended with a File.separator
+ * @param fast seems to be always true in practice
+ */
+ protected void scandir(String dir, String vpath, boolean fast) {
+ // avoid double scanning of directories, can only happen in fast mode
+ if (fast && hasBeenScanned(vpath)) {
+ return;
+ }
+ try {
+ if (!ftp.changeWorkingDirectory(dir)) {
+ return;
+ }
+ String completePath = null;
+ if (!vpath.equals("")) {
+ completePath = rootPath + task.getSeparator()
+ + vpath.replace(File.separatorChar, task.getSeparator().charAt(0));
+ } else {
+ completePath = rootPath;
+ }
+ FTPFile[] newfiles = listFiles(completePath, false);
+
+ if (newfiles == null) {
+ ftp.changeToParentDirectory();
+ return;
+ }
+ for (int i = 0; i < newfiles.length; i++) {
+ FTPFile file = newfiles[i];
+ if (file != null
+ && !file.getName().equals(".")
+ && !file.getName().equals("..")) {
+ String name = vpath + file.getName();
+ scannedDirs.put(name, new FTPFileProxy(file));
+ if (isFunctioningAsDirectory(ftp, dir, file)) {
+ boolean slowScanAllowed = true;
+ if (!isFollowSymlinks() && file.isSymbolicLink()) {
+ dirsExcluded.addElement(name);
+ slowScanAllowed = false;
+ } else if (isIncluded(name)) {
+ accountForIncludedDir(name,
+ new AntFTPFile(ftp, file, completePath) , fast);
+ } else {
+ dirsNotIncluded.addElement(name);
+ if (fast && couldHoldIncluded(name)) {
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ }
+ if (!fast && slowScanAllowed) {
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ } else {
+ if (!isFollowSymlinks() && file.isSymbolicLink()) {
+ filesExcluded.addElement(name);
+ } else if (isFunctioningAsFile(ftp, dir, file)) {
+ accountForIncludedFile(name);
+ }
+ }
+ }
+ }
+ ftp.changeToParentDirectory();
+ } catch (IOException e) {
+ throw new BuildException("Error while communicating with FTP "
+ + "server: ", e);
+ }
+ }
+ /**
+ * process included file
+ * @param name path of the file relative to the directory of the fileset
+ */
+ private void accountForIncludedFile(String name) {
+ if (!filesIncluded.contains(name)
+ && !filesExcluded.contains(name)) {
+
+ if (isIncluded(name)) {
+ if (!isExcluded(name)
+ && isSelected(name, (File) scannedDirs.get(name))) {
+ filesIncluded.addElement(name);
+ } else {
+ filesExcluded.addElement(name);
+ }
+ } else {
+ filesNotIncluded.addElement(name);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param name path of the directory relative to the directory of
+ * the fileset
+ * @param file directory as file
+ * @param fast
+ */
+ private void accountForIncludedDir(String name, AntFTPFile file, boolean fast) {
+ if (!dirsIncluded.contains(name)
+ && !dirsExcluded.contains(name)) {
+
+ if (!isExcluded(name)) {
+ if (fast) {
+ if (file.isSymbolicLink()) {
+ try {
+ file.getClient().changeWorkingDirectory(file.curpwd);
+ } catch (IOException ioe) {
+ throw new BuildException("could not change directory to curpwd");
+ }
+ scandir(file.getLink(),
+ name + File.separator, fast);
+ } else {
+ try {
+ file.getClient().changeWorkingDirectory(file.curpwd);
+ } catch (IOException ioe) {
+ throw new BuildException("could not change directory to curpwd");
+ }
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ }
+ dirsIncluded.addElement(name);
+ } else {
+ dirsExcluded.addElement(name);
+ if (fast && couldHoldIncluded(name)) {
+ try {
+ file.getClient().changeWorkingDirectory(file.curpwd);
+ } catch (IOException ioe) {
+ throw new BuildException("could not change directory to curpwd");
+ }
+ scandir(file.getName(),
+ name + File.separator, fast);
+ }
+ }
+ }
+ }
+ /**
+ * temporary table to speed up the various scanning methods below
+ *
+ * @since Ant 1.6
+ */
+ private Map fileListMap = new HashMap();
+ /**
+ * List of all scanned directories.
+ *
+ * @since Ant 1.6
+ */
+
+ private Map scannedDirs = new HashMap();
+
+ /**
+ * Has the directory with the given path relative to the base
+ * directory already been scanned?
+ *
+ * @since Ant 1.6
+ */
+ private boolean hasBeenScanned(String vpath) {
+ return scannedDirs.containsKey(vpath);
+ }
+
+ /**
+ * Clear internal caches.
+ *
+ * @since Ant 1.6
+ */
+ private void clearCaches() {
+ fileListMap.clear();
+ scannedDirs.clear();
+ }
+ /**
+ * list the files present in one directory.
+ * @param directory full path on the remote side
+ * @param changedir if true change to directory directory before listing
+ * @return array of FTPFile
+ */
+ public FTPFile[] listFiles(String directory, boolean changedir) {
+ //task.log("listing files in directory " + directory, Project.MSG_DEBUG);
+ String currentPath = directory;
+ if (changedir) {
+ try {
+ boolean result = ftp.changeWorkingDirectory(directory);
+ if (!result) {
+ return null;
+ }
+ currentPath = ftp.printWorkingDirectory();
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, task.getLocation());
+ }
+ }
+ if (fileListMap.containsKey(currentPath)) {
+ task.log("filelist map used in listing files", Project.MSG_DEBUG);
+ return ((FTPFile[]) fileListMap.get(currentPath));
+ }
+ FTPFile[] result = null;
+ try {
+ result = ftp.listFiles();
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, task.getLocation());
+ }
+ fileListMap.put(currentPath, result);
+ if (!remoteSensitivityChecked) {
+ checkRemoteSensitivity(result, directory);
+ }
+ return result;
+ }
+
+ private void forceRemoteSensitivityCheck() {
+ if (!remoteSensitivityChecked) {
+ try {
+ checkRemoteSensitivity(ftp.listFiles(), ftp.printWorkingDirectory());
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, task.getLocation());
+ }
+ }
+ }
+ /**
+ * cd into one directory and
+ * list the files present in one directory.
+ * @param directory full path on the remote side
+ * @return array of FTPFile
+ */
+ public FTPFile[] listFiles(String directory) {
+ return listFiles(directory, true);
+ }
+ private void checkRemoteSensitivity(FTPFile[] array, String directory) {
+ if (array == null) {
+ return;
+ }
+ boolean candidateFound = false;
+ String target = null;
+ for (int icounter = 0; icounter < array.length; icounter++) {
+ if (array[icounter] != null && array[icounter].isDirectory()) {
+ if (!array[icounter].getName().equals(".")
+ && !array[icounter].getName().equals("..")) {
+ candidateFound = true;
+ target = fiddleName(array[icounter].getName());
+ task.log("will try to cd to "
+ + target + " where a directory called " + array[icounter].getName()
+ + " exists", Project.MSG_DEBUG);
+ for (int pcounter = 0; pcounter < array.length; pcounter++) {
+ if (array[pcounter] != null
+ && pcounter != icounter
+ && target.equals(array[pcounter].getName())) {
+ candidateFound = false;
+ break;
+ }
+ }
+ if (candidateFound) {
+ break;
+ }
+ }
+ }
+ }
+ if (candidateFound) {
+ try {
+ task.log("testing case sensitivity, attempting to cd to "
+ + target, Project.MSG_DEBUG);
+ remoteSystemCaseSensitive = !ftp.changeWorkingDirectory(target);
+ } catch (IOException ioe) {
+ remoteSystemCaseSensitive = true;
+ } finally {
+ try {
+ ftp.changeWorkingDirectory(directory);
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, task.getLocation());
+ }
+ }
+ task.log("remote system is case sensitive : "
+ + remoteSystemCaseSensitive,
+ Project.MSG_VERBOSE);
+ remoteSensitivityChecked = true;
+ }
+ }
+ private String fiddleName(String origin) {
+ StringBuffer result = new StringBuffer();
+ for (int icounter = 0; icounter < origin.length(); icounter++) {
+ if (Character.isLowerCase(origin.charAt(icounter))) {
+ result.append(Character.toUpperCase(origin.charAt(icounter)));
+ } else if (Character.isUpperCase(origin.charAt(icounter))) {
+ result.append(Character.toLowerCase(origin.charAt(icounter)));
+ } else {
+ result.append(origin.charAt(icounter));
+ }
+ }
+ return result.toString();
+ }
+ /**
+ * an AntFTPFile is a representation of a remote file
+ * @since Ant 1.6
+ */
+ protected class AntFTPFile {
+ /**
+ * ftp client
+ */
+ private FTPClient client;
+ /**
+ * parent directory of the file
+ */
+ private String curpwd;
+ /**
+ * the file itself
+ */
+ private FTPFile ftpFile;
+ /**
+ *
+ */
+ private AntFTPFile parent = null;
+ private boolean relativePathCalculated = false;
+ private boolean traversesSymlinks = false;
+ private String relativePath = "";
+ /**
+ * constructor
+ * @param client ftp client variable
+ * @param ftpFile the file
+ * @param curpwd absolute remote path where the file is found
+ */
+ public AntFTPFile(FTPClient client, FTPFile ftpFile, String curpwd) {
+ this.client = client;
+ this.ftpFile = ftpFile;
+ this.curpwd = curpwd;
+ }
+ /**
+ * other constructor
+ * @param parent the parent file
+ * @param path a relative path to the parent file
+ */
+ public AntFTPFile(AntFTPFile parent, String path) {
+ this.parent = parent;
+ this.client = parent.client;
+ Vector pathElements = SelectorUtils.tokenizePath(path);
+ try {
+ boolean result = this.client.changeWorkingDirectory(parent.getAbsolutePath());
+ //this should not happen, except if parent has been deleted by another process
+ if (!result) {
+ return;
+ }
+ this.curpwd = parent.getAbsolutePath();
+ } catch (IOException ioe) {
+ throw new BuildException("could not change working dir to "
+ + parent.curpwd);
+ }
+ final int size = pathElements.size();
+ for (int fcount = 0; fcount < size - 1; fcount++) {
+ String currentPathElement = (String) pathElements.elementAt(fcount);
+ try {
+ boolean result = this.client.changeWorkingDirectory(currentPathElement);
+ if (!result && !isCaseSensitive()
+ && (remoteSystemCaseSensitive || !remoteSensitivityChecked)) {
+ currentPathElement = findPathElementCaseUnsensitive(this.curpwd,
+ currentPathElement);
+ if (currentPathElement == null) {
+ return;
+ }
+ } else if (!result) {
+ return;
+ }
+ this.curpwd = getCurpwdPlusFileSep()
+ + currentPathElement;
+ } catch (IOException ioe) {
+ throw new BuildException("could not change working dir to "
+ + (String) pathElements.elementAt(fcount)
+ + " from " + this.curpwd);
+ }
+
+ }
+ String lastpathelement = (String) pathElements.elementAt(size - 1);
+ FTPFile [] theFiles = listFiles(this.curpwd);
+ this.ftpFile = getFile(theFiles, lastpathelement);
+ }
+ /**
+ * find a file in a directory in case unsensitive way
+ * @param parentPath where we are
+ * @param soughtPathElement what is being sought
+ * @return the first file found or null if not found
+ */
+ private String findPathElementCaseUnsensitive(String parentPath,
+ String soughtPathElement) {
+ // we are already in the right path, so the second parameter
+ // is false
+ FTPFile[] theFiles = listFiles(parentPath, false);
+ if (theFiles == null) {
+ return null;
+ }
+ for (int icounter = 0; icounter < theFiles.length; icounter++) {
+ if (theFiles[icounter] != null
+ && theFiles[icounter].getName().equalsIgnoreCase(soughtPathElement)) {
+ return theFiles[icounter].getName();
+ }
+ }
+ return null;
+ }
+ /**
+ * find out if the file exists
+ * @return true if the file exists
+ */
+ public boolean exists() {
+ return (ftpFile != null);
+ }
+ /**
+ * if the file is a symbolic link, find out to what it is pointing
+ * @return the target of the symbolic link
+ */
+ public String getLink() {
+ return ftpFile.getLink();
+ }
+ /**
+ * get the name of the file
+ * @return the name of the file
+ */
+ public String getName() {
+ return ftpFile.getName();
+ }
+ /**
+ * find out the absolute path of the file
+ * @return absolute path as string
+ */
+ public String getAbsolutePath() {
+ return getCurpwdPlusFileSep() + ftpFile.getName();
+ }
+ /**
+ * find out the relative path assuming that the path used to construct
+ * this AntFTPFile was spelled properly with regards to case.
+ * This is OK on a case sensitive system such as UNIX
+ * @return relative path
+ */
+ public String getFastRelativePath() {
+ String absPath = getAbsolutePath();
+ if (absPath.startsWith(rootPath + task.getSeparator())) {
+ return absPath.substring(rootPath.length()
+ + task.getSeparator().length());
+ }
+ return null;
+ }
+ /**
+ * find out the relative path to the rootPath of the enclosing scanner.
+ * this relative path is spelled exactly like on disk,
+ * for instance if the AntFTPFile has been instantiated as ALPHA,
+ * but the file is really called alpha, this method will return alpha.
+ * If a symbolic link is encountered, it is followed, but the name of the link
+ * rather than the name of the target is returned.
+ * (ie does not behave like File.getCanonicalPath())
+ * @return relative path, separated by remoteFileSep
+ * @throws IOException if a change directory fails, ...
+ * @throws BuildException if one of the components of the relative path cannot
+ * be found.
+ */
+ public String getRelativePath() throws IOException, BuildException {
+ if (!relativePathCalculated) {
+ if (parent != null) {
+ traversesSymlinks = parent.isTraverseSymlinks();
+ relativePath = getRelativePath(parent.getAbsolutePath(),
+ parent.getRelativePath());
+ } else {
+ relativePath = getRelativePath(rootPath, "");
+ relativePathCalculated = true;
+ }
+ }
+ return relativePath;
+ }
+ /**
+ * get the relative path of this file
+ * @param currentPath base path
+ * @param currentRelativePath relative path of the base path with regards to remote dir
+ * @return relative path
+ */
+ private String getRelativePath(String currentPath, String currentRelativePath) {
+ Vector pathElements = SelectorUtils.tokenizePath(getAbsolutePath(), task.getSeparator());
+ Vector pathElements2 = SelectorUtils.tokenizePath(currentPath,
+ task.getSeparator());
+ String relPath = currentRelativePath;
+ final int size = pathElements.size();
+ for (int pcount = pathElements2.size(); pcount < size; pcount++) {
+ String currentElement = (String) pathElements.elementAt(pcount);
+ FTPFile[] theFiles = listFiles(currentPath);
+ FTPFile theFile = null;
+ if (theFiles != null) {
+ theFile = getFile(theFiles, currentElement);
+ }
+ if (!relPath.equals("")) {
+ relPath = relPath + task.getSeparator();
+ }
+ if (theFile == null) {
+ // hit a hidden file assume not a symlink
+ relPath = relPath + currentElement;
+ currentPath = currentPath + task.getSeparator()
+ + currentElement;
+ task.log("Hidden file " + relPath
+ + " assumed to not be a symlink.",
+ Project.MSG_VERBOSE);
+ } else {
+ traversesSymlinks = traversesSymlinks || theFile.isSymbolicLink();
+ relPath = relPath + theFile.getName();
+ currentPath = currentPath + task.getSeparator()
+ + theFile.getName();
+ }
+ }
+ return relPath;
+ }
+ /**
+ * find a file matching a string in an array of FTPFile.
+ * This method will find "alpha" when requested for "ALPHA"
+ * if and only if the caseSensitive attribute is set to false.
+ * When caseSensitive is set to true, only the exact match is returned.
+ * @param theFiles array of files
+ * @param lastpathelement the file name being sought
+ * @return null if the file cannot be found, otherwise return the matching file.
+ */
+ public FTPFile getFile(FTPFile[] theFiles, String lastpathelement) {
+ if (theFiles == null) {
+ return null;
+ }
+ for (int fcount = 0; fcount < theFiles.length; fcount++) {
+ if (theFiles[fcount] != null) {
+ if (theFiles[fcount].getName().equals(lastpathelement)) {
+ return theFiles[fcount];
+ } else if (!isCaseSensitive()
+ && theFiles[fcount].getName().equalsIgnoreCase(
+ lastpathelement)) {
+ return theFiles[fcount];
+ }
+ }
+ }
+ return null;
+ }
+ /**
+ * tell if a file is a directory.
+ * note that it will return false for symbolic links pointing to directories.
+ * @return <code>true</code> for directories
+ */
+ public boolean isDirectory() {
+ return ftpFile.isDirectory();
+ }
+ /**
+ * tell if a file is a symbolic link
+ * @return <code>true</code> for symbolic links
+ */
+ public boolean isSymbolicLink() {
+ return ftpFile.isSymbolicLink();
+ }
+ /**
+ * return the attached FTP client object.
+ * Warning : this instance is really shared with the enclosing class.
+ * @return FTP client
+ */
+ protected FTPClient getClient() {
+ return client;
+ }
+
+ /**
+ * sets the current path of an AntFTPFile
+ * @param curpwd the current path one wants to set
+ */
+ protected void setCurpwd(String curpwd) {
+ this.curpwd = curpwd;
+ }
+ /**
+ * returns the path of the directory containing the AntFTPFile.
+ * of the full path of the file itself in case of AntFTPRootFile
+ * @return parent directory of the AntFTPFile
+ */
+ public String getCurpwd() {
+ return curpwd;
+ }
+ /**
+ * returns the path of the directory containing the AntFTPFile.
+ * of the full path of the file itself in case of AntFTPRootFile
+ * and appends the remote file separator if necessary.
+ * @return parent directory of the AntFTPFile
+ * @since Ant 1.8.2
+ */
+ public String getCurpwdPlusFileSep() {
+ String sep = task.getSeparator();
+ return curpwd.endsWith(sep) ? curpwd : curpwd + sep;
+ }
+ /**
+ * find out if a symbolic link is encountered in the relative path of this file
+ * from rootPath.
+ * @return <code>true</code> if a symbolic link is encountered in the relative path.
+ * @throws IOException if one of the change directory or directory listing operations
+ * fails
+ * @throws BuildException if a path component in the relative path cannot be found.
+ */
+ public boolean isTraverseSymlinks() throws IOException, BuildException {
+ if (!relativePathCalculated) {
+ // getRelativePath also finds about symlinks
+ getRelativePath();
+ }
+ return traversesSymlinks;
+ }
+
+ /**
+ * Get a string rep of this object.
+ * @return a string containing the pwd and the file.
+ */
+ public String toString() {
+ return "AntFtpFile: " + curpwd + "%" + ftpFile;
+ }
+ }
+ /**
+ * special class to represent the remote directory itself
+ * @since Ant 1.6
+ */
+ protected class AntFTPRootFile extends AntFTPFile {
+ private String remotedir;
+ /**
+ * constructor
+ * @param aclient FTP client
+ * @param remotedir remote directory
+ */
+ public AntFTPRootFile(FTPClient aclient, String remotedir) {
+ super(aclient, null, remotedir);
+ this.remotedir = remotedir;
+ try {
+ this.getClient().changeWorkingDirectory(this.remotedir);
+ this.setCurpwd(this.getClient().printWorkingDirectory());
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, task.getLocation());
+ }
+ }
+ /**
+ * find the absolute path
+ * @return absolute path
+ */
+ public String getAbsolutePath() {
+ return this.getCurpwd();
+ }
+ /**
+ * find out the relative path to root
+ * @return empty string
+ * @throws BuildException actually never
+ * @throws IOException actually never
+ */
+ public String getRelativePath() throws BuildException, IOException {
+ return "";
+ }
+ }
+ }
+ /**
+ * check FTPFiles to check whether they function as directories too
+ * the FTPFile API seem to make directory and symbolic links incompatible
+ * we want to find out if we can cd to a symbolic link
+ * @param dir the parent directory of the file to test
+ * @param file the file to test
+ * @return true if it is possible to cd to this directory
+ * @since ant 1.6
+ */
+ private boolean isFunctioningAsDirectory(FTPClient ftp, String dir, FTPFile file) {
+ boolean result = false;
+ String currentWorkingDir = null;
+ if (file.isDirectory()) {
+ return true;
+ } else if (file.isFile()) {
+ return false;
+ }
+ try {
+ currentWorkingDir = ftp.printWorkingDirectory();
+ } catch (IOException ioe) {
+ task.log("could not find current working directory " + dir
+ + " while checking a symlink", Project.MSG_DEBUG);
+ }
+ if (currentWorkingDir != null) {
+ try {
+ result = ftp.changeWorkingDirectory(file.getLink());
+ } catch (IOException ioe) {
+ task.log("could not cd to " + file.getLink()
+ + " while checking a symlink",
+ Project.MSG_DEBUG);
+ }
+ if (result) {
+ boolean comeback = false;
+ try {
+ comeback = ftp.changeWorkingDirectory(currentWorkingDir);
+ } catch (IOException ioe) {
+ task.log("could not cd back to " + dir + " while checking a symlink",
+ Project.MSG_ERR);
+ } finally {
+ if (!comeback) {
+ throw new BuildException("could not cd back to " + dir
+ + " while checking a symlink");
+ }
+ }
+ }
+ }
+ return result;
+ }
+ /**
+ * check FTPFiles to check whether they function as directories too
+ * the FTPFile API seem to make directory and symbolic links incompatible
+ * we want to find out if we can cd to a symbolic link
+ * @param dir the parent directory of the file to test
+ * @param file the file to test
+ * @return true if it is possible to cd to this directory
+ * @since ant 1.6
+ */
+ private boolean isFunctioningAsFile(FTPClient ftp, String dir, FTPFile file) {
+ if (file.isDirectory()) {
+ return false;
+ } else if (file.isFile()) {
+ return true;
+ }
+ return !isFunctioningAsDirectory(ftp, dir, file);
+ }
+
+ /**
+ * Executable a retryable object.
+ * @param h the retry handler.
+ * @param r the object that should be retried until it succeeds
+ * or the number of retrys is reached.
+ * @param descr a description of the command that is being run.
+ * @throws IOException if there is a problem.
+ */
+ protected void executeRetryable(RetryHandler h, Retryable r, String descr)
+ throws IOException {
+ h.execute(r, descr);
+ }
+
+
+ /**
+ * For each file in the fileset, do the appropriate action: send, get,
+ * delete, or list.
+ *
+ * @param ftp the FTPClient instance used to perform FTP actions
+ * @param fs the fileset on which the actions are performed.
+ *
+ * @return the number of files to be transferred.
+ *
+ * @throws IOException if there is a problem reading a file
+ * @throws BuildException if there is a problem in the configuration.
+ */
+ protected int transferFiles(final FTPClient ftp, FileSet fs)
+ throws IOException, BuildException {
+ DirectoryScanner ds;
+ if (task.getAction() == FTPTask.SEND_FILES) {
+ ds = fs.getDirectoryScanner(task.getProject());
+ } else {
+ ds = new FTPDirectoryScanner(ftp);
+ fs.setupDirectoryScanner(ds, task.getProject());
+ ds.setFollowSymlinks(fs.isFollowSymlinks());
+ ds.scan();
+ }
+
+ String[] dsfiles = null;
+ if (task.getAction() == FTPTask.RM_DIR) {
+ dsfiles = ds.getIncludedDirectories();
+ } else {
+ dsfiles = ds.getIncludedFiles();
+ }
+ String dir = null;
+
+ if ((ds.getBasedir() == null)
+ && ((task.getAction() == FTPTask.SEND_FILES) || (task.getAction() == FTPTask.GET_FILES))) {
+ throw new BuildException("the dir attribute must be set for send "
+ + "and get actions");
+ } else {
+ if ((task.getAction() == FTPTask.SEND_FILES) || (task.getAction() == FTPTask.GET_FILES)) {
+ dir = ds.getBasedir().getAbsolutePath();
+ }
+ }
+
+ // If we are doing a listing, we need the output stream created now.
+ BufferedWriter bw = null;
+
+ try {
+ if (task.getAction() == FTPTask.LIST_FILES) {
+ File pd = task.getListing().getParentFile();
+
+ if (!pd.exists()) {
+ pd.mkdirs();
+ }
+ bw = new BufferedWriter(new FileWriter(task.getListing()));
+ }
+ RetryHandler h = new RetryHandler(task.getRetriesAllowed(), task);
+ if (task.getAction() == FTPTask.RM_DIR) {
+ // to remove directories, start by the end of the list
+ // the trunk does not let itself be removed before the leaves
+ for (int i = dsfiles.length - 1; i >= 0; i--) {
+ final String dsfile = dsfiles[i];
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ rmDir(ftp, dsfile);
+ }
+ }, dsfile);
+ }
+ } else {
+ final BufferedWriter fbw = bw;
+ final String fdir = dir;
+ if (task.isNewer()) {
+ task.setGranularityMillis(task.getTimestampGranularity()
+ .getMilliseconds(task.getAction()));
+ }
+ for (int i = 0; i < dsfiles.length; i++) {
+ final String dsfile = dsfiles[i];
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ switch (task.getAction()) {
+ case FTPTask.SEND_FILES:
+ sendFile(ftp, fdir, dsfile);
+ break;
+ case FTPTask.GET_FILES:
+ getFile(ftp, fdir, dsfile);
+ break;
+ case FTPTask.DEL_FILES:
+ delFile(ftp, dsfile);
+ break;
+ case FTPTask.LIST_FILES:
+ listFile(ftp, fbw, dsfile);
+ break;
+ case FTPTask.CHMOD:
+ doSiteCommand(ftp, "chmod " + task.getChmod() + " "
+ + resolveFile(dsfile));
+ transferred++;
+ break;
+ default:
+ throw new BuildException("unknown ftp action "
+ + task.getAction());
+ }
+ }
+ }, dsfile);
+ }
+ }
+ } finally {
+ if (bw != null) {
+ bw.close();
+ }
+ }
+
+ return dsfiles.length;
+ }
+
+
+ /**
+ * Sends all files specified by the configured filesets to the remote
+ * server.
+ *
+ * @param ftp the FTPClient instance used to perform FTP actions
+ *
+ * @throws IOException if there is a problem reading a file
+ * @throws BuildException if there is a problem in the configuration.
+ */
+ protected void transferFiles(FTPClient ftp)
+ throws IOException, BuildException {
+ transferred = 0;
+ skipped = 0;
+
+ if (task.getFilesets().size() == 0) {
+ throw new BuildException("at least one fileset must be specified.");
+ } else {
+ // get files from filesets
+ final int size = task.getFilesets().size();
+ for (int i = 0; i < size; i++) {
+ FileSet fs = (FileSet) task.getFilesets().elementAt(i);
+
+ if (fs != null) {
+ transferFiles(ftp, fs);
+ }
+ }
+ }
+
+ task.log(transferred + " " + FTPTask.ACTION_TARGET_STRS[task.getAction()] + " "
+ + FTPTask.COMPLETED_ACTION_STRS[task.getAction()]);
+ if (skipped != 0) {
+ task.log(skipped + " " + FTPTask.ACTION_TARGET_STRS[task.getAction()]
+ + " were not successfully " + FTPTask.COMPLETED_ACTION_STRS[task.getAction()]);
+ }
+ }
+
+
+ /**
+ * Correct a file path to correspond to the remote host requirements. This
+ * implementation currently assumes that the remote end can handle
+ * Unix-style paths with forward-slash separators. This can be overridden
+ * with the <code>separator</code> task parameter. No attempt is made to
+ * determine what syntax is appropriate for the remote host.
+ *
+ * @param file the remote file name to be resolved
+ *
+ * @return the filename as it will appear on the server.
+ */
+ protected String resolveFile(String file) {
+ return file.replace(System.getProperty("file.separator").charAt(0),
+ task.getSeparator().charAt(0));
+ }
+
+
+ /**
+ * Creates all parent directories specified in a complete relative
+ * pathname. Attempts to create existing directories will not cause
+ * errors.
+ *
+ * @param ftp the FTP client instance to use to execute FTP actions on
+ * the remote server.
+ * @param filename the name of the file whose parents should be created.
+ * @throws IOException under non documented circumstances
+ * @throws BuildException if it is impossible to cd to a remote directory
+ *
+ */
+ protected void createParents(FTPClient ftp, String filename)
+ throws IOException, BuildException {
+
+ File dir = new File(filename);
+ if (dirCache.contains(dir)) {
+ return;
+ }
+
+ Vector parents = new Vector();
+ String dirname;
+
+ while ((dirname = dir.getParent()) != null) {
+ File checkDir = new File(dirname);
+ if (dirCache.contains(checkDir)) {
+ break;
+ }
+ dir = checkDir;
+ parents.addElement(dir);
+ }
+
+ // find first non cached dir
+ int i = parents.size() - 1;
+
+ if (i >= 0) {
+ String cwd = ftp.printWorkingDirectory();
+ String parent = dir.getParent();
+ if (parent != null) {
+ if (!ftp.changeWorkingDirectory(resolveFile(parent))) {
+ throw new BuildException("could not change to "
+ + "directory: " + ftp.getReplyString());
+ }
+ }
+
+ while (i >= 0) {
+ dir = (File) parents.elementAt(i--);
+ // check if dir exists by trying to change into it.
+ if (!ftp.changeWorkingDirectory(dir.getName())) {
+ // could not change to it - try to create it
+ task.log("creating remote directory "
+ + resolveFile(dir.getPath()), Project.MSG_VERBOSE);
+ if (!ftp.makeDirectory(dir.getName())) {
+ handleMkDirFailure(ftp);
+ }
+ if (!ftp.changeWorkingDirectory(dir.getName())) {
+ throw new BuildException("could not change to "
+ + "directory: " + ftp.getReplyString());
+ }
+ }
+ dirCache.add(dir);
+ }
+ ftp.changeWorkingDirectory(cwd);
+ }
+ }
+ /**
+ * auto find the time difference between local and remote
+ * @param ftp handle to ftp client
+ * @return number of millis to add to remote time to make it comparable to local time
+ * @since ant 1.6
+ */
+ private long getTimeDiff(FTPClient ftp) {
+ long returnValue = 0;
+ File tempFile = findFileName(ftp);
+ try {
+ // create a local temporary file
+ FILE_UTILS.createNewFile(tempFile);
+ long localTimeStamp = tempFile.lastModified();
+ BufferedInputStream instream = new BufferedInputStream(new FileInputStream(tempFile));
+ ftp.storeFile(tempFile.getName(), instream);
+ instream.close();
+ boolean success = FTPReply.isPositiveCompletion(ftp.getReplyCode());
+ if (success) {
+ FTPFile [] ftpFiles = ftp.listFiles(tempFile.getName());
+ if (ftpFiles.length == 1) {
+ long remoteTimeStamp = ftpFiles[0].getTimestamp().getTime().getTime();
+ returnValue = localTimeStamp - remoteTimeStamp;
+ }
+ ftp.deleteFile(ftpFiles[0].getName());
+ }
+ // delegate the deletion of the local temp file to the delete task
+ // because of race conditions occurring on Windows
+ Delete mydelete = new Delete();
+ mydelete.bindToOwner(task);
+ mydelete.setFile(tempFile.getCanonicalFile());
+ mydelete.execute();
+ } catch (Exception e) {
+ throw new BuildException(e, task.getLocation());
+ }
+ return returnValue;
+ }
+ /**
+ * find a suitable name for local and remote temporary file
+ */
+ private File findFileName(FTPClient ftp) {
+ FTPFile [] theFiles = null;
+ final int maxIterations = 1000;
+ for (int counter = 1; counter < maxIterations; counter++) {
+ File localFile = FILE_UTILS.createTempFile(
+ "ant" + Integer.toString(counter), ".tmp",
+ null, false, false);
+ String fileName = localFile.getName();
+ boolean found = false;
+ try {
+ if (theFiles == null) {
+ theFiles = ftp.listFiles();
+ }
+ for (int counter2 = 0; counter2 < theFiles.length; counter2++) {
+ if (theFiles[counter2] != null
+ && theFiles[counter2].getName().equals(fileName)) {
+ found = true;
+ break;
+ }
+ }
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, task.getLocation());
+ }
+ if (!found) {
+ localFile.deleteOnExit();
+ return localFile;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks to see if the remote file is current as compared with the local
+ * file. Returns true if the target file is up to date.
+ * @param ftp ftpclient
+ * @param localFile local file
+ * @param remoteFile remote file
+ * @return true if the target file is up to date
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if the date of the remote files cannot be found and the action is
+ * GET_FILES
+ */
+ protected boolean isUpToDate(FTPClient ftp, File localFile,
+ String remoteFile)
+ throws IOException, BuildException {
+ task.log("checking date for " + remoteFile, Project.MSG_VERBOSE);
+
+ FTPFile[] files = ftp.listFiles(remoteFile);
+
+ // For Microsoft's Ftp-Service an Array with length 0 is
+ // returned if configured to return listings in "MS-DOS"-Format
+ if (files == null || files.length == 0) {
+ // If we are sending files, then assume out of date.
+ // If we are getting files, then throw an error
+
+ if (task.getAction() == FTPTask.SEND_FILES) {
+ task.log("Could not date test remote file: " + remoteFile
+ + "assuming out of date.", Project.MSG_VERBOSE);
+ return false;
+ } else {
+ throw new BuildException("could not date test remote file: "
+ + ftp.getReplyString());
+ }
+ }
+
+ long remoteTimestamp = files[0].getTimestamp().getTime().getTime();
+ long localTimestamp = localFile.lastModified();
+ long adjustedRemoteTimestamp = remoteTimestamp + task.getTimeDiffMillis()
+ + task.getGranularityMillis();
+
+ StringBuffer msg;
+ synchronized(TIMESTAMP_LOGGING_SDF) {
+ msg = new StringBuffer(" [")
+ .append(TIMESTAMP_LOGGING_SDF.format(new Date(localTimestamp)))
+ .append("] local");
+ }
+ task.log(msg.toString(), Project.MSG_VERBOSE);
+
+ synchronized(TIMESTAMP_LOGGING_SDF) {
+ msg = new StringBuffer(" [")
+ .append(TIMESTAMP_LOGGING_SDF.format(new Date(adjustedRemoteTimestamp)))
+ .append("] remote");
+ }
+ if (remoteTimestamp != adjustedRemoteTimestamp) {
+ synchronized(TIMESTAMP_LOGGING_SDF) {
+ msg.append(" - (raw: ")
+ .append(TIMESTAMP_LOGGING_SDF.format(new Date(remoteTimestamp)))
+ .append(")");
+ }
+ }
+ task.log(msg.toString(), Project.MSG_VERBOSE);
+
+ if (task.getAction() == FTPTask.SEND_FILES) {
+ return adjustedRemoteTimestamp >= localTimestamp;
+ } else {
+ return localTimestamp >= adjustedRemoteTimestamp;
+ }
+ }
+
+
+ /**
+ * Sends a site command to the ftp server
+ * @param ftp ftp client
+ * @param theCMD command to execute
+ * @throws IOException in unknown circumstances
+ * @throws BuildException in unknown circumstances
+ */
+ protected void doSiteCommand(FTPClient ftp, String theCMD)
+ throws IOException, BuildException {
+ boolean rc;
+ String[] myReply = null;
+
+ task.log("Doing Site Command: " + theCMD, Project.MSG_VERBOSE);
+
+ rc = ftp.sendSiteCommand(theCMD);
+
+ if (!rc) {
+ task.log("Failed to issue Site Command: " + theCMD, Project.MSG_WARN);
+ } else {
+
+ myReply = ftp.getReplyStrings();
+
+ for (int x = 0; x < myReply.length; x++) {
+ if (myReply[x].indexOf("200") == -1) {
+ task.log(myReply[x], Project.MSG_WARN);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Sends a single file to the remote host. <code>filename</code> may
+ * contain a relative path specification. When this is the case, <code>sendFile</code>
+ * will attempt to create any necessary parent directories before sending
+ * the file. The file will then be sent using the entire relative path
+ * spec - no attempt is made to change directories. It is anticipated that
+ * this may eventually cause problems with some FTP servers, but it
+ * simplifies the coding.
+ * @param ftp ftp client
+ * @param dir base directory of the file to be sent (local)
+ * @param filename relative path of the file to be send
+ * locally relative to dir
+ * remotely relative to the remotedir attribute
+ * @throws IOException in unknown circumstances
+ * @throws BuildException in unknown circumstances
+ */
+ protected void sendFile(FTPClient ftp, String dir, String filename)
+ throws IOException, BuildException {
+ InputStream instream = null;
+
+ try {
+ // TODO - why not simply new File(dir, filename)?
+ File file = task.getProject().resolveFile(new File(dir, filename).getPath());
+
+ if (task.isNewer() && isUpToDate(ftp, file, resolveFile(filename))) {
+ return;
+ }
+
+ if (task.isVerbose()) {
+ task.log("transferring " + file.getAbsolutePath());
+ }
+
+ instream = new BufferedInputStream(new FileInputStream(file));
+
+ createParents(ftp, filename);
+
+ ftp.storeFile(resolveFile(filename), instream);
+
+ boolean success = FTPReply.isPositiveCompletion(ftp.getReplyCode());
+
+ if (!success) {
+ String s = "could not put file: " + ftp.getReplyString();
+
+ if (task.isSkipFailedTransfers()) {
+ task.log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+
+ } else {
+ // see if we should issue a chmod command
+ if (task.getChmod() != null) {
+ doSiteCommand(ftp, "chmod " + task.getChmod() + " "
+ + resolveFile(filename));
+ }
+ task.log("File " + file.getAbsolutePath() + " copied to " + task.getServer(),
+ Project.MSG_VERBOSE);
+ transferred++;
+ }
+ } finally {
+ if (instream != null) {
+ try {
+ instream.close();
+ } catch (IOException ex) {
+ // ignore it
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Delete a file from the remote host.
+ * @param ftp ftp client
+ * @param filename file to delete
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if skipFailedTransfers is set to false
+ * and the deletion could not be done
+ */
+ protected void delFile(FTPClient ftp, String filename)
+ throws IOException, BuildException {
+ if (task.isVerbose()) {
+ task.log("deleting " + filename);
+ }
+
+ if (!ftp.deleteFile(resolveFile(filename))) {
+ String s = "could not delete file: " + ftp.getReplyString();
+
+ if (task.isSkipFailedTransfers()) {
+ task.log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+ } else {
+ task.log("File " + filename + " deleted from " + task.getServer(),
+ Project.MSG_VERBOSE);
+ transferred++;
+ }
+ }
+
+ /**
+ * Delete a directory, if empty, from the remote host.
+ * @param ftp ftp client
+ * @param dirname directory to delete
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if skipFailedTransfers is set to false
+ * and the deletion could not be done
+ */
+ protected void rmDir(FTPClient ftp, String dirname)
+ throws IOException, BuildException {
+ if (task.isVerbose()) {
+ task.log("removing " + dirname);
+ }
+
+ if (!ftp.removeDirectory(resolveFile(dirname))) {
+ String s = "could not remove directory: " + ftp.getReplyString();
+
+ if (task.isSkipFailedTransfers()) {
+ task.log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+ } else {
+ task.log("Directory " + dirname + " removed from " + task.getServer(),
+ Project.MSG_VERBOSE);
+ transferred++;
+ }
+ }
+
+
+ /**
+ * Retrieve a single file from the remote host. <code>filename</code> may
+ * contain a relative path specification. <p>
+ *
+ * The file will then be retreived using the entire relative path spec -
+ * no attempt is made to change directories. It is anticipated that this
+ * may eventually cause problems with some FTP servers, but it simplifies
+ * the coding.</p>
+ * @param ftp the ftp client
+ * @param dir local base directory to which the file should go back
+ * @param filename relative path of the file based upon the ftp remote directory
+ * and/or the local base directory (dir)
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if skipFailedTransfers is false
+ * and the file cannot be retrieved.
+ */
+ protected void getFile(FTPClient ftp, String dir, String filename)
+ throws IOException, BuildException {
+ OutputStream outstream = null;
+ try {
+ File file = task.getProject().resolveFile(new File(dir, filename).getPath());
+
+ if (task.isNewer() && isUpToDate(ftp, file, resolveFile(filename))) {
+ return;
+ }
+
+ if (task.isVerbose()) {
+ task.log("transferring " + filename + " to "
+ + file.getAbsolutePath());
+ }
+
+ File pdir = file.getParentFile();
+
+ if (!pdir.exists()) {
+ pdir.mkdirs();
+ }
+ outstream = new BufferedOutputStream(new FileOutputStream(file));
+ ftp.retrieveFile(resolveFile(filename), outstream);
+
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ String s = "could not get file: " + ftp.getReplyString();
+
+ if (task.isSkipFailedTransfers()) {
+ task.log(s, Project.MSG_WARN);
+ skipped++;
+ } else {
+ throw new BuildException(s);
+ }
+
+ } else {
+ task.log(
+ "File " + file.getAbsolutePath() + " copied from "
+ + task.getServer(), Project.MSG_VERBOSE);
+ transferred++;
+ if (task.isPreserveLastModified()) {
+ outstream.close();
+ outstream = null;
+ FTPFile[] remote = ftp.listFiles(resolveFile(filename));
+ if (remote.length > 0) {
+ FILE_UTILS.setFileLastModified(file,
+ remote[0].getTimestamp()
+ .getTime().getTime());
+ }
+ }
+ }
+ } finally {
+ if (outstream != null) {
+ try {
+ outstream.close();
+ } catch (IOException ex) {
+ // ignore it
+ }
+ }
+ }
+ }
+
+
+ /**
+ * List information about a single file from the remote host. <code>filename</code>
+ * may contain a relative path specification. <p>
+ *
+ * The file listing will then be retrieved using the entire relative path
+ * spec - no attempt is made to change directories. It is anticipated that
+ * this may eventually cause problems with some FTP servers, but it
+ * simplifies the coding.</p>
+ * @param ftp ftp client
+ * @param bw buffered writer
+ * @param filename the directory one wants to list
+ * @throws IOException in unknown circumstances
+ * @throws BuildException in unknown circumstances
+ */
+ protected void listFile(FTPClient ftp, BufferedWriter bw, String filename)
+ throws IOException, BuildException {
+ if (task.isVerbose()) {
+ task.log("listing " + filename);
+ }
+ FTPFile[] ftpfiles = ftp.listFiles(resolveFile(filename));
+
+ if (ftpfiles != null && ftpfiles.length > 0) {
+ bw.write(ftpfiles[0].toString());
+ bw.newLine();
+ transferred++;
+ }
+ }
+
+
+ /**
+ * Create the specified directory on the remote host.
+ *
+ * @param ftp The FTP client connection
+ * @param dir The directory to create (format must be correct for host
+ * type)
+ * @throws IOException in unknown circumstances
+ * @throws BuildException if ignoreNoncriticalErrors has not been set to true
+ * and a directory could not be created, for instance because it was
+ * already existing. Precisely, the codes 521, 550 and 553 will trigger
+ * a BuildException
+ */
+ protected void makeRemoteDir(FTPClient ftp, String dir)
+ throws IOException, BuildException {
+ String workingDirectory = ftp.printWorkingDirectory();
+ if (task.isVerbose()) {
+ if (dir.startsWith("/") || workingDirectory == null) {
+ task.log("Creating directory: " + dir + " in /");
+ } else {
+ task.log("Creating directory: " + dir + " in " + workingDirectory);
+ }
+ }
+ if (dir.startsWith("/")) {
+ ftp.changeWorkingDirectory("/");
+ }
+ String subdir = "";
+ StringTokenizer st = new StringTokenizer(dir, "/");
+ while (st.hasMoreTokens()) {
+ subdir = st.nextToken();
+ task.log("Checking " + subdir, Project.MSG_DEBUG);
+ if (!ftp.changeWorkingDirectory(subdir)) {
+ if (!ftp.makeDirectory(subdir)) {
+ // codes 521, 550 and 553 can be produced by FTP Servers
+ // to indicate that an attempt to create a directory has
+ // failed because the directory already exists.
+ int rc = ftp.getReplyCode();
+ if (!(task.isIgnoreNoncriticalErrors() && (rc == CODE_550
+ || rc == CODE_553
+ || rc == CODE_521))) {
+ throw new BuildException("could not create directory: "
+ + ftp.getReplyString());
+ }
+ if (task.isVerbose()) {
+ task.log("Directory already exists");
+ }
+ } else {
+ if (task.isVerbose()) {
+ task.log("Directory created OK");
+ }
+ ftp.changeWorkingDirectory(subdir);
+ }
+ }
+ }
+ if (workingDirectory != null) {
+ ftp.changeWorkingDirectory(workingDirectory);
+ }
+ }
+
+ /**
+ * look at the response for a failed mkdir action, decide whether
+ * it matters or not. If it does, we throw an exception
+ * @param ftp current ftp connection
+ * @throws BuildException if this is an error to signal
+ */
+ private void handleMkDirFailure(FTPClient ftp)
+ throws BuildException {
+ int rc = ftp.getReplyCode();
+ if (!(task.isIgnoreNoncriticalErrors() && (rc == CODE_550
+ || rc == CODE_553
+ || rc == CODE_521))) {
+ throw new BuildException("could not create directory: "
+ + ftp.getReplyString());
+ }
+ }
+
+ public void doFTP() throws BuildException {
+ FTPClient ftp = null;
+
+ try {
+ task.log("Opening FTP connection to " + task.getServer(), Project.MSG_VERBOSE);
+
+ ftp = new FTPClient();
+ if (task.isConfigurationSet()) {
+ ftp = FTPConfigurator.configure(ftp, task);
+ }
+
+ ftp.setRemoteVerificationEnabled(task.getEnableRemoteVerification());
+ ftp.connect(task.getServer(), task.getPort());
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("FTP connection failed: "
+ + ftp.getReplyString());
+ }
+
+ task.log("connected", Project.MSG_VERBOSE);
+ task.log("logging in to FTP server", Project.MSG_VERBOSE);
+
+ if ((task.getAccount() != null && !ftp.login(task.getUserid(), task.getPassword(), task.getAccount()))
+ || (task.getAccount() == null && !ftp.login(task.getUserid(), task.getPassword()))) {
+ throw new BuildException("Could not login to FTP server");
+ }
+
+ task.log("login succeeded", Project.MSG_VERBOSE);
+
+ if (task.isBinary()) {
+ ftp.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not set transfer type: "
+ + ftp.getReplyString());
+ }
+ } else {
+ ftp.setFileType(org.apache.commons.net.ftp.FTP.ASCII_FILE_TYPE);
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not set transfer type: "
+ + ftp.getReplyString());
+ }
+ }
+
+ if (task.isPassive()) {
+ task.log("entering passive mode", Project.MSG_VERBOSE);
+ ftp.enterLocalPassiveMode();
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not enter into passive "
+ + "mode: " + ftp.getReplyString());
+ }
+ }
+
+ // If an initial command was configured then send it.
+ // Some FTP servers offer different modes of operation,
+ // E.G. switching between a UNIX file system mode and
+ // a legacy file system.
+ if (task.getInitialSiteCommand() != null) {
+ RetryHandler h = new RetryHandler(task.getRetriesAllowed(), task);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ doSiteCommand(lftp, task.getInitialSiteCommand());
+ }
+ }, "initial site command: " + task.getInitialSiteCommand());
+ }
+
+
+ // For a unix ftp server you can set the default mask for all files
+ // created.
+
+ if (task.getUmask() != null) {
+ RetryHandler h = new RetryHandler(task.getRetriesAllowed(), task);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ doSiteCommand(lftp, "umask " + task.getUmask());
+ }
+ }, "umask " + task.getUmask());
+ }
+
+ // If the action is MK_DIR, then the specified remote
+ // directory is the directory to create.
+
+ if (task.getAction() == FTPTask.MK_DIR) {
+ RetryHandler h = new RetryHandler(task.getRetriesAllowed(), task);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ makeRemoteDir(lftp, task.getRemotedir());
+ }
+ }, task.getRemotedir());
+ } else if (task.getAction() == FTPTask.SITE_CMD) {
+ RetryHandler h = new RetryHandler(task.getRetriesAllowed(), task);
+ final FTPClient lftp = ftp;
+ executeRetryable(h, new Retryable() {
+ public void execute() throws IOException {
+ doSiteCommand(lftp, task.getSiteCommand());
+ }
+ }, "Site Command: " + task.getSiteCommand());
+ } else {
+ if (task.getRemotedir() != null) {
+ task.log("changing the remote directory", Project.MSG_VERBOSE);
+ ftp.changeWorkingDirectory(task.getRemotedir());
+ if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+ throw new BuildException("could not change remote "
+ + "directory: " + ftp.getReplyString());
+ }
+ }
+ if (task.isNewer() && task.isTimeDiffAuto()) {
+ // in this case we want to find how much time span there is between local
+ // and remote
+ task.setTimeDiffMillis(getTimeDiff(ftp));
+ }
+ task.log(FTPTask.ACTION_STRS[task.getAction()] + " " + FTPTask.ACTION_TARGET_STRS[task.getAction()]);
+ transferFiles(ftp);
+ }
+
+ } catch (IOException ex) {
+ throw new BuildException("error during FTP transfer: " + ex, ex);
+ } finally {
+ if (ftp != null && ftp.isConnected()) {
+ try {
+ task.log("disconnecting", Project.MSG_VERBOSE);
+ ftp.logout();
+ ftp.disconnect();
+ } catch (IOException ex) {
+ // ignore it
+ }
+ }
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java
new file mode 100644
index 00000000..fca4215e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.email.EmailTask;
+
+/**
+ * A task to send SMTP email; Use <tt>mail</tt> instead
+ *
+ * @deprecated since 1.6.x.
+ * Use {@link EmailTask} instead.
+ *
+ * @since Ant1.4
+ */
+public class MimeMail extends EmailTask {
+ /**
+ * Executes this build task.
+ *
+ * @exception BuildException On error.
+ */
+ public void execute()
+ throws BuildException {
+ log("DEPRECATED - The " + getTaskName() + " task is deprecated. "
+ + "Use the mail task instead.");
+ super.execute();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java
new file mode 100644
index 00000000..01cb4ba9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.commons.net.bsd.RExecClient;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Automates the rexec protocol.
+ *
+ * @since Ant 1.6
+ */
+
+public class RExecTask extends Task {
+
+ private static final int PAUSE_TIME = 250;
+
+ /**
+ * The userid to login with, if automated login is used
+ */
+ private String userid = null;
+
+ /**
+ * The password to login with, if automated login is used
+ */
+ private String password = null;
+
+ /**
+ * The command to execute
+ */
+ private String command = null;
+
+ /**
+ * The server to connect to.
+ */
+ private String server = null;
+
+ /**
+ * The tcp port to connect to.
+ */
+ private int port = RExecClient.DEFAULT_PORT;
+
+ /**
+ * The list of read/write commands for this session
+ */
+ private Vector rexecTasks = new Vector();
+
+ /**
+ * If true, adds a CR to beginning of login script
+ */
+ private boolean addCarriageReturn = false;
+
+ /**
+ * Default time allowed for waiting for a valid response
+ * for all child reads. A value of 0 means no limit.
+ */
+ private Integer defaultTimeout = null;
+
+ /**
+ * This class is the parent of the Read and Write tasks.
+ * It handles the common attributes for both.
+ */
+ public class RExecSubTask {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected String taskString = "";
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Execute the subtask.
+ * @param rexec the client
+ * @throws BuildException always as it is not allowed to instantiate this object
+ */
+ public void execute(AntRExecClient rexec)
+ throws BuildException {
+ throw new BuildException("Shouldn't be able instantiate a SubTask directly");
+ }
+
+ /**
+ * the message as nested text
+ * @param s the nested text
+ */
+ public void addText(String s) {
+ setString(getProject().replaceProperties(s));
+ }
+
+ /**
+ * the message as an attribute
+ * @param s a <code>String</code> value
+ */
+ public void setString(String s) {
+ taskString += s;
+ }
+ }
+
+ /**
+ * Sends text to the connected server
+ */
+ public class RExecWrite extends RExecSubTask {
+ private boolean echoString = true;
+ /**
+ * Execute the write exec task.
+ * @param rexec the task to use
+ * @throws BuildException on error
+ */
+ public void execute(AntRExecClient rexec)
+ throws BuildException {
+ rexec.sendString(taskString, echoString);
+ }
+
+ /**
+ * Whether or not the message should be echoed to the log.
+ * Defaults to <code>true</code>.
+ * @param b a <code>boolean</code> value
+ */
+ public void setEcho(boolean b) {
+ echoString = b;
+ }
+ }
+
+ /**
+ * Reads the output from the connected server
+ * until the required string is found or we time out.
+ */
+ public class RExecRead extends RExecSubTask {
+ private Integer timeout = null;
+ /**
+ * Execute the read exec task.
+ * @param rexec the task to use
+ * @throws BuildException on error
+ */
+ public void execute(AntRExecClient rexec)
+ throws BuildException {
+ rexec.waitForString(taskString, timeout);
+ }
+ /**
+ * a timeout value that overrides any task wide timeout.
+ * @param i an <code>Integer</code> value
+ */
+ public void setTimeout(Integer i) {
+ this.timeout = i;
+ }
+
+ /**
+ * Sets the default timeout if none has been set already
+ * @param defaultTimeout an <code>Integer</code> value
+ * @ant.attribute ignore="true"
+ */
+ public void setDefaultTimeout(Integer defaultTimeout) {
+ if (timeout == null) {
+ timeout = defaultTimeout;
+ }
+ }
+ }
+
+ /**
+ * This class handles the abstraction of the rexec protocol.
+ * Currently it is a wrapper around <a
+ * href="http://jakarta.apache.org/commons/net/index.html">Jakarta
+ * Commons Net</a>.
+ */
+ public class AntRExecClient extends RExecClient {
+ /**
+ * Read from the rexec session until the string we are
+ * waiting for is found
+ * @param s The string to wait on
+ */
+ public void waitForString(String s) {
+ waitForString(s, null);
+ }
+
+ /**
+ * Read from the rexec session until the string we are
+ * waiting for is found or the timeout has been reached
+ * @param s The string to wait on
+ * @param timeout The maximum number of seconds to wait
+ */
+ public void waitForString(String s, Integer timeout) {
+ InputStream is = this.getInputStream();
+ try {
+ StringBuffer sb = new StringBuffer();
+ int windowStart = -s.length();
+ if (timeout == null || timeout.intValue() == 0) {
+ while (windowStart < 0
+ || !sb.substring(windowStart).equals(s)) {
+ sb.append((char) is.read());
+ windowStart++;
+ }
+ } else {
+ Calendar endTime = Calendar.getInstance();
+ endTime.add(Calendar.SECOND, timeout.intValue());
+ while (windowStart < 0
+ || !sb.substring(windowStart).equals(s)) {
+ while (Calendar.getInstance().before(endTime)
+ && is.available() == 0) {
+ Thread.sleep(PAUSE_TIME);
+ }
+ if (is.available() == 0) {
+ throw new BuildException(
+ "Response timed-out waiting for \"" + s + '\"',
+ getLocation());
+ }
+ sb.append((char) is.read());
+ windowStart++;
+ }
+ }
+ log(sb.toString(), Project.MSG_INFO);
+ } catch (BuildException be) {
+ throw be;
+ } catch (Exception e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ /**
+ * Write this string to the rexec session.
+ * @param s the string to write
+ * @param echoString if true log the string sent
+ */
+ public void sendString(String s, boolean echoString) {
+ OutputStream os = this.getOutputStream();
+ try {
+ os.write((s + "\n").getBytes());
+ if (echoString) {
+ log(s, Project.MSG_INFO);
+ }
+ os.flush();
+ } catch (Exception e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+ /**
+ * Read from the rexec session until the EOF is found or
+ * the timeout has been reached
+ * @param timeout The maximum number of seconds to wait
+ */
+ public void waitForEOF(Integer timeout) {
+ InputStream is = this.getInputStream();
+ try {
+ StringBuffer sb = new StringBuffer();
+ if (timeout == null || timeout.intValue() == 0) {
+ int read;
+ while ((read = is.read()) != -1) {
+ char c = (char) read;
+ sb.append(c);
+ if (c == '\n') {
+ log(sb.toString(), Project.MSG_INFO);
+ sb.delete(0, sb.length());
+ }
+ }
+ } else {
+ Calendar endTime = Calendar.getInstance();
+ endTime.add(Calendar.SECOND, timeout.intValue());
+ int read = 0;
+ while (read != -1) {
+ while (Calendar.getInstance().before(endTime) && is.available() == 0) {
+ Thread.sleep(PAUSE_TIME);
+ }
+ if (is.available() == 0) {
+ log(sb.toString(), Project.MSG_INFO);
+ throw new BuildException(
+ "Response timed-out waiting for EOF",
+ getLocation());
+ }
+ read = is.read();
+ if (read != -1) {
+ char c = (char) read;
+ sb.append(c);
+ if (c == '\n') {
+ log(sb.toString(), Project.MSG_INFO);
+ sb.delete(0, sb.length());
+ }
+ }
+ }
+ }
+ if (sb.length() > 0) {
+ log(sb.toString(), Project.MSG_INFO);
+ }
+ } catch (BuildException be) {
+ throw be;
+ } catch (Exception e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ }
+ /**
+ * A string to wait for from the server.
+ * A subTask &lt;read&gt; tag was found. Create the object,
+ * Save it in our list, and return it.
+ * @return a read sub task
+ */
+
+ public RExecSubTask createRead() {
+ RExecSubTask task = (RExecSubTask) new RExecRead();
+ rexecTasks.addElement(task);
+ return task;
+ }
+ /**
+ * Add text to send to the server
+ * A subTask &lt;write&gt; tag was found. Create the object,
+ * Save it in our list, and return it.
+ * @return a write sub task
+ */
+ public RExecSubTask createWrite() {
+ RExecSubTask task = (RExecSubTask) new RExecWrite();
+ rexecTasks.addElement(task);
+ return task;
+ }
+ /**
+ * Verify that all parameters are included.
+ * Connect and possibly login.
+ * Iterate through the list of Reads and writes.
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+ /** A server name is required to continue */
+ if (server == null) {
+ throw new BuildException("No Server Specified");
+ }
+ /** A userid and password must appear together
+ * if they appear. They are not required.
+ */
+ if (userid == null && password != null) {
+ throw new BuildException("No Userid Specified");
+ }
+ if (password == null && userid != null) {
+ throw new BuildException("No Password Specified");
+ }
+
+ /** Create the telnet client object */
+ AntRExecClient rexec = null;
+ try {
+ rexec = new AntRExecClient();
+ try {
+ rexec.connect(server, port);
+ } catch (IOException e) {
+ throw new BuildException("Can't connect to " + server);
+ }
+ if (userid != null && password != null && command != null
+ && rexecTasks.size() == 0) {
+ // simple one-shot execution
+ rexec.rexec(userid, password, command);
+ } else {
+ // need nested read/write elements
+ handleMultipleTasks(rexec);
+ }
+
+ /** Keep reading input stream until end of it or time-out */
+ rexec.waitForEOF(defaultTimeout);
+ } catch (IOException e) {
+ throw new BuildException("Error r-executing command", e);
+ } finally {
+ if (rexec != null && rexec.isConnected()) {
+ try {
+ rexec.disconnect();
+ } catch (IOException e) {
+ throw new BuildException("Error disconnecting from "
+ + server);
+ }
+ }
+ }
+ }
+ /**
+ * Process a 'typical' login. If it differs, use the read
+ * and write tasks explicitly
+ */
+ private void login(AntRExecClient rexec) {
+ if (addCarriageReturn) {
+ rexec.sendString("\n", true);
+ }
+ rexec.waitForString("ogin:");
+ rexec.sendString(userid, true);
+ rexec.waitForString("assword:");
+ rexec.sendString(password, false);
+ }
+ /**
+ * Set the the command to execute on the server;
+ * @param c a <code>String</code> value
+ */
+ public void setCommand(String c) {
+ this.command = c;
+ }
+
+ /**
+ * send a carriage return after connecting; optional, defaults to false.
+ * @param b a <code>boolean</code> value
+ */
+ public void setInitialCR(boolean b) {
+ this.addCarriageReturn = b;
+ }
+ /**
+ * Set the the login password to use
+ * required if <tt>userid</tt> is set.
+ * @param p a <code>String</code> value
+ */
+ public void setPassword(String p) {
+ this.password = p;
+ }
+
+ /**
+ * Set the tcp port to connect to; default is 23.
+ * @param p an <code>int</code> value
+ */
+ public void setPort(int p) {
+ this.port = p;
+ }
+
+ /**
+ * Set the hostname or address of the remote server.
+ * @param m a <code>String</code> value
+ */
+ public void setServer(String m) {
+ this.server = m;
+ }
+
+ /**
+ * set a default timeout in seconds to wait for a response,
+ * zero means forever (the default)
+ * @param i an <code>Integer</code> value
+ */
+ public void setTimeout(Integer i) {
+ this.defaultTimeout = i;
+ }
+ /**
+ * Set the the login id to use on the server;
+ * required if <tt>password</tt> is set.
+ * @param u a <code>String</code> value
+ */
+ public void setUserid(String u) {
+ this.userid = u;
+ }
+
+ /**
+ * Deals with multiple read/write calls.
+ *
+ * @since Ant 1.6.3
+ */
+ private void handleMultipleTasks(AntRExecClient rexec) {
+
+ /** Login if userid and password were specified */
+ if (userid != null && password != null) {
+ login(rexec);
+ }
+ /** Process each sub command */
+ Enumeration tasksToRun = rexecTasks.elements();
+ while (tasksToRun != null && tasksToRun.hasMoreElements()) {
+ RExecSubTask task = (RExecSubTask) tasksToRun.nextElement();
+ if (task instanceof RExecRead && defaultTimeout != null) {
+ ((RExecRead) task).setDefaultTimeout(defaultTimeout);
+ }
+ task.execute(rexec);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java
new file mode 100644
index 00000000..1e1f6591
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.ProxySetup;
+
+/**
+ * Sets Java's web proxy properties, so that tasks and code run in
+ * the same JVM can have through-the-firewall access to remote web sites,
+ * and remote ftp sites.
+ * You can nominate an http and ftp proxy, or a socks server, reset the server
+ * settings, or do nothing at all.
+ * <p>
+ * Examples
+ * <pre>&lt;setproxy/&gt;</pre>
+ * do nothing
+ * <pre>&lt;setproxy proxyhost="firewall"/&gt;</pre>
+ * set the proxy to firewall:80
+ * <pre>&lt;setproxy proxyhost="firewall" proxyport="81"/&gt;</pre>
+ * set the proxy to firewall:81
+ * <pre>&lt;setproxy proxyhost=""/&gt;</pre>
+ * stop using the http proxy; don't change the socks settings
+ * <pre>&lt;setproxy socksproxyhost="socksy"/&gt;</pre>
+ * use socks via socksy:1080
+ * <pre>&lt;setproxy socksproxyhost=""/&gt;</pre>
+ * stop using the socks server.
+ * <p>
+ * You can set a username and password for http with the <tt>proxyHost</tt>
+ * and <tt>proxyPassword</tt> attributes. These can also be
+ * used against SOCKS5 servers.
+ * </p>
+ * @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html">
+ * java 1.5 network property list</a>
+ *@since Ant 1.5
+ * @ant.task category="network"
+ */
+public class SetProxy extends Task {
+ private static final int HTTP_PORT = 80;
+ private static final int SOCKS_PORT = 1080;
+ // CheckStyle:VisibilityModifier OFF - bc
+ /**
+ * proxy details
+ */
+ protected String proxyHost = null;
+
+ /**
+ * name of proxy port
+ */
+ protected int proxyPort = HTTP_PORT;
+
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * socks host.
+ */
+ private String socksProxyHost = null;
+
+ /**
+ * Socks proxy port. Default is 1080.
+ */
+ private int socksProxyPort = SOCKS_PORT;
+
+
+ /**
+ * list of non proxy hosts
+ */
+ private String nonProxyHosts = null;
+
+ /**
+ * user for http only
+ */
+ private String proxyUser = null;
+
+ /**
+ * password for http only
+ */
+ private String proxyPassword = null;
+
+ /**
+ * the HTTP/ftp proxy host. Set this to "" for the http proxy
+ * option to be disabled
+ *
+ * @param hostname the new proxy hostname
+ */
+ public void setProxyHost(String hostname) {
+ proxyHost = hostname;
+ }
+
+
+ /**
+ * the HTTP/ftp proxy port number; default is 80
+ *
+ * @param port port number of the proxy
+ */
+ public void setProxyPort(int port) {
+ proxyPort = port;
+ }
+
+ /**
+ * The name of a Socks server. Set to "" to turn socks
+ * proxying off.
+ *
+ * @param host The new SocksProxyHost value
+ */
+ public void setSocksProxyHost(String host) {
+ this.socksProxyHost = host;
+ }
+
+
+ /**
+ * Set the ProxyPort for socks connections. The default value is 1080
+ *
+ * @param port The new SocksProxyPort value
+ */
+ public void setSocksProxyPort(int port) {
+ this.socksProxyPort = port;
+ }
+
+
+ /**
+ * A list of hosts to bypass the proxy on. These should be separated
+ * with the vertical bar character '|'. Only in Java 1.4 does ftp use
+ * this list.
+ * e.g. fozbot.corp.sun.com|*.eng.sun.com
+ * @param nonProxyHosts lists of hosts to talk direct to
+ */
+ public void setNonProxyHosts(String nonProxyHosts) {
+ this.nonProxyHosts = nonProxyHosts;
+ }
+
+ /**
+ * set the proxy user. Probably requires a password to accompany this
+ * setting. Default=""
+ * @param proxyUser username
+ * @since Ant1.6
+ */
+ public void setProxyUser(String proxyUser) {
+ this.proxyUser = proxyUser;
+ }
+
+ /**
+ * Set the password for the proxy. Used only if the proxyUser is set.
+ * @param proxyPassword password to go with the username
+ * @since Ant1.6
+ */
+ public void setProxyPassword(String proxyPassword) {
+ this.proxyPassword = proxyPassword;
+ }
+
+ /**
+ * if the proxy port and host settings are not null, then the settings
+ * get applied these settings last beyond the life of the object and
+ * apply to all network connections
+ * Relevant docs: buglist #4183340
+ */
+
+ public void applyWebProxySettings() {
+ boolean settingsChanged = false;
+ boolean enablingProxy = false;
+ Properties sysprops = System.getProperties();
+ if (proxyHost != null) {
+ settingsChanged = true;
+ if (proxyHost.length() != 0) {
+ traceSettingInfo();
+ enablingProxy = true;
+ sysprops.put(ProxySetup.HTTP_PROXY_HOST, proxyHost);
+ String portString = Integer.toString(proxyPort);
+ sysprops.put(ProxySetup.HTTP_PROXY_PORT, portString);
+ sysprops.put(ProxySetup.HTTPS_PROXY_HOST, proxyHost);
+ sysprops.put(ProxySetup.HTTPS_PROXY_PORT, portString);
+ sysprops.put(ProxySetup.FTP_PROXY_HOST, proxyHost);
+ sysprops.put(ProxySetup.FTP_PROXY_PORT, portString);
+ if (nonProxyHosts != null) {
+ sysprops.put(ProxySetup.HTTP_NON_PROXY_HOSTS, nonProxyHosts);
+ sysprops.put(ProxySetup.HTTPS_NON_PROXY_HOSTS, nonProxyHosts);
+ sysprops.put(ProxySetup.FTP_NON_PROXY_HOSTS, nonProxyHosts);
+ }
+ if (proxyUser != null) {
+ sysprops.put(ProxySetup.HTTP_PROXY_USERNAME, proxyUser);
+ sysprops.put(ProxySetup.HTTP_PROXY_PASSWORD, proxyPassword);
+ }
+ } else {
+ log("resetting http proxy", Project.MSG_VERBOSE);
+ sysprops.remove(ProxySetup.HTTP_PROXY_HOST);
+ sysprops.remove(ProxySetup.HTTP_PROXY_PORT);
+ sysprops.remove(ProxySetup.HTTP_PROXY_USERNAME);
+ sysprops.remove(ProxySetup.HTTP_PROXY_PASSWORD);
+ sysprops.remove(ProxySetup.HTTPS_PROXY_HOST);
+ sysprops.remove(ProxySetup.HTTPS_PROXY_PORT);
+ sysprops.remove(ProxySetup.FTP_PROXY_HOST);
+ sysprops.remove(ProxySetup.FTP_PROXY_PORT);
+ }
+ }
+
+ //socks
+ if (socksProxyHost != null) {
+ settingsChanged = true;
+ if (socksProxyHost.length() != 0) {
+ enablingProxy = true;
+ sysprops.put(ProxySetup.SOCKS_PROXY_HOST, socksProxyHost);
+ sysprops.put(ProxySetup.SOCKS_PROXY_PORT, Integer.toString(socksProxyPort));
+ if (proxyUser != null) {
+ //this may be a java1.4 thingy only
+ sysprops.put(ProxySetup.SOCKS_PROXY_USERNAME, proxyUser);
+ sysprops.put(ProxySetup.SOCKS_PROXY_PASSWORD, proxyPassword);
+ }
+
+ } else {
+ log("resetting socks proxy", Project.MSG_VERBOSE);
+ sysprops.remove(ProxySetup.SOCKS_PROXY_HOST);
+ sysprops.remove(ProxySetup.SOCKS_PROXY_PORT);
+ sysprops.remove(ProxySetup.SOCKS_PROXY_USERNAME);
+ sysprops.remove(ProxySetup.SOCKS_PROXY_PASSWORD);
+ }
+ }
+
+ if (proxyUser != null) {
+ if (enablingProxy) {
+ Authenticator.setDefault(new ProxyAuth(proxyUser,
+ proxyPassword));
+ } else if (settingsChanged) {
+ Authenticator.setDefault(new ProxyAuth("", ""));
+ }
+ }
+ }
+
+ /**
+ * list out what is going on
+ */
+ private void traceSettingInfo() {
+ log("Setting proxy to "
+ + (proxyHost != null ? proxyHost : "''")
+ + ":" + proxyPort,
+ Project.MSG_VERBOSE);
+ }
+
+ /**
+ * Does the work.
+ *
+ * @exception BuildException thrown in unrecoverable error.
+ */
+ public void execute() throws BuildException {
+ applyWebProxySettings();
+ }
+
+ /**
+ * @since 1.6.3
+ */
+ private static final class ProxyAuth extends Authenticator {
+ private PasswordAuthentication auth;
+
+ private ProxyAuth(String user, String pass) {
+ auth = new PasswordAuthentication(user, pass.toCharArray());
+ }
+
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return auth;
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java
new file mode 100644
index 00000000..82625fa7
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java
@@ -0,0 +1,397 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.commons.net.telnet.TelnetClient;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Automates the telnet protocol.
+ *
+ */
+
+public class TelnetTask extends Task {
+ private static final int WAIT_INTERVAL = 250;
+ private static final int TELNET_PORT = 23;
+
+ /**
+ * The userid to login with, if automated login is used
+ */
+ private String userid = null;
+
+ /**
+ * The password to login with, if automated login is used
+ */
+ private String password = null;
+
+ /**
+ * The server to connect to.
+ */
+ private String server = null;
+
+ /**
+ * The tcp port to connect to.
+ */
+ private int port = TELNET_PORT;
+
+ /**
+ * The list of read/write commands for this session
+ */
+ private Vector telnetTasks = new Vector();
+
+ /**
+ * If true, adds a CR to beginning of login script
+ */
+ private boolean addCarriageReturn = false;
+
+ /**
+ * Default time allowed for waiting for a valid response
+ * for all child reads. A value of 0 means no limit.
+ */
+ private Integer defaultTimeout = null;
+
+ /**
+ * Verify that all parameters are included.
+ * Connect and possibly login
+ * Iterate through the list of Reads and writes
+ * @throws BuildException on error
+ */
+ public void execute() throws BuildException {
+ /** A server name is required to continue */
+ if (server == null) {
+ throw new BuildException("No Server Specified");
+ }
+ /** A userid and password must appear together
+ * if they appear. They are not required.
+ */
+ if (userid == null && password != null) {
+ throw new BuildException("No Userid Specified");
+ }
+ if (password == null && userid != null) {
+ throw new BuildException("No Password Specified");
+ }
+
+ /** Create the telnet client object */
+ AntTelnetClient telnet = null;
+ try {
+ telnet = new AntTelnetClient();
+ try {
+ telnet.connect(server, port);
+ } catch (IOException e) {
+ throw new BuildException("Can't connect to " + server);
+ }
+ /** Login if userid and password were specified */
+ if (userid != null && password != null) {
+ login(telnet);
+ }
+ /** Process each sub command */
+ Enumeration tasksToRun = telnetTasks.elements();
+ while (tasksToRun != null && tasksToRun.hasMoreElements()) {
+ TelnetSubTask task = (TelnetSubTask) tasksToRun.nextElement();
+ if (task instanceof TelnetRead && defaultTimeout != null) {
+ ((TelnetRead) task).setDefaultTimeout(defaultTimeout);
+ }
+ task.execute(telnet);
+ }
+ } finally {
+ if (telnet != null && telnet.isConnected()) {
+ try {
+ telnet.disconnect();
+ } catch (IOException e) {
+ throw new BuildException("Error disconnecting from "
+ + server);
+ }
+ }
+ }
+ }
+
+ /**
+ * Process a 'typical' login. If it differs, use the read
+ * and write tasks explicitly
+ */
+ private void login(AntTelnetClient telnet) {
+ if (addCarriageReturn) {
+ telnet.sendString("\n", true);
+ }
+ telnet.waitForString("ogin:");
+ telnet.sendString(userid, true);
+ telnet.waitForString("assword:");
+ telnet.sendString(password, false);
+ }
+
+ /**
+ * Set the the login id to use on the server;
+ * required if <tt>password</tt> is set.
+ * @param u a <code>String</code> value
+ */
+ public void setUserid(String u) {
+ this.userid = u;
+ }
+
+ /**
+ * Set the the login password to use
+ * required if <tt>userid</tt> is set.
+ * @param p a <code>String</code> value
+ */
+ public void setPassword(String p) {
+ this.password = p;
+ }
+
+ /**
+ * Set the hostname or address of the remote server.
+ * @param m a <code>String</code> value
+ */
+ public void setServer(String m) {
+ this.server = m;
+ }
+
+ /**
+ * Set the tcp port to connect to; default is 23.
+ * @param p an <code>int</code> value
+ */
+ public void setPort(int p) {
+ this.port = p;
+ }
+
+ /**
+ * send a carriage return after connecting; optional, defaults to false.
+ * @param b a <code>boolean</code> value
+ */
+ public void setInitialCR(boolean b) {
+ this.addCarriageReturn = b;
+ }
+
+ /**
+ * set a default timeout in seconds to wait for a response,
+ * zero means forever (the default)
+ * @param i an <code>Integer</code> value
+ */
+ public void setTimeout(Integer i) {
+ this.defaultTimeout = i;
+ }
+
+ /**
+ * A string to wait for from the server.
+ * A subTask &lt;read&gt; tag was found. Create the object,
+ * Save it in our list, and return it.
+ * @return a read telnet sub task
+ */
+
+ public TelnetSubTask createRead() {
+ TelnetSubTask task = (TelnetSubTask) new TelnetRead();
+ telnetTasks.addElement(task);
+ return task;
+ }
+
+ /**
+ * Add text to send to the server
+ * A subTask &lt;write&gt; tag was found. Create the object,
+ * Save it in our list, and return it.
+ * @return a write telnet sub task
+ */
+ public TelnetSubTask createWrite() {
+ TelnetSubTask task = (TelnetSubTask) new TelnetWrite();
+ telnetTasks.addElement(task);
+ return task;
+ }
+
+ /**
+ * This class is the parent of the Read and Write tasks.
+ * It handles the common attributes for both.
+ */
+ public class TelnetSubTask {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected String taskString = "";
+ // CheckStyle:VisibilityModifier ON
+ /**
+ * Execute the subtask.
+ * @param telnet the client
+ * @throws BuildException always as it is not allowed to instantiate this object
+ */
+ public void execute(AntTelnetClient telnet)
+ throws BuildException {
+ throw new BuildException("Shouldn't be able instantiate a SubTask directly");
+ }
+
+ /**
+ * the message as nested text
+ * @param s the nested text
+ */
+ public void addText(String s) {
+ setString(getProject().replaceProperties(s));
+ }
+
+ /**
+ * the message as an attribute
+ * @param s a <code>String</code> value
+ */
+ public void setString(String s) {
+ taskString += s;
+ }
+ }
+
+ /**
+ * Sends text to the connected server
+ */
+ public class TelnetWrite extends TelnetSubTask {
+ private boolean echoString = true;
+ /**
+ * Execute the write task.
+ * @param telnet the task to use
+ * @throws BuildException on error
+ */
+ public void execute(AntTelnetClient telnet)
+ throws BuildException {
+ telnet.sendString(taskString, echoString);
+ }
+
+ /**
+ * Whether or not the message should be echoed to the log.
+ * Defaults to <code>true</code>.
+ * @param b a <code>boolean</code> value
+ */
+ public void setEcho(boolean b) {
+ echoString = b;
+ }
+ }
+
+ /**
+ * Reads the output from the connected server
+ * until the required string is found or we time out.
+ */
+ public class TelnetRead extends TelnetSubTask {
+ private Integer timeout = null;
+ /**
+ * Execute the read task.
+ * @param telnet the task to use
+ * @throws BuildException on error
+ */
+ public void execute(AntTelnetClient telnet)
+ throws BuildException {
+ telnet.waitForString(taskString, timeout);
+ }
+ /**
+ * a timeout value that overrides any task wide timeout.
+ * @param i an <code>Integer</code> value
+ */
+ public void setTimeout(Integer i) {
+ this.timeout = i;
+ }
+
+ /**
+ * Sets the default timeout if none has been set already
+ * @param defaultTimeout an <code>Integer</code> value
+ * @ant.attribute ignore="true"
+ */
+ public void setDefaultTimeout(Integer defaultTimeout) {
+ if (timeout == null) {
+ timeout = defaultTimeout;
+ }
+ }
+ }
+
+ /**
+ * This class handles the abstraction of the telnet protocol.
+ * Currently it is a wrapper around <a
+ * href="http://jakarta.apache.org/commons/net/index.html">Jakarta
+ * Commons Net</a>.
+ */
+ public class AntTelnetClient extends TelnetClient {
+ /**
+ * Read from the telnet session until the string we are
+ * waiting for is found
+ * @param s The string to wait on
+ */
+ public void waitForString(String s) {
+ waitForString(s, null);
+ }
+
+ /**
+ * Read from the telnet session until the string we are
+ * waiting for is found or the timeout has been reached
+ * @param s The string to wait on
+ * @param timeout The maximum number of seconds to wait
+ */
+ public void waitForString(String s, Integer timeout) {
+ InputStream is = this.getInputStream();
+ try {
+ StringBuffer sb = new StringBuffer();
+ int windowStart = -s.length();
+ if (timeout == null || timeout.intValue() == 0) {
+ while (windowStart < 0
+ || !sb.substring(windowStart).equals(s)) {
+ sb.append((char) is.read());
+ windowStart++;
+ }
+ } else {
+ Calendar endTime = Calendar.getInstance();
+ endTime.add(Calendar.SECOND, timeout.intValue());
+ while (windowStart < 0
+ || !sb.substring(windowStart).equals(s)) {
+ while (Calendar.getInstance().before(endTime)
+ && is.available() == 0) {
+ Thread.sleep(WAIT_INTERVAL);
+ }
+ if (is.available() == 0) {
+ log("Read before running into timeout: "
+ + sb.toString(), Project.MSG_DEBUG);
+ throw new BuildException(
+ "Response timed-out waiting for \"" + s + '\"',
+ getLocation());
+ }
+ sb.append((char) is.read());
+ windowStart++;
+ }
+ }
+ log(sb.toString(), Project.MSG_INFO);
+ } catch (BuildException be) {
+ throw be;
+ } catch (Exception e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ /**
+ * Write this string to the telnet session.
+ * @param s the string to write
+ * @param echoString if true log the string sent
+ */
+ public void sendString(String s, boolean echoString) {
+ OutputStream os = this.getOutputStream();
+ try {
+ os.write((s + "\n").getBytes());
+ if (echoString) {
+ log(s, Project.MSG_INFO);
+ }
+ os.flush();
+ } catch (Exception e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java
new file mode 100644
index 00000000..dd6016a8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java
@@ -0,0 +1,675 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.pvcs;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.Enumeration;
+import java.util.Random;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ *
+ * Extracts the latest edition of the source code from a PVCS repository.
+ * PVCS is a version control system
+ * developed by <a href="http://www.merant.com/products/pvcs">Merant</a>.
+ * <br>
+ * Before using this tag, the user running ant must have access to the commands
+ * of PVCS (get and pcli) and must have access to the repository. Note that the way to specify
+ * the repository is platform dependent so use property to specify location of repository.
+ * <br>
+ * This version has been tested against PVCS version 6.5 and 6.6 under Windows and Solaris.
+
+ *
+ * <b>19-04-2001</b> <p>The task now has a more robust
+ * parser. It allows for platform independent file paths
+ * and supports file names with <i>()</i>. Thanks to Erik Husby for
+ * bringing the bug to my attention.
+ *
+ * <b>27-04-2001</b> <p>UNC paths are now handled properly.
+ * Fix provided by Don Jeffery. He also added an <i>UpdateOnly</i> flag
+ * that, when true, conditions the PVCS get using the -U option to only
+ * update those files that have a modification time (in PVCS) that is newer
+ * than the existing workfile.
+ *
+ * <b>25-10-2002</b> <p>Added a revision attribute that currently is a
+ * synonym for label, but in a future release the behavior of the label
+ * attribute will change to use the -v option of GET. See bug #13847 for
+ * discussion.
+ *
+ */
+public class Pvcs extends org.apache.tools.ant.Task {
+ // CheckStyle - magic numbers
+ // checking for "X:\ 0=dquote,1=letter,2=:,3=\
+ private static final int POS_1 = 1;
+ private static final int POS_2 = 2;
+ private static final int POS_3 = 3;
+
+ private String pvcsbin;
+ private String repository;
+ private String pvcsProject;
+ private Vector pvcsProjects;
+ private String workspace;
+ private String force;
+ private String promotiongroup;
+ private String label;
+ private String revision;
+ private boolean ignorerc;
+ private boolean updateOnly;
+ private String filenameFormat;
+ private String lineStart;
+ private String userId;
+ private String config;
+ /**
+ * Constant for the thing to execute
+ */
+ private static final String PCLI_EXE = "pcli";
+
+ /*
+ * Constant for the PCLI listversionedfiles recursive i a format "get" understands
+ */
+ // private static final String PCLI_LVF_ARGS = "lvf -z -aw";
+
+ /**
+ * Constant for the thing to execute
+ */
+ private static final String GET_EXE = "get";
+
+
+ /**
+ * Run the command.
+ * @param cmd the command line to use.
+ * @param out the output stream handler to use.
+ * @return the exit code of the command.
+ */
+ protected int runCmd(Commandline cmd, ExecuteStreamHandler out) {
+ try {
+ Project aProj = getProject();
+ Execute exe = new Execute(out);
+ exe.setAntRun(aProj);
+ exe.setWorkingDirectory(aProj.getBaseDir());
+ exe.setCommandline(cmd.getCommandline());
+ return exe.execute();
+ } catch (java.io.IOException e) {
+ String msg = "Failed executing: " + cmd.toString()
+ + ". Exception: " + e.getMessage();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ private String getExecutable(String exe) {
+ StringBuffer correctedExe = new StringBuffer();
+ if (getPvcsbin() != null) {
+ if (pvcsbin.endsWith(File.separator)) {
+ correctedExe.append(pvcsbin);
+ } else {
+ correctedExe.append(pvcsbin).append(File.separator);
+ }
+ }
+ return correctedExe.append(exe).toString();
+ }
+
+ /**
+ * @exception org.apache.tools.ant.BuildException Something is stopping the build...
+ */
+ public void execute() throws org.apache.tools.ant.BuildException {
+ int result = 0;
+
+ if (repository == null || repository.trim().equals("")) {
+ throw new BuildException("Required argument repository not specified");
+ }
+
+ // Check workspace exists
+ // Launch PCLI listversionedfiles -z -aw
+ // Capture output
+ // build the command line from what we got the format is
+ Commandline commandLine = new Commandline();
+ commandLine.setExecutable(getExecutable(PCLI_EXE));
+
+ commandLine.createArgument().setValue("lvf");
+ commandLine.createArgument().setValue("-z");
+ commandLine.createArgument().setValue("-aw");
+ if (getWorkspace() != null) {
+ commandLine.createArgument().setValue("-sp" + getWorkspace());
+ }
+ commandLine.createArgument().setValue("-pr" + getRepository());
+
+ String uid = getUserId();
+
+ if (uid != null) {
+ commandLine.createArgument().setValue("-id" + uid);
+ }
+
+ // default pvcs project is "/"
+ if (getPvcsproject() == null && getPvcsprojects().isEmpty()) {
+ pvcsProject = "/";
+ }
+
+ if (getPvcsproject() != null) {
+ commandLine.createArgument().setValue(getPvcsproject());
+ }
+ if (!getPvcsprojects().isEmpty()) {
+ Enumeration e = getPvcsprojects().elements();
+ while (e.hasMoreElements()) {
+ String projectName = ((PvcsProject) e.nextElement()).getName();
+ if (projectName == null || (projectName.trim()).equals("")) {
+ throw new BuildException("name is a required attribute "
+ + "of pvcsproject");
+ }
+ commandLine.createArgument().setValue(projectName);
+ }
+ }
+
+ File tmp = null;
+ File tmp2 = null;
+ try {
+ Random rand = new Random(System.currentTimeMillis());
+ tmp = new File("pvcs_ant_" + rand.nextLong() + ".log");
+ FileOutputStream fos = new FileOutputStream(tmp);
+ tmp2 = new File("pvcs_ant_" + rand.nextLong() + ".log");
+ log(commandLine.describeCommand(), Project.MSG_VERBOSE);
+ try {
+ result = runCmd(commandLine,
+ new PumpStreamHandler(fos,
+ new LogOutputStream(this,
+ Project.MSG_WARN)));
+ } finally {
+ FileUtils.close(fos);
+ }
+
+ if (Execute.isFailure(result) && !ignorerc) {
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+
+ if (!tmp.exists()) {
+ throw new BuildException("Communication between ant and pvcs "
+ + "failed. No output generated from executing PVCS "
+ + "commandline interface \"pcli\" and \"get\"");
+ }
+
+ // Create folders in workspace
+ log("Creating folders", Project.MSG_INFO);
+ createFolders(tmp);
+
+ // Massage PCLI lvf output transforming '\' to '/' so get command works appropriately
+ massagePCLI(tmp, tmp2);
+
+ // Launch get on output captured from PCLI lvf
+ commandLine.clearArgs();
+ commandLine.setExecutable(getExecutable(GET_EXE));
+
+ if (getConfig() != null && getConfig().length() > 0) {
+ commandLine.createArgument().setValue("-c" + getConfig());
+ }
+
+ if (getForce() != null && getForce().equals("yes")) {
+ commandLine.createArgument().setValue("-Y");
+ } else {
+ commandLine.createArgument().setValue("-N");
+ }
+
+ if (getPromotiongroup() != null) {
+ commandLine.createArgument().setValue("-G"
+ + getPromotiongroup());
+ } else {
+ if (getLabel() != null) {
+ commandLine.createArgument().setValue("-v" + getLabel());
+ } else {
+ if (getRevision() != null) {
+ commandLine.createArgument().setValue("-r"
+ + getRevision());
+ }
+ }
+ }
+
+ if (updateOnly) {
+ commandLine.createArgument().setValue("-U");
+ }
+
+ commandLine.createArgument().setValue("@" + tmp2.getAbsolutePath());
+ log("Getting files", Project.MSG_INFO);
+ log("Executing " + commandLine.toString(), Project.MSG_VERBOSE);
+ result = runCmd(commandLine,
+ new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN));
+ if (result != 0 && !ignorerc) {
+ String msg = "Failed executing: " + commandLine.toString()
+ + ". Return code was " + result;
+ throw new BuildException(msg, getLocation());
+ }
+
+ } catch (FileNotFoundException e) {
+ String msg = "Failed executing: " + commandLine.toString()
+ + ". Exception: " + e.getMessage();
+ throw new BuildException(msg, getLocation());
+ } catch (IOException e) {
+ String msg = "Failed executing: " + commandLine.toString()
+ + ". Exception: " + e.getMessage();
+ throw new BuildException(msg, getLocation());
+ } catch (ParseException e) {
+ String msg = "Failed executing: " + commandLine.toString()
+ + ". Exception: " + e.getMessage();
+ throw new BuildException(msg, getLocation());
+ } finally {
+ if (tmp != null) {
+ tmp.delete();
+ }
+ if (tmp2 != null) {
+ tmp2.delete();
+ }
+ }
+ }
+
+ /**
+ * Parses the file and creates the folders specified in the output section
+ */
+ private void createFolders(File file) throws IOException, ParseException {
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new FileReader(file));
+ MessageFormat mf = new MessageFormat(getFilenameFormat());
+ String line = in.readLine();
+ while (line != null) {
+ log("Considering \"" + line + "\"", Project.MSG_VERBOSE);
+ if (line.startsWith("\"\\") // Checking for "\
+ || line.startsWith("\"/") // or "/
+ // or "X:\...
+ || (line.length() > POS_3 && line.startsWith("\"")
+ && Character.isLetter(line.charAt(POS_1))
+ && String.valueOf(line.charAt(POS_2)).equals(":")
+ && String.valueOf(line.charAt(POS_3)).equals("\\"))) {
+ Object[] objs = mf.parse(line);
+ String f = (String) objs[1];
+ // Extract the name of the directory from the filename
+ int index = f.lastIndexOf(File.separator);
+ if (index > -1) {
+ File dir = new File(f.substring(0, index));
+ if (!dir.exists()) {
+ log("Creating " + dir.getAbsolutePath(),
+ Project.MSG_VERBOSE);
+ if (dir.mkdirs() || dir.isDirectory()) {
+ log("Created " + dir.getAbsolutePath(),
+ Project.MSG_INFO);
+ } else {
+ log("Failed to create "
+ + dir.getAbsolutePath(),
+ Project.MSG_INFO);
+ }
+ } else {
+ log(dir.getAbsolutePath() + " exists. Skipping",
+ Project.MSG_VERBOSE);
+ }
+ } else {
+ log("File separator problem with " + line,
+ Project.MSG_WARN);
+ }
+ } else {
+ log("Skipped \"" + line + "\"", Project.MSG_VERBOSE);
+ }
+ line = in.readLine();
+ }
+ } finally {
+ FileUtils.close(in);
+ }
+ }
+
+
+ /**
+ * Simple hack to handle the PVCS command-line tools botch when
+ * handling UNC notation.
+ * @throws IOException if there is an error.
+ */
+ private void massagePCLI(File in, File out)
+ throws IOException {
+ BufferedReader inReader = null;
+ BufferedWriter outWriter = null;
+ try {
+ inReader = new BufferedReader(new FileReader(in));
+ outWriter = new BufferedWriter(new FileWriter(out));
+ String s = null;
+ while ((s = inReader.readLine()) != null) {
+ String sNormal = s.replace('\\', '/');
+ outWriter.write(sNormal);
+ outWriter.newLine();
+ }
+ } finally {
+ FileUtils.close(inReader);
+ FileUtils.close(outWriter);
+ }
+ }
+
+ /**
+ * Get network name of the PVCS repository
+ * @return String
+ */
+ public String getRepository() {
+ return repository;
+ }
+
+ /**
+ * The filenameFormat attribute defines a MessageFormat string used
+ * to parse the output of the pcli command. It defaults to
+ * <code>{0}-arc({1})</code>. Repositories where the archive
+ * extension is not -arc should set this.
+ * @return the filename format attribute.
+ */
+ public String getFilenameFormat() {
+ return filenameFormat;
+ }
+
+ /**
+ * The format of the folder names; optional.
+ * This must be in a format suitable for
+ * <code>java.text.MessageFormat</code>.
+ * Index 1 of the format will be used as the file name.
+ * Defaults to <code>{0}-arc({1})</code>
+ * @param f the format to use.
+ */
+ public void setFilenameFormat(String f) {
+ filenameFormat = f;
+ }
+
+ /**
+
+ * The lineStart attribute is used to parse the output of the pcli
+ * command. It defaults to <code>&quot;P:</code>. The parser already
+ * knows about / and \\, this property is useful in cases where the
+ * repository is accessed on a Windows platform via a drive letter
+ * mapping.
+ * @return the lineStart attribute.
+ */
+ public String getLineStart() {
+ return lineStart;
+ }
+
+ /**
+ * What a valid return value from PVCS looks like
+ * when it describes a file. Defaults to <code>&quot;P:</code>.
+ * If you are not using an UNC name for your repository and the
+ * drive letter <code>P</code> is incorrect for your setup, you may
+ * need to change this value, UNC names will always be
+ * accepted.
+ * @param l the value to use.
+ */
+ public void setLineStart(String l) {
+ lineStart = l;
+ }
+
+ /**
+ * The network name of the PVCS repository; required.
+ * @param repo String
+ */
+ public void setRepository(String repo) {
+ repository = repo;
+ }
+
+ /**
+ * Get name of the project in the PVCS repository
+ * @return String
+ */
+ public String getPvcsproject() {
+ return pvcsProject;
+ }
+
+ /**
+ * The project within the PVCS repository to extract files from;
+ * optional, default &quot;/&quot;
+ * @param prj String
+ */
+ public void setPvcsproject(String prj) {
+ pvcsProject = prj;
+ }
+
+ /**
+ * Get name of the project in the PVCS repository
+ * @return Vector
+ */
+ public Vector getPvcsprojects() {
+ return pvcsProjects;
+ }
+
+ /**
+ * Get name of the workspace to store the retrieved files
+ * @return String
+ */
+ public String getWorkspace() {
+ return workspace;
+ }
+
+ /**
+ * Workspace to use; optional.
+ * By specifying a workspace, the files are extracted to that location.
+ * A PVCS workspace is a name for a location of the workfiles and
+ * isn't as such the location itself.
+ * You define the location for a workspace using the PVCS GUI clients.
+ * If this isn't specified the default workspace for the current user is used.
+ * @param ws String
+ */
+ public void setWorkspace(String ws) {
+ workspace = ws;
+ }
+
+ /**
+ * Get name of the PVCS bin directory
+ * @return String
+ */
+ public String getPvcsbin() {
+ return pvcsbin;
+ }
+
+ /**
+ * Specifies the location of the PVCS bin directory; optional if on the PATH.
+ * On some systems the PVCS executables <i>pcli</i>
+ * and <i>get</i> are not found in the PATH. In such cases this attribute
+ * should be set to the bin directory of the PVCS installation containing
+ * the executables mentioned before. If this attribute isn't specified the
+ * tag expects the executables to be found using the PATH environment variable.
+ * @param bin PVCS bin directory
+ * @todo use a File setter and resolve paths.
+ */
+ public void setPvcsbin(String bin) {
+ pvcsbin = bin;
+ }
+
+ /**
+ * Get value of force
+ * @return String
+ */
+ public String getForce() {
+ return force;
+ }
+
+ /**
+ * Specifies the value of the force argument; optional.
+ * If set to <i>yes</i> all files that exists and are
+ * writable are overwritten. Default <i>no</i> causes the files
+ * that are writable to be ignored. This stops the PVCS command
+ * <i>get</i> to stop asking questions!
+ * @todo make a boolean setter
+ * @param f String (yes/no)
+ */
+ public void setForce(String f) {
+ if (f != null && f.equalsIgnoreCase("yes")) {
+ force = "yes";
+ } else {
+ force = "no";
+ }
+ }
+
+ /**
+ * Get value of promotiongroup
+ * @return String
+ */
+ public String getPromotiongroup() {
+ return promotiongroup;
+ }
+
+ /**
+ * Specifies the name of the promotiongroup argument
+ * @param w String
+ */
+ public void setPromotiongroup(String w) {
+ promotiongroup = w;
+ }
+
+ /**
+ * Get value of label
+ * @return String
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Only files marked with this label are extracted; optional.
+ * @param l String
+ */
+ public void setLabel(String l) {
+ label = l;
+ }
+
+ /**
+ * Get value of revision
+ * @return String
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+ /**
+ * Only files with this revision are extract; optional.
+ * @param r String
+ */
+ public void setRevision(String r) {
+ revision = r;
+ }
+
+ /**
+ * Get value of ignorereturncode
+ * @return String
+ */
+ public boolean getIgnoreReturnCode() {
+ return ignorerc;
+ }
+
+ /**
+ * If set to true the return value from executing the pvcs
+ * commands are ignored; optional, default false.
+ * @param b a <code>boolean</code> value.
+ */
+ public void setIgnoreReturnCode(boolean b) {
+ ignorerc = b;
+ }
+
+ /**
+ * Specify a project within the PVCS repository to extract files from.
+ * @param p the pvcs project to use.
+ */
+ public void addPvcsproject(PvcsProject p) {
+ pvcsProjects.addElement(p);
+ }
+
+ /**
+ * get the updateOnly attribute.
+ * @return the updateOnly attribute.
+ */
+ public boolean getUpdateOnly() {
+ return updateOnly;
+ }
+
+ /**
+ * If set to <i>true</i> files are fetched only if
+ * newer than existing local files; optional, default false.
+ * @param l a <code>boolean</code> value.
+ */
+ public void setUpdateOnly(boolean l) {
+ updateOnly = l;
+ }
+
+ /**
+ * returns the path of the configuration file to be used
+ * @return the path of the config file
+ */
+ public String getConfig() {
+ return config;
+ }
+
+ /**
+ * Sets a configuration file other than the default to be used.
+ * These files have a .cfg extension and are often found in archive or pvcsprop folders.
+ * @param f config file - can be given absolute or relative to ant basedir
+ */
+ public void setConfig(File f) {
+ config = f.toString();
+ }
+
+
+ /**
+ * Get the userid.
+ * @return the userid.
+ */
+ public String getUserId() {
+ return userId;
+ }
+
+ /**
+ * User ID
+ * @param u the value to use.
+ */
+ public void setUserId(String u) {
+ userId = u;
+ }
+
+ /**
+ * Creates a Pvcs object
+ */
+ public Pvcs() {
+ super();
+ pvcsProject = null;
+ pvcsProjects = new Vector();
+ workspace = null;
+ repository = null;
+ pvcsbin = null;
+ force = null;
+ promotiongroup = null;
+ label = null;
+ ignorerc = false;
+ updateOnly = false;
+ lineStart = "\"P:";
+ filenameFormat = "{0}-arc({1})";
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java
new file mode 100644
index 00000000..a8c6a2a1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.pvcs;
+
+
+
+/**
+ * represents a project within the PVCS repository to extract files from.
+ */
+public class PvcsProject {
+ private String name;
+
+ /** no arg constructor */
+ public PvcsProject() {
+ super();
+ }
+
+ /**
+ * Set the name of the project
+ * @param name the value to use.
+ */
+ public void setName(String name) {
+ PvcsProject.this.name = name;
+ }
+
+ /**
+ * Get the name of the project
+ * @return the name of the project.
+ */
+ public String getName() {
+ return name;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java
new file mode 100644
index 00000000..ac9eb88e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java
@@ -0,0 +1,397 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.script;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.taskdefs.DefBase;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+
+/**
+ * Define a task using a script
+ *
+ * @since Ant 1.6
+ */
+public class ScriptDef extends DefBase {
+ /**
+ * script runner helper
+ */
+ private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+
+ /** the name by which this script will be activated */
+ private String name;
+
+ /** Attributes definitions of this script */
+ private List attributes = new ArrayList();
+
+ /** Nested Element definitions of this script */
+ private List nestedElements = new ArrayList();
+
+ /** The attribute names as a set */
+ private Set attributeSet;
+
+ /** The nested element definitions indexed by their names */
+ private Map nestedElementMap;
+
+ /**
+ * Set the project.
+ * @param project the project that this def belows to.
+ */
+ public void setProject(Project project) {
+ super.setProject(project);
+ helper.setProjectComponent(this);
+ helper.setSetBeans(false);
+ }
+
+ /**
+ * set the name under which this script will be activated in a build
+ * file
+ *
+ * @param name the name of the script
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Indicates whether the task supports a given attribute name
+ *
+ * @param attributeName the name of the attribute.
+ *
+ * @return true if the attribute is supported by the script.
+ */
+ public boolean isAttributeSupported(String attributeName) {
+ return attributeSet.contains(attributeName);
+ }
+
+ /**
+ * Class representing an attribute definition
+ */
+ public static class Attribute {
+ /** The attribute name */
+ private String name;
+
+ /**
+ * Set the attribute name
+ *
+ * @param name the attribute name
+ */
+ public void setName(String name) {
+ this.name = name.toLowerCase(Locale.ENGLISH);
+ }
+ }
+
+ /**
+ * Add an attribute definition to this script.
+ *
+ * @param attribute the attribute definition.
+ */
+ public void addAttribute(Attribute attribute) {
+ attributes.add(attribute);
+ }
+
+ /**
+ * Class to represent a nested element definition
+ */
+ public static class NestedElement {
+ /** The name of the nested element */
+ private String name;
+
+ /** The Ant type to which this nested element corresponds. */
+ private String type;
+
+ /** The class to be created for this nested element */
+ private String className;
+
+ /**
+ * set the tag name for this nested element
+ *
+ * @param name the name of this nested element
+ */
+ public void setName(String name) {
+ this.name = name.toLowerCase(Locale.ENGLISH);
+ }
+
+ /**
+ * Set the type of this element. This is the name of an
+ * Ant task or type which is to be used when this element is to be
+ * created. This is an alternative to specifying the class name directly
+ *
+ * @param type the name of an Ant type, or task, to use for this nested
+ * element.
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Set the classname of the class to be used for the nested element.
+ * This specifies the class directly and is an alternative to specifying
+ * the Ant type name.
+ *
+ * @param className the name of the class to use for this nested
+ * element.
+ */
+ public void setClassName(String className) {
+ this.className = className;
+ }
+ }
+
+ /**
+ * Add a nested element definition.
+ *
+ * @param nestedElement the nested element definition.
+ */
+ public void addElement(NestedElement nestedElement) {
+ nestedElements.add(nestedElement);
+ }
+
+ /**
+ * Define the script.
+ */
+ public void execute() {
+ if (name == null) {
+ throw new BuildException("scriptdef requires a name attribute to "
+ + "name the script");
+ }
+
+ if (helper.getLanguage() == null) {
+ throw new BuildException("<scriptdef> requires a language attribute "
+ + "to specify the script language");
+ }
+
+ // Check if need to set the loader
+ if (getAntlibClassLoader() != null || hasCpDelegate()) {
+ helper.setClassLoader(createLoader());
+ }
+
+ attributeSet = new HashSet();
+ for (Iterator i = attributes.iterator(); i.hasNext();) {
+ Attribute attribute = (Attribute) i.next();
+ if (attribute.name == null) {
+ throw new BuildException("scriptdef <attribute> elements "
+ + "must specify an attribute name");
+ }
+
+ if (attributeSet.contains(attribute.name)) {
+ throw new BuildException("scriptdef <" + name + "> declares "
+ + "the " + attribute.name + " attribute more than once");
+ }
+ attributeSet.add(attribute.name);
+ }
+
+ nestedElementMap = new HashMap();
+ for (Iterator i = nestedElements.iterator(); i.hasNext();) {
+ NestedElement nestedElement = (NestedElement) i.next();
+ if (nestedElement.name == null) {
+ throw new BuildException("scriptdef <element> elements "
+ + "must specify an element name");
+ }
+ if (nestedElementMap.containsKey(nestedElement.name)) {
+ throw new BuildException("scriptdef <" + name + "> declares "
+ + "the " + nestedElement.name + " nested element more "
+ + "than once");
+ }
+
+ if (nestedElement.className == null
+ && nestedElement.type == null) {
+ throw new BuildException("scriptdef <element> elements "
+ + "must specify either a classname or type attribute");
+ }
+ if (nestedElement.className != null
+ && nestedElement.type != null) {
+ throw new BuildException("scriptdef <element> elements "
+ + "must specify only one of the classname and type "
+ + "attributes");
+ }
+
+
+ nestedElementMap.put(nestedElement.name, nestedElement);
+ }
+
+ // find the script repository - it is stored in the project
+ Map scriptRepository = lookupScriptRepository();
+ name = ProjectHelper.genComponentName(getURI(), name);
+ scriptRepository.put(name, this);
+ AntTypeDefinition def = new AntTypeDefinition();
+ def.setName(name);
+ def.setClass(ScriptDefBase.class);
+ ComponentHelper.getComponentHelper(
+ getProject()).addDataTypeDefinition(def);
+ }
+
+ /**
+ * Find or create the script repository - it is stored in the project.
+ * This method is synchronized on the project under {@link MagicNames#SCRIPT_REPOSITORY}
+ * @return the current script repository registered as a reference.
+ */
+ private Map lookupScriptRepository() {
+ Map scriptRepository = null;
+ Project p = getProject();
+ synchronized (p) {
+ scriptRepository =
+ (Map) p.getReference(MagicNames.SCRIPT_REPOSITORY);
+ if (scriptRepository == null) {
+ scriptRepository = new HashMap();
+ p.addReference(MagicNames.SCRIPT_REPOSITORY,
+ scriptRepository);
+ }
+ }
+ return scriptRepository;
+ }
+
+ /**
+ * Create a nested element to be configured.
+ *
+ * @param elementName the name of the nested element.
+ * @return object representing the element name.
+ */
+ public Object createNestedElement(String elementName) {
+ NestedElement definition
+ = (NestedElement) nestedElementMap.get(elementName);
+ if (definition == null) {
+ throw new BuildException("<" + name + "> does not support "
+ + "the <" + elementName + "> nested element");
+ }
+
+ Object instance = null;
+ String classname = definition.className;
+ if (classname == null) {
+ instance = getProject().createTask(definition.type);
+ if (instance == null) {
+ instance = getProject().createDataType(definition.type);
+ }
+ } else {
+ /*
+ // try the context classloader
+ ClassLoader loader
+ = Thread.currentThread().getContextClassLoader();
+ */
+ ClassLoader loader = createLoader();
+
+ try {
+ instance = ClasspathUtils.newInstance(classname, loader);
+ } catch (BuildException e) {
+ instance = ClasspathUtils.newInstance(classname, ScriptDef.class.getClassLoader());
+ }
+
+ getProject().setProjectReference(instance);
+ }
+
+ if (instance == null) {
+ throw new BuildException("<" + name + "> is unable to create "
+ + "the <" + elementName + "> nested element");
+ }
+ return instance;
+ }
+
+ /**
+ * Execute the script.
+ *
+ * @param attributes collection of attributes
+ * @param elements a list of nested element values.
+ * @deprecated since 1.7.
+ * Use executeScript(attribute, elements, instance) instead.
+ */
+ public void executeScript(Map attributes, Map elements) {
+ executeScript(attributes, elements, null);
+ }
+
+ /**
+ * Execute the script.
+ * This is called by the script instance to execute the script for this
+ * definition.
+ *
+ * @param attributes collection of attributes
+ * @param elements a list of nested element values.
+ * @param instance the script instance; can be null
+ */
+ public void executeScript(Map attributes, Map elements, ScriptDefBase instance) {
+ ScriptRunnerBase runner = helper.getScriptRunner();
+ runner.addBean("attributes", attributes);
+ runner.addBean("elements", elements);
+ runner.addBean("project", getProject());
+ if (instance != null) {
+ runner.addBean("self", instance);
+ }
+ runner.executeScript("scriptdef_" + name);
+ }
+
+ /**
+ * Defines the manager.
+ *
+ * @param manager the scripting manager.
+ */
+ public void setManager(String manager) {
+ helper.setManager(manager);
+ }
+
+ /**
+ * Defines the language (required).
+ *
+ * @param language the scripting language name for the script.
+ */
+ public void setLanguage(String language) {
+ helper.setLanguage(language);
+ }
+
+ /**
+ * Load the script from an external file ; optional.
+ *
+ * @param file the file containing the script source.
+ */
+ public void setSrc(File file) {
+ helper.setSrc(file);
+ }
+
+ /**
+ * Set the script text.
+ *
+ * @param text a component of the script text to be added.
+ */
+ public void addText(String text) {
+ helper.addText(text);
+ }
+
+ /**
+ * Add any source resource.
+ * @since Ant1.7.1
+ * @param resource source of script
+ */
+ public void add(ResourceCollection resource) {
+ helper.add(resource);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java
new file mode 100644
index 00000000..95d15aa6
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.script;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicConfigurator;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Task;
+
+/**
+ * The script execution class. This class finds the defining script task
+ * and passes control to that task's executeScript method.
+ *
+ * @since Ant 1.6
+ */
+public class ScriptDefBase extends Task implements DynamicConfigurator {
+
+ /** Nested elements */
+ private Map nestedElementMap = new HashMap();
+
+ /** Attributes */
+ private Map attributes = new HashMap();
+
+ private String text;
+
+ /**
+ * Locate the script defining task and execute the script by passing
+ * control to it
+ */
+ public void execute() {
+ getScript().executeScript(attributes, nestedElementMap, this);
+ }
+
+ private ScriptDef getScript() {
+ String name = getTaskType();
+ Map scriptRepository
+ = (Map) getProject().getReference(MagicNames.SCRIPT_REPOSITORY);
+ if (scriptRepository == null) {
+ throw new BuildException("Script repository not found for " + name);
+ }
+
+ ScriptDef definition = (ScriptDef) scriptRepository.get(getTaskType());
+ if (definition == null) {
+ throw new BuildException("Script definition not found for " + name);
+ }
+ return definition;
+ }
+
+ /**
+ * Create a nested element
+ *
+ * @param name the nested element name
+ * @return the element to be configured
+ */
+ public Object createDynamicElement(String name) {
+ List nestedElementList = (List) nestedElementMap.get(name);
+ if (nestedElementList == null) {
+ nestedElementList = new ArrayList();
+ nestedElementMap.put(name, nestedElementList);
+ }
+ Object element = getScript().createNestedElement(name);
+ nestedElementList.add(element);
+ return element;
+ }
+
+ /**
+ * Set a task attribute
+ *
+ * @param name the attribute name.
+ * @param value the attribute's string value
+ */
+ public void setDynamicAttribute(String name, String value) {
+ ScriptDef definition = getScript();
+ if (!definition.isAttributeSupported(name)) {
+ throw new BuildException("<" + getTaskType()
+ + "> does not support the \"" + name + "\" attribute");
+ }
+
+ attributes.put(name, value);
+ }
+
+ /**
+ * Set the script text.
+ *
+ * @param text a component of the script text to be added.
+ * @since ant1.7
+ */
+ public void addText(String text) {
+ this.text = getProject().replaceProperties(text);
+ }
+
+ /**
+ * get the text of this element; may be null
+ * @return text or null for no nested text
+ * @since ant1.7
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Utility method for nested scripts; throws a BuildException
+ * with the given message.
+ * @param message text to pass to the BuildException
+ * @throws BuildException always.
+ * @since ant1.7
+ */
+ public void fail(String message) {
+ throw new BuildException(message);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java
new file mode 100644
index 00000000..03031d5e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * A base class for creating tasks for executing commands on SourceOffSite.
+ *
+ * These tasks were inspired by the VSS tasks.
+ *
+ */
+
+public abstract class SOS extends Task implements SOSCmd {
+
+ private static final int ERROR_EXIT_STATUS = 255;
+
+ private String sosCmdDir = null;
+ private String sosUsername = null;
+ private String sosPassword = "";
+ private String projectPath = null;
+ private String vssServerPath = null;
+ private String sosServerPath = null;
+ private String sosHome = null;
+ private String localPath = null;
+ private String version = null;
+ private String label = null;
+ private String comment = null;
+ private String filename = null;
+
+ private boolean noCompress = false;
+ private boolean noCache = false;
+ private boolean recursive = false;
+ private boolean verbose = false;
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /** Commandline to be executed. */
+ protected Commandline commandLine;
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Flag to disable the cache when set.
+ * Required if SOSHOME is set as an environment variable.
+ * Defaults to false.
+ *
+ * @param nocache True to disable caching.
+ */
+ public final void setNoCache(boolean nocache) {
+ noCache = nocache;
+ }
+
+ /**
+ * Flag to disable compression when set. Defaults to false.
+ *
+ * @param nocompress True to disable compression.
+ */
+ public final void setNoCompress(boolean nocompress) {
+ noCompress = nocompress;
+ }
+
+ /**
+ * The directory where soscmd(.exe) is located.
+ * soscmd must be on the path if omitted.
+ *
+ * @param dir The new sosCmd value.
+ */
+ public final void setSosCmd(String dir) {
+ sosCmdDir = FileUtils.translatePath(dir);
+ }
+
+ /**
+ * The SourceSafe username.
+ *
+ * @param username The new username value.
+ *
+ * @ant.attribute group="required"
+ */
+ public final void setUsername(String username) {
+ sosUsername = username;
+ }
+
+ /**
+ * The SourceSafe password.
+ *
+ * @param password The new password value.
+ */
+ public final void setPassword(String password) {
+ sosPassword = password;
+ }
+
+ /**
+ * The SourceSafe project path.
+ *
+ * @param projectpath The new projectpath value.
+ *
+ * @ant.attribute group="required"
+ */
+ public final void setProjectPath(String projectpath) {
+ if (projectpath.startsWith(SOSCmd.PROJECT_PREFIX)) {
+ projectPath = projectpath;
+ } else {
+ projectPath = SOSCmd.PROJECT_PREFIX + projectpath;
+ }
+ }
+
+ /**
+ * The path to the location of the ss.ini file.
+ *
+ * @param vssServerPath The new vssServerPath value.
+ *
+ * @ant.attribute group="required"
+ */
+ public final void setVssServerPath(String vssServerPath) {
+ this.vssServerPath = vssServerPath;
+ }
+
+ /**
+ * Path to the SourceOffSite home directory.
+ *
+ * @param sosHome The new sosHome value.
+ */
+ public final void setSosHome(String sosHome) {
+ this.sosHome = sosHome;
+ }
+
+ /**
+ * The address and port of SourceOffSite Server,
+ * for example 192.168.0.1:8888.
+ *
+ * @param sosServerPath The new sosServerPath value.
+ *
+ * @ant.attribute group="required"
+ */
+ public final void setSosServerPath(String sosServerPath) {
+ this.sosServerPath = sosServerPath;
+ }
+
+ /**
+ * Override the working directory and get to the specified path.
+ *
+ * @param path The new localPath value.
+ */
+ public final void setLocalPath(Path path) {
+ localPath = path.toString();
+ }
+
+ /**
+ * Enable verbose output. Defaults to false.
+ *
+ * @param verbose True for verbose output.
+ */
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ // Special setters for the sub-classes
+
+ /**
+ * Set the file name.
+ * @param file the filename to use.
+ */
+ protected void setInternalFilename(String file) {
+ filename = file;
+ }
+
+ /**
+ * Set the recursive flag.
+ * @param recurse if true use the recursive flag on the command line.
+ */
+ protected void setInternalRecursive(boolean recurse) {
+ recursive = recurse;
+ }
+
+ /**
+ * Set the comment text.
+ * @param text the comment text to use.
+ */
+ protected void setInternalComment(String text) {
+ comment = text;
+ }
+
+ /**
+ * Set the label.
+ * @param text the label to use.
+ */
+ protected void setInternalLabel(String text) {
+ label = text;
+ }
+
+ /**
+ * Set the version.
+ * @param text the version to use.
+ */
+ protected void setInternalVersion(String text) {
+ version = text;
+ }
+
+ /**
+ * Get the executable to run. Add the path if it was specified in the build file
+ *
+ * @return the executable to run.
+ */
+ protected String getSosCommand() {
+ if (sosCmdDir == null) {
+ return COMMAND_SOS_EXE;
+ } else {
+ return sosCmdDir + File.separator + COMMAND_SOS_EXE;
+ }
+ }
+
+ /**
+ * Get the comment
+ * @return if it was set, null if not.
+ */
+ protected String getComment() {
+ return comment;
+ }
+
+ /**
+ * Get the version
+ * @return if it was set, null if not.
+ */
+ protected String getVersion() {
+ return version;
+ }
+
+ /**
+ * Get the label
+ * @return if it was set, null if not.
+ */
+ protected String getLabel() {
+ return label;
+ }
+
+ /**
+ * Get the username
+ * @return if it was set, null if not.
+ */
+ protected String getUsername() {
+ return sosUsername;
+ }
+
+ /**
+ * Get the password
+ * @return empty string if it wasn't set.
+ */
+ protected String getPassword() {
+ return sosPassword;
+ }
+
+ /**
+ * Get the project path
+ * @return if it was set, null if not.
+ */
+ protected String getProjectPath() {
+ return projectPath;
+ }
+
+ /**
+ * Get the VSS server path
+ * @return if it was set, null if not.
+ */
+ protected String getVssServerPath() {
+ return vssServerPath;
+ }
+
+ /**
+ * Get the SOS home directory.
+ * @return if it was set, null if not.
+ */
+ protected String getSosHome() {
+ return sosHome;
+ }
+
+ /**
+ * Get the SOS serve path.
+ * @return if it was set, null if not.
+ */
+ protected String getSosServerPath() {
+ return sosServerPath;
+ }
+
+ /**
+ * Get the filename to be acted upon.
+ * @return if it was set, null if not.
+ */
+ protected String getFilename() {
+ return filename;
+ }
+
+ /**
+ * Get the NoCompress flag.
+ *
+ * @return the 'nocompress' Flag if the attribute was 'true',
+ * otherwise an empty string.
+ */
+ protected String getNoCompress() {
+ return noCompress ? FLAG_NO_COMPRESSION : "";
+ }
+
+ /**
+ * Get the NoCache flag.
+ *
+ * @return the 'nocache' Flag if the attribute was 'true', otherwise an empty string.
+ */
+ protected String getNoCache() {
+ return noCache ? FLAG_NO_CACHE : "";
+ }
+
+ /**
+ * Get the 'verbose' Flag.
+ *
+ * @return the 'verbose' Flag if the attribute was 'true', otherwise an empty string.
+ */
+ protected String getVerbose() {
+ return verbose ? FLAG_VERBOSE : "";
+ }
+
+ /**
+ * Get the 'recursive' Flag.
+ *
+ * @return the 'recursive' Flag if the attribute was 'true', otherwise an empty string.
+ */
+ protected String getRecursive() {
+ return recursive ? FLAG_RECURSION : "";
+ }
+
+ /**
+ * Builds and returns the working directory.
+ * <p>
+ * The localpath is created if it didn't exist.
+ *
+ * @return the absolute path of the working directory.
+ */
+ protected String getLocalPath() {
+ if (localPath == null) {
+ return getProject().getBaseDir().getAbsolutePath();
+ } else {
+ // make sure localDir exists, create it if it doesn't
+ File dir = getProject().resolveFile(localPath);
+ if (!dir.exists()) {
+ boolean done = dir.mkdirs() || dir.isDirectory();
+ if (!done) {
+ String msg = "Directory " + localPath + " creation was not "
+ + "successful for an unknown reason";
+ throw new BuildException(msg, getLocation());
+ }
+ getProject().log("Created dir: " + dir.getAbsolutePath());
+ }
+ return dir.getAbsolutePath();
+ }
+ }
+
+ /**
+ * Subclasses implement the logic required to construct the command line.
+ *
+ * @return The command line to execute.
+ */
+ abstract Commandline buildCmdLine();
+
+
+ /**
+ * Execute the created command line.
+ *
+ * @throws BuildException on error.
+ */
+ public void execute()
+ throws BuildException {
+ int result = 0;
+ buildCmdLine();
+ result = run(commandLine);
+ if (result == ERROR_EXIT_STATUS) { // This is the exit status
+ String msg = "Failed executing: " + commandLine.toString();
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ /**
+ * Execute the created command line.
+ *
+ * @param cmd The command line to run.
+ * @return int the exit code.
+ * @throws BuildException
+ */
+ protected int run(Commandline cmd) {
+ try {
+ Execute exe = new Execute(new LogStreamHandler(this,
+ Project.MSG_INFO,
+ Project.MSG_WARN));
+
+ exe.setAntRun(getProject());
+ exe.setWorkingDirectory(getProject().getBaseDir());
+ exe.setCommandline(cmd.getCommandline());
+ exe.setVMLauncher(false); // Use the OS VM launcher so we get environment variables
+ return exe.execute();
+ } catch (java.io.IOException e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ /** Sets the executable and add the required attributes to the command line. */
+ protected void getRequiredAttributes() {
+ // Get the path to the soscmd(.exe)
+ commandLine.setExecutable(getSosCommand());
+ // SOS server address is required
+ if (getSosServerPath() == null) {
+ throw new BuildException("sosserverpath attribute must be set!", getLocation());
+ }
+ commandLine.createArgument().setValue(FLAG_SOS_SERVER);
+ commandLine.createArgument().setValue(getSosServerPath());
+ // Login info is required
+ if (getUsername() == null) {
+ throw new BuildException("username attribute must be set!", getLocation());
+ }
+ commandLine.createArgument().setValue(FLAG_USERNAME);
+ commandLine.createArgument().setValue(getUsername());
+ // The SOS class knows that the SOS server needs the password flag,
+ // even if there is no password ,so we send a " "
+ commandLine.createArgument().setValue(FLAG_PASSWORD);
+ commandLine.createArgument().setValue(getPassword());
+ // VSS Info is required
+ if (getVssServerPath() == null) {
+ throw new BuildException("vssserverpath attribute must be set!", getLocation());
+ }
+ commandLine.createArgument().setValue(FLAG_VSS_SERVER);
+ commandLine.createArgument().setValue(getVssServerPath());
+ // VSS project is required
+ if (getProjectPath() == null) {
+ throw new BuildException("projectpath attribute must be set!", getLocation());
+ }
+ commandLine.createArgument().setValue(FLAG_PROJECT);
+ commandLine.createArgument().setValue(getProjectPath());
+ }
+
+ /** Adds the optional attributes to the command line. */
+ protected void getOptionalAttributes() {
+ // -verbose
+ commandLine.createArgument().setValue(getVerbose());
+ // Disable Compression
+ commandLine.createArgument().setValue(getNoCompress());
+ // Path to the SourceOffSite home directory /home/user/.sos
+ if (getSosHome() == null) {
+ // If -soshome was not specified then we can look for nocache
+ commandLine.createArgument().setValue(getNoCache());
+ } else {
+ commandLine.createArgument().setValue(FLAG_SOS_HOME);
+ commandLine.createArgument().setValue(getSosHome());
+ }
+ //If a working directory was specified then add it to the command line
+ if (getLocalPath() != null) {
+ commandLine.createArgument().setValue(FLAG_WORKING_DIR);
+ commandLine.createArgument().setValue(getLocalPath());
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java
new file mode 100644
index 00000000..9095f075
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Commits and unlocks files in Visual SourceSafe via a SourceOffSite server.
+ *
+ * @ant.task name="soscheckin" category="scm"
+ */
+public class SOSCheckin extends SOS {
+
+ /**
+ * The filename to act upon.
+ * If no file is specified then the task
+ * acts upon the project.
+ *
+ * @param filename The new file value
+ */
+ public final void setFile(String filename) {
+ super.setInternalFilename(filename);
+ }
+
+ /**
+ * Flag to recursively apply the action. Defaults to false.
+ *
+ * @param recursive True for recursive operation.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * The comment to apply to all files being labelled.
+ *
+ * @param comment The new comment value
+ */
+ public void setComment(String comment) {
+ super.setInternalComment(comment);
+ }
+
+ /**
+ * Build the command line. <p>
+ *
+ * CheckInFile required parameters: -server -name -password -database -project
+ * -file<br>
+ * CheckInFile optional parameters: -workdir -log -verbose -nocache -nocompression
+ * -soshome<br>
+ * CheckInProject required parameters: -server -name -password -database
+ * -project<br>
+ * CheckInProject optional parameters: workdir -recursive -log -verbose
+ * -nocache -nocompression -soshome<br>
+ *
+ * @return Commandline the generated command to be executed
+ */
+ protected Commandline buildCmdLine() {
+ commandLine = new Commandline();
+
+ // If we find a "file" attribute then act on a file otherwise act on a project
+ if (getFilename() != null) {
+ // add -command CheckInFile to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKIN_FILE);
+ // add -file xxxxx to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_FILE);
+ commandLine.createArgument().setValue(getFilename());
+ } else {
+ // add -command CheckInProject to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKIN_PROJECT);
+ // look for a recursive option
+ commandLine.createArgument().setValue(getRecursive());
+ }
+
+ getRequiredAttributes();
+ getOptionalAttributes();
+
+ // Look for a comment
+ if (getComment() != null) {
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMENT);
+ commandLine.createArgument().setValue(getComment());
+ }
+ return commandLine;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java
new file mode 100644
index 00000000..fab6fb9f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Retrieves and locks files in Visual SourceSafe via a SourceOffSite server.
+ *
+ * @ant.task name="soscheckout" category="scm"
+ */
+public class SOSCheckout extends SOS {
+
+ /**
+ * The filename to act upon.
+ * If no file is specified then the task
+ * acts upon the project.
+ *
+ * @param filename The new file value
+ */
+ public final void setFile(String filename) {
+ super.setInternalFilename(filename);
+ }
+
+ /**
+ * Flag to recursively apply the action. Defaults to false.
+ *
+ * @param recursive True for recursive operation.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Build the command line <br>
+ *
+ * CheckOutFile required parameters: -server -name -password -database -project -file<br>
+ * CheckOutFile optional parameters: -workdir -verbose -nocache -nocompression -soshome<br>
+ *
+ * CheckOutProject required parameters: -server -name -password -database -project<br>
+ * CheckOutProject optional parameters:-workdir -recursive -verbose -nocache
+ * -nocompression -soshome<br>
+ *
+ * @return Commandline the generated command to be executed
+ */
+ protected Commandline buildCmdLine() {
+ commandLine = new Commandline();
+
+ // If we find a "file" attribute then act on a file otherwise act on a project
+ if (getFilename() != null) {
+ // add -command CheckOutFile to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKOUT_FILE);
+ // add -file xxxxx to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_FILE);
+ commandLine.createArgument().setValue(getFilename());
+ } else {
+ // add -command CheckOutProject to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKOUT_PROJECT);
+ // look for a recursive option
+ commandLine.createArgument().setValue(getRecursive());
+ }
+
+ getRequiredAttributes();
+ getOptionalAttributes();
+
+ return commandLine;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java
new file mode 100644
index 00000000..3543c414
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+/**
+ * Interface to hold constants used by the SOS tasks
+ *
+ */
+// CheckStyle:InterfaceIsTypeCheck OFF (bc)
+public interface SOSCmd {
+ // soscmd Command options
+ /** The sos executable */
+ String COMMAND_SOS_EXE = "soscmd";
+ /** The get file command */
+ String COMMAND_GET_FILE = "GetFile";
+ /** The get project command */
+ String COMMAND_GET_PROJECT = "GetProject";
+ /** The checkout file command */
+ String COMMAND_CHECKOUT_FILE = "CheckOutFile";
+ /** The checkout project command */
+ String COMMAND_CHECKOUT_PROJECT = "CheckOutProject";
+ /** The checkin file command */
+ String COMMAND_CHECKIN_FILE = "CheckInFile";
+ /** The checkin project command */
+ String COMMAND_CHECKIN_PROJECT = "CheckInProject";
+ /** The get history command */
+ String COMMAND_HISTORY = "GetFileHistory";
+ /** The add label command */
+ String COMMAND_LABEL = "AddLabel";
+ /** The project prefix */
+ String PROJECT_PREFIX = "$";
+
+ // soscmd Option flags
+ /** The command option */
+ String FLAG_COMMAND = "-command";
+ /** The database (vss server) option */
+ String FLAG_VSS_SERVER = "-database";
+ /** The username option */
+ String FLAG_USERNAME = "-name";
+ /** The password option */
+ String FLAG_PASSWORD = "-password";
+ /** The log option */
+ String FLAG_COMMENT = "-log";
+ /** The workdir option */
+ String FLAG_WORKING_DIR = "-workdir";
+ /** The recursive option */
+ String FLAG_RECURSION = "-recursive";
+ /** The revision option */
+ String FLAG_VERSION = "-revision";
+ /** The label option */
+ String FLAG_LABEL = "-label";
+ /** The no compression option */
+ String FLAG_NO_COMPRESSION = "-nocompress";
+ /** The no cache option */
+ String FLAG_NO_CACHE = "-nocache";
+ /** The server option */
+ String FLAG_SOS_SERVER = "-server";
+ /** The sos home option */
+ String FLAG_SOS_HOME = "-soshome";
+ /** The project option */
+ String FLAG_PROJECT = "-project";
+ /** The file option */
+ String FLAG_FILE = "-file";
+ /** The verbose option */
+ String FLAG_VERBOSE = "-verbose";
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java
new file mode 100644
index 00000000..cdbf92bc
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Retrieves a read-only copy of the specified project or file
+ * from Visual SourceSafe via a SourceOffSite server.
+ *
+ * @ant.task name="sosget" category="scm"
+ */
+public class SOSGet extends SOS {
+
+ /**
+ * The Filename to act upon.
+ * If no file is specified then the tasks
+ * act upon the project.
+ *
+ * @param filename The new file value
+ */
+ public final void setFile(String filename) {
+ super.setInternalFilename(filename);
+ }
+
+ /**
+ * Flag to recursively apply the action. Defaults to false
+ *
+ * @param recursive True for recursive operation.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Set the version number to get -
+ * only works with SOSGet on a file.
+ *
+ * @param version The new version value
+ */
+ public void setVersion(String version) {
+ super.setInternalVersion(version);
+ }
+
+ /**
+ * The labeled version to operate on in SourceSafe.
+ *
+ * @param label The new label value
+ */
+ public void setLabel(String label) {
+ super.setInternalLabel(label);
+ }
+
+ /**
+ * Build the command line <br>
+ *
+ * GetFile required parameters: -server -name -password -database -project -file<br>
+ * GetFile optional parameters: -workdir -revision -verbose -nocache -nocompression -soshome<br>
+ *
+ * GetProject required parameters: -server -name -password -database -project<br>
+ * GetProject optional parameters: -label -workdir -recursive -verbose -nocache
+ * -nocompression -soshome<br>
+ *
+ * @return Commandline the generated command to be executed
+ */
+ protected Commandline buildCmdLine() {
+ commandLine = new Commandline();
+
+ // If we find a "file" attribute then act on a file otherwise act on a project
+ if (getFilename() != null) {
+ // add -command GetFile to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_GET_FILE);
+ // add -file xxxxx to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_FILE);
+ commandLine.createArgument().setValue(getFilename());
+ // look for a version attribute
+ if (getVersion() != null) {
+ //add -revision xxxxx to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_VERSION);
+ commandLine.createArgument().setValue(getVersion());
+ }
+ } else {
+ // add -command GetProject to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_GET_PROJECT);
+ // look for a recursive option
+ commandLine.createArgument().setValue(getRecursive());
+ // look for a label option
+ if (getLabel() != null) {
+ commandLine.createArgument().setValue(SOSCmd.FLAG_LABEL);
+ commandLine.createArgument().setValue(getLabel());
+ }
+ }
+
+ getRequiredAttributes();
+ getOptionalAttributes();
+
+ return commandLine;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java
new file mode 100644
index 00000000..dd6b13a2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Labels Visual SourceSafe files via a SourceOffSite server.
+ *
+ * @ant.task name="soslabel" category="scm"
+ */
+public class SOSLabel extends SOS {
+
+ /**
+ * The version number to label.
+ *
+ * @param version The new version value
+ */
+ public void setVersion(String version) {
+ super.setInternalVersion(version);
+ }
+
+ /**
+ * The label to apply the the files in SourceSafe.
+ *
+ * @param label The new label value
+ *
+ * @ant.attribute group="required"
+ */
+ public void setLabel(String label) {
+ super.setInternalLabel(label);
+ }
+
+ /**
+ * The comment to apply to all files being labelled.
+ *
+ * @param comment The new comment value
+ */
+ public void setComment(String comment) {
+ super.setInternalComment(comment);
+ }
+
+ /**
+ * Build the command line <br>
+ * AddLabel required parameters: -server -name -password -database -project -label<br>
+ * AddLabel optional parameters: -verbose -comment<br>
+ *
+ * @return Commandline the generated command to be executed
+ */
+ protected Commandline buildCmdLine() {
+ commandLine = new Commandline();
+
+ // add -command AddLabel to the commandline
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+ commandLine.createArgument().setValue(SOSCmd.COMMAND_LABEL);
+
+ getRequiredAttributes();
+
+ // a label is required
+ if (getLabel() == null) {
+ throw new BuildException("label attribute must be set!", getLocation());
+ }
+ commandLine.createArgument().setValue(SOSCmd.FLAG_LABEL);
+ commandLine.createArgument().setValue(getLabel());
+
+ // -verbose
+ commandLine.createArgument().setValue(getVerbose());
+ // Look for a comment
+ if (getComment() != null) {
+ commandLine.createArgument().setValue(SOSCmd.FLAG_COMMENT);
+ commandLine.createArgument().setValue(getComment());
+ }
+ return commandLine;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html
new file mode 100644
index 00000000..a0538c21
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html
@@ -0,0 +1,29 @@
+<html>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<body>
+ <p>
+ Ant tasks for working with a SourceOffSite source control system.
+ </p>
+ <p>
+ The &lt;SOSGet&gt; Retreives file(s) from a SOS database<br>
+ The &lt;SOSCheckin&gt; Commits and unlocks file(s) in a SOS database<br>
+ The &lt;SOSCheckout&gt; Retreives and lock file(s) in a SOS database<br>
+ The &lt;SOSLabel&gt; Label a SOS database<br>
+ </p>
+</body>
+</html>
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java
new file mode 100644
index 00000000..7988bc60
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.sound;
+
+// ant includes
+import java.io.File;
+import java.io.IOException;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.Project;
+
+
+
+/**
+ * This class is designed to be used by any AntTask that requires audio output.
+ *
+ * It implements the BuildListener interface to listen for BuildEvents
+ * and could be easily extended to provide audio output upon any
+ * specific build events occurring.
+ *
+ * I have only tested this with .WAV and .AIFF sound file formats. Both seem to work fine.
+ *
+ */
+
+public class AntSoundPlayer implements LineListener, BuildListener {
+
+ private File fileSuccess = null;
+ private int loopsSuccess = 0;
+ private Long durationSuccess = null;
+
+ private File fileFail = null;
+ private int loopsFail = 0;
+ private Long durationFail = null;
+
+ /** Constructor for AntSoundPlayer. */
+ public AntSoundPlayer() {
+ }
+
+ /**
+ * @param file the location of the audio file to be played when the
+ * build is successful
+ * @param loops the number of times the file should be played when
+ * the build is successful
+ * @param duration the number of milliseconds the file should be
+ * played when the build is successful
+ */
+ public void addBuildSuccessfulSound(File file, int loops, Long duration) {
+ this.fileSuccess = file;
+ this.loopsSuccess = loops;
+ this.durationSuccess = duration;
+ }
+
+
+ /**
+ * @param fileFail the location of the audio file to be played
+ * when the build fails
+ * @param loopsFail the number of times the file should be played
+ * when the build is fails
+ * @param durationFail the number of milliseconds the file should be
+ * played when the build fails
+ */
+ public void addBuildFailedSound(File fileFail, int loopsFail, Long durationFail) {
+ this.fileFail = fileFail;
+ this.loopsFail = loopsFail;
+ this.durationFail = durationFail;
+ }
+
+ /**
+ * Plays the file for duration milliseconds or loops.
+ */
+ private void play(Project project, File file, int loops, Long duration) {
+
+ Clip audioClip = null;
+
+ AudioInputStream audioInputStream = null;
+
+
+ try {
+ audioInputStream = AudioSystem.getAudioInputStream(file);
+ } catch (UnsupportedAudioFileException uafe) {
+ project.log("Audio format is not yet supported: "
+ + uafe.getMessage());
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+
+ if (audioInputStream != null) {
+ AudioFormat format = audioInputStream.getFormat();
+ DataLine.Info info = new DataLine.Info(Clip.class, format,
+ AudioSystem.NOT_SPECIFIED);
+ try {
+ audioClip = (Clip) AudioSystem.getLine(info);
+ audioClip.addLineListener(this);
+ audioClip.open(audioInputStream);
+ } catch (LineUnavailableException e) {
+ project.log("The sound device is currently unavailable");
+ return;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (duration != null) {
+ playClip(audioClip, duration.longValue());
+ } else {
+ playClip(audioClip, loops);
+ }
+ audioClip.drain();
+ audioClip.close();
+ } else {
+ project.log("Can't get data from file " + file.getName());
+ }
+ }
+
+ private void playClip(Clip clip, int loops) {
+
+ clip.loop(loops);
+ do {
+ try {
+ long timeLeft =
+ (clip.getMicrosecondLength() - clip.getMicrosecondPosition())
+ / 1000;
+ if (timeLeft > 0) {
+ Thread.sleep(timeLeft);
+ }
+ } catch (InterruptedException e) {
+ break;
+ }
+ } while (clip.isRunning());
+
+ if (clip.isRunning()) {
+ clip.stop();
+ }
+ }
+
+ private void playClip(Clip clip, long duration) {
+ clip.loop(Clip.LOOP_CONTINUOUSLY);
+ try {
+ Thread.sleep(duration);
+ } catch (InterruptedException e) {
+ // Ignore Exception
+ }
+ clip.stop();
+ }
+
+ /**
+ * This is implemented to listen for any line events and closes the
+ * clip if required.
+ * @param event the line event to follow
+ */
+ public void update(LineEvent event) {
+ if (event.getType().equals(LineEvent.Type.STOP)) {
+ Line line = event.getLine();
+ line.close();
+ }
+ }
+
+
+ /**
+ * Fired before any targets are started.
+ * @param event ignored
+ */
+ public void buildStarted(BuildEvent event) {
+ }
+
+ /**
+ * Fired after the last target has finished. This event
+ * will still be thrown if an error occurred during the build.
+ * @param event the build finished event.
+ * @see BuildEvent#getException()
+ */
+ public void buildFinished(BuildEvent event) {
+ if (event.getException() == null && fileSuccess != null) {
+ // build successful!
+ play(event.getProject(), fileSuccess, loopsSuccess, durationSuccess);
+ } else if (event.getException() != null && fileFail != null) {
+ play(event.getProject(), fileFail, loopsFail, durationFail);
+ }
+ }
+
+ /**
+ * Fired when a target is started.
+ * @param event ignored.
+ * @see BuildEvent#getTarget()
+ */
+ public void targetStarted(BuildEvent event) {
+ }
+
+ /**
+ * Fired when a target has finished. This event will
+ * still be thrown if an error occurred during the build.
+ * @param event ignored.
+ * @see BuildEvent#getException()
+ */
+ public void targetFinished(BuildEvent event) {
+ }
+
+ /**
+ * Fired when a task is started.
+ * @param event ignored.
+ * @see BuildEvent#getTask()
+ */
+ public void taskStarted(BuildEvent event) {
+ }
+
+ /**
+ * Fired when a task has finished. This event will still
+ * be throw if an error occurred during the build.
+ * @param event ignored.
+ * @see BuildEvent#getException()
+ */
+ public void taskFinished(BuildEvent event) {
+ }
+
+ /**
+ * Fired whenever a message is logged.
+ * @param event the build event
+ * @see BuildEvent#getMessage()
+ * @see BuildEvent#getPriority()
+ */
+ public void messageLogged(BuildEvent event) {
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java
new file mode 100644
index 00000000..dfb6e69a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.sound;
+
+import java.io.File;
+import java.util.Random;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Plays a sound file at the end of the build, according to whether the build failed or succeeded.
+ *
+ * There are three attributes to be set:
+ *
+ * <code>source</code>: the location of the audio file to be played
+ * <code>duration</code>: play the sound file continuously until "duration" milliseconds has expired
+ * <code>loops</code>: the number of times the sound file should be played until stopped
+ *
+ * I have only tested this with .WAV and .AIFF sound file formats. Both seem
+ * to work fine.
+ *
+ * plans for the future:
+ * - use the midi api to define sounds (or drum beat etc) in xml and have
+ * Ant play them back
+ *
+ */
+
+public class SoundTask extends Task {
+
+ private BuildAlert success = null;
+ private BuildAlert fail = null;
+
+ /**
+ * add a sound when the build succeeds
+ * @return a BuildAlert to be configured
+ */
+ public BuildAlert createSuccess() {
+ success = new BuildAlert();
+ return success;
+ }
+
+ /**
+ * add a sound when the build fails
+ * @return a BuildAlert to be configured
+ */
+ public BuildAlert createFail() {
+ fail = new BuildAlert();
+ return fail;
+ }
+
+ /** Constructor for SoundTask. */
+ public SoundTask() {
+ }
+
+ /**
+ * Initialize the task.
+ */
+ public void init() {
+ }
+
+ /**
+ * Execute the task.
+ */
+ public void execute() {
+
+ AntSoundPlayer soundPlayer = new AntSoundPlayer();
+
+ if (success == null) {
+ log("No nested success element found.", Project.MSG_WARN);
+ } else {
+ soundPlayer.addBuildSuccessfulSound(success.getSource(),
+ success.getLoops(), success.getDuration());
+ }
+
+ if (fail == null) {
+ log("No nested failure element found.", Project.MSG_WARN);
+ } else {
+ soundPlayer.addBuildFailedSound(fail.getSource(),
+ fail.getLoops(), fail.getDuration());
+ }
+
+ getProject().addBuildListener(soundPlayer);
+
+ }
+
+ /**
+ * A class to be extended by any BuildAlert's that require the output
+ * of sound.
+ */
+ public class BuildAlert {
+ private File source = null;
+ private int loops = 0;
+ private Long duration = null;
+
+ /**
+ * Sets the duration in milliseconds the file should be played; optional.
+ * @param duration the duration in milliseconds
+ */
+ public void setDuration(Long duration) {
+ this.duration = duration;
+ }
+
+ /**
+ * Sets the location of the file to get the audio; required.
+ *
+ * @param source the name of a sound-file directory or of the audio file
+ */
+ public void setSource(File source) {
+ this.source = source;
+ }
+
+ /**
+ * Sets the number of times the source file should be played; optional.
+ *
+ * @param loops the number of loops to play the source file
+ */
+ public void setLoops(int loops) {
+ this.loops = loops;
+ }
+
+ /**
+ * Gets the location of the file to get the audio.
+ * @return the file location
+ */
+ public File getSource() {
+ File nofile = null;
+ // Check if source is a directory
+ if (source.exists()) {
+ if (source.isDirectory()) {
+ // get the list of files in the dir
+ String[] entries = source.list();
+ Vector files = new Vector();
+ for (int i = 0; i < entries.length; i++) {
+ File f = new File(source, entries[i]);
+ if (f.isFile()) {
+ files.addElement(f);
+ }
+ }
+ if (files.size() < 1) {
+ throw new BuildException("No files found in directory " + source);
+ }
+ int numfiles = files.size();
+ // get a random number between 0 and the number of files
+ Random rn = new Random();
+ int x = rn.nextInt(numfiles);
+ // set the source to the file at that location
+ this.source = (File) files.elementAt(x);
+ }
+ } else {
+ log(source + ": invalid path.", Project.MSG_WARN);
+ this.source = nofile;
+ }
+ return this.source;
+ }
+
+ /**
+ * Sets the number of times the source file should be played.
+ *
+ * @return the number of loops to play the source file
+ */
+ public int getLoops() {
+ return this.loops;
+ }
+
+ /**
+ * Gets the duration in milliseconds the file should be played.
+ * @return the duration in milliseconds
+ */
+ public Long getDuration() {
+ return this.duration;
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java
new file mode 100644
index 00000000..5de84cca
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.splash;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JWindow;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+
+class SplashScreen extends JWindow implements ActionListener, BuildListener {
+ private static final int FONT_SIZE = 12;
+ private JLabel text;
+ private JProgressBar pb;
+ private int total;
+ private static final int MIN = 0;
+ private static final int MAX = 200;
+ private Pattern progressRegExpPattern;
+
+ public SplashScreen(String msg) {
+ this(msg, null, null);
+ }
+
+ public SplashScreen(ImageIcon img) {
+ this(img, null, null);
+ }
+
+ public SplashScreen(String msg, String progressRegExp, String displayText) {
+ init(null, progressRegExp, displayText);
+ setText(msg);
+ }
+
+ public SplashScreen(ImageIcon img, String progressRegExp,
+ String displayText) {
+ init(img, progressRegExp, displayText);
+ }
+
+ protected void init(ImageIcon img) {
+ init(img, null, null);
+ }
+
+ protected void init(ImageIcon img, String progressRegExp,
+ String displayText) {
+ if (progressRegExp != null) {
+ progressRegExpPattern = Pattern.compile(progressRegExp);
+ }
+
+ JPanel pan = (JPanel) getContentPane();
+ JLabel piccy;
+ if (img == null) {
+ piccy = new JLabel();
+ } else {
+ piccy = new JLabel(img);
+ }
+
+ piccy.setBorder(BorderFactory.createLineBorder(Color.black, 1));
+ if (displayText == null) {
+ displayText = "Building....";
+ }
+ text = new JLabel(displayText, JLabel.CENTER);
+ text.setFont(new Font("Sans-Serif", Font.BOLD, FONT_SIZE));
+ text.setBorder(BorderFactory.createEtchedBorder());
+
+ pb = new JProgressBar(MIN, MAX);
+ pb.setBorder(BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
+ JPanel pan2 = new JPanel();
+ pan2.setLayout(new BorderLayout());
+
+ pan2.add(text, BorderLayout.NORTH);
+ pan2.add(pb, BorderLayout.SOUTH);
+
+ pan.setLayout(new BorderLayout());
+ pan.add(piccy, BorderLayout.CENTER);
+ pan.add(pan2, BorderLayout.SOUTH);
+
+ pan.setBorder(BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
+
+ pack();
+
+ Dimension size = getSize();
+ Dimension scr = Toolkit.getDefaultToolkit().getScreenSize();
+ int x = (scr.width - size.width) / 2;
+ int y = (scr.height - size.height) / 2;
+ setBounds(x, y, size.width, size.height);
+ }
+
+ public void setText(String txt) {
+ text.setText(txt);
+ }
+
+ public void actionPerformed(ActionEvent a) {
+ if (!hasProgressPattern()) {
+ if (total < MAX) {
+ total++;
+ } else {
+ total = MIN;
+ }
+ pb.setValue(total);
+ }
+ }
+
+ public void buildStarted(BuildEvent event) {
+ actionPerformed(null);
+ }
+
+ public void buildFinished(BuildEvent event) {
+ pb.setValue(MAX);
+ setVisible(false);
+ dispose();
+ }
+ public void targetStarted(BuildEvent event) {
+ actionPerformed(null);
+ }
+
+ public void targetFinished(BuildEvent event) {
+ actionPerformed(null);
+ }
+
+ public void taskStarted(BuildEvent event) {
+ actionPerformed(null);
+ }
+
+ public void taskFinished(BuildEvent event) {
+ actionPerformed(null);
+ }
+
+ public void messageLogged(BuildEvent event) {
+ actionPerformed(null);
+ if (hasProgressPattern()) {
+ String message = event.getMessage();
+ Matcher matcher = progressRegExpPattern.matcher(message);
+ if (matcher != null && matcher.matches()) {
+ String gr = matcher.group(1);
+ try {
+ int i = Math.min(new Integer(gr).intValue() * 2, MAX);
+ pb.setValue(i);
+ } catch (NumberFormatException e) {
+ //TODO: how to reach logger?!?
+ //log("Number parsing error in progressRegExp", Project.MSG_VERBOSE);
+
+ }
+ }
+ }
+ }
+
+ protected boolean hasProgressPattern() {
+ return progressRegExpPattern != null;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java
new file mode 100644
index 00000000..3a73bdf7
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.splash;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.swing.ImageIcon;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.net.SetProxy;
+import org.apache.tools.ant.util.Base64Converter;
+
+/**
+ * Creates a splash screen. The splash screen is displayed
+ * for the duration of the build and includes a handy progress bar as
+ * well. Use in conjunction with the sound task to provide interest
+ * whilst waiting for your builds to complete...
+ * @since Ant1.5
+ */
+public class SplashTask extends Task {
+ private static final int DEFAULT_SHOW_DURATION = 5000;
+
+ private String imgurl = null;
+ private String proxy = null;
+ private String user = null;
+ private String password = null;
+ private String port = "80";
+ private int showDuration = DEFAULT_SHOW_DURATION;
+ private boolean useProxy = false;
+ private String progressRegExp = null;
+ private String displayText = null;
+
+ private static SplashScreen splash = null;
+
+ /**
+ * A URL pointing to an image to display; optional, default antlogo.gif
+ * from the classpath.
+ * @param imgurl the url string pointing to the image
+ */
+ public void setImageURL(String imgurl) {
+ this.imgurl = imgurl;
+ }
+
+ /**
+ * flag to enable proxy settings; optional, deprecated : consider
+ * using &lt;setproxy&gt; instead
+ * @param useProxy if ture, enable proxy settings
+ * @deprecated since 1.5.x.
+ * Use org.apache.tools.ant.taskdefs.optional.net.SetProxy
+ */
+ @Deprecated
+ public void setUseproxy(boolean useProxy) {
+ this.useProxy = useProxy;
+ }
+
+ /**
+ * name of proxy; optional.
+ * @param proxy the name of the proxy host
+ * @deprecated since 1.5.x.
+ * Use org.apache.tools.ant.taskdefs.optional.net.SetProxy
+ */
+ @Deprecated
+ public void setProxy(String proxy) {
+ this.proxy = proxy;
+ }
+
+ /**
+ * Proxy port; optional, default 80.
+ * @param port the proxy port
+ * @deprecated since 1.5.x.
+ * Use org.apache.tools.ant.taskdefs.optional.net.SetProxy
+ */
+ @Deprecated
+ public void setPort(String port) {
+ this.port = port;
+ }
+
+ /**
+ * Proxy user; optional, default =none.
+ * @param user the proxy user
+ * @deprecated since 1.5.x.
+ * Use org.apache.tools.ant.taskdefs.optional.net.SetProxy
+ */
+ @Deprecated
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ /**
+ * Proxy password; required if <tt>user</tt> is set.
+ * @param password the proxy password
+ * @deprecated since 1.5.x.
+ * Use org.apache.tools.ant.taskdefs.optional.net.SetProxy
+ */
+ @Deprecated
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * how long to show the splash screen in milliseconds,
+ * optional; default 5000 ms.
+ * @param duration the splash duration in milliseconds
+ */
+ public void setShowduration(int duration) {
+ this.showDuration = duration;
+ }
+
+
+ /**
+ * Progress regular expression which is used to parse the output
+ * and dig out current progress optional; if not provided,
+ * progress is increased every action and log output line
+ * @param progressRegExp Progress regular expression, exactly one
+ * group pattern must exists, and it represents the progress
+ * number (0-100) (i.e "Progress: (.*)%")
+ * @since Ant 1.8.0
+ */
+ public void setProgressRegExp(String progressRegExp) {
+ this.progressRegExp = progressRegExp;
+ }
+
+ /**
+ * Sets the display text presented in the splash window.
+ * optional; defaults to "Building ..."
+ * @param displayText the display text presented the splash window
+ * @since Ant 1.8.0
+ */
+ public void setDisplayText(String displayText) {
+ this.displayText = displayText;
+ }
+
+ /**
+ * Execute the task.
+ * @throws BuildException on error
+ */
+ @Override
+ public void execute() throws BuildException {
+ if (splash != null) {
+ splash.setVisible(false);
+ getProject().removeBuildListener(splash);
+ splash.dispose();
+ splash = null;
+ }
+
+ log("Creating new SplashScreen", Project.MSG_VERBOSE);
+ InputStream in = null;
+
+ if (imgurl != null) {
+ try {
+ URLConnection conn = null;
+
+ SetProxy sp = new SetProxy();
+ sp.setProxyHost(proxy);
+ if (port != null) {
+ sp.setProxyPort(Integer.parseInt(port));
+ }
+ sp.setProxyUser(user);
+ sp.setProxyPassword(password);
+ sp.applyWebProxySettings();
+
+ if (useProxy && (proxy != null && proxy.length() > 0)
+ && (port != null && port.length() > 0)) {
+
+ log("Using proxied Connection", Project.MSG_DEBUG);
+ System.getProperties().put("http.proxySet", "true");
+
+ URL url = new URL(imgurl);
+
+ conn = url.openConnection();
+ if (user != null && user.length() > 0) {
+ // converted from sun internal classes to
+ // new Base64Converter
+ // utility class extracted from Get task
+ String encodedcreds =
+ new Base64Converter().encode(user + ":" + password);
+ conn.setRequestProperty("Proxy-Authorization",
+ encodedcreds);
+ }
+
+ } else {
+ System.getProperties().put("http.proxySet", "false");
+ log("Using Direction HTTP Connection", Project.MSG_DEBUG);
+ URL url = new URL(imgurl);
+ conn = url.openConnection();
+ }
+ conn.setDoInput(true);
+ conn.setDoOutput(false);
+
+ in = conn.getInputStream();
+
+ // Catch everything - some of the above return nulls,
+ // throw exceptions or generally misbehave
+ // in the event of a problem etc
+
+ } catch (Throwable ioe) {
+ log("Unable to download image, trying default Ant Logo",
+ Project.MSG_DEBUG);
+ log("(Exception was \"" + ioe.getMessage() + "\"",
+ Project.MSG_DEBUG);
+ }
+ }
+
+ if (in == null) {
+ ClassLoader cl = SplashTask.class.getClassLoader();
+ if (cl != null) {
+ in = cl.getResourceAsStream("images/ant_logo_large.gif");
+ } else {
+ in = ClassLoader
+ .getSystemResourceAsStream("images/ant_logo_large.gif");
+ }
+ }
+
+ boolean success = false;
+ if (in != null) {
+ DataInputStream din = new DataInputStream(in);
+ try {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ int data;
+ while ((data = din.read()) != -1) {
+ bout.write((byte) data);
+ }
+
+ log("Got ByteArray, creating splash", Project.MSG_DEBUG);
+
+ try {
+ ImageIcon img = new ImageIcon(bout.toByteArray());
+ splash = new SplashScreen(img, progressRegExp, displayText);
+ success = true;
+ } catch (Throwable e) {
+ logHeadless(e);
+ }
+ } catch (Exception e) {
+ throw new BuildException(e);
+ } finally {
+ try {
+ din.close();
+ } catch (IOException ioe) {
+ // swallow if there was an error before so that
+ // original error will be passed up
+ if (success) {
+ throw new BuildException(ioe);
+ }
+ }
+ }
+ } else {
+ try {
+ splash = new SplashScreen("Image Unavailable.", progressRegExp,
+ displayText);
+ success = true;
+ } catch (Throwable e) {
+ logHeadless(e);
+ }
+ }
+
+ if (success) {
+ splash.setVisible(true);
+ splash.toFront();
+ getProject().addBuildListener(splash);
+ try {
+ Thread.sleep(showDuration);
+ } catch (InterruptedException e) {
+ // Ignore Exception
+ }
+ }
+ }
+
+ private void logHeadless(Throwable e) {
+ log("failed to display SplashScreen, caught "
+ + e.getClass().getName() + " with message: " + e.getMessage(),
+ Project.MSG_WARN);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java
new file mode 100644
index 00000000..9365e8cd
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.NumberFormat;
+
+import org.apache.tools.ant.BuildException;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.SftpProgressMonitor;
+
+/**
+ * Abstract class for ssh upload and download
+ */
+public abstract class AbstractSshMessage {
+ private static final double ONE_SECOND = 1000.0;
+
+ private final Session session;
+ private final boolean verbose;
+ private LogListener listener = new LogListener() {
+ public void log(final String message) {
+ // do nothing;
+ }
+ };
+
+ /**
+ * Constructor for AbstractSshMessage
+ * @param session the ssh session to use
+ */
+ public AbstractSshMessage(final Session session) {
+ this(false, session);
+ }
+
+ /**
+ * Constructor for AbstractSshMessage
+ * @param verbose if true do verbose logging
+ * @param session the ssh session to use
+ * @since Ant 1.6.2
+ */
+ public AbstractSshMessage(final boolean verbose, final Session session) {
+ this.verbose = verbose;
+ this.session = session;
+ }
+
+ /**
+ * Open an ssh channel.
+ * @param command the command to use
+ * @return the channel
+ * @throws JSchException on error
+ */
+ protected Channel openExecChannel(final String command) throws JSchException {
+ final ChannelExec channel = (ChannelExec) session.openChannel("exec");
+ channel.setCommand(command);
+
+ return channel;
+ }
+
+ /**
+ * Open an ssh sftp channel.
+ * @return the channel
+ * @throws JSchException on error
+ */
+ protected ChannelSftp openSftpChannel() throws JSchException {
+ final ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
+
+ return channel;
+ }
+
+ /**
+ * Send an ack.
+ * @param out the output stream to use
+ * @throws IOException on error
+ */
+ protected void sendAck(final OutputStream out) throws IOException {
+ final byte[] buf = new byte[1];
+ buf[0] = 0;
+ out.write(buf);
+ out.flush();
+ }
+
+ /**
+ * Reads the response, throws a BuildException if the response
+ * indicates an error.
+ * @param in the input stream to use
+ * @throws IOException on I/O error
+ * @throws BuildException on other errors
+ */
+ protected void waitForAck(final InputStream in)
+ throws IOException, BuildException {
+ final int b = in.read();
+
+ // b may be 0 for success,
+ // 1 for error,
+ // 2 for fatal error,
+
+ if (b == -1) {
+ // didn't receive any response
+ throw new BuildException("No response from server");
+ } else if (b != 0) {
+ final StringBuffer sb = new StringBuffer();
+
+ int c = in.read();
+ while (c > 0 && c != '\n') {
+ sb.append((char) c);
+ c = in.read();
+ }
+
+ if (b == 1) {
+ throw new BuildException("server indicated an error: "
+ + sb.toString());
+ } else if (b == 2) {
+ throw new BuildException("server indicated a fatal error: "
+ + sb.toString());
+ } else {
+ throw new BuildException("unknown response, code " + b
+ + " message: " + sb.toString());
+ }
+ }
+ }
+
+ /**
+ * Carry out the transfer.
+ * @throws IOException on I/O errors
+ * @throws JSchException on ssh errors
+ */
+ public abstract void execute() throws IOException, JSchException;
+
+ /**
+ * Set a log listener.
+ * @param aListener the log listener
+ */
+ public void setLogListener(final LogListener aListener) {
+ listener = aListener;
+ }
+
+ /**
+ * Log a message to the log listener.
+ * @param message the message to log
+ */
+ protected void log(final String message) {
+ listener.log(message);
+ }
+
+ /**
+ * Log transfer stats to the log listener.
+ * @param timeStarted the time started
+ * @param timeEnded the finishing time
+ * @param totalLength the total length
+ */
+ protected void logStats(final long timeStarted,
+ final long timeEnded,
+ final long totalLength) {
+ final double duration = (timeEnded - timeStarted) / ONE_SECOND;
+ final NumberFormat format = NumberFormat.getNumberInstance();
+ format.setMaximumFractionDigits(2);
+ format.setMinimumFractionDigits(1);
+ listener.log("File transfer time: " + format.format(duration)
+ + " Average Rate: " + format.format(totalLength / duration)
+ + " B/s");
+ }
+
+ /**
+ * Is the verbose attribute set.
+ * @return true if the verbose attribute is set
+ * @since Ant 1.6.2
+ */
+ protected final boolean getVerbose() {
+ return verbose;
+ }
+
+ /**
+ * Track progress every 10% if 100kb < filesize < 1mb. For larger
+ * files track progress for every percent transmitted.
+ * @param filesize the size of the file been transmitted
+ * @param totalLength the total transmission size
+ * @param percentTransmitted the current percent transmitted
+ * @return the percent that the file is of the total
+ */
+ protected final int trackProgress(final long filesize, final long totalLength,
+ final int percentTransmitted) {
+
+ // CheckStyle:MagicNumber OFF
+ final int percent = (int) Math.round(Math.floor((totalLength
+ / (double) filesize) * 100));
+
+ if (percent > percentTransmitted) {
+ if (filesize < 1048576) {
+ if (percent % 10 == 0) {
+ if (percent == 100) {
+ System.out.println(" 100%");
+ } else {
+ System.out.print("*");
+ }
+ }
+ } else {
+ if (percent == 50) {
+ System.out.println(" 50%");
+ } else if (percent == 100) {
+ System.out.println(" 100%");
+ } else {
+ System.out.print(".");
+ }
+ }
+ }
+ // CheckStyle:MagicNumber ON
+
+ return percent;
+ }
+
+ private ProgressMonitor monitor = null;
+
+ /**
+ * Get the progress monitor.
+ * @return the progress monitor.
+ */
+ protected SftpProgressMonitor getProgressMonitor() {
+ if (monitor == null) {
+ monitor = new ProgressMonitor();
+ }
+ return monitor;
+ }
+
+ private class ProgressMonitor implements SftpProgressMonitor {
+ private long initFileSize = 0;
+ private long totalLength = 0;
+ private int percentTransmitted = 0;
+
+ public void init(final int op, final String src, final String dest, final long max) {
+ initFileSize = max;
+ totalLength = 0;
+ percentTransmitted = 0;
+ }
+
+ public boolean count(final long len) {
+ totalLength += len;
+ percentTransmitted = trackProgress(initFileSize,
+ totalLength,
+ percentTransmitted);
+ return true;
+ }
+
+ public void end() {
+ }
+
+ public long getTotalLength() {
+ return totalLength;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java
new file mode 100644
index 00000000..b5088a7d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * A helper object for Scp representing a directory in a file system.
+ */
+public class Directory {
+
+ private File directory;
+ private Set childDirectories;
+ private ArrayList files;
+ private Directory parent;
+
+ /**
+ * Constructor for a Directory.
+ * @param directory a directory.
+ */
+ public Directory(File directory) {
+ this(directory, null);
+ }
+
+ /**
+ * Constructor for a Directory.
+ * @param directory a directory
+ * @param parent a parent Directory
+ */
+ public Directory(File directory , Directory parent) {
+ this.parent = parent;
+ this.childDirectories = new LinkedHashSet();
+ this.files = new ArrayList();
+ this.directory = directory;
+ }
+
+ /**
+ * Add a directory to the child directories.
+ * @param directory a Directory
+ */
+ public void addDirectory(Directory directory) {
+ if (!childDirectories.contains(directory)) {
+ childDirectories.add(directory);
+ }
+ }
+
+ /**
+ * Add a file to the list of files.
+ * @param file a file to add
+ */
+ public void addFile(File file) {
+ files.add(file);
+ }
+
+ /**
+ * Get an iterator over the child Directories.
+ * @return an iterator
+ */
+ public Iterator directoryIterator() {
+ return childDirectories.iterator();
+ }
+
+ /**
+ * Get an iterator over the files.
+ * @return an iterator
+ */
+ public Iterator filesIterator() {
+ return files.iterator();
+ }
+
+ /**
+ * Get the parent Directory.
+ * @return the parent Directory.
+ */
+ public Directory getParent() {
+ return parent;
+ }
+
+ /**
+ * Is this a root Directory?
+ * @return true if there is no parent Directory
+ */
+ public boolean isRoot() {
+ return parent == null;
+ }
+
+ /**
+ * Get the directory file.
+ * @return the directory file
+ */
+ public File getDirectory() {
+ return directory;
+ }
+
+ /**
+ * Get a child directory of this directory.
+ * @param dir the directory to look for
+ * @return the child directory, or null if not found
+ */
+ public Directory getChild(File dir) {
+ for (Iterator i = childDirectories.iterator(); i.hasNext();) {
+ Directory current = (Directory) i.next();
+ if (current.getDirectory().equals(dir)) {
+ return current;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * The equality method.
+ * This checks if the directory field is the same.
+ * @param obj the object to compare to
+ * @return true if this object has an equal directory field as the other object
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof Directory)) {
+ return false;
+ }
+
+ Directory d = (Directory) obj;
+
+ return this.directory.equals(d.directory);
+ }
+
+ /**
+ * The hashcode method.
+ * @return the hash code of the directory field
+ */
+ @Override
+ public int hashCode() {
+ return directory.hashCode();
+ }
+
+ /**
+ * Get the path components of this directory.
+ * @return the path components as an array of strings.
+ */
+ public String[] getPath() {
+ return getPath(directory.getAbsolutePath());
+ }
+
+ /**
+ * Convert a file path to an array of path components.
+ * This uses File.separator to split the file path string.
+ * @param thePath the file path string to convert
+ * @return an array of path components
+ */
+ public static String[] getPath(String thePath) {
+ StringTokenizer tokenizer = new StringTokenizer(thePath,
+ File.separator);
+ String[] path = new String[ tokenizer.countTokens() ];
+
+ int i = 0;
+ while (tokenizer.hasMoreTokens()) {
+ path[i] = tokenizer.nextToken();
+ i++;
+ }
+
+ return path;
+ }
+
+ /**
+ * Get the number of files in the files attribute.
+ * @return the number of files
+ */
+ public int fileSize() {
+ return files.size();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java
new file mode 100644
index 00000000..41209ceb
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+/**
+ * Interface for ssh log listeners to implement.
+ */
+public interface LogListener {
+ /**
+ * Method for the loglistener to implement to receive log messages.
+ * @param message the message to log
+ */
+ void log(String message);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
new file mode 100644
index 00000000..68419a85
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+/**
+ * Base class for Ant tasks using jsch.
+ *
+ * @since Ant 1.6
+ */
+public abstract class SSHBase extends Task implements LogListener {
+
+ /** Default listen port for SSH daemon */
+ private static final int SSH_PORT = 22;
+
+ private String host;
+ private String knownHosts;
+ private int port = SSH_PORT;
+ private boolean failOnError = true;
+ private boolean verbose;
+ private final SSHUserInfo userInfo;
+
+ /**
+ * Constructor for SSHBase.
+ */
+ public SSHBase() {
+ super();
+ userInfo = new SSHUserInfo();
+ }
+
+ /**
+ * Remote host, either DNS name or IP.
+ *
+ * @param host The new host value
+ */
+ public void setHost(final String host) {
+ this.host = host;
+ }
+
+ /**
+ * Get the host.
+ * @return the host
+ */
+ public String getHost() {
+ return host;
+ }
+
+ /**
+ * Set the failonerror flag.
+ * Default is true
+ * @param failure if true throw a build exception when a failure occuries,
+ * otherwise just log the failure and continue
+ */
+ public void setFailonerror(final boolean failure) {
+ failOnError = failure;
+ }
+
+ /**
+ * Get the failonerror flag.
+ * @return the failonerror flag
+ */
+ public boolean getFailonerror() {
+ return failOnError;
+ }
+
+ /**
+ * Set the verbose flag.
+ * @param verbose if true output more verbose logging
+ * @since Ant 1.6.2
+ */
+ public void setVerbose(final boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ /**
+ * Get the verbose flag.
+ * @return the verbose flag
+ * @since Ant 1.6.2
+ */
+ public boolean getVerbose() {
+ return verbose;
+ }
+
+ /**
+ * Username known to remote host.
+ *
+ * @param username The new username value
+ */
+ public void setUsername(final String username) {
+ userInfo.setName(username);
+ }
+
+
+ /**
+ * Sets the password for the user.
+ *
+ * @param password The new password value
+ */
+ public void setPassword(final String password) {
+ userInfo.setPassword(password);
+ }
+
+ /**
+ * Sets the keyfile for the user.
+ *
+ * @param keyfile The new keyfile value
+ */
+ public void setKeyfile(final String keyfile) {
+ userInfo.setKeyfile(keyfile);
+ }
+
+ /**
+ * Sets the passphrase for the users key.
+ *
+ * @param passphrase The new passphrase value
+ */
+ public void setPassphrase(final String passphrase) {
+ userInfo.setPassphrase(passphrase);
+ }
+
+ /**
+ * Sets the path to the file that has the identities of
+ * all known hosts. This is used by SSH protocol to validate
+ * the identity of the host. The default is
+ * <i>${user.home}/.ssh/known_hosts</i>.
+ *
+ * @param knownHosts a path to the known hosts file.
+ */
+ public void setKnownhosts(final String knownHosts) {
+ this.knownHosts = knownHosts;
+ }
+
+ /**
+ * Setting this to true trusts hosts whose identity is unknown.
+ *
+ * @param yesOrNo if true trust the identity of unknown hosts.
+ */
+ public void setTrust(final boolean yesOrNo) {
+ userInfo.setTrust(yesOrNo);
+ }
+
+ /**
+ * Changes the port used to connect to the remote host.
+ *
+ * @param port port number of remote host.
+ */
+ public void setPort(final int port) {
+ this.port = port;
+ }
+
+ /**
+ * Get the port attribute.
+ * @return the port
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Initialize the task.
+ * This initializizs the known hosts and sets the default port.
+ * @throws BuildException on error
+ */
+ public void init() throws BuildException {
+ super.init();
+ this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts";
+ this.port = SSH_PORT;
+ }
+
+ /**
+ * Open an ssh session.
+ * @return the opened session
+ * @throws JSchException on error
+ */
+ protected Session openSession() throws JSchException {
+ final JSch jsch = new JSch();
+ final SSHBase base = this;
+ if (verbose) {
+ JSch.setLogger(new com.jcraft.jsch.Logger(){
+ public boolean isEnabled(final int level){
+ return true;
+ }
+ public void log(final int level, final String message){
+ base.log(message, Project.MSG_INFO);
+ }
+ });
+ }
+ if (null != userInfo.getKeyfile()) {
+ jsch.addIdentity(userInfo.getKeyfile());
+ }
+
+ if (!userInfo.getTrust() && knownHosts != null) {
+ log("Using known hosts: " + knownHosts, Project.MSG_DEBUG);
+ jsch.setKnownHosts(knownHosts);
+ }
+
+ final Session session = jsch.getSession(userInfo.getName(), host, port);
+ session.setConfig("PreferredAuthentications",
+ "publickey,keyboard-interactive,password");
+ session.setUserInfo(userInfo);
+ log("Connecting to " + host + ":" + port);
+ session.connect();
+ return session;
+ }
+
+ /**
+ * Get the user information.
+ * @return the user information
+ */
+ protected SSHUserInfo getUserInfo() {
+ return userInfo;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
new file mode 100644
index 00000000..a04dfefa
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
@@ -0,0 +1,519 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.StringReader;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.KeepAliveInputStream;
+import org.apache.tools.ant.util.KeepAliveOutputStream;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+/**
+ * Executes a command on a remote machine via ssh.
+ * @since Ant 1.6 (created February 2, 2003)
+ */
+public class SSHExec extends SSHBase {
+
+ private static final int BUFFER_SIZE = 8192;
+ private static final int RETRY_INTERVAL = 500;
+
+ /** the command to execute via ssh */
+ private String command = null;
+
+ /** units are milliseconds, default is 0=infinite */
+ private long maxwait = 0;
+
+ /** for waiting for the command to finish */
+ private Thread thread = null;
+
+ private String outputProperty = null; // like <exec>
+ private String errorProperty = null;
+ private String resultProperty = null;
+ private File outputFile = null; // like <exec>
+ private File errorFile = null;
+ private String inputProperty = null;
+ private String inputString = null; // like <exec>
+ private File inputFile = null; // like <exec>
+ private boolean append = false; // like <exec>
+ private boolean appenderr = false;
+ private boolean usePty = false;
+ private boolean useSystemIn = false;
+
+ private Resource commandResource = null;
+
+ private static final String TIMEOUT_MESSAGE =
+ "Timeout period exceeded, connection dropped.";
+
+ /**
+ * To suppress writing logs to System.out
+ */
+ private boolean suppressSystemOut = false;
+
+ /**
+ * To suppress writing logs to System.err
+ */
+ private boolean suppressSystemErr = false;
+
+ /**
+ * Constructor for SSHExecTask.
+ */
+ public SSHExec() {
+ super();
+ }
+
+ /**
+ * Sets the command to execute on the remote host.
+ *
+ * @param command The new command value
+ */
+ public void setCommand(final String command) {
+ this.command = command;
+ }
+
+ /**
+ * Sets a commandResource from a file
+ * @param f the value to use.
+ * @since Ant 1.7.1
+ */
+ public void setCommandResource(final String f) {
+ this.commandResource = new FileResource(new File(f));
+ }
+
+ /**
+ * The connection can be dropped after a specified number of
+ * milliseconds. This is sometimes useful when a connection may be
+ * flaky. Default is 0, which means &quot;wait forever&quot;.
+ *
+ * @param timeout The new timeout value in seconds
+ */
+ public void setTimeout(final long timeout) {
+ maxwait = timeout;
+ }
+
+ /**
+ * If used, stores the output of the command to the given file.
+ *
+ * @param output The file to write to.
+ */
+ public void setOutput(final File output) {
+ outputFile = output;
+ }
+
+ /**
+ * If used, stores the erroutput of the command to the given file.
+ *
+ * @param output The file to write to.
+ * @since Apache Ant 1.9.4
+ */
+ public void setErrorOutput(final File output) {
+ errorFile = output;
+ }
+
+ /**
+ * If used, the content of the file is piped to the remote command
+ *
+ * @param input The file which provides the input data for the remote command
+ *
+ * @since Ant 1.8.0
+ */
+ public void setInput(final File input) {
+ inputFile = input;
+ }
+
+ /**
+ * If used, the content of the property is piped to the remote command
+ *
+ * @param inputProperty The property which contains the input data
+ * for the remote command.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setInputProperty(final String inputProperty) {
+ this.inputProperty = inputProperty;
+ }
+
+ /**
+ * If used, the string is piped to the remote command.
+ *
+ * @param inputString the input data for the remote command.
+ *
+ * @since Ant 1.8.3
+ */
+ public void setInputString(final String inputString) {
+ this.inputString = inputString;
+ }
+
+ /**
+ * Determines if the output is appended to the file given in
+ * <code>setOutput</code>. Default is false, that is, overwrite
+ * the file.
+ *
+ * @param append True to append to an existing file, false to overwrite.
+ */
+ public void setAppend(final boolean append) {
+ this.append = append;
+ }
+
+ /**
+ * Determines if the output is appended to the file given in
+ * <code>setErrorOutput</code>. Default is false, that is, overwrite
+ * the file.
+ *
+ * @param appenderr True to append to an existing file, false to overwrite.
+ * @since Apache Ant 1.9.4
+ */
+ public void setErrAppend(final boolean appenderr) {
+ this.appenderr = appenderr;
+ }
+
+ /**
+ * If set, the output of the command will be stored in the given property.
+ *
+ * @param property The name of the property in which the command output
+ * will be stored.
+ */
+ public void setOutputproperty(final String property) {
+ outputProperty = property;
+ }
+
+ /**
+ * If set, the erroroutput of the command will be stored in the given property.
+ *
+ * @param property The name of the property in which the command erroroutput
+ * will be stored.
+ * @since Apache Ant 1.9.4
+ */
+ public void setErrorproperty (final String property) {
+ errorProperty = property;
+ }
+
+ /**
+ * If set, the exitcode of the command will be stored in the given property.
+ *
+ * @param property The name of the property in which the exitcode
+ * will be stored.
+ * @since Apache Ant 1.9.4
+ */
+ public void setResultproperty(final String property) {
+ resultProperty = property;
+ }
+
+ /**
+ * Whether a pseudo-tty should be allocated.
+ * @since Apache Ant 1.8.3
+ */
+ public void setUsePty(final boolean b) {
+ usePty = b;
+ }
+
+ /**
+ * If set, input will be taken from System.in
+ *
+ * @param useSystemIn True to use System.in as InputStream, false otherwise
+ * @since Apache Ant 1.9.4
+ */
+ public void setUseSystemIn(final boolean useSystemIn) {
+ this.useSystemIn = useSystemIn;
+ }
+
+ /**
+ * If suppressSystemOut is <code>true</code>, output will not be sent to System.out<br/>
+ * If suppressSystemOut is <code>false</code>, normal behavior
+ * @since Ant 1.9.0
+ */
+ public void setSuppressSystemOut(final boolean suppressSystemOut) {
+ this.suppressSystemOut = suppressSystemOut;
+ }
+
+ /**
+ * If suppressSystemErr is <code>true</code>, output will not be sent to System.err<br/>
+ * If suppressSystemErr is <code>false</code>, normal behavior
+ * @since Ant 1.9.4
+ */
+ public void setSuppressSystemErr(final boolean suppressSystemErr) {
+ this.suppressSystemErr = suppressSystemErr;
+ }
+
+ /**
+ * Execute the command on the remote host.
+ *
+ * @exception BuildException Most likely a network error or bad parameter.
+ */
+ @Override
+ public void execute() throws BuildException {
+
+ if (getHost() == null) {
+ throw new BuildException("Host is required.");
+ }
+ if (getUserInfo().getName() == null) {
+ throw new BuildException("Username is required.");
+ }
+ if (getUserInfo().getKeyfile() == null
+ && getUserInfo().getPassword() == null) {
+ throw new BuildException("Password or Keyfile is required.");
+ }
+ if (command == null && commandResource == null) {
+ throw new BuildException("Command or commandResource is required.");
+ }
+
+ final int numberOfInputs = (inputFile != null ? 1 : 0)
+ + (inputProperty != null ? 1 : 0)
+ + (inputString != null ? 1 : 0);
+ if (numberOfInputs > 1) {
+ throw new BuildException("You can't specify more than one of"
+ + " inputFile, inputProperty and"
+ + " inputString.");
+ }
+ if (inputFile != null && !inputFile.exists()) {
+ throw new BuildException("The input file "
+ + inputFile.getAbsolutePath()
+ + " does not exist.");
+ }
+
+ Session session = null;
+ final StringBuffer output = new StringBuffer();
+ try {
+ session = openSession();
+ /* called once */
+ if (command != null) {
+ log("cmd : " + command, Project.MSG_INFO);
+ executeCommand(session, command, output);
+ } else { // read command resource and execute for each command
+ try {
+ final BufferedReader br = new BufferedReader(
+ new InputStreamReader(commandResource.getInputStream()));
+ String cmd;
+ while ((cmd = br.readLine()) != null) {
+ log("cmd : " + cmd, Project.MSG_INFO);
+ output.append(cmd).append(" : ");
+ executeCommand(session, cmd, output);
+ output.append("\n");
+ }
+ FileUtils.close(br);
+ } catch (final IOException e) {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(),
+ Project.MSG_ERR);
+ }
+ }
+ }
+ } catch (final JSchException e) {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+ }
+ } finally {
+ if (outputProperty != null) {
+ getProject().setNewProperty(outputProperty, output.toString());
+ }
+ if (session != null && session.isConnected()) {
+ session.disconnect();
+ }
+ }
+ }
+
+ private void executeCommand(final Session session, final String cmd, final StringBuffer sb)
+ throws BuildException {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final ByteArrayOutputStream errout = new ByteArrayOutputStream();
+ final OutputStream teeErr = suppressSystemErr ? errout : new TeeOutputStream(errout, KeepAliveOutputStream.wrapSystemErr());
+ final OutputStream tee = suppressSystemOut ? out : new TeeOutputStream(out, KeepAliveOutputStream.wrapSystemOut());
+
+ InputStream istream = null;
+ if (inputFile != null) {
+ try {
+ istream = new FileInputStream(inputFile);
+ } catch (final IOException e) {
+ // because we checked the existence before, this one
+ // shouldn't happen What if the file exists, but there
+ // are no read permissions?
+ log("Failed to read " + inputFile + " because of: "
+ + e.getMessage(), Project.MSG_WARN);
+ }
+ }
+ if (inputProperty != null) {
+ final String inputData = getProject().getProperty(inputProperty);
+ if (inputData != null) {
+ istream = new ByteArrayInputStream(inputData.getBytes());
+ }
+ }
+ if (inputString != null) {
+ istream = new ByteArrayInputStream(inputString.getBytes());
+ }
+
+ if (useSystemIn) {
+ istream = KeepAliveInputStream.wrapSystemIn();
+ }
+
+ try {
+ final ChannelExec channel;
+ session.setTimeout((int) maxwait);
+ /* execute the command */
+ channel = (ChannelExec) session.openChannel("exec");
+ channel.setCommand(cmd);
+ channel.setOutputStream(tee);
+ channel.setExtOutputStream(tee);
+ channel.setErrStream(teeErr);
+ if (istream != null) {
+ channel.setInputStream(istream);
+ }
+ channel.setPty(usePty);
+ channel.connect();
+ // wait for it to finish
+ thread =
+ new Thread() {
+ @Override
+ public void run() {
+ while (!channel.isClosed()) {
+ if (thread == null) {
+ return;
+ }
+ try {
+ sleep(RETRY_INTERVAL);
+ } catch (final Exception e) {
+ // ignored
+ }
+ }
+ }
+ };
+
+ thread.start();
+ thread.join(maxwait);
+
+ if (thread.isAlive()) {
+ // ran out of time
+ thread = null;
+ if (getFailonerror()) {
+ throw new BuildException(TIMEOUT_MESSAGE);
+ } else {
+ log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+ }
+ } else {
+ // stdout to outputFile
+ if (outputFile != null) {
+ writeToFile(out.toString(), append, outputFile);
+ }
+ // set errorProperty
+ if (errorProperty != null) {
+ getProject().setNewProperty(errorProperty, errout.toString());
+ }
+ // stderr to errorFile
+ if (errorFile != null) {
+ writeToFile(errout.toString(), appenderr, errorFile);
+ }
+ // this is the wrong test if the remote OS is OpenVMS,
+ // but there doesn't seem to be a way to detect it.
+ final int ec = channel.getExitStatus();
+ // set resultproperty
+ if (resultProperty != null) {
+ getProject().setNewProperty(resultProperty, Integer.toString(ec));
+ }
+ if (ec != 0) {
+ final String msg = "Remote command failed with exit status " + ec;
+ if (getFailonerror()) {
+ throw new BuildException(msg);
+ } else {
+ log(msg, Project.MSG_ERR);
+ }
+ }
+ }
+ } catch (final BuildException e) {
+ throw e;
+ } catch (final JSchException e) {
+ if (e.getMessage().indexOf("session is down") >= 0) {
+ if (getFailonerror()) {
+ throw new BuildException(TIMEOUT_MESSAGE, e);
+ } else {
+ log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+ }
+ } else {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(),
+ Project.MSG_ERR);
+ }
+ }
+ } catch (final Exception e) {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+ }
+ } finally {
+ sb.append(out.toString());
+ FileUtils.close(istream);
+ }
+ }
+
+ /**
+ * Writes a string to a file. If destination file exists, it may be
+ * overwritten depending on the "append" value.
+ *
+ * @param from string to write
+ * @param to file to write to
+ * @param append if true, append to existing file, else overwrite
+ * @exception Exception most likely an IOException
+ */
+ private void writeToFile(final String from, final boolean append, final File to)
+ throws IOException {
+ FileWriter out = null;
+ try {
+ out = new FileWriter(to.getAbsolutePath(), append);
+ final StringReader in = new StringReader(from);
+ final char[] buffer = new char[BUFFER_SIZE];
+ int bytesRead;
+ while (true) {
+ bytesRead = in.read(buffer);
+ if (bytesRead == -1) {
+ break;
+ }
+ out.write(buffer, 0, bytesRead);
+ }
+ out.flush();
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java
new file mode 100644
index 00000000..e9f26757
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHSession.java
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+
+/**
+ * Establishes an ssh session with a remote machine, optionally
+ * establishing port forwarding, then executes any nested task(s)
+ * before closing the session.
+ * @since Ant 1.8.0
+ */
+public class SSHSession extends SSHBase {
+
+ /** units are milliseconds, default is 0=infinite */
+ private long maxwait = 0;
+
+ private final Vector localTunnels = new Vector();
+ private final Set localPortsUsed = new TreeSet();
+ private final Vector remoteTunnels = new Vector();
+ private final Set remotePortsUsed = new TreeSet();
+ private NestedSequential nestedSequential = null;
+
+ private static final String TIMEOUT_MESSAGE =
+ "Timeout period exceeded, connection dropped.";
+
+
+ /** Optional Vector holding the nested tasks */
+ private final Vector nestedTasks = new Vector();
+
+ /**
+ * Add a nested task to Sequential.
+ * <p>
+ * @param nestedTask Nested task to execute Sequential
+ * <p>
+ */
+ public void addTask(final Task nestedTask) {
+ nestedTasks.addElement(nestedTask);
+ }
+
+ /**
+ * The connection can be dropped after a specified number of
+ * milliseconds. This is sometimes useful when a connection may be
+ * flaky. Default is 0, which means &quot;wait forever&quot;.
+ *
+ * @param timeout The new timeout value in seconds
+ */
+ public void setTimeout(final long timeout) {
+ maxwait = timeout;
+ }
+
+ /**
+ * Changes the comma-delimited list of local tunnels to establish
+ * on the connection.
+ *
+ * @param tunnels a comma-delimited list of lport:rhost:rport
+ * tunnel specifications
+ */
+ public void setLocaltunnels(final String tunnels) {
+ final String[] specs = tunnels.split(", ");
+ for (int i = 0; i < specs.length; i++) {
+ if (specs[i].length() > 0) {
+ final String[] spec = specs[i].split(":", 3);
+ final int lport = Integer.parseInt(spec[0]);
+ final String rhost = spec[1];
+ final int rport = Integer.parseInt(spec[2]);
+ final LocalTunnel tunnel = createLocalTunnel();
+ tunnel.setLPort(lport);
+ tunnel.setRHost(rhost);
+ tunnel.setRPort(rport);
+ }
+ }
+ }
+
+ /**
+ * Changes the comma-delimited list of remote tunnels to establish
+ * on the connection.
+ *
+ * @param tunnels a comma-delimited list of rport:lhost:lport
+ * tunnel specifications
+ */
+ public void setRemotetunnels(final String tunnels) {
+ final String[] specs = tunnels.split(", ");
+ for (int i = 0; i < specs.length; i++) {
+ if (specs[i].length() > 0) {
+ final String[] spec = specs[i].split(":", 3);
+ final int rport = Integer.parseInt(spec[0]);
+ final String lhost = spec[1];
+ final int lport = Integer.parseInt(spec[2]);
+ final RemoteTunnel tunnel = createRemoteTunnel();
+ tunnel.setRPort(rport);
+ tunnel.setLHost(lhost);
+ tunnel.setLPort(lport);
+ }
+ }
+ }
+
+
+ /**
+ * Establish the ssh session and execute all nestedTasks
+ *
+ * @exception BuildException if one of the nested tasks fails, or
+ * network error or bad parameter.
+ */
+ @Override
+ public void execute() throws BuildException {
+ if (getHost() == null) {
+ throw new BuildException("Host is required.");
+ }
+ if (getUserInfo().getName() == null) {
+ throw new BuildException("Username is required.");
+ }
+ if (getUserInfo().getKeyfile() == null
+ && getUserInfo().getPassword() == null) {
+ throw new BuildException("Password or Keyfile is required.");
+ }
+ if (nestedSequential == null) {
+ throw new BuildException("Missing sequential element.");
+ }
+
+
+ Session session = null;
+ try {
+ // establish the session
+ session = openSession();
+ session.setTimeout((int) maxwait);
+
+ for (final Iterator i = localTunnels.iterator(); i.hasNext();) {
+ final LocalTunnel tunnel = (LocalTunnel) i.next();
+ session.setPortForwardingL(tunnel.getLPort(),
+ tunnel.getRHost(),
+ tunnel.getRPort());
+ }
+
+ for (final Iterator i = remoteTunnels.iterator(); i.hasNext();) {
+ final RemoteTunnel tunnel = (RemoteTunnel) i.next();
+ session.setPortForwardingR(tunnel.getRPort(),
+ tunnel.getLHost(),
+ tunnel.getLPort());
+ }
+
+ for (final Iterator i = nestedSequential.getNested().iterator();
+ i.hasNext();) {
+ final Task nestedTask = (Task) i.next();
+ nestedTask.perform();
+ }
+ // completed successfully
+
+ } catch (final JSchException e) {
+ if (e.getMessage().indexOf("session is down") >= 0) {
+ if (getFailonerror()) {
+ throw new BuildException(TIMEOUT_MESSAGE, e);
+ } else {
+ log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+ }
+ } else {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(),
+ Project.MSG_ERR);
+ }
+ }
+ } catch (final BuildException e) {
+ // avoid wrapping it into yet another BuildException further down
+ throw e;
+ } catch (final Exception e) {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+ }
+ } finally {
+ if (session != null && session.isConnected()) {
+ session.disconnect();
+ }
+ }
+ }
+
+ public LocalTunnel createLocalTunnel() {
+ final LocalTunnel tunnel = new LocalTunnel();
+ localTunnels.add(tunnel);
+ return tunnel;
+ }
+
+ public RemoteTunnel createRemoteTunnel() {
+ final RemoteTunnel tunnel = new RemoteTunnel();
+ remoteTunnels.add(tunnel);
+ return tunnel;
+ }
+
+ public class LocalTunnel {
+ public LocalTunnel() {}
+
+ int lport = 0;
+ String rhost = null;
+ int rport = 0;
+ public void setLPort(final int lport) {
+ final Integer portKey = new Integer(lport);
+ if (localPortsUsed.contains(portKey)) {
+ throw new BuildException("Multiple local tunnels defined to"
+ + " use same local port " + lport);
+ }
+ localPortsUsed.add(portKey);
+ this.lport = lport;
+ }
+ public void setRHost(final String rhost) { this.rhost = rhost; }
+ public void setRPort(final int rport) { this.rport = rport; }
+ public int getLPort() {
+ if (lport == 0) {
+ throw new BuildException("lport is required for LocalTunnel.");
+ }
+ return lport;
+ }
+ public String getRHost() {
+ if (rhost == null) {
+ throw new BuildException("rhost is required for LocalTunnel.");
+ }
+ return rhost;
+ }
+ public int getRPort() {
+ if (rport == 0) {
+ throw new BuildException("rport is required for LocalTunnel.");
+ }
+ return rport;
+ }
+ }
+
+ public class RemoteTunnel {
+ public RemoteTunnel() {}
+
+ int lport = 0;
+ String lhost = null;
+ int rport = 0;
+ public void setLPort(final int lport) { this.lport = lport; }
+ public void setLHost(final String lhost) { this.lhost = lhost; }
+ public void setRPort(final int rport) {
+ final Integer portKey = new Integer(rport);
+ if (remotePortsUsed.contains(portKey)) {
+ throw new BuildException("Multiple remote tunnels defined to"
+ + " use same remote port " + rport);
+ }
+ remotePortsUsed.add(portKey);
+ this.rport = rport;
+ }
+ public int getLPort() {
+ if (lport == 0) {
+ throw new BuildException("lport is required for RemoteTunnel.");
+ }
+ return lport;
+ }
+ public String getLHost() {
+ if (lhost == null) {
+ throw new BuildException("lhost is required for RemoteTunnel.");
+ }
+ return lhost;
+ }
+ public int getRPort() {
+ if (rport == 0) {
+ throw new BuildException("rport is required for RemoteTunnel.");
+ }
+ return rport;
+ }
+ }
+
+ /**
+ * This is the sequential nested element of the macrodef.
+ *
+ * @return a sequential element to be configured.
+ */
+ public NestedSequential createSequential() {
+ if (this.nestedSequential != null) {
+ throw new BuildException("Only one sequential allowed");
+ }
+ this.nestedSequential = new NestedSequential();
+ return this.nestedSequential;
+ }
+
+ /**
+ * The class corresponding to the sequential nested element.
+ * This is a simple task container.
+ */
+ public static class NestedSequential implements TaskContainer {
+ private final List<Task> nested = new ArrayList<Task>();
+
+ /**
+ * Add a task or type to the container.
+ *
+ * @param task an unknown element.
+ */
+ public void addTask(final Task task) {
+ nested.add(task);
+ }
+
+ /**
+ * @return the list of unknown elements
+ */
+ public List<Task> getNested() {
+ return nested;
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java
new file mode 100644
index 00000000..54e70293
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.UIKeyboardInteractive;
+import com.jcraft.jsch.UserInfo;
+
+
+/**
+ * Class containing information on an SSH user.
+ */
+public class SSHUserInfo implements UserInfo, UIKeyboardInteractive {
+
+ private String name;
+ private String password = null;
+ private String keyfile;
+ private String passphrase = null;
+ private boolean trustAllCertificates;
+
+ /** Constructor for SSHUserInfo. */
+ public SSHUserInfo() {
+ super();
+ this.trustAllCertificates = false;
+ }
+
+ /**
+ * Constructor for SSHUserInfo.
+ * @param password the user's password
+ * @param trustAllCertificates if true trust hosts whose identity is unknown
+ */
+ public SSHUserInfo(String password, boolean trustAllCertificates) {
+ super();
+ this.password = password;
+ this.trustAllCertificates = trustAllCertificates;
+ }
+
+ /**
+ * Gets the user name.
+ * @return the user name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the pass phrase of the user.
+ * @param message a message
+ * @return the passphrase
+ */
+ public String getPassphrase(String message) {
+ return passphrase;
+ }
+
+ /**
+ * Gets the user's password.
+ * @return the user's password
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Prompts a string.
+ * @param str the string
+ * @return whether the string was prompted
+ */
+ public boolean prompt(String str) {
+ return false;
+ }
+
+ /**
+ * Indicates whether a retry was done.
+ * @return whether a retry was done
+ */
+ public boolean retry() {
+ return false;
+ }
+
+ /**
+ * Sets the name.
+ * @param name The name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the passphrase.
+ * @param passphrase The passphrase to set
+ */
+ public void setPassphrase(String passphrase) {
+ this.passphrase = passphrase;
+ }
+
+ /**
+ * Sets the password.
+ * @param password The password to set
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Sets the trust.
+ * @param trust whether to trust or not.
+ */
+ public void setTrust(boolean trust) {
+ this.trustAllCertificates = trust;
+ }
+
+ /**
+ * @return whether to trust or not.
+ */
+ public boolean getTrust() {
+ return this.trustAllCertificates;
+ }
+
+ /**
+ * Returns the passphrase.
+ * @return String
+ */
+ public String getPassphrase() {
+ return passphrase;
+ }
+
+ /**
+ * Returns the keyfile.
+ * @return String
+ */
+ public String getKeyfile() {
+ return keyfile;
+ }
+
+ /**
+ * Sets the keyfile.
+ * @param keyfile The keyfile to set
+ */
+ public void setKeyfile(String keyfile) {
+ this.keyfile = keyfile;
+ }
+
+ /**
+ * Implement the UserInfo interface.
+ * @param message ignored
+ * @return true always
+ */
+ public boolean promptPassphrase(String message) {
+ return true;
+ }
+
+ /**
+ * Implement the UserInfo interface.
+ * @param passwordPrompt ignored
+ * @return true the first time this is called, false otherwise
+ */
+ public boolean promptPassword(String passwordPrompt) {
+ return true;
+ }
+
+ /**
+ * Implement the UserInfo interface.
+ * @param message ignored
+ * @return the value of trustAllCertificates
+ */
+ public boolean promptYesNo(String message) {
+ return trustAllCertificates;
+ }
+
+//why do we do nothing?
+ /**
+ * Implement the UserInfo interface (noop).
+ * @param message ignored
+ */
+ public void showMessage(String message) {
+ //log(message, Project.MSG_DEBUG);
+ }
+
+ /**
+ * Implementation of UIKeyboardInteractive#promptKeyboardInteractive.
+ * @param destination not used.
+ * @param name not used.
+ * @param instruction not used.
+ * @param prompt the method checks if this is one in length.
+ * @param echo the method checks if the first element is false.
+ * @return the password in an size one array if there is a password
+ * and if the prompt and echo checks pass.
+ */
+ public String[] promptKeyboardInteractive(String destination,
+ String name,
+ String instruction,
+ String[] prompt,
+ boolean[] echo) {
+ if (prompt.length != 1 || echo[0] || this.password == null) {
+ return null;
+ }
+ String[] response = new String[1];
+ response[0] = this.password;
+ return response;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
new file mode 100644
index 00000000..46e2ac64
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+/**
+ * Ant task for sending files to remote machine over ssh/scp.
+ *
+ * @since Ant 1.6
+ */
+public class Scp extends SSHBase {
+
+ private static final String[] FROM_ATTRS = {
+ "file", "localfile", "remotefile" };
+
+ private static final String[] TO_ATTRS = {
+ "todir", "localtodir", "remotetodir", "localtofile", "remotetofile" };
+
+ private String fromUri;
+ private String toUri;
+ private boolean preserveLastModified = false;
+ private List fileSets = null;
+ private boolean isFromRemote, isToRemote;
+ private boolean isSftp = false;
+ private Integer fileMode, dirMode;
+
+ /**
+ * Sets the file to be transferred. This can either be a remote
+ * file or a local file. Remote files take the form:<br>
+ * <i>user:password@host:/directory/path/file.example</i><br>
+ * Files to transfer can also include a wildcard to include all
+ * files in a remote directory. For example:<br>
+ * <i>user:password@host:/directory/path/*</i><br>
+ * @param aFromUri a string representing the file to transfer.
+ */
+ public void setFile(final String aFromUri) {
+ setFromUri(aFromUri);
+ this.isFromRemote = isRemoteUri(this.fromUri);
+ }
+
+ /**
+ * Sets the location where files will be transferred to.
+ * This can either be a remote directory or a local directory.
+ * Remote directories take the form of:<br>
+ * <i>user:password@host:/directory/path/</i><br>
+ * This parameter is required.
+
+ * @param aToUri a string representing the target of the copy.
+ */
+ public void setTodir(final String aToUri) {
+ setToUri(aToUri);
+ this.isToRemote = isRemoteUri(this.toUri);
+ }
+
+ /**
+ * Similar to {@link #setFile setFile} but explicitly states that
+ * the file is a local file. This is the only way to specify a
+ * local file with a @ character.
+ * @param aFromUri a string representing the source of the copy.
+ * @since Ant 1.6.2
+ */
+ public void setLocalFile(final String aFromUri) {
+ setFromUri(aFromUri);
+ this.isFromRemote = false;
+ }
+
+ /**
+ * Similar to {@link #setFile setFile} but explicitly states that
+ * the file is a remote file.
+ * @param aFromUri a string representing the source of the copy.
+ * @since Ant 1.6.2
+ */
+ public void setRemoteFile(final String aFromUri) {
+ validateRemoteUri("remoteFile", aFromUri);
+ setFromUri(aFromUri);
+ this.isFromRemote = true;
+ }
+
+ /**
+ * Similar to {@link #setTodir setTodir} but explicitly states
+ * that the directory is a local. This is the only way to specify
+ * a local directory with a @ character.
+ * @param aToUri a string representing the target of the copy.
+ * @since Ant 1.6.2
+ */
+ public void setLocalTodir(final String aToUri) {
+ setToUri(aToUri);
+ this.isToRemote = false;
+ }
+
+ /**
+ * Sets flag to determine if file timestamp from
+ * remote system is to be preserved during copy.
+ * @since Ant 1.8.0
+ */
+ public void setPreservelastmodified(final boolean yesOrNo) {
+ this.preserveLastModified = yesOrNo;
+ }
+
+ /**
+ * Similar to {@link #setTodir setTodir} but explicitly states
+ * that the directory is a remote.
+ * @param aToUri a string representing the target of the copy.
+ * @since Ant 1.6.2
+ */
+ public void setRemoteTodir(final String aToUri) {
+ validateRemoteUri("remoteToDir", aToUri);
+ setToUri(aToUri);
+ this.isToRemote = true;
+ }
+
+ private static void validateRemoteUri(final String type, final String aToUri) {
+ if (!isRemoteUri(aToUri)) {
+ throw new BuildException(type + " '" + aToUri + "' is invalid. "
+ + "The 'remoteToDir' attribute must "
+ + "have syntax like the "
+ + "following: user:password@host:/path"
+ + " - the :password part is optional");
+ }
+ }
+
+ /**
+ * Changes the file name to the given name while receiving it,
+ * only useful if receiving a single file.
+ * @param aToUri a string representing the target of the copy.
+ * @since Ant 1.6.2
+ */
+ public void setLocalTofile(final String aToUri) {
+ setToUri(aToUri);
+ this.isToRemote = false;
+ }
+
+ /**
+ * Changes the file name to the given name while sending it,
+ * only useful if sending a single file.
+ * @param aToUri a string representing the target of the copy.
+ * @since Ant 1.6.2
+ */
+ public void setRemoteTofile(final String aToUri) {
+ validateRemoteUri("remoteToFile", aToUri);
+ setToUri(aToUri);
+ this.isToRemote = true;
+ }
+
+ /**
+ * Setting this to true to use sftp protocol.
+ *
+ * @param yesOrNo if true sftp protocol will be used.
+ */
+ public void setSftp(final boolean yesOrNo) {
+ isSftp = yesOrNo;
+ }
+
+ /**
+ * Set the file mode, defaults to "644".
+ * @since Ant 1.9.5
+ */
+ public void setFileMode(String fileMode) {
+ this.fileMode = Integer.parseInt(fileMode, 8);
+ }
+
+ /**
+ * Set the dir mode, defaults to "755".
+ * @since Ant 1.9.5
+ */
+ public void setDirMode(String dirMode) {
+ this.dirMode = Integer.parseInt(dirMode, 8);
+ }
+
+ /**
+ * Adds a FileSet transfer to remote host. NOTE: Either
+ * addFileSet() or setFile() are required. But, not both.
+ *
+ * @param set FileSet to send to remote host.
+ */
+ public void addFileset(final FileSet set) {
+ if (fileSets == null) {
+ fileSets = new LinkedList();
+ }
+ fileSets.add(set);
+ }
+
+ /**
+ * Initialize this task.
+ * @throws BuildException on error
+ */
+ @Override
+ public void init() throws BuildException {
+ super.init();
+ this.toUri = null;
+ this.fromUri = null;
+ this.fileSets = null;
+ }
+
+ /**
+ * Execute this task.
+ * @throws BuildException on error
+ */
+ @Override
+ public void execute() throws BuildException {
+ if (toUri == null) {
+ throw exactlyOne(TO_ATTRS);
+ }
+ if (fromUri == null && fileSets == null) {
+ throw exactlyOne(FROM_ATTRS, "one or more nested filesets");
+ }
+ try {
+ if (isFromRemote && !isToRemote) {
+ download(fromUri, toUri);
+ } else if (!isFromRemote && isToRemote) {
+ if (fileSets != null) {
+ upload(fileSets, toUri);
+ } else {
+ upload(fromUri, toUri);
+ }
+ } else if (isFromRemote && isToRemote) {
+ throw new BuildException(
+ "Copying from a remote server to a remote server is not supported.");
+ } else {
+ throw new BuildException("'todir' and 'file' attributes "
+ + "must have syntax like the following: "
+ + "user:password@host:/path");
+ }
+ } catch (final Exception e) {
+ if (getFailonerror()) {
+ if(e instanceof BuildException) {
+ final BuildException be = (BuildException) e;
+ if(be.getLocation() == null) {
+ be.setLocation(getLocation());
+ }
+ throw be;
+ } else {
+ throw new BuildException(e);
+ }
+ } else {
+ log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+ }
+ }
+ }
+
+ private void download(final String fromSshUri, final String toPath)
+ throws JSchException, IOException {
+ final String file = parseUri(fromSshUri);
+
+ Session session = null;
+ try {
+ session = openSession();
+ ScpFromMessage message = null;
+ if (!isSftp) {
+ message =
+ new ScpFromMessage(getVerbose(), session, file,
+ getProject().resolveFile(toPath),
+ fromSshUri.endsWith("*"),
+ preserveLastModified);
+ } else {
+ message =
+ new ScpFromMessageBySftp(getVerbose(), session, file,
+ getProject().resolveFile(toPath),
+ fromSshUri.endsWith("*"),
+ preserveLastModified);
+ }
+ log("Receiving file: " + file);
+ message.setLogListener(this);
+ message.execute();
+ } finally {
+ if (session != null) {
+ session.disconnect();
+ }
+ }
+ }
+
+ private void upload(final List fileSet, final String toSshUri)
+ throws IOException, JSchException {
+ final String file = parseUri(toSshUri);
+
+ Session session = null;
+ try {
+ final List list = new ArrayList(fileSet.size());
+ for (final Iterator i = fileSet.iterator(); i.hasNext();) {
+ final FileSet set = (FileSet) i.next();
+ final Directory d = createDirectory(set);
+ if (d != null) {
+ list.add(d);
+ }
+ }
+ if (!list.isEmpty()) {
+ session = openSession();
+ ScpToMessage message = null;
+ if (!isSftp) {
+ message = new ScpToMessage(getVerbose(), session,
+ list, file);
+ } else {
+ message = new ScpToMessageBySftp(getVerbose(), session,
+ list, file);
+ }
+ message.setLogListener(this);
+ if (fileMode != null) {
+ message.setFileMode(fileMode.intValue());
+ }
+ if (dirMode != null) {
+ message.setDirMode(dirMode.intValue());
+ }
+ message.execute();
+ }
+ } finally {
+ if (session != null) {
+ session.disconnect();
+ }
+ }
+ }
+
+ private void upload(final String fromPath, final String toSshUri)
+ throws IOException, JSchException {
+ final String file = parseUri(toSshUri);
+
+ Session session = null;
+ try {
+ session = openSession();
+ ScpToMessage message = null;
+ if (!isSftp) {
+ message =
+ new ScpToMessage(getVerbose(), session,
+ getProject().resolveFile(fromPath), file);
+ } else {
+ message =
+ new ScpToMessageBySftp(getVerbose(), session,
+ getProject().resolveFile(fromPath),
+ file);
+ }
+ message.setLogListener(this);
+ if (fileMode != null) {
+ message.setFileMode(fileMode.intValue());
+ }
+ if (dirMode != null) {
+ message.setDirMode(dirMode.intValue());
+ }
+ message.execute();
+ } finally {
+ if (session != null) {
+ session.disconnect();
+ }
+ }
+ }
+
+ private String parseUri(final String uri) {
+
+ int indexOfAt = uri.indexOf('@');
+ final int indexOfColon = uri.indexOf(':');
+
+ if (indexOfColon > -1 && indexOfColon < indexOfAt) {
+ // user:password@host:/path notation
+ // everything upto the last @ before the last : is considered
+ // password. (so if the path contains an @ and a : it will not work)
+ int indexOfCurrentAt = indexOfAt;
+ final int indexOfLastColon = uri.lastIndexOf(':');
+ while (indexOfCurrentAt > -1 && indexOfCurrentAt < indexOfLastColon)
+ {
+ indexOfAt = indexOfCurrentAt;
+ indexOfCurrentAt = uri.indexOf('@', indexOfCurrentAt + 1);
+ }
+ setUsername(uri.substring(0, indexOfColon));
+ setPassword(uri.substring(indexOfColon + 1, indexOfAt));
+ } else if (indexOfAt > -1) {
+ // no password, will require keyfile
+ setUsername(uri.substring(0, indexOfAt));
+ } else {
+ throw new BuildException("no username was given. Can't authenticate.");
+ }
+
+ if (getUserInfo().getPassword() == null
+ && getUserInfo().getKeyfile() == null) {
+ throw new BuildException("neither password nor keyfile for user "
+ + getUserInfo().getName() + " has been "
+ + "given. Can't authenticate.");
+ }
+
+ final int indexOfPath = uri.indexOf(':', indexOfAt + 1);
+ if (indexOfPath == -1) {
+ throw new BuildException("no remote path in " + uri);
+ }
+
+ setHost(uri.substring(indexOfAt + 1, indexOfPath));
+ String remotePath = uri.substring(indexOfPath + 1);
+ if (remotePath.equals("")) {
+ remotePath = ".";
+ }
+ return remotePath;
+ }
+
+ private static boolean isRemoteUri(final String uri) {
+ boolean isRemote = true;
+ final int indexOfAt = uri.indexOf('@');
+ if (indexOfAt < 0) {
+ isRemote = false;
+ }
+ return isRemote;
+ }
+
+ private Directory createDirectory(final FileSet set) {
+ final DirectoryScanner scanner = set.getDirectoryScanner(getProject());
+ Directory root = new Directory(scanner.getBasedir());
+ final String[] files = scanner.getIncludedFiles();
+ if (files.length != 0) {
+ for (int j = 0; j < files.length; j++) {
+ final String[] path = Directory.getPath(files[j]);
+ Directory current = root;
+ File currentParent = scanner.getBasedir();
+ for (int i = 0; i < path.length; i++) {
+ final File file = new File(currentParent, path[i]);
+ if (file.isDirectory()) {
+ current.addDirectory(new Directory(file));
+ current = current.getChild(file);
+ currentParent = current.getDirectory();
+ } else if (file.isFile()) {
+ current.addFile(file);
+ }
+ }
+ }
+ } else {
+ // skip
+ root = null;
+ }
+ return root;
+ }
+
+ private void setFromUri(final String fromUri) {
+ if (this.fromUri != null) {
+ throw exactlyOne(FROM_ATTRS);
+ }
+ this.fromUri = fromUri;
+ }
+
+ private void setToUri(final String toUri) {
+ if (this.toUri != null) {
+ throw exactlyOne(TO_ATTRS);
+ }
+ this.toUri = toUri;
+ }
+
+ private BuildException exactlyOne(final String[] attrs) {
+ return exactlyOne(attrs, null);
+ }
+
+ private BuildException exactlyOne(final String[] attrs, final String alt) {
+ final StringBuffer buf = new StringBuffer("Exactly one of ").append(
+ '[').append(attrs[0]);
+ for (int i = 1; i < attrs.length; i++) {
+ buf.append('|').append(attrs[i]);
+ }
+ buf.append(']');
+ if (alt != null) {
+ buf.append(" or ").append(alt);
+ }
+ return new BuildException(buf.append(" is required.").toString());
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
new file mode 100644
index 00000000..b6d47379
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
@@ -0,0 +1,311 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.util.FileUtils;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.SftpATTRS;
+import com.jcraft.jsch.SftpException;
+
+/**
+ * A helper object representing an scp download.
+ */
+public class ScpFromMessage extends AbstractSshMessage {
+
+ private static final int HUNDRED_KILOBYTES = 102400;
+ private static final byte LINE_FEED = 0x0a;
+ private static final int BUFFER_SIZE = 100*1024;
+
+ private String remoteFile;
+ private File localFile;
+ private boolean isRecursive = false;
+ private boolean preserveLastModified = false;
+
+ /**
+ * Constructor for ScpFromMessage
+ * @param session the ssh session to use
+ */
+ public ScpFromMessage(final Session session) {
+ super(session);
+ }
+
+ /**
+ * Constructor for ScpFromMessage
+ * @param verbose if true do verbose logging
+ * @param session the ssh session to use
+ * @since Ant 1.7
+ */
+ public ScpFromMessage(final boolean verbose, final Session session) {
+ super(verbose, session);
+ }
+
+ /**
+ * Constructor for ScpFromMessage.
+ * @param verbose if true log extra information
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion (-r option to scp)
+ * @since Ant 1.6.2
+ */
+ public ScpFromMessage(final boolean verbose,
+ final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive) {
+ this(false, session, aRemoteFile, aLocalFile, recursive, false);
+ }
+
+ /**
+ * Constructor for ScpFromMessage.
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion (-r option to scp)
+ */
+ public ScpFromMessage(final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive) {
+ this(false, session, aRemoteFile, aLocalFile, recursive);
+ }
+
+ /**
+ * Constructor for ScpFromMessage.
+ * @param verbose if true log extra information
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion (-r option to scp)
+ * @param preserveLastModified whether to preserve file
+ * modification times
+ * @since Ant 1.8.0
+ */
+ public ScpFromMessage(final boolean verbose,
+ final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive,
+ final boolean preserveLastModified) {
+ super(verbose, session);
+ this.remoteFile = aRemoteFile;
+ this.localFile = aLocalFile;
+ this.isRecursive = recursive;
+ this.preserveLastModified = preserveLastModified;
+ }
+
+ /**
+ * Carry out the transfer.
+ * @throws IOException on i/o errors
+ * @throws JSchException on errors detected by scp
+ */
+ public void execute() throws IOException, JSchException {
+ String command = "scp -f ";
+ if (isRecursive) {
+ command += "-r ";
+ }
+ command += remoteFile;
+ final Channel channel = openExecChannel(command);
+ try {
+ // get I/O streams for remote scp
+ final OutputStream out = channel.getOutputStream();
+ final InputStream in = channel.getInputStream();
+
+ channel.connect();
+
+ sendAck(out);
+ startRemoteCpProtocol(in, out, localFile);
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ log("done\n");
+ }
+
+ protected boolean getPreserveLastModified() {
+ return preserveLastModified;
+ }
+
+ private void startRemoteCpProtocol(final InputStream in,
+ final OutputStream out,
+ final File localFile)
+ throws IOException, JSchException {
+ File startFile = localFile;
+ while (true) {
+ // C0644 filesize filename - header for a regular file
+ // T time 0 time 0\n - present if perserve time.
+ // D directory - this is the header for a directory.
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ while (true) {
+ final int read = in.read();
+ if (read < 0) {
+ return;
+ }
+ if ((byte) read == LINE_FEED) {
+ break;
+ }
+ stream.write(read);
+ }
+ final String serverResponse = stream.toString("UTF-8");
+ if (serverResponse.charAt(0) == 'C') {
+ parseAndFetchFile(serverResponse, startFile, out, in);
+ } else if (serverResponse.charAt(0) == 'D') {
+ startFile = parseAndCreateDirectory(serverResponse,
+ startFile);
+ sendAck(out);
+ } else if (serverResponse.charAt(0) == 'E') {
+ startFile = startFile.getParentFile();
+ sendAck(out);
+ } else if (serverResponse.charAt(0) == '\01'
+ || serverResponse.charAt(0) == '\02') {
+ // this indicates an error.
+ throw new IOException(serverResponse.substring(1));
+ }
+ }
+ }
+
+ private File parseAndCreateDirectory(final String serverResponse,
+ final File localFile) {
+ int start = serverResponse.indexOf(" ");
+ // appears that the next token is not used and it's zero.
+ start = serverResponse.indexOf(" ", start + 1);
+ final String directoryName = serverResponse.substring(start + 1);
+ if (localFile.isDirectory()) {
+ final File dir = new File(localFile, directoryName);
+ dir.mkdir();
+ log("Creating: " + dir);
+ return dir;
+ }
+ return null;
+ }
+
+ private void parseAndFetchFile(final String serverResponse,
+ final File localFile,
+ final OutputStream out,
+ final InputStream in)
+ throws IOException, JSchException {
+ int start = 0;
+ int end = serverResponse.indexOf(" ", start + 1);
+ start = end + 1;
+ end = serverResponse.indexOf(" ", start + 1);
+ final long filesize = Long.parseLong(serverResponse.substring(start, end));
+ final String filename = serverResponse.substring(end + 1);
+ log("Receiving: " + filename + " : " + filesize);
+ final File transferFile = (localFile.isDirectory())
+ ? new File(localFile, filename)
+ : localFile;
+ fetchFile(transferFile, filesize, out, in);
+ waitForAck(in);
+ sendAck(out);
+ }
+
+ private void fetchFile(final File localFile,
+ long filesize,
+ final OutputStream out,
+ final InputStream in)
+ throws IOException, JSchException {
+ final byte[] buf = new byte[BUFFER_SIZE];
+ sendAck(out);
+
+ // read a content of lfile
+ final FileOutputStream fos = new FileOutputStream(localFile);
+ int length;
+ long totalLength = 0;
+ final long startTime = System.currentTimeMillis();
+
+ // only track progress for files larger than 100kb in verbose mode
+ final boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+ // since filesize keeps on decreasing we have to store the
+ // initial filesize
+ final long initFilesize = filesize;
+ int percentTransmitted = 0;
+
+ try {
+ while (true) {
+ length = in.read(buf, 0,
+ (BUFFER_SIZE < filesize) ? BUFFER_SIZE
+ : (int) filesize);
+ if (length < 0) {
+ throw new EOFException("Unexpected end of stream.");
+ }
+ fos.write(buf, 0, length);
+ filesize -= length;
+ totalLength += length;
+ if (filesize == 0) {
+ break;
+ }
+
+ if (trackProgress) {
+ percentTransmitted = trackProgress(initFilesize,
+ totalLength,
+ percentTransmitted);
+ }
+ }
+ } finally {
+ final long endTime = System.currentTimeMillis();
+ logStats(startTime, endTime, totalLength);
+ fos.flush();
+ fos.close();
+ }
+
+ if (getPreserveLastModified()) {
+ setLastModified(localFile);
+ }
+ }
+
+ private void setLastModified(final File localFile) throws JSchException {
+ SftpATTRS fileAttributes = null;
+ final ChannelSftp channel = openSftpChannel();
+ channel.connect();
+ try {
+ fileAttributes = channel.lstat(remoteDir(remoteFile)
+ + localFile.getName());
+ } catch (final SftpException e) {
+ throw new JSchException("failed to stat remote file", e);
+ }
+ FileUtils.getFileUtils().setFileLastModified(localFile,
+ ((long) fileAttributes
+ .getMTime())
+ * 1000);
+ }
+
+ /**
+ * returns the directory part of the remote file, if any.
+ */
+ private static String remoteDir(final String remoteFile) {
+ int index = remoteFile.lastIndexOf("/");
+ if (index < 0) {
+ index = remoteFile.lastIndexOf("\\");
+ }
+ return index > -1 ? remoteFile.substring(0, index + 1) : "";
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java
new file mode 100644
index 00000000..04f72d23
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.util.FileUtils;
+
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.SftpATTRS;
+import com.jcraft.jsch.SftpException;
+import com.jcraft.jsch.SftpProgressMonitor;
+
+/**
+ * A helper object representing an scp download.
+ */
+public class ScpFromMessageBySftp extends ScpFromMessage {
+
+ private static final int HUNDRED_KILOBYTES = 102400;
+
+ private String remoteFile;
+ private final File localFile;
+ private boolean isRecursive = false;
+ private boolean verbose = false;
+
+ /**
+ * Constructor for ScpFromMessageBySftp.
+ * @param verbose if true log extra information
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion
+ * @since Ant 1.7
+ */
+ public ScpFromMessageBySftp(final boolean verbose,
+ final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive) {
+ this(verbose, session, aRemoteFile, aLocalFile, recursive, false);
+ }
+
+ /**
+ * Constructor for ScpFromMessageBySftp.
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion
+ */
+ public ScpFromMessageBySftp(final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive) {
+ this(false, session, aRemoteFile, aLocalFile, recursive);
+ }
+
+ /**
+ * Constructor for ScpFromMessageBySftp.
+ * @param verbose if true log extra information
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion
+ * @param preserveLastModified whether to preserve file
+ * modification times
+ * @since Ant 1.8.0
+ */
+ public ScpFromMessageBySftp(final boolean verbose,
+ final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive,
+ final boolean preserveLastModified) {
+ super(verbose, session, aRemoteFile, aLocalFile, recursive,
+ preserveLastModified);
+ this.verbose = verbose;
+ this.remoteFile = aRemoteFile;
+ this.localFile = aLocalFile;
+ this.isRecursive = recursive;
+ }
+
+ /**
+ * Carry out the transfer.
+ * @throws IOException on i/o errors
+ * @throws JSchException on errors detected by scp
+ */
+ public void execute() throws IOException, JSchException {
+ final ChannelSftp channel = openSftpChannel();
+ try {
+ channel.connect();
+ try {
+ final SftpATTRS attrs = channel.stat(remoteFile);
+ if (attrs.isDir() && !remoteFile.endsWith("/")) {
+ remoteFile = remoteFile + "/";
+ }
+ } catch (final SftpException ee) {
+ // Ignored
+ }
+ getDir(channel, remoteFile, localFile);
+ } catch (final SftpException e) {
+ final JSchException schException = new JSchException("Could not get '"+ remoteFile
+ +"' to '"+localFile+"' - "
+ +e.toString());
+ schException.initCause(e);
+ throw schException;
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ log("done\n");
+ }
+
+ private void getDir(final ChannelSftp channel,
+ final String remoteFile,
+ final File localFile) throws IOException, SftpException {
+ String pwd = remoteFile;
+ if (remoteFile.lastIndexOf('/') != -1) {
+ if (remoteFile.length() > 1) {
+ pwd = remoteFile.substring(0, remoteFile.lastIndexOf('/'));
+ }
+ }
+ channel.cd(pwd);
+ if (!localFile.exists()) {
+ localFile.mkdirs();
+ }
+ final java.util.Vector files = channel.ls(remoteFile);
+ final int size = files.size();
+ for (int i = 0; i < size; i++) {
+ final ChannelSftp.LsEntry le = (ChannelSftp.LsEntry) files.elementAt(i);
+ final String name = le.getFilename();
+ if (le.getAttrs().isDir()) {
+ if (name.equals(".") || name.equals("..")) {
+ continue;
+ }
+ getDir(channel,
+ channel.pwd() + "/" + name + "/",
+ new File(localFile, le.getFilename()));
+ } else {
+ getFile(channel, le, localFile);
+ }
+ }
+ channel.cd("..");
+ }
+
+ private void getFile(final ChannelSftp channel,
+ final ChannelSftp.LsEntry le,
+ File localFile) throws IOException, SftpException {
+ final String remoteFile = le.getFilename();
+ if (!localFile.exists()) {
+ final String path = localFile.getAbsolutePath();
+ final int i = path.lastIndexOf(File.pathSeparator);
+ if (i != -1) {
+ if (path.length() > File.pathSeparator.length()) {
+ new File(path.substring(0, i)).mkdirs();
+ }
+ }
+ }
+
+ if (localFile.isDirectory()) {
+ localFile = new File(localFile, remoteFile);
+ }
+
+ final long startTime = System.currentTimeMillis();
+ final long totalLength = le.getAttrs().getSize();
+
+ SftpProgressMonitor monitor = null;
+ final boolean trackProgress = getVerbose() && totalLength > HUNDRED_KILOBYTES;
+ if (trackProgress) {
+ monitor = getProgressMonitor();
+ }
+ try {
+ log("Receiving: " + remoteFile + " : " + le.getAttrs().getSize());
+ channel.get(remoteFile, localFile.getAbsolutePath(), monitor);
+ } finally {
+ final long endTime = System.currentTimeMillis();
+ logStats(startTime, endTime, (int) totalLength);
+ }
+ if (getPreserveLastModified()) {
+ FileUtils.getFileUtils().setFileLastModified(localFile,
+ ((long) le.getAttrs()
+ .getMTime())
+ * 1000);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java
new file mode 100644
index 00000000..5ba6b559
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java
@@ -0,0 +1,331 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.List;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+/**
+ * Utility class to carry out an upload scp transfer.
+ */
+public class ScpToMessage extends AbstractSshMessage {
+
+ private static final int HUNDRED_KILOBYTES = 102400;
+ private static final int BUFFER_SIZE = 100*1024;
+ private static final int DEFAULT_DIR_MODE = 0755;
+ private static final int DEFAULT_FILE_MODE = 0644;
+
+ private File localFile;
+ private String remotePath;
+ private List directoryList;
+ private Integer fileMode, dirMode;
+
+ /**
+ * Constructor for ScpToMessage
+ * @param session the ssh session to use
+ */
+ public ScpToMessage(final Session session) {
+ super(session);
+ }
+
+ /**
+ * Constructor for ScpToMessage
+ * @param verbose if true do verbose logging
+ * @param session the ssh session to use
+ * @since Ant 1.7
+ */
+ public ScpToMessage(final boolean verbose, final Session session) {
+ super(verbose, session);
+ }
+
+ /**
+ * Constructor for a local file to remote.
+ * @param verbose if true do verbose logging
+ * @param session the scp session to use
+ * @param aLocalFile the local file
+ * @param aRemotePath the remote path
+ * @since Ant 1.6.2
+ */
+ public ScpToMessage(final boolean verbose,
+ final Session session,
+ final File aLocalFile,
+ final String aRemotePath) {
+ this(verbose, session, aRemotePath);
+
+ this.localFile = aLocalFile;
+ }
+
+ /**
+ * Constructor for a local directories to remote.
+ * @param verbose if true do verbose logging
+ * @param session the scp session to use
+ * @param aDirectoryList a list of directories
+ * @param aRemotePath the remote path
+ * @since Ant 1.6.2
+ */
+ public ScpToMessage(final boolean verbose,
+ final Session session,
+ final List aDirectoryList,
+ final String aRemotePath) {
+ this(verbose, session, aRemotePath);
+
+ this.directoryList = aDirectoryList;
+ }
+
+ /**
+ * Constructor for ScpToMessage.
+ * @param verbose if true do verbose logging
+ * @param session the scp session to use
+ * @param aRemotePath the remote path
+ * @since Ant 1.6.2
+ */
+ private ScpToMessage(final boolean verbose,
+ final Session session,
+ final String aRemotePath) {
+ super(verbose, session);
+ this.remotePath = aRemotePath;
+ }
+
+ /**
+ * Constructor for ScpToMessage.
+ * @param session the scp session to use
+ * @param aLocalFile the local file
+ * @param aRemotePath the remote path
+ */
+ public ScpToMessage(final Session session,
+ final File aLocalFile,
+ final String aRemotePath) {
+ this(false, session, aLocalFile, aRemotePath);
+ }
+
+ /**
+ * Constructor for ScpToMessage.
+ * @param session the scp session to use
+ * @param aDirectoryList a list of directories
+ * @param aRemotePath the remote path
+ */
+ public ScpToMessage(final Session session,
+ final List aDirectoryList,
+ final String aRemotePath) {
+ this(false, session, aDirectoryList, aRemotePath);
+ }
+
+ /**
+ * Carry out the transfer.
+ * @throws IOException on i/o errors
+ * @throws JSchException on errors detected by scp
+ */
+ @Override
+ public void execute() throws IOException, JSchException {
+ if (directoryList != null) {
+ doMultipleTransfer();
+ }
+ if (localFile != null) {
+ doSingleTransfer();
+ }
+ log("done.\n");
+ }
+
+ private void doSingleTransfer() throws IOException, JSchException {
+ final String cmd = "scp -t " + remotePath;
+ final Channel channel = openExecChannel(cmd);
+ try {
+
+ final OutputStream out = channel.getOutputStream();
+ final InputStream in = channel.getInputStream();
+
+ channel.connect();
+
+ waitForAck(in);
+ sendFileToRemote(localFile, in, out);
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ }
+
+ private void doMultipleTransfer() throws IOException, JSchException {
+ final Channel channel = openExecChannel("scp -r -d -t " + remotePath);
+ try {
+ final OutputStream out = channel.getOutputStream();
+ final InputStream in = channel.getInputStream();
+
+ channel.connect();
+
+ waitForAck(in);
+ for (final Iterator i = directoryList.iterator(); i.hasNext();) {
+ final Directory current = (Directory) i.next();
+ sendDirectory(current, in, out);
+ }
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ }
+
+ private void sendDirectory(final Directory current,
+ final InputStream in,
+ final OutputStream out) throws IOException {
+ for (final Iterator fileIt = current.filesIterator(); fileIt.hasNext();) {
+ sendFileToRemote((File) fileIt.next(), in, out);
+ }
+ for (final Iterator dirIt = current.directoryIterator(); dirIt.hasNext();) {
+ final Directory dir = (Directory) dirIt.next();
+ sendDirectoryToRemote(dir, in, out);
+ }
+ }
+
+ private void sendDirectoryToRemote(final Directory directory,
+ final InputStream in,
+ final OutputStream out) throws IOException {
+ String command = "D0";
+ command += Integer.toOctalString(getDirMode());
+ command += " 0 ";
+ command += directory.getDirectory().getName();
+ command += "\n";
+
+ out.write(command.getBytes());
+ out.flush();
+
+ waitForAck(in);
+ sendDirectory(directory, in, out);
+ out.write("E\n".getBytes());
+ out.flush();
+ waitForAck(in);
+ }
+
+ private void sendFileToRemote(final File localFile,
+ final InputStream in,
+ final OutputStream out) throws IOException {
+ // send "C0644 filesize filename", where filename should not include '/'
+ final long filesize = localFile.length();
+ String command = "C0";
+ command += Integer.toOctalString(getFileMode());
+ command += " " + filesize + " ";
+ command += localFile.getName();
+ command += "\n";
+
+ out.write(command.getBytes());
+ out.flush();
+
+ waitForAck(in);
+
+ // send a content of lfile
+ final FileInputStream fis = new FileInputStream(localFile);
+ final byte[] buf = new byte[BUFFER_SIZE];
+ final long startTime = System.currentTimeMillis();
+ long totalLength = 0;
+
+ // only track progress for files larger than 100kb in verbose mode
+ final boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+ // since filesize keeps on decreasing we have to store the
+ // initial filesize
+ final long initFilesize = filesize;
+ int percentTransmitted = 0;
+
+ try {
+ if (this.getVerbose()) {
+ log("Sending: " + localFile.getName() + " : " + localFile.length());
+ }
+ while (true) {
+ final int len = fis.read(buf, 0, buf.length);
+ if (len <= 0) {
+ break;
+ }
+ out.write(buf, 0, len);
+ totalLength += len;
+
+ if (trackProgress) {
+ percentTransmitted = trackProgress(initFilesize,
+ totalLength,
+ percentTransmitted);
+ }
+ }
+ out.flush();
+ sendAck(out);
+ waitForAck(in);
+ } finally {
+ if (this.getVerbose()) {
+ final long endTime = System.currentTimeMillis();
+ logStats(startTime, endTime, totalLength);
+ }
+ fis.close();
+ }
+ }
+
+ /**
+ * Get the local file
+ * @return the local file
+ */
+ public File getLocalFile() {
+ return localFile;
+ }
+
+ /**
+ * Get the remote path
+ * @return the remote path
+ */
+ public String getRemotePath() {
+ return remotePath;
+ }
+
+ /**
+ * Set the file mode, defaults to 0644.
+ * @since Ant 1.9.5
+ */
+ public void setFileMode(int fileMode) {
+ this.fileMode = fileMode;
+ }
+
+ /**
+ * Get the file mode.
+ * @since Ant 1.9.5
+ */
+ public int getFileMode() {
+ return fileMode != null ? fileMode.intValue() : DEFAULT_FILE_MODE;
+ }
+
+ /**
+ * Set the dir mode, defaults to 0755.
+ * @since Ant 1.9.5
+ */
+ public void setDirMode(int dirMode) {
+ this.dirMode = dirMode;
+ }
+
+ /**
+ * Get the dir mode.
+ * @since Ant 1.9.5
+ */
+ public int getDirMode() {
+ return dirMode != null ? dirMode.intValue() : DEFAULT_DIR_MODE;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java
new file mode 100644
index 00000000..2b32907d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.SftpException;
+import com.jcraft.jsch.SftpProgressMonitor;
+
+/**
+ * Utility class to carry out an upload by sftp.
+ */
+public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ {
+
+ private static final int HUNDRED_KILOBYTES = 102400;
+
+ private File localFile;
+ private final String remotePath;
+ private List directoryList;
+
+ /**
+ * Constructor for a local file to remote.
+ * @param verbose if true do verbose logging
+ * @param session the scp session to use
+ * @param aLocalFile the local file
+ * @param aRemotePath the remote path
+ * @since Ant 1.7
+ */
+ public ScpToMessageBySftp(final boolean verbose,
+ final Session session,
+ final File aLocalFile,
+ final String aRemotePath) {
+ this(verbose, session, aRemotePath);
+
+ this.localFile = aLocalFile;
+ }
+
+ /**
+ * Constructor for a local directories to remote.
+ * @param verbose if true do verbose logging
+ * @param session the scp session to use
+ * @param aDirectoryList a list of directories
+ * @param aRemotePath the remote path
+ * @since Ant 1.7
+ */
+ public ScpToMessageBySftp(final boolean verbose,
+ final Session session,
+ final List aDirectoryList,
+ final String aRemotePath) {
+ this(verbose, session, aRemotePath);
+
+ this.directoryList = aDirectoryList;
+ }
+
+ /**
+ * Constructor for ScpToMessage.
+ * @param verbose if true do verbose logging
+ * @param session the scp session to use
+ * @param aRemotePath the remote path
+ * @since Ant 1.6.2
+ */
+ private ScpToMessageBySftp(final boolean verbose,
+ final Session session,
+ final String aRemotePath) {
+ super(verbose, session);
+ this.remotePath = aRemotePath;
+ }
+
+ /**
+ * Constructor for ScpToMessage.
+ * @param session the scp session to use
+ * @param aLocalFile the local file
+ * @param aRemotePath the remote path
+ */
+ public ScpToMessageBySftp(final Session session,
+ final File aLocalFile,
+ final String aRemotePath) {
+ this(false, session, aLocalFile, aRemotePath);
+ }
+
+ /**
+ * Constructor for ScpToMessage.
+ * @param session the scp session to use
+ * @param aDirectoryList a list of directories
+ * @param aRemotePath the remote path
+ */
+ public ScpToMessageBySftp(final Session session,
+ final List aDirectoryList,
+ final String aRemotePath) {
+ this(false, session, aDirectoryList, aRemotePath);
+ }
+
+ /**
+ * Carry out the transfer.
+ * @throws IOException on i/o errors
+ * @throws JSchException on errors detected by scp
+ */
+ @Override
+ public void execute() throws IOException, JSchException {
+ if (directoryList != null) {
+ doMultipleTransfer();
+ }
+ if (localFile != null) {
+ doSingleTransfer();
+ }
+ log("done.\n");
+ }
+
+ private void doSingleTransfer() throws IOException, JSchException {
+ final ChannelSftp channel = openSftpChannel();
+ try {
+ channel.connect();
+ try {
+ sendFileToRemote(channel, localFile, remotePath);
+ } catch (final SftpException e) {
+ final JSchException schException = new JSchException("Could not send '" + localFile
+ + "' to '" + remotePath + "' - "
+ + e.toString());
+ schException.initCause(e);
+ throw schException;
+ }
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ }
+
+ private void doMultipleTransfer() throws IOException, JSchException {
+ final ChannelSftp channel = openSftpChannel();
+ try {
+ channel.connect();
+
+ try {
+ try {
+ channel.stat(remotePath);
+ } catch (final SftpException e) {
+ if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
+ // dir does not exist.
+ channel.mkdir(remotePath);
+ channel.chmod(getDirMode(), remotePath);
+ } else {
+ throw new JSchException("failed to access remote dir '"
+ + remotePath + "'", e);
+ }
+ }
+ channel.cd(remotePath);
+ } catch (final SftpException e) {
+ throw new JSchException("Could not CD to '" + remotePath
+ + "' - " + e.toString(), e);
+ }
+ Directory current = null;
+ try {
+ for (final Iterator i = directoryList.iterator(); i.hasNext();) {
+ current = (Directory) i.next();
+ if (getVerbose()) {
+ log("Sending directory " + current);
+ }
+ sendDirectory(channel, current);
+ }
+ } catch (final SftpException e) {
+ String msg = "Error sending directory";
+ if (current != null && current.getDirectory() != null) {
+ msg += " '" + current.getDirectory().getName() + "'";
+ }
+ throw new JSchException(msg, e);
+ }
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ }
+
+ private void sendDirectory(final ChannelSftp channel,
+ final Directory current)
+ throws IOException, SftpException {
+ for (final Iterator fileIt = current.filesIterator(); fileIt.hasNext();) {
+ sendFileToRemote(channel, (File) fileIt.next(), null);
+ }
+ for (final Iterator dirIt = current.directoryIterator(); dirIt.hasNext();) {
+ final Directory dir = (Directory) dirIt.next();
+ sendDirectoryToRemote(channel, dir);
+ }
+ }
+
+ private void sendDirectoryToRemote(final ChannelSftp channel,
+ final Directory directory)
+ throws IOException, SftpException {
+ final String dir = directory.getDirectory().getName();
+ try {
+ channel.stat(dir);
+ } catch (final SftpException e) {
+ // dir does not exist.
+ if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
+ channel.mkdir(dir);
+ channel.chmod(getDirMode(), dir);
+ }
+ }
+ channel.cd(dir);
+ sendDirectory(channel, directory);
+ channel.cd("..");
+ }
+
+ private void sendFileToRemote(final ChannelSftp channel,
+ final File localFile,
+ String remotePath)
+ throws IOException, SftpException {
+ final long filesize = localFile.length();
+
+ if (remotePath == null) {
+ remotePath = localFile.getName();
+ }
+
+ final long startTime = System.currentTimeMillis();
+ final long totalLength = filesize;
+
+ // only track progress for files larger than 100kb in verbose mode
+ final boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+
+ SftpProgressMonitor monitor = null;
+ if (trackProgress) {
+ monitor = getProgressMonitor();
+ }
+
+ try {
+ if (this.getVerbose()) {
+ log("Sending: " + localFile.getName() + " : " + filesize);
+ }
+ channel.put(localFile.getAbsolutePath(), remotePath, monitor);
+ channel.chmod(getFileMode(), remotePath);
+ } finally {
+ if (this.getVerbose()) {
+ final long endTime = System.currentTimeMillis();
+ logStats(startTime, endTime, (int) totalLength);
+ }
+ }
+ }
+
+ /**
+ * Get the local file.
+ * @return the local file.
+ */
+ public File getLocalFile() {
+ return localFile;
+ }
+
+ /**
+ * Get the remote path.
+ * @return the remote path.
+ */
+ public String getRemotePath() {
+ return remotePath;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java
new file mode 100644
index 00000000..4b2978ab
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.testing;
+
+import org.apache.tools.ant.taskdefs.WaitFor;
+
+/**
+ * @since Ant 1.8
+ */
+
+public class BlockFor extends WaitFor {
+
+ /**
+ * Text to include in a message
+ */
+ private String text;
+
+
+ /**
+ * Constructor that takes the name of the task in the task name.
+ *
+ */
+ public BlockFor() {
+ super("blockfor");
+ text = getTaskName() + " timed out";
+ }
+
+ /**
+ * Constructor that takes the name of the task in the task name.
+ *
+ * @param taskName the name of the task.
+ */
+ public BlockFor(String taskName) {
+ super(taskName);
+ }
+
+ /**
+ * If the wait fails, a BuildException is thrown. All the superclasses actions are called first.
+ * @throws BuildTimeoutException on timeout, using the text in {@link #text}
+ *
+ */
+ protected void processTimeout() throws BuildTimeoutException {
+ super.processTimeout();
+ throw new BuildTimeoutException(text, getLocation());
+ }
+
+ /**
+ * Set the error text; all properties are expanded in the message.
+ *
+ * @param message the text to use in a failure message
+ */
+ public void addText(String message) {
+ text = getProject().replaceProperties(message);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java
new file mode 100644
index 00000000..143d08c9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.testing;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+
+/**
+ *
+ * This exception is used to indicate timeouts.
+ * @since Ant1.8
+ *
+ */
+
+public class BuildTimeoutException extends BuildException {
+
+ private static final long serialVersionUID = -8057644603246297562L;
+
+ /**
+ * Constructs a build exception with no descriptive information.
+ */
+ public BuildTimeoutException() {
+ }
+
+ /**
+ * Constructs an exception with the given descriptive message.
+ *
+ * @param message A description of or information about the exception.
+ * Should not be <code>null</code>.
+ */
+ public BuildTimeoutException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an exception with the given message and exception as
+ * a root cause.
+ *
+ * @param message A description of or information about the exception.
+ * Should not be <code>null</code> unless a cause is specified.
+ * @param cause The exception that might have caused this one.
+ * May be <code>null</code>.
+ */
+ public BuildTimeoutException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs an exception with the given message and exception as
+ * a root cause and a location in a file.
+ *
+ * @param msg A description of or information about the exception.
+ * Should not be <code>null</code> unless a cause is specified.
+ * @param cause The exception that might have caused this one.
+ * May be <code>null</code>.
+ * @param location The location in the project file where the error
+ * occurred. Must not be <code>null</code>.
+ */
+ public BuildTimeoutException(String msg, Throwable cause, Location location) {
+ super(msg, cause, location);
+ }
+
+ /**
+ * Constructs an exception with the given exception as a root cause.
+ *
+ * @param cause The exception that might have caused this one.
+ * Should not be <code>null</code>.
+ */
+ public BuildTimeoutException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs an exception with the given descriptive message and a
+ * location in a file.
+ *
+ * @param message A description of or information about the exception.
+ * Should not be <code>null</code>.
+ * @param location The location in the project file where the error
+ * occurred. Must not be <code>null</code>.
+ */
+ public BuildTimeoutException(String message, Location location) {
+ super(message, location);
+ }
+
+ /**
+ * Constructs an exception with the given exception as
+ * a root cause and a location in a file.
+ *
+ * @param cause The exception that might have caused this one.
+ * Should not be <code>null</code>.
+ * @param location The location in the project file where the error
+ * occurred. Must not be <code>null</code>.
+ */
+ public BuildTimeoutException(Throwable cause, Location location) {
+ super(cause, location);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java
new file mode 100644
index 00000000..2eb357a3
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java
@@ -0,0 +1,577 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.testing;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskAdapter;
+import org.apache.tools.ant.taskdefs.Parallel;
+import org.apache.tools.ant.taskdefs.Sequential;
+import org.apache.tools.ant.taskdefs.WaitFor;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.condition.ConditionBase;
+import org.apache.tools.ant.util.WorkerAnt;
+
+/**
+ * Task to provide functional testing under Ant, with a fairly complex workflow of:
+ *
+ * <ul>
+ * <li>Conditional execution</li>
+ * <li>Application to start</li>
+ * <li>A probe to "waitfor" before running tests</li>
+ * <li>A tests sequence</li>
+ * <li>A reporting sequence that runs after the tests have finished</li>
+ * <li>A "teardown" clause that runs after the rest.</li>
+ * <li>Automated termination of the program it executes, if a timeout is not met</li>
+ * <li>Checking of a failure property and automatic raising of a fault
+ * (with the text in failureText)
+ * if test shutdown and reporting succeeded</li>
+ * </ul>
+ *
+ * The task is designed to be framework neutral; it will work with JUnit,
+ * TestNG and other test frameworks That can be
+ * executed from Ant. It bears a resemblance to the FunctionalTest task from
+ * SmartFrog, as the attribute names were
+ * chosen to make migration easier. However, this task benefits from the
+ * ability to tweak Ant's internals, and so
+ * simplify the workflow, and from the experience of using the SmartFrog task.
+ * No code has been shared.
+ *
+ * @since Ant 1.8
+ */
+
+public class Funtest extends Task {
+
+ /**
+ * A condition that must be true before the tests are run. This makes it
+ * easier to define complex tests that only
+ * run if certain conditions are met, such as OS or network state.
+ */
+
+ private NestedCondition condition;
+
+
+ /**
+ * Used internally to set the workflow up
+ */
+ private Parallel timedTests;
+
+ /**
+ * Setup runs if the condition is met. Once setup is complete, teardown
+ * will be run when the task finishes
+ */
+ private Sequential setup;
+
+ /**
+ * The application to run
+ */
+ private Sequential application;
+
+ /**
+ * A block that halts the tests until met.
+ */
+ private BlockFor block;
+
+ /**
+ * Tests to run
+ */
+ private Sequential tests;
+
+ /**
+ * Reporting only runs if the tests were executed. If the block stopped
+ * them, reporting is skipped.
+ */
+ private Sequential reporting;
+
+ /**
+ * Any teardown operations.
+ */
+ private Sequential teardown;
+
+ /**
+ * time for the tests to time out
+ */
+ private long timeout;
+
+ private long timeoutUnitMultiplier = WaitFor.ONE_MILLISECOND;
+
+ /**
+ * time for the execution to time out.
+ */
+ private long shutdownTime = 10 * WaitFor.ONE_SECOND;
+
+ private long shutdownUnitMultiplier = WaitFor.ONE_MILLISECOND;
+
+ /**
+ * Name of a property to look for
+ */
+ private String failureProperty;
+
+ /**
+ * Message to send when tests failed
+ */
+ private String failureMessage = "Tests failed";
+
+ /**
+ * Flag to set to true if you don't care about any shutdown errors.
+ * <p/>
+ * In that situation, errors raised during teardown are logged but not
+ * turned into BuildFault events. Similar to catching and ignoring
+ * <code>finally {}</code> clauses in Java/
+ */
+ private boolean failOnTeardownErrors = true;
+
+
+ /**
+ * What was thrown in the test run (including reporting)
+ */
+ private BuildException testException;
+ /**
+ * What got thrown during teardown
+ */
+ private BuildException teardownException;
+
+ /**
+ * Did the application throw an exception
+ */
+ private BuildException applicationException;
+
+ /**
+ * Did the task throw an exception
+ */
+ private BuildException taskException;
+
+ /** {@value} */
+ public static final String WARN_OVERRIDING = "Overriding previous definition of ";
+ /** {@value} */
+ public static final String APPLICATION_FORCIBLY_SHUT_DOWN = "Application forcibly shut down";
+ /** {@value} */
+ public static final String SHUTDOWN_INTERRUPTED = "Shutdown interrupted";
+ /** {@value} */
+ public static final String SKIPPING_TESTS
+ = "Condition failed -skipping tests";
+ /** Application exception : {@value} */
+ public static final String APPLICATION_EXCEPTION = "Application Exception";
+ /** Teardown exception : {@value} */
+ public static final String TEARDOWN_EXCEPTION = "Teardown Exception";
+
+ /**
+ * Log if the definition is overriding something
+ *
+ * @param name what is being defined
+ * @param definition what should be null if you don't want a warning
+ */
+ private void logOverride(String name, Object definition) {
+ if (definition != null) {
+ log(WARN_OVERRIDING + '<' + name + '>', Project.MSG_INFO);
+ }
+ }
+
+ /**
+ * Add a condition element.
+ * @return <code>ConditionBase</code>.
+ * @since Ant 1.6.2
+ */
+ public ConditionBase createCondition() {
+ logOverride("condition", condition);
+ condition = new NestedCondition();
+ return condition;
+ }
+
+ /**
+ * Add an application.
+ * @param sequence the application to add.
+ */
+ public void addApplication(Sequential sequence) {
+ logOverride("application", application);
+ application = sequence;
+ }
+
+ /**
+ * Add a setup sequence.
+ * @param sequence the setup sequence to add.
+ */
+ public void addSetup(Sequential sequence) {
+ logOverride("setup", setup);
+ setup = sequence;
+ }
+
+ /**
+ * Add a block.
+ * @param sequence the block for to add.
+ */
+ public void addBlock(BlockFor sequence) {
+ logOverride("block", block);
+ block = sequence;
+ }
+
+ /**
+ * add tests.
+ * @param sequence a sequence to add.
+ */
+ public void addTests(Sequential sequence) {
+ logOverride("tests", tests);
+ tests = sequence;
+ }
+
+ /**
+ * set reporting sequence of tasks.
+ * @param sequence a reporting sequence to use.
+ */
+ public void addReporting(Sequential sequence) {
+ logOverride("reporting", reporting);
+ reporting = sequence;
+ }
+
+ /**
+ * set teardown sequence of tasks.
+ * @param sequence a teardown sequence to use.
+ */
+ public void addTeardown(Sequential sequence) {
+ logOverride("teardown", teardown);
+ teardown = sequence;
+ }
+
+ /**
+ * Set the failOnTeardownErrors attribute.
+ * @param failOnTeardownErrors the value to use.
+ */
+ public void setFailOnTeardownErrors(boolean failOnTeardownErrors) {
+ this.failOnTeardownErrors = failOnTeardownErrors;
+ }
+
+ /**
+ * Set the failureMessage attribute.
+ * @param failureMessage the value to use.
+ */
+ public void setFailureMessage(String failureMessage) {
+ this.failureMessage = failureMessage;
+ }
+
+ /**
+ * Set the failureProperty attribute.
+ * @param failureProperty the value to use.
+ */
+ public void setFailureProperty(String failureProperty) {
+ this.failureProperty = failureProperty;
+ }
+
+ /**
+ * Set the shutdownTime attribute.
+ * @param shutdownTime the value to use.
+ */
+ public void setShutdownTime(long shutdownTime) {
+ this.shutdownTime = shutdownTime;
+ }
+
+ /**
+ * Set the timeout attribute.
+ * @param timeout the value to use.
+ */
+ public void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ /**
+ * Set the timeoutunit attribute.
+ * @param unit the value to use.
+ */
+ public void setTimeoutUnit(WaitFor.Unit unit) {
+ timeoutUnitMultiplier = unit.getMultiplier();
+ }
+
+ /**
+ * Set the shutdownunit attribute.
+ * @param unit the value to use.
+ */
+ public void setShutdownUnit(WaitFor.Unit unit) {
+ shutdownUnitMultiplier = unit.getMultiplier();
+ }
+
+
+ /**
+ * Get the application exception.
+ * @return the application exception.
+ */
+ public BuildException getApplicationException() {
+ return applicationException;
+ }
+
+ /**
+ * Get the teardown exception.
+ * @return the teardown exception.
+ */
+ public BuildException getTeardownException() {
+ return teardownException;
+ }
+
+ /**
+ * Get the test exception.
+ * @return the test exception.
+ */
+ public BuildException getTestException() {
+ return testException;
+ }
+
+ /**
+ * Get the task exception.
+ * @return the task exception.
+ */
+ public BuildException getTaskException() {
+ return taskException;
+ }
+
+ /**
+ * Bind and initialise a task
+ * @param task task to bind
+ */
+ private void bind(Task task) {
+ task.bindToOwner(this);
+ task.init();
+ }
+
+ /**
+ * Create a newly bound parallel instance
+ * @param parallelTimeout timeout
+ * @return a bound and initialised parallel instance.
+ */
+ private Parallel newParallel(long parallelTimeout) {
+ Parallel par = new Parallel();
+ bind(par);
+ par.setFailOnAny(true);
+ par.setTimeout(parallelTimeout);
+ return par;
+ }
+
+ /**
+ * Create a newly bound parallel instance with one child
+ * @param parallelTimeout timeout
+ * @param child task
+ * @return a bound and initialised parallel instance.
+ */
+ private Parallel newParallel(long parallelTimeout, Task child) {
+ Parallel par = newParallel(parallelTimeout);
+ par.addTask(child);
+ return par;
+ }
+
+ /**
+ * Add any task validation needed to ensure internal code quality
+ * @param task task
+ * @param role role of the task
+ */
+ private void validateTask(Task task, String role) {
+ if (task!=null && task.getProject() == null) {
+ throw new BuildException(role + " task is not bound to the project" + task);
+ }
+ }
+
+ /**
+ * Run the functional test sequence.
+ * <p>
+ * This is a fairly complex workflow -what is going on is that we try to clean up
+ * no matter how the run ended, and to retain the innermost exception that got thrown
+ * during cleanup. That is, if teardown fails after the tests themselves failed, it is the
+ * test failing that is more important.
+ * @throws BuildException if something was caught during the run or teardown.
+ */
+ public void execute() throws BuildException {
+
+ //validation
+ validateTask(setup, "setup");
+ validateTask(application, "application");
+ validateTask(tests, "tests");
+ validateTask(reporting, "reporting");
+ validateTask(teardown, "teardown");
+
+ //check the condition
+ //and bail out if it is defined but not true
+ if (condition != null && !condition.eval()) {
+ //we are skipping the test
+ log(SKIPPING_TESTS);
+ return;
+ }
+
+ long timeoutMillis = timeout * timeoutUnitMultiplier;
+
+ //set up the application to run in a separate thread
+ Parallel applicationRun = newParallel(timeoutMillis);
+ //with a worker which we can use to manage it
+ WorkerAnt worker = new WorkerAnt(applicationRun, null);
+ if (application != null) {
+ applicationRun.addTask(application);
+ }
+
+ //The test run consists of the block followed by the tests.
+ long testRunTimeout = 0;
+ Sequential testRun = new Sequential();
+ bind(testRun);
+ if (block != null) {
+ //waitfor is not a task, it needs to be adapted
+ TaskAdapter ta = new TaskAdapter(block);
+ ta.bindToOwner(this);
+ validateTask(ta, "block");
+ testRun.addTask(ta);
+ //add the block time to the total test run timeout
+ testRunTimeout = block.calculateMaxWaitMillis();
+ }
+
+ //add the tests and more delay
+ if (tests != null) {
+ testRun.addTask(tests);
+ testRunTimeout += timeoutMillis;
+ }
+ //add the reporting and more delay
+ if (reporting != null) {
+ testRun.addTask(reporting);
+ testRunTimeout += timeoutMillis;
+ }
+
+ //wrap this in a parallel purely to set up timeouts for the
+ //test run
+ timedTests = newParallel(testRunTimeout, testRun);
+
+ try {
+ //run any setup task
+ if (setup != null) {
+ Parallel setupRun = newParallel(timeoutMillis, setup);
+ setupRun.execute();
+ }
+ //start the worker thread and leave it running
+ worker.start();
+ //start the probe+test sequence
+ timedTests.execute();
+ } catch (BuildException e) {
+ //Record the exception and continue
+ testException = e;
+ } finally {
+ //teardown always runs; its faults are filed away
+ if (teardown != null) {
+ try {
+ Parallel teardownRun = newParallel(timeoutMillis, teardown);
+ teardownRun.execute();
+ } catch (BuildException e) {
+ teardownException = e;
+ }
+ }
+ }
+
+ //we get here whether or not the tests/teardown have thrown a BuildException.
+ //do a forced shutdown of the running application, before processing the faults
+
+ try {
+ //wait for the worker to have finished
+ long shutdownTimeMillis = shutdownTime * shutdownUnitMultiplier;
+ worker.waitUntilFinished(shutdownTimeMillis);
+ if (worker.isAlive()) {
+ //then, if it is still running, interrupt it a second time.
+ log(APPLICATION_FORCIBLY_SHUT_DOWN, Project.MSG_WARN);
+ worker.interrupt();
+ worker.waitUntilFinished(shutdownTimeMillis);
+ }
+ } catch (InterruptedException e) {
+ //success, something interrupted the shutdown. There may be a leaked
+ //worker;
+ log(SHUTDOWN_INTERRUPTED, e, Project.MSG_VERBOSE);
+ }
+ applicationException = worker.getBuildException();
+
+ //Now faults are analysed
+
+ processExceptions();
+ }
+
+ /**
+ * Now faults are analysed.
+ * <p> The priority is
+ * <ol>
+ * <li>testexceptions, except those indicating a build timeout when the application itself
+ failed.<br>
+ (because often it is the application fault that is more interesting than the probe
+ failure, which is usually triggered by the application not starting
+ </li><li>
+ Application exceptions (above test timeout exceptions)
+ </li><li>
+ Teardown exceptions -except when they are being ignored
+ </li><li>
+ Test failures as indicated by the failure property
+ </li></ol>
+
+ */
+ protected void processExceptions() {
+ taskException = testException;
+
+ //look for an application fault
+ if (applicationException != null) {
+ if (taskException == null || taskException instanceof BuildTimeoutException) {
+ taskException = applicationException;
+ } else {
+ ignoringThrowable(APPLICATION_EXCEPTION, applicationException);
+ }
+ }
+
+ //now look for teardown faults, which may be ignored
+ if (teardownException != null) {
+ if (taskException == null && failOnTeardownErrors) {
+ taskException = teardownException;
+ } else {
+ //don't let the cleanup exception get in the way of any other failure
+ ignoringThrowable(TEARDOWN_EXCEPTION, teardownException);
+ }
+ }
+
+ //now, analyse the tests
+ if (failureProperty != null
+ && getProject().getProperty(failureProperty) != null) {
+ //we've failed
+ log(failureMessage);
+ if (taskException == null) {
+ taskException = new BuildException(failureMessage);
+ }
+ }
+
+ //at this point taskException is null or not.
+ //if not, throw the exception
+ if (taskException != null) {
+ throw taskException;
+ }
+ }
+
+ /**
+ * log that we are ignoring something rather than rethrowing it.
+ * @param type name of exception
+ * @param thrown what was thrown
+ */
+ protected void ignoringThrowable(String type, Throwable thrown) {
+ log(type + ": " + thrown.toString(),
+ thrown,
+ Project.MSG_WARN);
+ }
+
+ private static class NestedCondition extends ConditionBase implements Condition {
+ public boolean eval() {
+ if (countConditions() != 1) {
+ throw new BuildException(
+ "A single nested condition is required.");
+ }
+ return ((Condition) (getConditions().nextElement())).eval();
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java
new file mode 100644
index 00000000..d3385e6c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * @since Ant 1.6
+ *
+ * @ant.task category="filesystem"
+ */
+
+public abstract class AbstractAccessTask
+ extends org.apache.tools.ant.taskdefs.ExecuteOn {
+
+ /**
+ * Chmod task for setting file and directory permissions.
+ */
+ public AbstractAccessTask() {
+ super.setParallel(true);
+ super.setSkipEmptyFilesets(true);
+ }
+
+ /**
+ * Set the file which should have its access attributes modified.
+ * @param src the file to modify
+ */
+ public void setFile(File src) {
+ FileSet fs = new FileSet();
+ fs.setFile(src);
+ addFileset(fs);
+ }
+
+ /**
+ * Prevent the user from specifying a different command.
+ *
+ * @ant.attribute ignore="true"
+ * @param cmdl A user supplied command line that we won't accept.
+ */
+ public void setCommand(Commandline cmdl) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the command attribute",
+ getLocation());
+ }
+
+ /**
+ * Prevent the skipping of empty filesets
+ *
+ * @ant.attribute ignore="true"
+ * @param skip A user supplied boolean we won't accept.
+ */
+ public void setSkipEmptyFilesets(boolean skip) {
+ throw new BuildException(getTaskType() + " doesn\'t support the "
+ + "skipemptyfileset attribute",
+ getLocation());
+ }
+
+ /**
+ * Prevent the use of the addsourcefile attribute.
+ *
+ * @ant.attribute ignore="true"
+ * @param b A user supplied boolean we won't accept.
+ */
+ public void setAddsourcefile(boolean b) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the addsourcefile attribute", getLocation());
+ }
+
+ /**
+ * Automatically approve Unix OS's.
+ * @return true if a valid OS, for unix this is always true, otherwise
+ * use the superclasses' test (user set).
+ */
+ protected boolean isValidOs() {
+ return getOs() == null && getOsFamily() == null
+ ? Os.isFamily(Os.FAMILY_UNIX) : super.isValidOs();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java
new file mode 100644
index 00000000..1279a2c8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Chgrp equivalent for unix-like environments.
+ *
+ * @since Ant 1.6
+ *
+ * @ant.task category="filesystem"
+ */
+public class Chgrp extends AbstractAccessTask {
+
+ private boolean haveGroup = false;
+
+ /**
+ * Chgrp task for setting unix group of a file.
+ */
+ public Chgrp() {
+ super.setExecutable("chgrp");
+ }
+
+ /**
+ * Set the group attribute.
+ *
+ * @param group The new group for the file(s) or directory(ies)
+ */
+ public void setGroup(String group) {
+ createArg().setValue(group);
+ haveGroup = true;
+ }
+
+ /**
+ * Ensure that all the required arguments and other conditions have
+ * been set.
+ */
+ protected void checkConfiguration() {
+ if (!haveGroup) {
+ throw new BuildException("Required attribute group not set in "
+ + "chgrp", getLocation());
+ }
+ super.checkConfiguration();
+ }
+
+ /**
+ * We don't want to expose the executable attribute, so override it.
+ *
+ * @param e User supplied executable that we won't accept.
+ */
+ public void setExecutable(String e) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the executable"
+ + " attribute", getLocation());
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java
new file mode 100644
index 00000000..53f72536
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Chown equivalent for unix-like environments.
+ *
+ * @since Ant 1.6
+ *
+ * @ant.task category="filesystem"
+ */
+public class Chown extends AbstractAccessTask {
+
+ private boolean haveOwner = false;
+
+ /**
+ * Chown task for setting file and directory permissions.
+ */
+ public Chown() {
+ super.setExecutable("chown");
+ }
+
+ /**
+ * Set the owner attribute.
+ *
+ * @param owner The new owner for the file(s) or directory(ies)
+ */
+ public void setOwner(String owner) {
+ createArg().setValue(owner);
+ haveOwner = true;
+ }
+
+ /**
+ * Ensure that all the required arguments and other conditions have
+ * been set.
+ */
+ protected void checkConfiguration() {
+ if (!haveOwner) {
+ throw new BuildException("Required attribute owner not set in"
+ + " chown", getLocation());
+ }
+ super.checkConfiguration();
+ }
+
+ /**
+ * We don't want to expose the executable attribute, so override it.
+ *
+ * @param e User supplied executable that we won't accept.
+ */
+ public void setExecutable(String e) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the executable"
+ + " attribute", getLocation());
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java
new file mode 100644
index 00000000..ad9aee8b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java
@@ -0,0 +1,600 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was developed on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.dispatch.DispatchTask;
+import org.apache.tools.ant.dispatch.DispatchUtils;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.SymbolicLinkUtils;
+
+/**
+ * Creates, Deletes, Records and Restores Symlinks.
+ *
+ * <p> This task performs several related operations. In the most trivial
+ * and default usage, it creates a link specified in the link attribute to
+ * a resource specified in the resource attribute. The second usage of this
+ * task is to traverse a directory structure specified by a fileset,
+ * and write a properties file in each included directory describing the
+ * links found in that directory. The third usage is to traverse a
+ * directory structure specified by a fileset, looking for properties files
+ * (also specified as included in the fileset) and recreate the links
+ * that have been previously recorded for each directory. Finally, it can be
+ * used to remove a symlink without deleting the associated resource.
+ *
+ * <p> Usage examples:
+ *
+ * <p> Make a link named &quot;foo&quot; to a resource named
+ * &quot;bar.foo&quot; in subdir:
+ * <pre>
+ * &lt;symlink link=&quot;${dir.top}/foo&quot; resource=&quot;${dir.top}/subdir/bar.foo&quot;/&gt;
+ * </pre>
+ *
+ * <p> Record all links in subdir and its descendants in files named
+ * &quot;dir.links&quot;:
+ * <pre>
+ * &lt;symlink action=&quot;record&quot; linkfilename=&quot;dir.links&quot;&gt;
+ * &lt;fileset dir=&quot;${dir.top}&quot; includes=&quot;subdir&#47;**&quot; /&gt;
+ * &lt;/symlink&gt;
+ * </pre>
+ *
+ * <p> Recreate the links recorded in the previous example:
+ * <pre>
+ * &lt;symlink action=&quot;recreate&quot;&gt;
+ * &lt;fileset dir=&quot;${dir.top}&quot; includes=&quot;subdir&#47;**&#47;dir.links&quot; /&gt;
+ * &lt;/symlink&gt;
+ * </pre>
+ *
+ * <p> Delete a link named &quot;foo&quot; to a resource named
+ * &quot;bar.foo&quot; in subdir:
+ * <pre>
+ * &lt;symlink action=&quot;delete&quot; link=&quot;${dir.top}/foo&quot;/&gt;
+ * </pre>
+ *
+ * <p><strong>LIMITATIONS:</strong> Because Java has no direct support for
+ * handling symlinks this task divines them by comparing canonical and
+ * absolute paths. On non-unix systems this may cause false positives.
+ * Furthermore, any operating system on which the command
+ * <code>ln -s link resource</code> is not a valid command on the command line
+ * will not be able to use action=&quot;delete&quot;, action=&quot;single&quot;
+ * or action=&quot;recreate&quot;, but action=&quot;record&quot; should still
+ * work. Finally, the lack of support for symlinks in Java means that all links
+ * are recorded as links to the <strong>canonical</strong> resource name.
+ * Therefore the link: <code>link --> subdir/dir/../foo.bar</code> will be
+ * recorded as <code>link=subdir/foo.bar</code> and restored as
+ * <code>link --> subdir/foo.bar</code>.
+ *
+ */
+public class Symlink extends DispatchTask {
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+ private static final SymbolicLinkUtils SYMLINK_UTILS =
+ SymbolicLinkUtils.getSymbolicLinkUtils();
+
+ private String resource;
+ private String link;
+ private Vector fileSets = new Vector();
+ private String linkFileName;
+ private boolean overwrite;
+ private boolean failonerror;
+ private boolean executing = false;
+
+ /**
+ * Initialize the task.
+ * @throws BuildException on error.
+ */
+ @Override
+ public void init() throws BuildException {
+ super.init();
+ setDefaults();
+ }
+
+ /**
+ * The standard method for executing any task.
+ * @throws BuildException on error.
+ */
+ @Override
+ public synchronized void execute() throws BuildException {
+ if (executing) {
+ throw new BuildException(
+ "Infinite recursion detected in Symlink.execute()");
+ }
+ try {
+ executing = true;
+ DispatchUtils.execute(this);
+ } finally {
+ executing = false;
+ }
+ }
+
+ /**
+ * Create a symlink.
+ * @throws BuildException on error.
+ * @since Ant 1.7
+ */
+ public void single() throws BuildException {
+ try {
+ if (resource == null) {
+ handleError("Must define the resource to symlink to!");
+ return;
+ }
+ if (link == null) {
+ handleError("Must define the link name for symlink!");
+ return;
+ }
+ doLink(resource, link);
+ } finally {
+ setDefaults();
+ }
+ }
+
+ /**
+ * Delete a symlink.
+ * @throws BuildException on error.
+ * @since Ant 1.7
+ */
+ public void delete() throws BuildException {
+ try {
+ if (link == null) {
+ handleError("Must define the link name for symlink!");
+ return;
+ }
+ log("Removing symlink: " + link);
+ SYMLINK_UTILS.deleteSymbolicLink(FILE_UTILS
+ .resolveFile(new File("."), link),
+ this);
+ } catch (FileNotFoundException fnfe) {
+ handleError(fnfe.toString());
+ } catch (IOException ioe) {
+ handleError(ioe.toString());
+ } finally {
+ setDefaults();
+ }
+ }
+
+ /**
+ * Restore symlinks.
+ * @throws BuildException on error.
+ * @since Ant 1.7
+ */
+ public void recreate() throws BuildException {
+ try {
+ if (fileSets.isEmpty()) {
+ handleError("File set identifying link file(s) "
+ + "required for action recreate");
+ return;
+ }
+ Properties links = loadLinks(fileSets);
+
+ for (Iterator kitr = links.keySet().iterator(); kitr.hasNext();) {
+ String lnk = (String) kitr.next();
+ String res = links.getProperty(lnk);
+ // handle the case where lnk points to a directory (bug 25181)
+ try {
+ File test = new File(lnk);
+ if (!SYMLINK_UTILS.isSymbolicLink(lnk)) {
+ doLink(res, lnk);
+ } else if (!test.getCanonicalPath().equals(
+ new File(res).getCanonicalPath())) {
+ SYMLINK_UTILS.deleteSymbolicLink(test, this);
+ doLink(res, lnk);
+ } // else lnk exists, do nothing
+ } catch (IOException ioe) {
+ handleError("IO exception while creating link");
+ }
+ }
+ } finally {
+ setDefaults();
+ }
+ }
+
+ /**
+ * Record symlinks.
+ * @throws BuildException on error.
+ * @since Ant 1.7
+ */
+ public void record() throws BuildException {
+ try {
+ if (fileSets.isEmpty()) {
+ handleError("Fileset identifying links to record required");
+ return;
+ }
+ if (linkFileName == null) {
+ handleError("Name of file to record links in required");
+ return;
+ }
+ // create a hashtable to group them by parent directory:
+ Hashtable byDir = new Hashtable();
+
+ // get an Iterator of file objects representing links (canonical):
+ for (Iterator litr = findLinks(fileSets).iterator();
+ litr.hasNext();) {
+ File thisLink = (File) litr.next();
+ File parent = thisLink.getParentFile();
+ Vector v = (Vector) byDir.get(parent);
+ if (v == null) {
+ v = new Vector();
+ byDir.put(parent, v);
+ }
+ v.addElement(thisLink);
+ }
+ // write a Properties file in each directory:
+ for (Iterator dirs = byDir.keySet().iterator(); dirs.hasNext();) {
+ File dir = (File) dirs.next();
+ Vector linksInDir = (Vector) byDir.get(dir);
+ Properties linksToStore = new Properties();
+
+ // fill up a Properties object with link and resource names:
+ for (Iterator dlnk = linksInDir.iterator(); dlnk.hasNext();) {
+ File lnk = (File) dlnk.next();
+ try {
+ linksToStore.put(lnk.getName(), lnk.getCanonicalPath());
+ } catch (IOException ioe) {
+ handleError("Couldn't get canonical name of parent link");
+ }
+ }
+ writePropertyFile(linksToStore, dir);
+ }
+ } finally {
+ setDefaults();
+ }
+ }
+
+ /**
+ * Return all variables to their default state for the next invocation.
+ * @since Ant 1.7
+ */
+ private void setDefaults() {
+ resource = null;
+ link = null;
+ linkFileName = null;
+ failonerror = true; // default behavior is to fail on an error
+ overwrite = false; // default behavior is to not overwrite
+ setAction("single"); // default behavior is make a single link
+ fileSets.clear();
+ }
+
+ /**
+ * Set overwrite mode. If set to false (default)
+ * the task will not overwrite existing links, and may stop the build
+ * if a link already exists depending on the setting of failonerror.
+ *
+ * @param owrite If true overwrite existing links.
+ */
+ public void setOverwrite(boolean owrite) {
+ this.overwrite = owrite;
+ }
+
+ /**
+ * Set failonerror mode. If set to true (default) the entire build fails
+ * upon error; otherwise the error is logged and the build will continue.
+ *
+ * @param foe If true throw BuildException on error, else log it.
+ */
+ public void setFailOnError(boolean foe) {
+ this.failonerror = foe;
+ }
+
+ /**
+ * Set the action to be performed. May be &quot;single&quot;,
+ * &quot;delete&quot;, &quot;recreate&quot; or &quot;record&quot;.
+ *
+ * @param action The action to perform.
+ */
+ @Override
+ public void setAction(String action) {
+ super.setAction(action);
+ }
+
+ /**
+ * Set the name of the link. Used when action = &quot;single&quot;.
+ *
+ * @param lnk The name for the link.
+ */
+ public void setLink(String lnk) {
+ this.link = lnk;
+ }
+
+ /**
+ * Set the name of the resource to which a link should be created.
+ * Used when action = &quot;single&quot;.
+ *
+ * @param src The resource to be linked.
+ */
+ public void setResource(String src) {
+ this.resource = src;
+ }
+
+ /**
+ * Set the name of the file to which links will be written.
+ * Used when action = &quot;record&quot;.
+ *
+ * @param lf The name of the file to write links to.
+ */
+ public void setLinkfilename(String lf) {
+ this.linkFileName = lf;
+ }
+
+ /**
+ * Add a fileset to this task.
+ *
+ * @param set The fileset to add.
+ */
+ public void addFileset(FileSet set) {
+ fileSets.addElement(set);
+ }
+
+ /**
+ * Delete a symlink (without deleting the associated resource).
+ *
+ * <p>This is a convenience method that simply invokes
+ * <code>deleteSymlink(java.io.File)</code>.
+ *
+ * @param path A string containing the path of the symlink to delete.
+ *
+ * @throws FileNotFoundException When the path results in a
+ * <code>File</code> that doesn't exist.
+ * @throws IOException If calls to <code>File.rename</code>
+ * or <code>File.delete</code> fail.
+ * @deprecated use
+ * org.apache.tools.ant.util.SymbolicLinkUtils#deleteSymbolicLink
+ * instead
+ */
+ @Deprecated
+ public static void deleteSymlink(String path)
+ throws IOException, FileNotFoundException {
+ SYMLINK_UTILS.deleteSymbolicLink(new File(path), null);
+ }
+
+ /**
+ * Delete a symlink (without deleting the associated resource).
+ *
+ * <p>This is a utility method that removes a unix symlink without removing
+ * the resource that the symlink points to. If it is accidentally invoked
+ * on a real file, the real file will not be harmed.</p>
+ *
+ * <p>This method works by
+ * getting the canonical path of the link, using the canonical path to
+ * rename the resource (breaking the link) and then deleting the link.
+ * The resource is then returned to its original name inside a finally
+ * block to ensure that the resource is unharmed even in the event of
+ * an exception.</p>
+ *
+ * <p>Since Ant 1.8.0 this method will try to delete the File object if
+ * it reports it wouldn't exist (as symlinks pointing nowhere usually do).
+ * Prior version would throw a FileNotFoundException in that case.</p>
+ *
+ * @param linkfil A <code>File</code> object of the symlink to delete.
+ *
+ * @throws IOException If calls to <code>File.rename</code>,
+ * <code>File.delete</code> or
+ * <code>File.getCanonicalPath</code>
+ * fail.
+ * @deprecated use
+ * org.apache.tools.ant.util.SymbolicLinkUtils#deleteSymbolicLink
+ * instead
+ */
+ @Deprecated
+ public static void deleteSymlink(File linkfil)
+ throws IOException {
+ SYMLINK_UTILS.deleteSymbolicLink(linkfil, null);
+ }
+
+ /**
+ * Write a properties file. This method uses <code>Properties.store</code>
+ * and thus may throw exceptions that occur while writing the file.
+ *
+ * @param properties The properties object to be written.
+ * @param dir The directory for which we are writing the links.
+ * @throws BuildException if the property file could not be written
+ */
+ private void writePropertyFile(Properties properties, File dir)
+ throws BuildException {
+ BufferedOutputStream bos = null;
+ try {
+ bos = new BufferedOutputStream(
+ new FileOutputStream(new File(dir, linkFileName)));
+ properties.store(bos, "Symlinks from " + dir);
+ } catch (IOException ioe) {
+ throw new BuildException(ioe, getLocation());
+ } finally {
+ FileUtils.close(bos);
+ }
+ }
+
+ /**
+ * Handle errors based on the setting of failonerror.
+ *
+ * @param msg The message to log, or include in the
+ * <code>BuildException</code>.
+ * @throws BuildException with the message if failonerror=true
+ */
+ private void handleError(String msg) {
+ if (failonerror) {
+ throw new BuildException(msg);
+ }
+ log(msg);
+ }
+
+ /**
+ * Conduct the actual construction of a link.
+ *
+ * <p> The link is constructed by calling <code>Execute.runCommand</code>.
+ *
+ * @param res The path of the resource we are linking to.
+ * @param lnk The name of the link we wish to make.
+ * @throws BuildException when things go wrong
+ */
+ private void doLink(String res, String lnk) throws BuildException {
+ File linkfil = new File(lnk);
+ String options = "-s";
+ if (overwrite) {
+ options += "f";
+ if (linkfil.exists()) {
+ try {
+ SYMLINK_UTILS.deleteSymbolicLink(linkfil, this);
+ } catch (FileNotFoundException fnfe) {
+ log("Symlink disappeared before it was deleted: " + lnk);
+ } catch (IOException ioe) {
+ log("Unable to overwrite preexisting link or file: " + lnk,
+ ioe, Project.MSG_INFO);
+ }
+ }
+ }
+ String[] cmd = new String[] {"ln", options, res, lnk};
+ try {
+ Execute.runCommand(this, cmd);
+ } catch (BuildException failedToExecute) {
+ if (failonerror) {
+ throw failedToExecute;
+ } else {
+ //log at the info level, and keep going.
+ log(failedToExecute.getMessage(), failedToExecute, Project.MSG_INFO);
+ }
+ }
+ }
+
+ /**
+ * Find all the links in all supplied filesets.
+ *
+ * <p> This method is invoked when the action attribute is
+ * &quot;record&quot;. This means that filesets are interpreted
+ * as the directories in which links may be found.
+ *
+ * @param v The filesets specified by the user.
+ * @return A HashSet of <code>File</code> objects containing the
+ * links (with canonical parent directories).
+ */
+ private HashSet findLinks(Vector v) {
+ HashSet result = new HashSet();
+ final int size = v.size();
+ for (int i = 0; i < size; i++) {
+ FileSet fs = (FileSet) v.get(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ String[][] fnd = new String[][]
+ {ds.getIncludedFiles(), ds.getIncludedDirectories()};
+ File dir = fs.getDir(getProject());
+ for (int j = 0; j < fnd.length; j++) {
+ for (int k = 0; k < fnd[j].length; k++) {
+ try {
+ File f = new File(dir, fnd[j][k]);
+ File pf = f.getParentFile();
+ String name = f.getName();
+ if (SYMLINK_UTILS.isSymbolicLink(pf, name)) {
+ result.add(new File(pf.getCanonicalFile(), name));
+ }
+ } catch (IOException e) {
+ handleError("IOException: " + fnd[j][k] + " omitted");
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Load links from properties files included in one or more FileSets.
+ *
+ * <p> This method is only invoked when the action attribute is set to
+ * &quot;recreate&quot;. The filesets passed in are assumed to specify the
+ * names of the property files with the link information and the
+ * subdirectories in which to look for them.
+ *
+ * @param v The <code>FileSet</code>s for this task.
+ * @return The links to be made.
+ */
+ private Properties loadLinks(Vector v) {
+ Properties finalList = new Properties();
+ // loop through the supplied file sets:
+ final int size = v.size();
+ for (int i = 0; i < size; i++) {
+ FileSet fs = (FileSet) v.elementAt(i);
+ DirectoryScanner ds = new DirectoryScanner();
+ fs.setupDirectoryScanner(ds, getProject());
+ ds.setFollowSymlinks(false);
+ ds.scan();
+ String[] incs = ds.getIncludedFiles();
+ File dir = fs.getDir(getProject());
+
+ // load included files as properties files:
+ for (int j = 0; j < incs.length; j++) {
+ File inc = new File(dir, incs[j]);
+ File pf = inc.getParentFile();
+ Properties lnks = new Properties();
+ InputStream is = null;
+ try {
+ is = new BufferedInputStream(new FileInputStream(inc));
+ lnks.load(is);
+ pf = pf.getCanonicalFile();
+ } catch (FileNotFoundException fnfe) {
+ handleError("Unable to find " + incs[j] + "; skipping it.");
+ continue;
+ } catch (IOException ioe) {
+ handleError("Unable to open " + incs[j]
+ + " or its parent dir; skipping it.");
+ continue;
+ } finally {
+ FileUtils.close(is);
+ }
+ lnks.list(new PrintStream(
+ new LogOutputStream(this, Project.MSG_INFO)));
+ // Write the contents to our master list of links
+ // This method assumes that all links are defined in
+ // terms of absolute paths, or paths relative to the
+ // working directory:
+ for (Iterator kitr = lnks.keySet().iterator(); kitr.hasNext();) {
+ String key = (String) kitr.next();
+ finalList.put(new File(pf, key).getAbsolutePath(),
+ lnks.getProperty(key));
+ }
+ }
+ }
+ return finalList;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java
new file mode 100644
index 00000000..f514fc62
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java
@@ -0,0 +1,784 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * A base class for creating tasks for executing commands on Visual SourceSafe.
+ * <p>
+ * The class extends the 'exec' task as it operates by executing the ss.exe program
+ * supplied with SourceSafe. By default the task expects ss.exe to be in the path,
+ * you can override this be specifying the ssdir attribute.
+ * </p>
+ * <p>
+ * This class provides set and get methods for 'login' and 'vsspath' attributes. It
+ * also contains constants for the flags that can be passed to SS.
+ * </p>
+ *
+ */
+public abstract class MSVSS extends Task implements MSVSSConstants {
+
+ private String ssDir = null;
+ private String vssLogin = null;
+ private String vssPath = null;
+ private String serverPath = null;
+
+ /** Version */
+ private String version = null;
+ /** Date */
+ private String date = null;
+ /** Label */
+ private String label = null;
+ /** Auto response */
+ private String autoResponse = null;
+ /** Local path */
+ private String localPath = null;
+ /** Comment */
+ private String comment = null;
+ /** From label */
+ private String fromLabel = null;
+ /** To label */
+ private String toLabel = null;
+ /** Output file name */
+ private String outputFileName = null;
+ /** User */
+ private String user = null;
+ /** From date */
+ private String fromDate = null;
+ /** To date */
+ private String toDate = null;
+ /** History style */
+ private String style = null;
+ /** Quiet defaults to false */
+ private boolean quiet = false;
+ /** Recursive defaults to false */
+ private boolean recursive = false;
+ /** Writable defaults to false */
+ private boolean writable = false;
+ /** Fail on error defaults to true */
+ private boolean failOnError = true;
+ /** Get local copy for checkout defaults to true */
+ private boolean getLocalCopy = true;
+ /** Number of days offset for History */
+ private int numDays = Integer.MIN_VALUE;
+ /** Date format for History */
+ private DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
+ /** Timestamp for retreived files */
+ private CurrentModUpdated timestamp = null;
+ /** Behaviour for writable files */
+ private WritableFiles writableFiles = null;
+
+ /**
+ * Each sub-class must implemnt this method and return the constructed
+ * command line to be executed. It is up to the sub-task to determine the
+ * required attrubutes and their order.
+ * @return The Constructed command line.
+ */
+ abstract Commandline buildCmdLine();
+
+ /**
+ * Directory where <code>ss.exe</code> resides.
+ * By default the task expects it to be in the PATH.
+ * @param dir The directory containing ss.exe.
+ */
+ public final void setSsdir(String dir) {
+ this.ssDir = FileUtils.translatePath(dir);
+ }
+
+ /**
+ * Login to use when accessing VSS, formatted as "username,password".
+ * <p>
+ * You can omit the password if your database is not password protected.
+ * If you have a password and omit it, Ant will hang.
+ * @param vssLogin The login string to use.
+ */
+ public final void setLogin(final String vssLogin) {
+ this.vssLogin = vssLogin;
+ }
+
+ /**
+ * SourceSafe path which specifies the project/file(s) you wish to perform
+ * the action on.
+ * <p>
+ * A prefix of 'vss://' will be removed if specified.
+ * @param vssPath The VSS project path.
+ * @ant.attribute group="required"
+ */
+ public final void setVsspath(final String vssPath) {
+ String projectPath;
+ // CheckStyle:MagicNumber OFF
+ if (vssPath.startsWith("vss://")) { //$NON-NLS-1$
+ projectPath = vssPath.substring(5);
+ } else {
+ projectPath = vssPath;
+ }
+ // CheckStyle:MagicNumber ON
+
+ if (projectPath.startsWith(PROJECT_PREFIX)) {
+ this.vssPath = projectPath;
+ } else {
+ this.vssPath = PROJECT_PREFIX + projectPath;
+ }
+ }
+
+ /**
+ * Directory where <code>srssafe.ini</code> resides.
+ * @param serverPath The path to the VSS server.
+ */
+ public final void setServerpath(final String serverPath) {
+ this.serverPath = serverPath;
+ }
+
+ /**
+ * Indicates if the build should fail if the Sourcesafe command does. Defaults to true.
+ * @param failOnError True if task should fail on any error.
+ */
+ public final void setFailOnError(final boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ /**
+ * Executes the task. <br>
+ * Builds a command line to execute ss.exe and then calls Exec's run method
+ * to execute the command line.
+ * @throws BuildException if the command cannot execute.
+ */
+ public void execute() throws BuildException {
+ int result = 0;
+ Commandline commandLine = buildCmdLine();
+ result = run(commandLine);
+ if (Execute.isFailure(result) && getFailOnError()) {
+ String msg = "Failed executing: " + formatCommandLine(commandLine)
+ + " With a return code of " + result;
+ throw new BuildException(msg, getLocation());
+ }
+ }
+
+ // Special setters for the sub-classes
+
+ /**
+ * Set the internal comment attribute.
+ * @param comment the value to use.
+ */
+ protected void setInternalComment(final String comment) {
+ this.comment = comment;
+ }
+
+ /**
+ * Set the auto response attribute.
+ * @param autoResponse the value to use.
+ */
+ protected void setInternalAutoResponse(final String autoResponse) {
+ this.autoResponse = autoResponse;
+ }
+
+ /**
+ * Set the date attribute.
+ * @param date the value to use.
+ */
+ protected void setInternalDate(final String date) {
+ this.date = date;
+ }
+
+ /**
+ * Set the date format attribute.
+ * @param dateFormat the value to use.
+ */
+ protected void setInternalDateFormat(final DateFormat dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ /**
+ * Set the failOnError attribute.
+ * @param failOnError the value to use.
+ */
+ protected void setInternalFailOnError(final boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ /**
+ * Set the from date attribute.
+ * @param fromDate the value to use.
+ */
+ protected void setInternalFromDate(final String fromDate) {
+ this.fromDate = fromDate;
+ }
+
+ /**
+ * Set the from label attribute.
+ * @param fromLabel the value to use.
+ */
+ protected void setInternalFromLabel(final String fromLabel) {
+ this.fromLabel = fromLabel;
+ }
+
+ /**
+ * Set the label attribute.
+ * @param label the value to use.
+ */
+ protected void setInternalLabel(final String label) {
+ this.label = label;
+ }
+
+ /**
+ * Set the local path comment attribute.
+ * @param localPath the value to use.
+ */
+ protected void setInternalLocalPath(final String localPath) {
+ this.localPath = localPath;
+ }
+
+ /**
+ * Set the num days attribute.
+ * @param numDays the value to use.
+ */
+ protected void setInternalNumDays(final int numDays) {
+ this.numDays = numDays;
+ }
+
+ /**
+ * Set the outputFileName comment attribute.
+ * @param outputFileName the value to use.
+ */
+ protected void setInternalOutputFilename(final String outputFileName) {
+ this.outputFileName = outputFileName;
+ }
+
+ /**
+ * Set the quiet attribute.
+ * @param quiet the value to use.
+ */
+ protected void setInternalQuiet(final boolean quiet) {
+ this.quiet = quiet;
+ }
+
+ /**
+ * Set the recursive attribute.
+ * @param recursive the value to use.
+ */
+ protected void setInternalRecursive(final boolean recursive) {
+ this.recursive = recursive;
+ }
+
+ /**
+ * Set the style attribute.
+ * @param style the value to use.
+ */
+ protected void setInternalStyle(final String style) {
+ this.style = style;
+ }
+
+ /**
+ * Set the to date attribute.
+ * @param toDate the value to use.
+ */
+ protected void setInternalToDate(final String toDate) {
+ this.toDate = toDate;
+ }
+
+ /**
+ * Set the to label attribute.
+ * @param toLabel the value to use.
+ */
+ protected void setInternalToLabel(final String toLabel) {
+ this.toLabel = toLabel;
+ }
+
+ /**
+ * Set the user attribute.
+ * @param user the value to use.
+ */
+ protected void setInternalUser(final String user) {
+ this.user = user;
+ }
+
+ /**
+ * Set the version attribute.
+ * @param version the value to use.
+ */
+ protected void setInternalVersion(final String version) {
+ this.version = version;
+ }
+
+ /**
+ * Set the writable attribute.
+ * @param writable the value to use.
+ */
+ protected void setInternalWritable(final boolean writable) {
+ this.writable = writable;
+ }
+
+ /**
+ * Set the timestamp attribute.
+ * @param timestamp the value to use.
+ */
+ protected void setInternalFileTimeStamp(final CurrentModUpdated timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ /**
+ * Set the writableFiles attribute.
+ * @param writableFiles the value to use.
+ */
+ protected void setInternalWritableFiles(final WritableFiles writableFiles) {
+ this.writableFiles = writableFiles;
+ }
+
+ /**
+ * Set the getLocalCopy attribute.
+ * @param getLocalCopy the value to use.
+ */
+ protected void setInternalGetLocalCopy(final boolean getLocalCopy) {
+ this.getLocalCopy = getLocalCopy;
+ }
+
+ /**
+ * Gets the sscommand string. "ss" or "c:\path\to\ss"
+ * @return The path to ss.exe or just ss if sscommand is not set.
+ */
+ protected String getSSCommand() {
+ if (ssDir == null) {
+ return SS_EXE;
+ }
+ return ssDir.endsWith(File.separator) ? ssDir + SS_EXE : ssDir
+ + File.separator + SS_EXE;
+ }
+
+ /**
+ * Gets the vssserverpath string.
+ * @return null if vssserverpath is not set.
+ */
+ protected String getVsspath() {
+ return vssPath;
+ }
+
+ /**
+ * Gets the quiet string. -O-
+ * @return An empty string if quiet is not set or is false.
+ */
+ protected String getQuiet() {
+ return quiet ? FLAG_QUIET : "";
+ }
+
+ /**
+ * Gets the recursive string. "-R"
+ * @return An empty string if recursive is not set or is false.
+ */
+ protected String getRecursive() {
+ return recursive ? FLAG_RECURSION : "";
+ }
+
+ /**
+ * Gets the writable string. "-W"
+ * @return An empty string if writable is not set or is false.
+ */
+ protected String getWritable() {
+ return writable ? FLAG_WRITABLE : "";
+ }
+
+ /**
+ * Gets the label string. "-Lbuild1"
+ * Max label length is 32 chars
+ * @return An empty string if label is not set.
+ */
+ protected String getLabel() {
+ String shortLabel = "";
+ if (label != null && label.length() > 0) {
+ shortLabel = FLAG_LABEL + getShortLabel();
+ }
+ return shortLabel;
+ }
+ /**
+ * Return at most the 30 first chars of the label,
+ * logging a warning message about the truncation
+ * @return at most the 30 first chars of the label
+ */
+ private String getShortLabel() {
+ String shortLabel;
+ // CheckStyle:MagicNumber OFF
+ if (label != null && label.length() > 31) {
+ shortLabel = this.label.substring(0, 30);
+ log("Label is longer than 31 characters, truncated to: " + shortLabel,
+ Project.MSG_WARN);
+ } else {
+ shortLabel = label;
+ }
+ // CheckStyle:MagicNumber ON
+ return shortLabel;
+ }
+ /**
+ * Gets the style string. "-Lbuild1"
+ * @return An empty string if label is not set.
+ */
+ protected String getStyle() {
+ return style != null ? style : "";
+ }
+
+ /**
+ * Gets the version string. Returns the first specified of version "-V1.0",
+ * date "-Vd01.01.01", label "-Vlbuild1".
+ * @return An empty string if a version, date and label are not set.
+ */
+ protected String getVersionDateLabel() {
+ String versionDateLabel = "";
+ if (version != null) {
+ versionDateLabel = FLAG_VERSION + version;
+ } else if (date != null) {
+ versionDateLabel = FLAG_VERSION_DATE + date;
+ } else {
+ // Use getShortLabel() so labels longer then 30 char are truncated
+ // and the user is warned
+ String shortLabel = getShortLabel();
+ if (shortLabel != null && !shortLabel.equals("")) {
+ versionDateLabel = FLAG_VERSION_LABEL + shortLabel;
+ }
+ }
+ return versionDateLabel;
+ }
+
+ /**
+ * Gets the version string.
+ * @return An empty string if a version is not set.
+ */
+ protected String getVersion() {
+ return version != null ? FLAG_VERSION + version : "";
+ }
+
+ /**
+ * Gets the localpath string. "-GLc:\source" <p>
+ * The localpath is created if it didn't exist.
+ * @return An empty string if localpath is not set.
+ */
+ protected String getLocalpath() {
+ String lclPath = ""; //set to empty str if no local path return
+ if (localPath != null) {
+ //make sure m_LocalDir exists, create it if it doesn't
+ File dir = getProject().resolveFile(localPath);
+ if (!dir.exists()) {
+ boolean done = dir.mkdirs();
+ if (!done) {
+ String msg = "Directory " + localPath + " creation was not "
+ + "successful for an unknown reason";
+ throw new BuildException(msg, getLocation());
+ }
+ getProject().log("Created dir: " + dir.getAbsolutePath());
+ }
+ lclPath = FLAG_OVERRIDE_WORKING_DIR + localPath;
+ }
+ return lclPath;
+ }
+
+ /**
+ * Gets the comment string. "-Ccomment text"
+ * @return A comment of "-" if comment is not set.
+ */
+ protected String getComment() {
+ return comment != null ? FLAG_COMMENT + comment : FLAG_COMMENT + "-";
+ }
+
+ /**
+ * Gets the auto response string. This can be Y "-I-Y" or N "-I-N".
+ * @return The default value "-I-" if autoresponse is not set.
+ */
+ protected String getAutoresponse() {
+ if (autoResponse == null) {
+ return FLAG_AUTORESPONSE_DEF;
+ }
+ if (autoResponse.equalsIgnoreCase("Y")) {
+ return FLAG_AUTORESPONSE_YES;
+ } else if (autoResponse.equalsIgnoreCase("N")) {
+ return FLAG_AUTORESPONSE_NO;
+ } else {
+ return FLAG_AUTORESPONSE_DEF;
+ }
+ }
+
+ /**
+ * Gets the login string. This can be user and password, "-Yuser,password"
+ * or just user "-Yuser".
+ * @return An empty string if login is not set.
+ */
+ protected String getLogin() {
+ return vssLogin != null ? FLAG_LOGIN + vssLogin : "";
+ }
+
+ /**
+ * Gets the output file string. "-Ooutput.file"
+ * @return An empty string if user is not set.
+ */
+ protected String getOutput() {
+ return outputFileName != null ? FLAG_OUTPUT + outputFileName : "";
+ }
+
+ /**
+ * Gets the user string. "-Uusername"
+ * @return An empty string if user is not set.
+ */
+ protected String getUser() {
+ return user != null ? FLAG_USER + user : "";
+ }
+
+ /**
+ * Gets the version string. This can be to-from "-VLbuild2~Lbuild1", from
+ * "~Lbuild1" or to "-VLbuild2".
+ * @return An empty string if neither tolabel or fromlabel are set.
+ */
+ protected String getVersionLabel() {
+ if (fromLabel == null && toLabel == null) {
+ return "";
+ }
+ // CheckStyle:MagicNumber OFF
+ if (fromLabel != null && toLabel != null) {
+ if (fromLabel.length() > 31) {
+ fromLabel = fromLabel.substring(0, 30);
+ log("FromLabel is longer than 31 characters, truncated to: "
+ + fromLabel, Project.MSG_WARN);
+ }
+ if (toLabel.length() > 31) {
+ toLabel = toLabel.substring(0, 30);
+ log("ToLabel is longer than 31 characters, truncated to: "
+ + toLabel, Project.MSG_WARN);
+ }
+ return FLAG_VERSION_LABEL + toLabel + VALUE_FROMLABEL + fromLabel;
+ } else if (fromLabel != null) {
+ if (fromLabel.length() > 31) {
+ fromLabel = fromLabel.substring(0, 30);
+ log("FromLabel is longer than 31 characters, truncated to: "
+ + fromLabel, Project.MSG_WARN);
+ }
+ return FLAG_VERSION + VALUE_FROMLABEL + fromLabel;
+ } else {
+ if (toLabel.length() > 31) {
+ toLabel = toLabel.substring(0, 30);
+ log("ToLabel is longer than 31 characters, truncated to: "
+ + toLabel, Project.MSG_WARN);
+ }
+ return FLAG_VERSION_LABEL + toLabel;
+ }
+ // CheckStyle:MagicNumber ON
+ }
+
+ /**
+ * Gets the Version date string.
+ * @return An empty string if neither Todate or from date are set.
+ * @throws BuildException if there is an error.
+ */
+ protected String getVersionDate() throws BuildException {
+ if (fromDate == null && toDate == null
+ && numDays == Integer.MIN_VALUE) {
+ return "";
+ }
+ if (fromDate != null && toDate != null) {
+ return FLAG_VERSION_DATE + toDate + VALUE_FROMDATE + fromDate;
+ } else if (toDate != null && numDays != Integer.MIN_VALUE) {
+ try {
+ return FLAG_VERSION_DATE + toDate + VALUE_FROMDATE
+ + calcDate(toDate, numDays);
+ } catch (ParseException ex) {
+ String msg = "Error parsing date: " + toDate;
+ throw new BuildException(msg, getLocation());
+ }
+ } else if (fromDate != null && numDays != Integer.MIN_VALUE) {
+ try {
+ return FLAG_VERSION_DATE + calcDate(fromDate, numDays)
+ + VALUE_FROMDATE + fromDate;
+ } catch (ParseException ex) {
+ String msg = "Error parsing date: " + fromDate;
+ throw new BuildException(msg, getLocation());
+ }
+ } else {
+ return fromDate != null ? FLAG_VERSION + VALUE_FROMDATE
+ + fromDate : FLAG_VERSION_DATE + toDate;
+ }
+ }
+
+ /**
+ * Builds and returns the -G- flag if required.
+ * @return An empty string if get local copy is true.
+ */
+ protected String getGetLocalCopy() {
+ return (!getLocalCopy) ? FLAG_NO_GET : "";
+ }
+
+ /**
+ * Gets the value of the fail on error flag.
+ * @return True if the FailOnError flag has been set or if 'writablefiles=skip'.
+ */
+ private boolean getFailOnError() {
+ return getWritableFiles().equals(WRITABLE_SKIP) ? false : failOnError;
+ }
+
+
+ /**
+ * Gets the value set for the FileTimeStamp.
+ * if it equals "current" then we return -GTC
+ * if it equals "modified" then we return -GTM
+ * if it equals "updated" then we return -GTU
+ * otherwise we return -GTC
+ *
+ * @return The default file time flag, if not set.
+ */
+ public String getFileTimeStamp() {
+ if (timestamp == null) {
+ return "";
+ } else if (timestamp.getValue().equals(TIME_MODIFIED)) {
+ return FLAG_FILETIME_MODIFIED;
+ } else if (timestamp.getValue().equals(TIME_UPDATED)) {
+ return FLAG_FILETIME_UPDATED;
+ } else {
+ return FLAG_FILETIME_DEF;
+ }
+ }
+
+
+ /**
+ * Gets the value to determine the behaviour when encountering writable files.
+ * @return An empty String, if not set.
+ */
+ public String getWritableFiles() {
+ if (writableFiles == null) {
+ return "";
+ } else if (writableFiles.getValue().equals(WRITABLE_REPLACE)) {
+ return FLAG_REPLACE_WRITABLE;
+ } else if (writableFiles.getValue().equals(WRITABLE_SKIP)) {
+ // ss.exe exits with '100', when files have been skipped
+ // so we have to ignore the failure
+ failOnError = false;
+ return FLAG_SKIP_WRITABLE;
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Sets up the required environment and executes the command line.
+ *
+ * @param cmd The command line to execute.
+ * @return The return code from the exec'd process.
+ */
+ private int run(Commandline cmd) {
+ try {
+ Execute exe = new Execute(new LogStreamHandler(this,
+ Project.MSG_INFO,
+ Project.MSG_WARN));
+
+ // If location of ss.ini is specified we need to set the
+ // environment-variable SSDIR to this value
+ if (serverPath != null) {
+ String[] env = exe.getEnvironment();
+ if (env == null) {
+ env = new String[0];
+ }
+ String[] newEnv = new String[env.length + 1];
+ System.arraycopy(env, 0, newEnv, 0, env.length);
+ newEnv[env.length] = "SSDIR=" + serverPath;
+
+ exe.setEnvironment(newEnv);
+ }
+
+ exe.setAntRun(getProject());
+ exe.setWorkingDirectory(getProject().getBaseDir());
+ exe.setCommandline(cmd.getCommandline());
+ // Use the OS launcher so we get environment variables
+ exe.setVMLauncher(false);
+ return exe.execute();
+ } catch (IOException e) {
+ throw new BuildException(e, getLocation());
+ }
+ }
+
+ /**
+ * Calculates the start date for version comparison.
+ * <p>
+ * Calculates the date numDay days earlier than startdate.
+ * @param startDate The start date.
+ * @param daysToAdd The number of days to add.
+ * @return The calculated date.
+ * @throws ParseException
+ */
+ private String calcDate(String startDate, int daysToAdd) throws ParseException {
+ Calendar calendar = new GregorianCalendar();
+ Date currentDate = dateFormat.parse(startDate);
+ calendar.setTime(currentDate);
+ calendar.add(Calendar.DATE, daysToAdd);
+ return dateFormat.format(calendar.getTime());
+ }
+
+ /**
+ * Changes the password to '***' so it isn't displayed on screen if the build fails
+ *
+ * @param cmd The command line to clean
+ * @return The command line as a string with out the password
+ */
+ private String formatCommandLine(Commandline cmd) {
+ StringBuffer sBuff = new StringBuffer(cmd.toString());
+ int indexUser = sBuff.substring(0).indexOf(FLAG_LOGIN);
+ if (indexUser > 0) {
+ int indexPass = sBuff.substring(0).indexOf(",", indexUser);
+ int indexAfterPass = sBuff.substring(0).indexOf(" ", indexPass);
+
+ for (int i = indexPass + 1; i < indexAfterPass; i++) {
+ sBuff.setCharAt(i, '*');
+ }
+ }
+ return sBuff.toString();
+ }
+
+ /**
+ * Extension of EnumeratedAttribute to hold the values for file time stamp.
+ */
+ public static class CurrentModUpdated extends EnumeratedAttribute {
+ /**
+ * Gets the list of allowable values.
+ * @return The values.
+ */
+ public String[] getValues() {
+ return new String[] {TIME_CURRENT, TIME_MODIFIED, TIME_UPDATED};
+ }
+ }
+
+ /**
+ * Extension of EnumeratedAttribute to hold the values for writable filess.
+ */
+ public static class WritableFiles extends EnumeratedAttribute {
+ /**
+ * Gets the list of allowable values.
+ * @return The values.
+ */
+ public String[] getValues() {
+ return new String[] {WRITABLE_REPLACE, WRITABLE_SKIP, WRITABLE_FAIL};
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java
new file mode 100644
index 00000000..0241ee3c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Performs Add commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vssadd" category="scm"
+ */
+public class MSVSSADD extends MSVSS {
+
+ private String localPath = null;
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ protected Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a localPath ...
+ if (getLocalpath() == null) {
+ String msg = "localPath attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got the format is
+ // ss Add VSS items [-B] [-C] [-D-] [-H] [-I-] [-K] [-N] [-O] [-R] [-W] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_ADD);
+
+ // VSS items
+ commandLine.createArgument().setValue(getLocalpath());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -R
+ commandLine.createArgument().setValue(getRecursive());
+ // -W
+ commandLine.createArgument().setValue(getWritable());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+ // -C
+ commandLine.createArgument().setValue(getComment());
+
+ return commandLine;
+ }
+
+ /**
+ * Returns the local path without the flag.; required
+ * @todo See why this returns the local path without the flag.
+ * @return The local path value.
+ */
+ protected String getLocalpath() {
+ return localPath;
+ }
+
+ /**
+ * Add files recursively. Defaults to false.
+ *
+ * @param recursive The boolean value for recursive.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Unset the READ-ONLY flag on local copies of files added to VSS. Defaults to false.
+ *
+ * @param writable The boolean value for writable.
+ */
+ public final void setWritable(boolean writable) {
+ super.setInternalWritable(writable);
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+
+ /**
+ * Comment to apply to files added to SourceSafe.
+ *
+ * @param comment The comment to apply in SourceSafe
+ */
+ public void setComment(String comment) {
+ super.setInternalComment(comment);
+ }
+
+ /**
+ * Override the project working directory.
+ *
+ * @param localPath The path on disk.
+ */
+ public void setLocalpath(Path localPath) {
+ this.localPath = localPath.toString();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java
new file mode 100644
index 00000000..f9521aa0
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Performs CheckIn commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsscheckin" category="scm"
+ */
+public class MSVSSCHECKIN extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ protected Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a vssdir ...
+ if (getVsspath() == null) {
+ String msg = "vsspath attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got the format is
+ // ss Checkin VSS items [-H] [-C] [-I-] [-N] [-O] [-R] [-W] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_CHECKIN);
+
+ // VSS items
+ commandLine.createArgument().setValue(getVsspath());
+ // -GL
+ commandLine.createArgument().setValue(getLocalpath());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -R
+ commandLine.createArgument().setValue(getRecursive());
+ // -W
+ commandLine.createArgument().setValue(getWritable());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+ // -C
+ commandLine.createArgument().setValue(getComment());
+
+ return commandLine;
+ }
+
+ /**
+ * Override the project working directory.
+ *
+ * @param localPath The path on disk.
+ */
+ public void setLocalpath(Path localPath) {
+ super.setInternalLocalPath(localPath.toString());
+ }
+
+ /**
+ * Check-in files recursively. Defaults to false.
+ *
+ * @param recursive The boolean value for recursive.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Unset the READ-ONLY flag on local copies of files checked-in to VSS.
+ * Defaults to false.
+ *
+ * @param writable The boolean value for writable.
+ */
+ public final void setWritable(boolean writable) {
+ super.setInternalWritable(writable);
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+
+ /**
+ * Comment to apply to files checked-in to SourceSafe.
+ *
+ * @param comment The comment to apply in SourceSafe
+ */
+ public void setComment(String comment) {
+ super.setInternalComment(comment);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java
new file mode 100644
index 00000000..edbcde96
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Performs CheckOut commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsscheckout" category="scm"
+ * @ant.attribute.group name="vdl" description="Only one of version, date or label"
+ */
+public class MSVSSCHECKOUT extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ protected Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a vssdir ...
+ if (getVsspath() == null) {
+ String msg = "vsspath attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got the format is
+ // ss Checkout VSS items [-G] [-C] [-H] [-I-] [-N] [-O] [-R] [-V] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_CHECKOUT);
+
+ // VSS items
+ commandLine.createArgument().setValue(getVsspath());
+ // -GL
+ commandLine.createArgument().setValue(getLocalpath());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -R
+ commandLine.createArgument().setValue(getRecursive());
+ // -V
+ commandLine.createArgument().setValue(getVersionDateLabel());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+ // -G
+ commandLine.createArgument().setValue(getFileTimeStamp());
+ // -GWS or -GWR
+ commandLine.createArgument().setValue(getWritableFiles());
+ // -G-
+ commandLine.createArgument().setValue(getGetLocalCopy());
+
+ return commandLine;
+ }
+
+ /**
+ * Override the project working directory.
+ *
+ * @param localPath The path on disk.
+ */
+ public void setLocalpath(Path localPath) {
+ super.setInternalLocalPath(localPath.toString());
+ }
+
+ /**
+ * Check-out files recursively. Defaults to false.
+ *
+ * @param recursive The boolean value for recursive.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Version to check-out.
+ *
+ * @param version The version to check-out.
+ *
+ * @ant.attribute group="vdl"
+ */
+ public void setVersion(String version) {
+ super.setInternalVersion(version);
+ }
+
+ /**
+ * Date to check-out.
+ *
+ * @param date The date to check-out.
+ *
+ * @ant.attribute group="vdl"
+ */
+ public void setDate(String date) {
+ super.setInternalDate(date);
+ }
+
+ /**
+ * Label to check-out.
+ *
+ * @param label The label to check-out.
+ *
+ * @ant.attribute group="vdl"
+ */
+ public void setLabel(String label) {
+ super.setInternalLabel(label);
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+
+ /**
+ * Date and time stamp given to the local copy. Defaults to <code>current</code>.
+ *
+ * @param timestamp The file time stamping behaviour.
+ */
+ public void setFileTimeStamp(CurrentModUpdated timestamp) {
+ super.setInternalFileTimeStamp(timestamp);
+ }
+
+ /**
+ * Action taken when local files are writable. Defaults to <code>fail</code>.
+ * <p>
+ * Due to ss.exe returning with an exit code of '100' for both errors and when
+ * a file has been skipped, <code>failonerror</code> is set to false when using
+ * the <code>skip</code> option.
+ * </p>
+ *
+ * @param files The writable files behaviour
+ */
+ public void setWritableFiles(WritableFiles files) {
+ super.setInternalWritableFiles(files);
+ }
+
+ /**
+ * Retrieve a local copy during a checkout. Defaults to true.
+ *
+ * @param get The get local copy behaviour
+ */
+ public void setGetLocalCopy(boolean get) {
+ super.setInternalGetLocalCopy(get);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java
new file mode 100644
index 00000000..ae2fcb7c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs CP (Change Project) commands to Microsoft Visual SourceSafe.
+ * <p>This task is typically used before a VssAdd in order to set the target project</p>
+ *
+ * @ant.task name="vsscp" category="scm"
+ */
+public class MSVSSCP extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ protected Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a vssdir ...
+ if (getVsspath() == null) {
+ String msg = "vsspath attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got the format is
+ // ss CP VSS items [-H] [-I-] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_CP);
+
+ // VSS items
+ commandLine.createArgument().setValue(getVsspath());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+
+ return commandLine;
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java
new file mode 100644
index 00000000..4f298c03
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Creates a new project in Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsscreate" category="scm"
+ */
+public class MSVSSCREATE extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a vssdir...
+ if (getVsspath() == null) {
+ String msg = "vsspath attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got
+ // the format is:
+ // ss Create VSS items [-C] [-H] [-I-] [-N] [-O] [-S] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_CREATE);
+
+ // VSS items
+ commandLine.createArgument().setValue(getVsspath());
+ // -C
+ commandLine.createArgument().setValue(getComment());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -O-
+ commandLine.createArgument().setValue(getQuiet());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+
+ return commandLine;
+ }
+
+ /**
+ * Comment to apply to the project created in SourceSafe.
+ *
+ * @param comment The comment to apply in SourceSafe
+ */
+ public void setComment(String comment) {
+ super.setInternalComment(comment);
+ }
+
+ /**
+ * Enable quiet mode. Defaults to false.
+ *
+ * @param quiet The boolean value for quiet.
+ */
+ public final void setQuiet (boolean quiet) {
+ super.setInternalQuiet(quiet);
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java
new file mode 100644
index 00000000..9e5ec606
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+/**
+ * Holds all the constants for the VSS tasks.
+ *
+ */
+// CheckStyle:InterfaceIsType OFF (bc)
+public interface MSVSSConstants {
+ /** Constant for the thing to execute */
+ String SS_EXE = "ss";
+ /** Dollar Sigh to prefix the project path */
+ String PROJECT_PREFIX = "$";
+
+ /** The 'CP' command */
+ String COMMAND_CP = "CP";
+ /** The 'Add' command */
+ String COMMAND_ADD = "Add";
+ /** The 'Get' command */
+ String COMMAND_GET = "Get";
+ /** The 'Checkout' command */
+ String COMMAND_CHECKOUT = "Checkout";
+ /** The 'Checkin' command */
+ String COMMAND_CHECKIN = "Checkin";
+ /** The 'Label' command */
+ String COMMAND_LABEL = "Label";
+ /** The 'History' command */
+ String COMMAND_HISTORY = "History";
+ /** The 'Create' command */
+ String COMMAND_CREATE = "Create";
+
+ /** The brief style flag */
+ String STYLE_BRIEF = "brief";
+ /** The codediff style flag */
+ String STYLE_CODEDIFF = "codediff";
+ /** The nofile style flag */
+ String STYLE_NOFILE = "nofile";
+ /** The default style flag */
+ String STYLE_DEFAULT = "default";
+
+ /** The text for current (default) timestamp */
+ String TIME_CURRENT = "current";
+ /** The text for modified timestamp */
+ String TIME_MODIFIED = "modified";
+ /** The text for updated timestamp */
+ String TIME_UPDATED = "updated";
+
+ /** The text for replacing writable files */
+ String WRITABLE_REPLACE = "replace";
+ /** The text for skipping writable files */
+ String WRITABLE_SKIP = "skip";
+ /** The text for failing on writable files */
+ String WRITABLE_FAIL = "fail";
+
+ /** -Y flag */
+ String FLAG_LOGIN = "-Y";
+ /** -GL flag */
+ String FLAG_OVERRIDE_WORKING_DIR = "-GL";
+ /** -I- flag */
+ String FLAG_AUTORESPONSE_DEF = "-I-";
+ /** -I-Y flag */
+ String FLAG_AUTORESPONSE_YES = "-I-Y";
+ /** -I-N flag */
+ String FLAG_AUTORESPONSE_NO = "-I-N";
+ /** -R flag */
+ String FLAG_RECURSION = "-R";
+ /** -V flag */
+ String FLAG_VERSION = "-V";
+ /** -Vd flag */
+ String FLAG_VERSION_DATE = "-Vd";
+ /** -VL flag */
+ String FLAG_VERSION_LABEL = "-VL";
+ /** -W flag */
+ String FLAG_WRITABLE = "-W";
+ /** -N flag */
+ String VALUE_NO = "-N";
+ /** -Y flag */
+ String VALUE_YES = "-Y";
+ /** -O- flag */
+ String FLAG_QUIET = "-O-";
+ /** -C flag */
+ String FLAG_COMMENT = "-C";
+ /** -L flag */
+ String FLAG_LABEL = "-L";
+ /** ~d flag */
+ String VALUE_FROMDATE = "~d";
+ /** ~L flag */
+ String VALUE_FROMLABEL = "~L";
+ /** -O flag */
+ String FLAG_OUTPUT = "-O";
+ /** -U flag */
+ String FLAG_USER = "-U";
+ /** -F- flag */
+ String FLAG_NO_FILE = "-F-";
+ /** -B flag */
+ String FLAG_BRIEF = "-B";
+ /** -D flag */
+ String FLAG_CODEDIFF = "-D";
+ /** -GTC flag */
+ String FLAG_FILETIME_DEF = "-GTC";
+ /** -GTM flag */
+ String FLAG_FILETIME_MODIFIED = "-GTM";
+ /** -GTU flag */
+ String FLAG_FILETIME_UPDATED = "-GTU";
+ /** -GWR flag */
+ String FLAG_REPLACE_WRITABLE = "-GWR";
+ /** -GWS flag */
+ String FLAG_SKIP_WRITABLE = "-GWS";
+ /** -G- flag */
+ String FLAG_NO_GET = "-G-";
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java
new file mode 100644
index 00000000..fd5ed096
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Perform Get commands from Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vssget" category="scm"
+ * @ant.attribute.group name="vdl" description="Only one of version, date or label"
+ */
+public class MSVSSGET extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // build the command line from what we got the format is
+ // ss Get VSS items [-G] [-H] [-I-] [-N] [-O] [-R] [-V] [-W] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_GET);
+
+ if (getVsspath() == null) {
+ throw new BuildException("vsspath attribute must be set!", getLocation());
+ }
+ commandLine.createArgument().setValue(getVsspath());
+
+ // -GL
+ commandLine.createArgument().setValue(getLocalpath());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -O-
+ commandLine.createArgument().setValue(getQuiet());
+ // -R
+ commandLine.createArgument().setValue(getRecursive());
+ // -V
+ commandLine.createArgument().setValue(getVersionDateLabel());
+ // -W
+ commandLine.createArgument().setValue(getWritable());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+ // -G
+ commandLine.createArgument().setValue(getFileTimeStamp());
+ // -GWS or -GWR
+ commandLine.createArgument().setValue(getWritableFiles());
+
+ return commandLine;
+ }
+
+ /**
+ * Override the project working directory.
+ *
+ * @param localPath The path on disk.
+ */
+ public void setLocalpath(Path localPath) {
+ super.setInternalLocalPath(localPath.toString());
+ }
+
+ /**
+ * Get files recursively. Defaults to false.
+ *
+ * @param recursive The boolean value for recursive.
+ */
+ public final void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Enable quiet mode. Defaults to false.
+ *
+ * @param quiet The boolean value for quiet.
+ */
+ public final void setQuiet (boolean quiet) {
+ super.setInternalQuiet(quiet);
+ }
+
+ /**
+ * Unset the READ-ONLY flag on files retrieved from VSS. Defaults to false.
+ *
+ * @param writable The boolean value for writable.
+ */
+ public final void setWritable(boolean writable) {
+ super.setInternalWritable(writable);
+ }
+
+ /**
+ * Version to get.
+ *
+ * @param version The version to get.
+ *
+ * @ant.attribute group="vdl"
+ */
+ public void setVersion(String version) {
+ super.setInternalVersion(version);
+ }
+
+ /**
+ * Date to get.
+ *
+ * @param date The date to get.
+ *
+ * @ant.attribute group="vdl"
+ */
+ public void setDate(String date) {
+ super.setInternalDate(date);
+ }
+
+ /**
+ * Label to get.
+ *
+ * @param label The label to get.
+ *
+ * @ant.attribute group="vdl"
+ */
+ public void setLabel(String label) {
+ super.setInternalLabel(label);
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+
+ /**
+ * Date and time stamp given to the local copy. Defaults to <code>current</code>.
+ *
+ * @param timestamp The file time stamping behaviour.
+ */
+ public void setFileTimeStamp(CurrentModUpdated timestamp) {
+ super.setInternalFileTimeStamp(timestamp);
+ }
+
+ /**
+ * Action taken when local files are writable. Defaults to <code>fail</code>.
+ * <p>
+ * Due to ss.exe returning with an exit code of '100' for both errors and when
+ * a file has been skipped, <code>failonerror</code> is set to false when using
+ * the <code>skip</code> option.
+ *
+ * @param files The action to take.
+ */
+ public void setWritableFiles(WritableFiles files) {
+ super.setInternalWritableFiles(files);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java
new file mode 100644
index 00000000..05ec91c2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Performs History commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsshistory" category="scm"
+ */
+public class MSVSSHISTORY extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a vssdir and a label ...
+ if (getVsspath() == null) {
+ String msg = "vsspath attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got the format is
+ // ss History elements [-H] [-L] [-N] [-O] [-V] [-Y] [-#] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_HISTORY);
+
+ // VSS items
+ commandLine.createArgument().setValue(getVsspath());
+ // -I-
+ commandLine.createArgument().setValue(FLAG_AUTORESPONSE_DEF); // ignore all errors
+ // -Vd
+ commandLine.createArgument().setValue(getVersionDate());
+ // -VL
+ commandLine.createArgument().setValue(getVersionLabel());
+ // -R
+ commandLine.createArgument().setValue(getRecursive());
+ // -B / -D / -F-
+ commandLine.createArgument().setValue(getStyle());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+ // -O
+ commandLine.createArgument().setValue(getOutput());
+
+ return commandLine;
+ }
+
+ /**
+ * Retrieve history recursively. Defaults to false.
+ *
+ * @param recursive The boolean value for recursive.
+ */
+ public void setRecursive(boolean recursive) {
+ super.setInternalRecursive(recursive);
+ }
+
+ /**
+ * Name of the user whose change history is generated.
+ *
+ * @param user The username.
+ */
+ public void setUser(String user) {
+ super.setInternalUser(user);
+ }
+
+ /**
+ * Date representing the 'start' of the range.
+ *
+ * @param fromDate The start date.
+ */
+ public void setFromDate(String fromDate) {
+ super.setInternalFromDate(fromDate);
+ }
+
+ /**
+ * Date representing the 'end' of the range.
+ *
+ * @param toDate The end date.
+ */
+ public void setToDate(String toDate) {
+ super.setInternalToDate(toDate);
+ }
+
+ /**
+ * Label representing the 'start' of the range.
+ *
+ * @param fromLabel The start label.
+ */
+ public void setFromLabel(String fromLabel) {
+ super.setInternalFromLabel(fromLabel);
+ }
+
+ /**
+ * Label representing the 'end' of the range.
+ *
+ * @param toLabel The end label.
+ */
+ public void setToLabel(String toLabel) {
+ super.setInternalToLabel(toLabel);
+ }
+
+ /**
+ * Number of days for comparison.
+ * Defaults to 2 days.
+ *
+ * @param numd The number of days.
+ */
+ public void setNumdays(int numd) {
+ super.setInternalNumDays(numd);
+ }
+
+ /**
+ * Output file name for the history.
+ *
+ * @param outfile The output file name.
+ */
+ public void setOutput(File outfile) {
+ if (outfile != null) {
+ super.setInternalOutputFilename(outfile.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Format of dates in <code>fromDate</code and <code>toDate</code>.
+ * Used when calculating dates with the numdays attribute.
+ * This string uses the formatting rules of <code>SimpleDateFormat</code>.
+ * Defaults to <code>DateFormat.SHORT</code>.
+ *
+ * @param dateFormat The date format.
+ */
+ public void setDateFormat(String dateFormat) {
+ super.setInternalDateFormat(new SimpleDateFormat(dateFormat));
+ }
+
+ /**
+ * Output style. Valid options are:
+ * <ul>
+ * <li>brief: -B Display a brief history.
+ * <li>codediff: -D Display line-by-line file changes.
+ * <li>nofile: -F- Do not display individual file updates in the project history.
+ * <li>default: No option specified. Display in Source Safe's default format.
+ * </ul>
+ *
+ * @param attr The history style:
+ */
+ public void setStyle(BriefCodediffNofile attr) {
+ String option = attr.getValue();
+ if (option.equals(STYLE_BRIEF)) {
+ super.setInternalStyle(FLAG_BRIEF);
+ } else if (option.equals(STYLE_CODEDIFF)) {
+ super.setInternalStyle(FLAG_CODEDIFF);
+ } else if (option.equals(STYLE_DEFAULT)) {
+ super.setInternalStyle("");
+ } else if (option.equals(STYLE_NOFILE)) {
+ super.setInternalStyle(FLAG_NO_FILE);
+ } else {
+ throw new BuildException("Style " + attr + " unknown.", getLocation());
+ }
+ }
+
+ /**
+ * Extension of EnumeratedAttribute to hold the values for style.
+ */
+ public static class BriefCodediffNofile extends EnumeratedAttribute {
+ /**
+ * Gets the list of allowable values.
+ * @return The values.
+ */
+ public String[] getValues() {
+ return new String[] {STYLE_BRIEF, STYLE_CODEDIFF, STYLE_NOFILE, STYLE_DEFAULT};
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java
new file mode 100644
index 00000000..4ba9d7b3
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs Label commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsslabel" category="scm"
+ */
+public class MSVSSLABEL extends MSVSS {
+
+ /**
+ * Builds a command line to execute ss.
+ * @return The constructed commandline.
+ */
+ Commandline buildCmdLine() {
+ Commandline commandLine = new Commandline();
+
+ // first off, make sure that we've got a command and a vssdir and a label ...
+ if (getVsspath() == null) {
+ throw new BuildException("vsspath attribute must be set!", getLocation());
+ }
+
+ String label = getLabel();
+ if (label.equals("")) {
+ String msg = "label attribute must be set!";
+ throw new BuildException(msg, getLocation());
+ }
+
+ // build the command line from what we got the format is
+ // ss Label VSS items [-C] [-H] [-I-] [-Llabel] [-N] [-O] [-V] [-Y] [-?]
+ // as specified in the SS.EXE help
+ commandLine.setExecutable(getSSCommand());
+ commandLine.createArgument().setValue(COMMAND_LABEL);
+
+ // VSS items
+ commandLine.createArgument().setValue(getVsspath());
+ // -C
+ commandLine.createArgument().setValue(getComment());
+ // -I- or -I-Y or -I-N
+ commandLine.createArgument().setValue(getAutoresponse());
+ // -L Specify the new label on the command line (instead of being prompted)
+ commandLine.createArgument().setValue(label);
+ // -V Label an existing file or project version
+ commandLine.createArgument().setValue(getVersion());
+ // -Y
+ commandLine.createArgument().setValue(getLogin());
+
+ return commandLine;
+ }
+
+ /**
+ * Label to apply in SourceSafe.
+ *
+ * @param label The label to apply.
+ *
+ * @ant.attribute group="required"
+ */
+ public void setLabel(String label) {
+ super.setInternalLabel(label);
+ }
+
+ /**
+ * Version to label.
+ *
+ * @param version The version to label.
+ */
+ public void setVersion(String version) {
+ super.setInternalVersion(version);
+ }
+
+ /**
+ * Comment to apply to files labeled in SourceSafe.
+ *
+ * @param comment The comment to apply in SourceSafe
+ */
+ public void setComment(String comment) {
+ super.setInternalComment(comment);
+ }
+
+ /**
+ * Autoresponce behaviour. Valid options are Y and N.
+ *
+ * @param response The auto response value.
+ */
+ public void setAutoresponse(String response) {
+ super.setInternalAutoResponse(response);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java
new file mode 100644
index 00000000..e0291914
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.windows;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.ExecuteOn;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Attrib equivalent for Win32 environments.
+ * Note: Attrib parameters /S and /D are not handled.
+ *
+ * @since Ant 1.6
+ */
+public class Attrib extends ExecuteOn {
+
+ private static final String ATTR_READONLY = "R";
+ private static final String ATTR_ARCHIVE = "A";
+ private static final String ATTR_SYSTEM = "S";
+ private static final String ATTR_HIDDEN = "H";
+ private static final String SET = "+";
+ private static final String UNSET = "-";
+
+ private boolean haveAttr = false;
+
+ /** Constructor for Attrib. */
+ public Attrib() {
+ super.setExecutable("attrib");
+ super.setParallel(false);
+ }
+
+ /**
+ * A file to be attribed.
+ * @param src a file
+ */
+ public void setFile(File src) {
+ FileSet fs = new FileSet();
+ fs.setFile(src);
+ addFileset(fs);
+ }
+
+ /**
+ * Set the ReadOnly file attribute.
+ * @param value a <code>boolean</code> value
+ */
+ public void setReadonly(boolean value) {
+ addArg(value, ATTR_READONLY);
+ }
+
+ /**
+ * Set the Archive file attribute.
+ * @param value a <code>boolean</code> value
+ */
+ public void setArchive(boolean value) {
+ addArg(value, ATTR_ARCHIVE);
+ }
+
+ /**
+ * Set the System file attribute.
+ * @param value a <code>boolean</code> value
+ */
+ public void setSystem(boolean value) {
+ addArg(value, ATTR_SYSTEM);
+ }
+
+ /**
+ * Set the Hidden file attribute.
+ * @param value a <code>boolean</code> value
+ */
+ public void setHidden(boolean value) {
+ addArg(value, ATTR_HIDDEN);
+ }
+
+ /**
+ * Check the attributes.
+ */
+ protected void checkConfiguration() {
+ if (!haveAttr()) {
+ throw new BuildException("Missing attribute parameter",
+ getLocation());
+ }
+ super.checkConfiguration();
+ }
+
+ /**
+ * Set the executable.
+ * This is not allowed, and it always throws a BuildException.
+ * @param e ignored
+ * @ant.attribute ignore="true"
+ */
+ public void setExecutable(String e) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the executable attribute", getLocation());
+ }
+
+ /**
+ * Set the executable.
+ * This is not allowed, and it always throws a BuildException.
+ * @param e ignored
+ * @ant.attribute ignore="true"
+ */
+ public void setCommand(String e) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the command attribute", getLocation());
+ }
+
+ /**
+ * Add source file.
+ * This is not allowed, and it always throws a BuildException.
+ * @param b ignored
+ * @ant.attribute ignore="true"
+ */
+ public void setAddsourcefile(boolean b) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the addsourcefile attribute", getLocation());
+ }
+
+ /**
+ * Set skip empty file sets.
+ * This is not allowed, and it always throws a BuildException.
+ * @param skip ignored
+ * @ant.attribute ignore="true"
+ */
+ public void setSkipEmptyFilesets(boolean skip) {
+ throw new BuildException(getTaskType() + " doesn\'t support the "
+ + "skipemptyfileset attribute",
+ getLocation());
+ }
+
+ /**
+ * Set parallel.
+ * This is not allowed, and it always throws a BuildException.
+ * @param parallel ignored
+ * @ant.attribute ignore="true"
+ */
+ public void setParallel(boolean parallel) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the parallel attribute",
+ getLocation());
+ }
+
+ /**
+ * Set max parallel.
+ * This is not allowed, and it always throws a BuildException.
+ * @param max ignored
+ * @ant.attribute ignore="true"
+ */
+ public void setMaxParallel(int max) {
+ throw new BuildException(getTaskType()
+ + " doesn\'t support the maxparallel attribute",
+ getLocation());
+ }
+
+ /**
+ * Check if the os is valid.
+ * Default is to allow windows
+ * @return true if the os is valid.
+ */
+ protected boolean isValidOs() {
+ return getOs() == null && getOsFamily() == null ?
+ Os.isFamily(Os.FAMILY_WINDOWS) : super.isValidOs();
+ }
+
+ private static String getSignString(boolean attr) {
+ return (attr ? SET : UNSET);
+ }
+
+ private void addArg(boolean sign, String attribute) {
+ createArg().setValue(getSignString(sign) + attribute);
+ haveAttr = true;
+ }
+
+ private boolean haveAttr() {
+ return haveAttr;
+ }
+
+}